]> jfr.im git - irc/quakenet/newserv.git/blob - xsb/xsb-preircd.c
trusts changes
[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 "xsb.h"
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 CommandTree *cmds;
27
28 struct messagequeue {
29 struct messagequeue *next;
30 long numeric;
31 char buf[];
32 };
33
34 struct messagequeue *head, *tail;
35
36 static nick *xsbnick;
37 static void *xsbnicksched;
38
39 static void handler(nick *target, int messagetype, void **args);
40 static void flushqueue(void);
41
42 static 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
57 static 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
68 void _init(void) {
69 const char **p;
70 array *servicemasks;
71
72 cmds = newcommandtree();
73 if(!cmds)
74 return;
75
76 xsbnicksched = scheduleoneshot(time(NULL)+1, setuplocaluser, NULL);
77
78 registerhook(HOOK_NICK_MASKPRIVMSG, &handlemaskprivmsg);
79
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)
91 Error("xsb", ERR_WARNING, "No service masks in config file (xsb/servicemask), using defaults.");
92 }
93
94 void _fini(void) {
95 int i;
96 struct messagequeue *q, *nq;
97
98 if(xsbnick)
99 deregisterlocaluser(xsbnick, NULL);
100
101 if(xsbnicksched)
102 deleteschedule(xsbnicksched, setuplocaluser, NULL);
103
104 if(!cmds)
105 return;
106
107 destroycommandtree(cmds);
108
109 deregisterhook(HOOK_NICK_MASKPRIVMSG, &handlemaskprivmsg);
110
111 for(i=0;i<defaultservicemasks_a.cursi;i++)
112 freesstring(defaultservicemasks[i]);
113 array_free(&defaultservicemasks_a);
114
115 for(q=head;q;q=nq) {
116 nq = q->next;
117 free(q);
118 }
119
120 head = NULL;
121 tail = NULL;
122 }
123
124 void xsb_addcommand(const char *name, const int maxparams, CommandHandler handler) {
125 addcommandtotree(cmds, name, 0, maxparams, handler);
126 }
127
128 void xsb_delcommand(const char *name, CommandHandler handler) {
129 deletecommandfromtree(cmds, name, handler);
130 }
131
132 static 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
160 #ifndef XSB_DEBUG
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
179 static void directsend(struct messagequeue *q) {
180 nick *np = getnickbynumeric(q->numeric);
181 if(!np || !IsOper(np) || !IsService(np))
182 return;
183
184 #ifndef XSB_DEBUG
185 if(!(serverlist[homeserver(np->numeric)].flags & SMODE_SERVICE))
186 return;
187 #endif
188
189 sendmessagetouser(xsbnick, np, "XSB1 %s", q->buf);
190 }
191
192 static void flushqueue(void) {
193 struct messagequeue *q, *nq;
194
195 for(q=head;q;q=nq) {
196 nq = q->next;
197
198 directsend(q);
199 free(q);
200 }
201 head = NULL;
202 tail = NULL;
203 }
204
205 static 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
215 static void xsb_send(nick *target, const char *format, ...) {
216 char buf[512];
217 va_list va;
218 size_t len;
219 struct messagequeue *q;
220
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);
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);
235 } else {
236 q->next = NULL;
237 if(tail) {
238 tail->next = q;
239 } else {
240 head = q;
241 }
242 tail = q;
243 }
244 }
245
246 void xsb_broadcast(const char *command, server *service, const char *format, ...) {
247 char buf[512];
248 va_list va;
249 sstring **servicemasks;
250 int i, j;
251 nick *np;
252 unsigned int marker;
253
254 va_start(va, format);
255 vsnprintf(buf, sizeof(buf), format, va);
256 va_end(va);
257
258 if(service) {
259 np = getnickbynick(servicenick(service->name->content));
260 if(!np)
261 return;
262
263 xsb_send(np, "%s %s", command, buf);
264 return;
265 }
266
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
275 if(!match(mask, serverlist[j].name->content)) {
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 }
284 }
285
286 void 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);
293
294 xsb_send(np, "%s %s", command, buf);
295 }
296
297 int 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
312 static 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 }