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