- I forgot to add new file to cvs repo during my last commit, I'm sorry
[blender.git] / extern / verse / dist / vs_master.c
1 /*
2  * Master server communication code.
3 */
4
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "verse.h"
9 #include "v_util.h"
10 #include "vs_server.h"
11
12 #define MASTER_SERVER_PERIOD    (60.0)  /* Period between ANNOUNCE to master server, in seconds. */
13
14 static struct {
15         boolean         enabled;
16         boolean         started;
17         const char      *master;
18         char            desc[64];
19         const char      *tags;
20         VUtilTimer      timer;
21 } server_info;
22
23 #define LEFT(d) (sizeof server_info.desc - (d - server_info.desc) - 1)
24
25 void vs_master_set_enabled(boolean enabled)
26 {
27         server_info.enabled = enabled;
28 }
29
30 const char * vs_master_get_address(void)
31 {
32         return server_info.master;
33 }
34
35 void vs_master_set_address(const char *address)
36 {
37         server_info.master = address;
38 }
39
40 void vs_master_set_desc(const char *desc)
41 {
42         const char      *src = desc;
43         char            *dst = server_info.desc;
44
45         for(; *src != '\0' && LEFT(dst) > 0;)
46         {
47                 if(*src == '"')
48                 {
49                         if(LEFT(dst) < 2)
50                                 break;
51                         *dst++ = '\\';
52                 }
53                 else if(*src == '\\')
54                 {
55                         if(LEFT(dst) < 2)
56                                 break;
57                         *dst++ = '\\';
58                 }
59                 *dst++ = *src++;
60         }
61         *dst = '\0';
62 }
63
64 void vs_master_set_tags(const char *tags)
65 {
66         server_info.tags = tags;        /* This needs more protection, instead of relying on the master server. */
67 }
68
69 void vs_master_update(void)
70 {
71         if(!server_info.enabled || server_info.master == NULL)
72                 return;
73
74         if(!server_info.started)
75         {
76                 v_timer_start(&server_info.timer);
77                 v_timer_advance(&server_info.timer, MASTER_SERVER_PERIOD);
78                 server_info.started = TRUE;
79                 return;
80         }
81         if(v_timer_elapsed(&server_info.timer) < MASTER_SERVER_PERIOD)
82                 return;
83         verse_send_ping(server_info.master, "MS:ANNOUNCE");
84         v_timer_start(&server_info.timer);
85 /*      printf("MS:ANNOUNCE sent to %s\n", server_info.master);*/
86 }
87
88 /* Check if a description request, of the form "A,B,C,...,D" includes the given keyword. This needs to
89  * do more than just a simple strstr(), since the keyword may be a prefix. Shades of OpenGL extensions.
90 */
91 static int desc_has_keyword(const char *desc, const char *keyword)
92 {
93         const char      *ptr;
94
95         if(desc == NULL || *desc == '\0')       /* Quick-check for empty description. */
96                 return 0;
97
98         if((ptr = strstr(desc, keyword)) != NULL)
99         {
100                 size_t  kl = strlen(keyword);
101
102                 return ptr[kl] == ',' || ptr[kl] == '\0';
103         }
104         return 0;
105 }
106
107 static int keyword_fits(size_t used, size_t max, const char *key, const char *value)
108 {
109         size_t  vsize = 0;
110
111         if(key != NULL && value != NULL)
112                 vsize += 1 + strlen(key) + 1 + 1 + strlen(value) + 1;
113
114         return max - 1 - used >= vsize;
115 }
116
117 static char * append_desc(char *buf, const char *key, const char *value)
118 {
119         return buf + sprintf(buf, " %s=\"%s\"", key, value);
120 }
121
122 void vs_master_handle_describe(const char *address, const char *message)
123 {
124         char    desc[1380] = "DESCRIPTION", *put = desc + 11;
125
126         if(desc_has_keyword(message, "DE") && server_info.desc != NULL && keyword_fits(put - desc, sizeof desc, "DE", server_info.desc))
127                 put = append_desc(put, "DE", server_info.desc);
128         if(desc_has_keyword(message, "TA") && server_info.tags != NULL && keyword_fits(put - desc, sizeof desc, "TA", server_info.tags))
129                 put = append_desc(put, "TA", server_info.tags);
130         verse_send_ping(address, desc);
131 }