]>
Commit | Line | Data |
---|---|---|
1 | /* TODO: catch control messages */ | |
2 | ||
3 | #include <string.h> | |
4 | #include <stdio.h> | |
5 | #include <stdarg.h> | |
6 | #include "../core/hooks.h" | |
7 | #include "../lib/splitline.h" | |
8 | #include "../core/config.h" | |
9 | #include "../irc/irc.h" | |
10 | #include "../lib/array.h" | |
11 | #include "../lib/base64.h" | |
12 | #include "../lib/irc_string.h" | |
13 | #include "../core/error.h" | |
14 | #include "../localuser/localuser.h" | |
15 | #include "../lib/strlfunc.h" | |
16 | #include "xsb.h" | |
17 | ||
18 | #undef XSB_DEBUG | |
19 | ||
20 | static const char *DEFAULT_SERVICE_MASKS[] = { "services*.*.quakenet.org", (char *)0 }; | |
21 | ||
22 | static array defaultservicemasks_a; | |
23 | static sstring **defaultservicemasks; | |
24 | ||
25 | static void handlemaskprivmsg(int, void *); | |
26 | static void handlecontrolregistered(int, void *); | |
27 | static CommandTree *cmds; | |
28 | ||
29 | static char controlnum[6]; | |
30 | ||
31 | struct messagequeue { | |
32 | struct messagequeue *next; | |
33 | char buf[]; | |
34 | }; | |
35 | ||
36 | struct messagequeue *head, *tail; | |
37 | ||
38 | void _init(void) { | |
39 | const char **p; | |
40 | array *servicemasks; | |
41 | ||
42 | controlnum[0] = '\0'; | |
43 | ||
44 | cmds = newcommandtree(); | |
45 | if(!cmds) | |
46 | return; | |
47 | ||
48 | registerhook(HOOK_NICK_MASKPRIVMSG, &handlemaskprivmsg); | |
49 | registerhook(HOOK_CONTROL_REGISTERED, &handlecontrolregistered); | |
50 | ||
51 | array_init(&defaultservicemasks_a, sizeof(sstring *)); | |
52 | ||
53 | for(p=DEFAULT_SERVICE_MASKS;*p;p++) { | |
54 | int i = array_getfreeslot(&defaultservicemasks_a); | |
55 | defaultservicemasks = (sstring **)defaultservicemasks_a.content; | |
56 | ||
57 | defaultservicemasks[i] = getsstring(*p, strlen(*p)); | |
58 | } | |
59 | ||
60 | servicemasks = getconfigitems("xsb", "servicemask"); | |
61 | if(!servicemasks || !servicemasks->cursi) | |
62 | Error("xsb", ERR_WARNING, "No service masks in config file (xsb/servicemask), using defaults"); | |
63 | } | |
64 | ||
65 | void _fini(void) { | |
66 | int i; | |
67 | struct messagequeue *q, *nq; | |
68 | ||
69 | if(!cmds) | |
70 | return; | |
71 | ||
72 | destroycommandtree(cmds); | |
73 | ||
74 | deregisterhook(HOOK_NICK_MASKPRIVMSG, &handlemaskprivmsg); | |
75 | deregisterhook(HOOK_CONTROL_REGISTERED, &handlecontrolregistered); | |
76 | ||
77 | for(i=0;i<defaultservicemasks_a.cursi;i++) | |
78 | freesstring(defaultservicemasks[i]); | |
79 | array_free(&defaultservicemasks_a); | |
80 | ||
81 | for(q=head;q;q=nq) { | |
82 | nq = q->next; | |
83 | free(q); | |
84 | } | |
85 | ||
86 | head = NULL; | |
87 | tail = NULL; | |
88 | } | |
89 | ||
90 | void xsb_addcommand(const char *name, const int maxparams, CommandHandler handler) { | |
91 | addcommandtotree(cmds, name, 0, maxparams, handler); | |
92 | } | |
93 | ||
94 | void xsb_delcommand(const char *name, CommandHandler handler) { | |
95 | deletecommandfromtree(cmds, name, handler); | |
96 | } | |
97 | ||
98 | static void handlemaskprivmsg(int hooknum, void *args) { | |
99 | void **hargs = (void **)args; | |
100 | nick *source = hargs[0]; | |
101 | char *message = hargs[2]; | |
102 | Command *cmd; | |
103 | int cargc; | |
104 | char *cargv[50]; | |
105 | server *s; | |
106 | ||
107 | if(!source) | |
108 | return; | |
109 | ||
110 | if(!IsOper(source) || !IsService(source)) | |
111 | return; | |
112 | ||
113 | cargc = splitline(message, cargv, 50, 0); | |
114 | if(cargc < 2) | |
115 | return; | |
116 | ||
117 | if(strcmp(cargv[0], "XSB1")) | |
118 | return; | |
119 | ||
120 | s = &serverlist[homeserver(source->numeric)]; | |
121 | if(s->linkstate != LS_LINKED) { | |
122 | Error("xsb", ERR_WARNING, "Got XSB message from unlinked server (%s): %s", s->name->content, source->nick); | |
123 | return; | |
124 | } | |
125 | ||
126 | #ifndef XSB_DEBUG | |
127 | if(!(s->flags & SMODE_SERVICE)) { | |
128 | Error("xsb", ERR_WARNING, "Got XSB message from non-service server (%s): %s", s->name->content, source->nick); | |
129 | return; | |
130 | } | |
131 | #endif | |
132 | ||
133 | cmd = findcommandintree(cmds, cargv[1], 1); | |
134 | if(!cmd) | |
135 | return; | |
136 | ||
137 | if(cmd->maxparams < (cargc - 2)) { | |
138 | rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams)); | |
139 | cargc = (cmd->maxparams) + 2; | |
140 | } | |
141 | ||
142 | (cmd->handler)(source, cargc - 2, &cargv[2]); | |
143 | } | |
144 | ||
145 | static void directsend(char *buf) { | |
146 | irc_send("%s P %s", controlnum, buf); | |
147 | } | |
148 | ||
149 | static void handlecontrolregistered(int hooknum, void *args) { | |
150 | nick *np = (nick *)args; | |
151 | ||
152 | if(np) { | |
153 | struct messagequeue *q, *nq; | |
154 | ||
155 | longtonumeric2(np->numeric, 5, controlnum); | |
156 | ||
157 | for(q=head;q;q=nq) { | |
158 | nq = q->next; | |
159 | ||
160 | directsend(q->buf); | |
161 | free(q); | |
162 | } | |
163 | head = NULL; | |
164 | tail = NULL; | |
165 | } else { | |
166 | controlnum[0] = '\0'; | |
167 | } | |
168 | } | |
169 | ||
170 | static int getservicemasks(sstring ***masks) { | |
171 | array *aservicemasks = getconfigitems("xsb", "servicemask"); | |
172 | if(!aservicemasks || !aservicemasks->cursi) | |
173 | aservicemasks = &defaultservicemasks_a; | |
174 | ||
175 | *masks = (sstring **)aservicemasks->content; | |
176 | ||
177 | return aservicemasks->cursi; | |
178 | } | |
179 | ||
180 | static void xsb_send(const char *format, ...) { | |
181 | char buf[512]; | |
182 | va_list va; | |
183 | size_t len; | |
184 | ||
185 | va_start(va, format); | |
186 | len = vsnprintf(buf, sizeof(buf), format, va); | |
187 | va_end(va); | |
188 | if(len >= sizeof(buf)) | |
189 | len = sizeof(buf); | |
190 | ||
191 | if(controlnum[0]) { | |
192 | directsend(buf); | |
193 | } else { | |
194 | struct messagequeue *q = (struct messagequeue *)malloc(sizeof(struct messagequeue) + len); | |
195 | ||
196 | strlcpy(q->buf, buf, len + 1); | |
197 | q->next = NULL; | |
198 | if(tail) { | |
199 | tail->next = q; | |
200 | } else { | |
201 | head = q; | |
202 | } | |
203 | tail = q; | |
204 | } | |
205 | } | |
206 | ||
207 | void xsb_broadcast(const char *command, server *service, const char *format, ...) { | |
208 | char buf[512]; | |
209 | va_list va; | |
210 | sstring **servicemasks; | |
211 | int i; | |
212 | ||
213 | va_start(va, format); | |
214 | vsnprintf(buf, sizeof(buf), format, va); | |
215 | va_end(va); | |
216 | ||
217 | if(service) { | |
218 | xsb_send("$%s :XSB1 %s %s", service->name->content, command, buf); | |
219 | return; | |
220 | } | |
221 | ||
222 | for(i=getservicemasks(&servicemasks)-1;i>=0;i--) | |
223 | xsb_send("$%s :XSB1 %s %s", servicemasks[i]->content, command, buf); | |
224 | } | |
225 | ||
226 | void xsb_unicast(const char *command, nick *np, const char *format, ...) { | |
227 | char buf[512]; | |
228 | va_list va; | |
229 | ||
230 | va_start(va, format); | |
231 | vsnprintf(buf, sizeof(buf), format, va); | |
232 | va_end(va); | |
233 | ||
234 | /* TODO */ | |
235 | xsb_send("$%s :XSB1 %s %s", serverlist[homeserver(np->numeric)].name, command, buf); | |
236 | /* xsb_send("%s :XSB1 %s %s", longtonumeric(np->numeric, 5), command, buf);*/ | |
237 | ||
238 | } | |
239 | ||
240 | int xsb_isservice(server *service) { | |
241 | int i; | |
242 | sstring **servicemasks; | |
243 | char *name = service->name->content; | |
244 | ||
245 | if(!(service->flags & SMODE_SERVICE)) | |
246 | return 0; | |
247 | ||
248 | for(i=getservicemasks(&servicemasks)-1;i>=0;i--) | |
249 | if(match2strings(servicemasks[i]->content, name)) | |
250 | return 1; | |
251 | ||
252 | return 0; | |
253 | } | |
254 |