]> jfr.im git - irc/quakenet/newserv.git/blob - xsb/xsb-preircd.c
BUILD: add require-all build mode
[irc/quakenet/newserv.git] / xsb / xsb-preircd.c
1 #include <string.h>
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include "../core/hooks.h"
5 #include "../lib/splitline.h"
6 #include "../core/config.h"
7 #include "../irc/irc.h"
8 #include "../lib/array.h"
9 #include "../lib/base64.h"
10 #include "../lib/irc_string.h"
11 #include "../core/error.h"
12 #include "../localuser/localuser.h"
13 #include "../lib/strlfunc.h"
14 #include "../lib/sha1.h"
15 #include "../irc/irc.h"
16 #include "../lib/hmac.h"
17 #include "../core/schedule.h"
18 #include "../lib/version.h"
19 #include "xsb.h"
20
21 MODULE_VERSION("");
22
23 static const char *DEFAULT_SERVICE_MASKS[] = { "services*.*.quakenet.org", (char *)0 };
24
25 static array defaultservicemasks_a;
26 static sstring **defaultservicemasks;
27
28 static void handlemaskprivmsg(int, void *);
29 static CommandTree *cmds;
30
31 struct messagequeue {
32 struct messagequeue *next;
33 long numeric;
34 char buf[];
35 };
36
37 struct messagequeue *head, *tail;
38
39 static nick *xsbnick;
40 static void *xsbnicksched;
41
42 static void handler(nick *target, int messagetype, void **args);
43 static void flushqueue(void);
44
45 static char *servicenick(char *server) {
46 static char nickbuf[NICKLEN+1];
47 char digest[SHA1_DIGESTSIZE*2+1];
48 unsigned char digestbuf[SHA1_DIGESTSIZE];
49 SHA1_CTX s;
50
51 SHA1Init(&s);
52 SHA1Update(&s, (unsigned char *)server, strlen(server));
53 SHA1Final(digestbuf, &s);
54
55 snprintf(nickbuf, sizeof(nickbuf), "XSB1-%s", hmac_printhex(digestbuf, digest, SHA1_DIGESTSIZE));
56
57 return nickbuf;
58 }
59
60 static void setuplocaluser(void *arg) {
61 xsbnicksched = NULL;
62
63 xsbnick = registerlocaluser(servicenick(myserver->content), "xsb", "xsb.quakenet.org", "eXtended service broadcast localuser (v1)", NULL, UMODE_OPER | UMODE_SERVICE | UMODE_INV, handler);
64 if(!xsbnick) {
65 xsbnicksched = scheduleoneshot(time(NULL)+1, setuplocaluser, NULL);
66 } else {
67 flushqueue();
68 }
69 }
70
71 void _init(void) {
72 const char **p;
73 array *servicemasks;
74
75 cmds = newcommandtree();
76 if(!cmds)
77 return;
78
79 xsbnicksched = scheduleoneshot(time(NULL)+1, setuplocaluser, NULL);
80
81 registerhook(HOOK_NICK_MASKPRIVMSG, &handlemaskprivmsg);
82
83 array_init(&defaultservicemasks_a, sizeof(sstring *));
84
85 for(p=DEFAULT_SERVICE_MASKS;*p;p++) {
86 int i = array_getfreeslot(&defaultservicemasks_a);
87 defaultservicemasks = (sstring **)defaultservicemasks_a.content;
88
89 defaultservicemasks[i] = getsstring(*p, strlen(*p));
90 }
91
92 servicemasks = getconfigitems("xsb", "servicemask");
93 if(!servicemasks || !servicemasks->cursi)
94 Error("xsb", ERR_WARNING, "No service masks in config file (xsb/servicemask), using defaults.");
95 }
96
97 void _fini(void) {
98 int i;
99 struct messagequeue *q, *nq;
100
101 if(xsbnick)
102 deregisterlocaluser(xsbnick, NULL);
103
104 if(xsbnicksched)
105 deleteschedule(xsbnicksched, setuplocaluser, NULL);
106
107 if(!cmds)
108 return;
109
110 destroycommandtree(cmds);
111
112 deregisterhook(HOOK_NICK_MASKPRIVMSG, &handlemaskprivmsg);
113
114 for(i=0;i<defaultservicemasks_a.cursi;i++)
115 freesstring(defaultservicemasks[i]);
116 array_free(&defaultservicemasks_a);
117
118 for(q=head;q;q=nq) {
119 nq = q->next;
120 free(q);
121 }
122
123 head = NULL;
124 tail = NULL;
125 }
126
127 void xsb_addcommand(const char *name, const int maxparams, CommandHandler handler) {
128 addcommandtotree(cmds, name, 0, maxparams, handler);
129 }
130
131 void xsb_delcommand(const char *name, CommandHandler handler) {
132 deletecommandfromtree(cmds, name, handler);
133 }
134
135 static void handlemaskprivmsg(int hooknum, void *args) {
136 void **hargs = (void **)args;
137 nick *source = hargs[0];
138 char *message = hargs[2];
139 Command *cmd;
140 int cargc;
141 char *cargv[50];
142 server *s;
143
144 if(!source)
145 return;
146
147 if(!IsOper(source) || !IsService(source))
148 return;
149
150 cargc = splitline(message, cargv, 50, 0);
151 if(cargc < 2)
152 return;
153
154 if(strcmp(cargv[0], "XSB1"))
155 return;
156
157 s = &serverlist[homeserver(source->numeric)];
158 if(s->linkstate != LS_LINKED) {
159 Error("xsb", ERR_WARNING, "Got XSB message from unlinked server (%s): %s", s->name->content, source->nick);
160 return;
161 }
162
163 #ifndef XSB_DEBUG
164 if(!(s->flags & SMODE_SERVICE)) {
165 Error("xsb", ERR_WARNING, "Got XSB message from non-service server (%s): %s", s->name->content, source->nick);
166 return;
167 }
168 #endif
169
170 cmd = findcommandintree(cmds, cargv[1], 1);
171 if(!cmd)
172 return;
173
174 if(cmd->maxparams < (cargc - 2)) {
175 rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams));
176 cargc = (cmd->maxparams) + 2;
177 }
178
179 (cmd->handler)(source, cargc - 2, &cargv[2]);
180 }
181
182 static void directsend(struct messagequeue *q) {
183 nick *np = getnickbynumeric(q->numeric);
184 if(!np || !IsOper(np) || !IsService(np))
185 return;
186
187 #ifndef XSB_DEBUG
188 if(!(serverlist[homeserver(np->numeric)].flags & SMODE_SERVICE))
189 return;
190 #endif
191
192 sendmessagetouser(xsbnick, np, "XSB1 %s", q->buf);
193 }
194
195 static void flushqueue(void) {
196 struct messagequeue *q, *nq;
197
198 for(q=head;q;q=nq) {
199 nq = q->next;
200
201 directsend(q);
202 free(q);
203 }
204 head = NULL;
205 tail = NULL;
206 }
207
208 static int getservicemasks(sstring ***masks) {
209 array *aservicemasks = getconfigitems("xsb", "servicemask");
210 if(!aservicemasks || !aservicemasks->cursi)
211 aservicemasks = &defaultservicemasks_a;
212
213 *masks = (sstring **)aservicemasks->content;
214
215 return aservicemasks->cursi;
216 }
217
218 static void xsb_send(nick *target, const char *format, ...) {
219 char buf[512];
220 va_list va;
221 size_t len;
222 struct messagequeue *q;
223
224 va_start(va, format);
225 len = vsnprintf(buf, sizeof(buf), format, va);
226 va_end(va);
227 if(len >= sizeof(buf))
228 len = sizeof(buf);
229
230 /* sucks */
231 q = (struct messagequeue *)malloc(sizeof(struct messagequeue) + len + 5);
232 q->numeric = target->numeric;
233 strlcpy(q->buf, buf, len + 2);
234
235 if(xsbnick) {
236 directsend(q);
237 free(q);
238 } else {
239 q->next = NULL;
240 if(tail) {
241 tail->next = q;
242 } else {
243 head = q;
244 }
245 tail = q;
246 }
247 }
248
249 void xsb_broadcast(const char *command, server *service, const char *format, ...) {
250 char buf[512];
251 va_list va;
252 sstring **servicemasks;
253 int i, j;
254 nick *np;
255 unsigned int marker;
256
257 va_start(va, format);
258 vsnprintf(buf, sizeof(buf), format, va);
259 va_end(va);
260
261 if(service) {
262 np = getnickbynick(servicenick(service->name->content));
263 if(!np)
264 return;
265
266 xsb_send(np, "%s %s", command, buf);
267 return;
268 }
269
270 marker = nextservermarker();
271
272 for(i=getservicemasks(&servicemasks)-1;i>=0;i--) {
273 char *mask = servicemasks[i]->content;
274 for(j=0;j<MAXSERVERS;j++) {
275 if(!serverlist[j].name || serverlist[j].marker == marker)
276 continue;
277
278 if(!match(mask, serverlist[j].name->content)) {
279 serverlist[j].marker = marker;
280
281 np = getnickbynick(servicenick(serverlist[j].name->content));
282 if(np)
283 xsb_send(np, "%s %s", command, buf);
284 }
285 }
286 }
287 }
288
289 void xsb_unicast(const char *command, nick *np, const char *format, ...) {
290 char buf[512];
291 va_list va;
292
293 va_start(va, format);
294 vsnprintf(buf, sizeof(buf), format, va);
295 va_end(va);
296
297 xsb_send(np, "%s %s", command, buf);
298 }
299
300 int xsb_isservice(server *service) {
301 int i;
302 sstring **servicemasks;
303 char *name = service->name->content;
304
305 if(!(service->flags & SMODE_SERVICE))
306 return 0;
307
308 for(i=getservicemasks(&servicemasks)-1;i>=0;i--)
309 if(match2strings(servicemasks[i]->content, name))
310 return 1;
311
312 return 0;
313 }
314
315 static void handler(nick *target, int messagetype, void **args) {
316 switch(messagetype) {
317 case LU_PRIVMSG: {
318 void *newargs[3];
319 nick *sender = args[0];
320 char *cargv = args[1];
321
322 newargs[0] = sender;
323 newargs[1] = NULL;
324 newargs[2] = cargv;
325
326 handlemaskprivmsg(0, newargs);
327 break;
328 }
329 case LU_KILLED:
330 xsbnick = NULL;
331 xsbnicksched = scheduleoneshot(time(NULL)+1, setuplocaluser, NULL);
332 break;
333 }
334 }