]> jfr.im git - irc/quakenet/newserv.git/blame - xsb/xsb-preircd.c
LUA: port luadb to dbapi2 to drop postgres dependency
[irc/quakenet/newserv.git] / xsb / xsb-preircd.c
CommitLineData
2172bfc8
CP
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"
4c551b15 10#include "../lib/irc_string.h"
2172bfc8 11#include "../core/error.h"
4c551b15
CP
12#include "../localuser/localuser.h"
13#include "../lib/strlfunc.h"
5b5aa98c
CP
14#include "../lib/sha1.h"
15#include "../irc/irc.h"
16#include "../lib/hmac.h"
17#include "../core/schedule.h"
7f32dbdf 18#include "../lib/version.h"
2172bfc8
CP
19#include "xsb.h"
20
7f32dbdf
P
21MODULE_VERSION("");
22
2172bfc8 23static const char *DEFAULT_SERVICE_MASKS[] = { "services*.*.quakenet.org", (char *)0 };
4c551b15 24
2172bfc8
CP
25static array defaultservicemasks_a;
26static sstring **defaultservicemasks;
27
28static void handlemaskprivmsg(int, void *);
29static CommandTree *cmds;
30
4c551b15
CP
31struct messagequeue {
32 struct messagequeue *next;
5b5aa98c 33 long numeric;
4c551b15
CP
34 char buf[];
35};
36
37struct messagequeue *head, *tail;
2172bfc8 38
5b5aa98c
CP
39static nick *xsbnick;
40static void *xsbnicksched;
41
42static void handler(nick *target, int messagetype, void **args);
43static void flushqueue(void);
44
45static 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
60static 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
2172bfc8
CP
71void _init(void) {
72 const char **p;
73 array *servicemasks;
74
75 cmds = newcommandtree();
4c551b15
CP
76 if(!cmds)
77 return;
5b5aa98c
CP
78
79 xsbnicksched = scheduleoneshot(time(NULL)+1, setuplocaluser, NULL);
4c551b15
CP
80
81 registerhook(HOOK_NICK_MASKPRIVMSG, &handlemaskprivmsg);
4c551b15 82
2172bfc8
CP
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)
5b5aa98c 94 Error("xsb", ERR_WARNING, "No service masks in config file (xsb/servicemask), using defaults.");
2172bfc8
CP
95}
96
97void _fini(void) {
98 int i;
4c551b15 99 struct messagequeue *q, *nq;
5b5aa98c
CP
100
101 if(xsbnick)
102 deregisterlocaluser(xsbnick, NULL);
103
104 if(xsbnicksched)
105 deleteschedule(xsbnicksched, setuplocaluser, NULL);
106
4c551b15
CP
107 if(!cmds)
108 return;
109
110 destroycommandtree(cmds);
111
112 deregisterhook(HOOK_NICK_MASKPRIVMSG, &handlemaskprivmsg);
2172bfc8
CP
113
114 for(i=0;i<defaultservicemasks_a.cursi;i++)
115 freesstring(defaultservicemasks[i]);
116 array_free(&defaultservicemasks_a);
117
4c551b15
CP
118 for(q=head;q;q=nq) {
119 nq = q->next;
120 free(q);
121 }
122
123 head = NULL;
124 tail = NULL;
125}
2172bfc8 126
4c551b15
CP
127void xsb_addcommand(const char *name, const int maxparams, CommandHandler handler) {
128 addcommandtotree(cmds, name, 0, maxparams, handler);
129}
2172bfc8 130
4c551b15
CP
131void xsb_delcommand(const char *name, CommandHandler handler) {
132 deletecommandfromtree(cmds, name, handler);
2172bfc8
CP
133}
134
135static 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
4c551b15 163#ifndef XSB_DEBUG
2172bfc8
CP
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
5b5aa98c
CP
182static void directsend(struct messagequeue *q) {
183 nick *np = getnickbynumeric(q->numeric);
184 if(!np || !IsOper(np) || !IsService(np))
185 return;
2172bfc8 186
5b5aa98c
CP
187#ifndef XSB_DEBUG
188 if(!(serverlist[homeserver(np->numeric)].flags & SMODE_SERVICE))
189 return;
190#endif
4c551b15 191
5b5aa98c
CP
192 sendmessagetouser(xsbnick, np, "XSB1 %s", q->buf);
193}
194
195static void flushqueue(void) {
196 struct messagequeue *q, *nq;
4c551b15 197
5b5aa98c
CP
198 for(q=head;q;q=nq) {
199 nq = q->next;
200
201 directsend(q);
202 free(q);
4c551b15 203 }
5b5aa98c
CP
204 head = NULL;
205 tail = NULL;
2172bfc8
CP
206}
207
4c551b15
CP
208static 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
5b5aa98c 218static void xsb_send(nick *target, const char *format, ...) {
4c551b15
CP
219 char buf[512];
220 va_list va;
221 size_t len;
5b5aa98c
CP
222 struct messagequeue *q;
223
4c551b15
CP
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);
5b5aa98c
CP
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);
4c551b15 238 } else {
4c551b15
CP
239 q->next = NULL;
240 if(tail) {
241 tail->next = q;
242 } else {
243 head = q;
244 }
245 tail = q;
246 }
247}
248
249void xsb_broadcast(const char *command, server *service, const char *format, ...) {
2172bfc8
CP
250 char buf[512];
251 va_list va;
252 sstring **servicemasks;
5b5aa98c
CP
253 int i, j;
254 nick *np;
255 unsigned int marker;
2172bfc8
CP
256
257 va_start(va, format);
258 vsnprintf(buf, sizeof(buf), format, va);
259 va_end(va);
260
4c551b15 261 if(service) {
5b5aa98c
CP
262 np = getnickbynick(servicenick(service->name->content));
263 if(!np)
264 return;
265
266 xsb_send(np, "%s %s", command, buf);
4c551b15
CP
267 return;
268 }
2172bfc8 269
5b5aa98c
CP
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
f139c388 278 if(!match(mask, serverlist[j].name->content)) {
5b5aa98c
CP
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 }
4c551b15 287}
2172bfc8 288
4c551b15
CP
289void 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);
2172bfc8 296
5b5aa98c 297 xsb_send(np, "%s %s", command, buf);
2172bfc8 298}
4c551b15
CP
299
300int 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
5b5aa98c
CP
315static 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}