1 /*
2 * Copyright (c) 2005-2006 William Pitcock, et al.
3 * Rights to this code are documented in doc/LICENSE.
4 *
5 * This file contains protocol support for P10 ircd's.
6 * Some sources used: Run's documentation, beware's description,
7 * raw data sent by nefarious.
8 *
9 */
10
11 #include "atheme.h"
12 #include "uplink.h"
13 #include "pmodule.h"
14 #include "protocol/nefarious.h"
15
16 DECLARE_MODULE_V1("protocol/nefarious", true, _modinit, NULL, PACKAGE_STRING, VENDOR_STRING);
17
18 /* *INDENT-OFF* */
19
20 ircd_t Nefarious = {
21 .ircdname = "Nefarious IRCU 0.4.0 or later",
22 .tldprefix = "$",
23 .uses_uid = true,
24 .uses_rcommand = false,
25 .uses_owner = false,
26 .uses_protect = false,
27 .uses_halfops = true,
28 .uses_p10 = true,
29 .uses_vhost = true,
30 .oper_only_modes = CMODE_PERM | CMODE_OPERONLY | CMODE_ADMONLY,
31 .owner_mode = 0,
32 .protect_mode = 0,
33 .halfops_mode = CSTATUS_HALFOP,
34 .owner_mchar = "+",
35 .protect_mchar = "+",
36 .halfops_mchar = "+",
37 .type = PROTOCOL_NEFARIOUS,
38 .perm_mode = CMODE_PERM,
39 .oimmune_mode = 0,
40 .ban_like_modes = "be",
41 .except_mchar = 'e',
42 .invex_mchar = 'e',
43 .flags = IRCD_CIDR_BANS,
44 };
45
46 struct cmode_ nefarious_mode_list[] = {
47 { 'a', CMODE_ADMONLY },
48 { 'i', CMODE_INVITE },
49 { 'm', CMODE_MOD },
50 { 'n', CMODE_NOEXT },
51 { 'p', CMODE_PRIV },
52 { 'r', CMODE_REGONLY },
53 { 's', CMODE_SEC },
54 { 't', CMODE_TOPIC },
55 { 'z', CMODE_PERM },
56 { 'c', CMODE_NOCOLOR },
57 { 'C', CMODE_NOCTCP },
58 { 'D', CMODE_DELAYED },
59 { 'Q', CMODE_NOQUIT },
60 { 'N', CMODE_NONOTICE },
61 { 'M', CMODE_SOFTMOD },
62 { 'C', CMODE_NOCTCP },
63 { 'S', CMODE_STRIP },
64 { 'T', CMODE_NOAMSG },
65 { 'O', CMODE_OPERONLY },
66 { 'L', CMODE_SOFTPRIV },
67 { 'Z', CMODE_SSLONLY },
68 { '\0', 0 }
69 };
70
71 struct extmode nefarious_ignore_mode_list[] = {
72 { '\0', 0 }
73 };
74
75 struct cmode_ nefarious_status_mode_list[] = {
76 { 'o', CSTATUS_OP },
77 { 'h', CSTATUS_HALFOP },
78 { 'v', CSTATUS_VOICE },
79 { '\0', 0 }
80 };
81
82 struct cmode_ nefarious_prefix_mode_list[] = {
83 { '@', CSTATUS_OP },
84 { '%', CSTATUS_HALFOP },
85 { '+', CSTATUS_VOICE },
86 { '\0', 0 }
87 };
88
89 struct cmode_ nefarious_user_mode_list[] = {
90 { 'a', UF_ADMIN },
91 { 'i', UF_INVIS },
92 { 'o', UF_IRCOP },
93 { 'd', UF_DEAF },
94 { 'k', UF_IMMUNE },
95 { '\0', 0 }
96 };
97
98 static void check_hidehost(user_t *u);
99
100 /* *INDENT-ON* */
101
102 /* join a channel */
nefarious_join_sts(channel_t * c,user_t * u,bool isnew,char * modes)103 static void nefarious_join_sts(channel_t *c, user_t *u, bool isnew, char *modes)
104 {
105 /* If the channel doesn't exist, we need to create it. */
106 if (isnew)
107 {
108 sts("%s C %s %lu", u->uid, c->name, (unsigned long)c->ts);
109 if (modes[0] && modes[1])
110 sts("%s M %s %s", u->uid, c->name, modes);
111 }
112 else
113 {
114 sts("%s J %s %lu", u->uid, c->name, (unsigned long)c->ts);
115 sts("%s M %s +o %s", u->uid, c->name, u->uid);
116 }
117 }
118
119 /* kicks a user from a channel */
nefarious_kick(user_t * source,channel_t * c,user_t * u,const char * reason)120 static void nefarious_kick(user_t *source, channel_t *c, user_t *u, const char *reason)
121 {
122 sts("%s K %s %s :%s", source->uid, c->name, u->uid, reason);
123
124 chanuser_delete(c, u);
125 }
126
127 /* NOTICE wrapper */
nefarious_notice_channel_sts(user_t * from,channel_t * target,const char * text)128 static void nefarious_notice_channel_sts(user_t *from, channel_t *target, const char *text)
129 {
130 sts("%s O %s :%s", from ? from->uid : me.numeric, target->name, text);
131 }
132
133 /* topic wrapper */
nefarious_topic_sts(channel_t * c,user_t * source,const char * setter,time_t ts,time_t prevts,const char * topic)134 static void nefarious_topic_sts(channel_t *c, user_t *source, const char *setter, time_t ts, time_t prevts, const char *topic)
135 {
136 return_if_fail(c != NULL);
137
138 /* for nefarious, set topicsetter iff we can set the proper topicTS */
139 if (ts > prevts || prevts == 0)
140 sts("%s T %s %s %lu %lu :%s", source->uid, c->name, setter, (unsigned long)c->ts, (unsigned long)ts, topic);
141 else
142 {
143 ts = CURRTIME;
144 if (ts < prevts)
145 ts = prevts + 1;
146 sts("%s T %s %lu %lu :%s", source->uid, c->name, (unsigned long)c->ts, (unsigned long)ts, topic);
147 c->topicts = ts;
148 }
149 }
150
151 /* protocol-specific stuff to do on login */
nefarious_on_login(user_t * u,myuser_t * mu,const char * wantedhost)152 static void nefarious_on_login(user_t *u, myuser_t *mu, const char *wantedhost)
153 {
154 return_if_fail(u != NULL);
155 return_if_fail(mu != NULL);
156
157 sts("%s AC %s R %s %lu", me.numeric, u->uid, entity(mu)->name,
158 (unsigned long)mu->registered);
159 check_hidehost(u);
160 }
161
162 /* P10 does not support logout, so kill the user
163 * we can't keep track of which logins are stale and which aren't -- jilles
164 * Except we can in Nefarious --nenolod
165 */
nefarious_on_logout(user_t * u,const char * account)166 static bool nefarious_on_logout(user_t *u, const char *account)
167 {
168 return_val_if_fail(u != NULL, false);
169
170 sts("%s AC %s U", me.numeric, u->uid);
171 if (u->flags & UF_HIDEHOSTREQ && me.hidehostsuffix != NULL &&
172 !strcmp(u->vhost + strlen(u->vhost) - strlen(me.hidehostsuffix), me.hidehostsuffix))
173 {
174 slog(LG_DEBUG, "nefarious_on_logout(): removing +x vhost for %s: %s -> %s",
175 u->nick, u->vhost, u->host);
176
177 strshare_unref(u->vhost);
178 u->vhost = strshare_get(u->host);
179 }
180
181 return false;
182 }
183
nefarious_sasl_sts(char * target,char mode,char * data)184 static void nefarious_sasl_sts(char *target, char mode, char *data)
185 {
186 sts("%s SASL %c%c %s %c %s", me.numeric, target[0], target[1], target, mode, data);
187 }
188
nefarious_svslogin_sts(char * target,char * nick,char * user,char * host,myuser_t * account)189 static void nefarious_svslogin_sts(char *target, char *nick, char *user, char *host, myuser_t *account)
190 {
191 sts("%s SASL %c%c %s L %s %lu", me.numeric, target[0], target[1], target,
192 entity(account)->name, (unsigned long)account->registered);
193 }
194
nefarious_sethost_sts(user_t * source,user_t * target,const char * host)195 static void nefarious_sethost_sts(user_t *source, user_t *target, const char *host)
196 {
197 sts("%s FA %s %s", me.numeric, target->uid, host);
198 /* need to set +x; this will be echoed */
199 if (!(target->flags & UF_HIDEHOSTREQ))
200 sts("%s M %s +x", me.numeric, target->uid);
201 }
202
nefarious_quarantine_sts(user_t * source,user_t * victim,long duration,const char * reason)203 static void nefarious_quarantine_sts(user_t *source, user_t *victim, long duration, const char *reason)
204 {
205 sts("%s SU * +*@%s %lu :%s", me.numeric, victim->host, CURRTIME + duration, reason);
206 }
207
m_topic(sourceinfo_t * si,int parc,char * parv[])208 static void m_topic(sourceinfo_t *si, int parc, char *parv[])
209 {
210 channel_t *c = channel_find(parv[0]);
211 const char *source;
212 time_t ts = 0;
213
214 if (!c)
215 return;
216
217 if (si->s != NULL)
218 source = si->s->name;
219 else
220 source = si->su->nick;
221
222 if (parc > 2)
223 ts = atoi(parv[parc - 2]);
224 if (ts == 0)
225 ts = CURRTIME;
226 else if (c->topic != NULL && ts < c->topicts)
227 return;
228 handle_topic_from(si, c, parc > 4 ? parv[parc - 4] : source, ts, parv[parc - 1]);
229 }
230
m_burst(sourceinfo_t * si,int parc,char * parv[])231 static void m_burst(sourceinfo_t *si, int parc, char *parv[])
232 {
233 channel_t *c;
234 unsigned int modec;
235 char *modev[16];
236 unsigned int userc;
237 char *userv[256];
238 unsigned int i;
239 int j;
240 char prefix[16];
241 char newnick[16+NICKLEN];
242 char *p;
243 time_t ts;
244 int bantype;
245
246 /* S BURST <channel> <ts> [parameters]
247 * parameters can be:
248 * +<simple mode>
249 * %<bans separated with spaces>
250 * <nicks>
251 */
252 ts = atoi(parv[1]);
253
254 c = channel_find(parv[0]);
255
256 if (c == NULL)
257 {
258 slog(LG_DEBUG, "m_burst(): new channel: %s", parv[0]);
259 c = channel_add(parv[0], ts, si->s);
260 }
261 else if (ts < c->ts)
262 {
263 chanuser_t *cu;
264 mowgli_node_t *n;
265
266 clear_simple_modes(c);
267 chanban_clear(c);
268 handle_topic_from(si, c, "", 0, "");
269 MOWGLI_ITER_FOREACH(n, c->members.head)
270 {
271 cu = (chanuser_t *)n->data;
272 if (cu->user->server == me.me)
273 {
274 /* it's a service, reop */
275 sts("%s M %s +o %s", me.numeric, c->name, CLIENT_NAME(cu->user));
276 cu->modes = CSTATUS_OP;
277 }
278 else
279 cu->modes = 0;
280 }
281
282 slog(LG_DEBUG, "m_burst(): TS changed for %s (%lu -> %lu)", c->name, (unsigned long)c->ts, (unsigned long)ts);
283 c->ts = ts;
284 hook_call_channel_tschange(c);
285 }
286 if (parc < 3 || parv[2][0] != '+')
287 {
288 /* Tell the core to check mode locks now,
289 * otherwise it may only happen after the next
290 * mode change. -- jilles */
291 channel_mode_va(NULL, c, 1, "+");
292 }
293
294 bantype = 'b';
295 j = 2;
296 while (j < parc)
297 {
298 if (parv[j][0] == '+')
299 {
300 modec = 0;
301 modev[modec++] = parv[j++];
302 if (strchr(modev[0], 'k') && j < parc)
303 modev[modec++] = parv[j++];
304 if (strchr(modev[0], 'l') && j < parc)
305 modev[modec++] = parv[j++];
306 channel_mode(NULL, c, modec, modev);
307 }
308 else if (parv[j][0] == '%')
309 {
310 userc = sjtoken(parv[j++] + 1, ' ', userv);
311 for (i = 0; i < userc; i++)
312 if (!strcmp(userv[i], "~"))
313 /* A ban "~" means exceptions are
314 * following */
315 bantype = 'e';
316 else
317 chanban_add(c, userv[i], bantype);
318 }
319 else
320 {
321 userc = sjtoken(parv[j++], ',', userv);
322
323 prefix[0] = '\0';
324 for (i = 0; i < userc; i++)
325 {
326 p = strchr(userv[i], ':');
327 if (p != NULL)
328 {
329 *p = '\0';
330 prefix[0] = '\0';
331 prefix[1] = '\0';
332 prefix[2] = '\0';
333 p++;
334 while (*p)
335 {
336 if (*p == 'o' || (*p >= '0' && *p <= '9' && !prefix[0]))
337 prefix[prefix[0] ? 1 : 0] = '@';
338 else if (*p == 'h')
339 prefix[prefix[0] ? 1 : 0] = '%';
340 else if (*p == 'v')
341 prefix[prefix[0] ? 1 : 0] = '+';
342 p++;
343 }
344 }
345 mowgli_strlcpy(newnick, prefix, sizeof newnick);
346 mowgli_strlcat(newnick, userv[i], sizeof newnick);
347 chanuser_add(c, newnick);
348 }
349 }
350 }
351
352 if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
353 channel_delete(c);
354 }
355
m_nick(sourceinfo_t * si,int parc,char * parv[])356 static void m_nick(sourceinfo_t *si, int parc, char *parv[])
357 {
358 user_t *u;
359 char ipstring[HOSTIPLEN];
360 char *p;
361 int i;
362
363 /* got the right number of args for an introduction? */
364 if (parc >= 8)
365 {
366 /*
367 * -> Mh N jilles 1 1460435852 jilles 127.0.0.1 +ixCc 1A130C.572B1.6F53B5.8DD3B8.IP 1A130C.572B1.6F53B5.8DD3B8.IP DSBHPW Mhw2O :Real Name
368 */
369 slog(LG_DEBUG, "m_nick(): new user on `%s': %s@%s (%s)", si->s->name, parv[0],parv[4],parv[7]);
370
371 decode_p10_ip(parv[parc - 3], ipstring);
372 u = user_add(parv[0], parv[3], parv[4], parv[7], ipstring, parv[parc - 2], parv[parc - 1], si->s, atoi(parv[2]));
373 if (u == NULL)
374 return;
375
376 if (parv[5][0] == '+')
377 {
378 user_mode(u, parv[5]);
379 i = 1;
380 if (strchr(parv[5], 'r'))
381 {
382 p = strchr(parv[5+i], ':');
383 if (p != NULL)
384 *p++ = '\0';
385 handle_burstlogin(u, parv[5+i], p ? atol(p) : 0);
386 /* killed to force logout? */
387 if (user_find(parv[parc - 2]) == NULL)
388 return;
389 i++;
390 }
391 if (strchr(parv[5], 'h'))
392 {
393 p = strchr(parv[5+i], '@');
394 if (p == NULL)
395 {
396 strshare_unref(u->vhost);
397 u->vhost = strshare_get(parv[5 + i]);
398 }
399 else
400 {
401 char userbuf[USERLEN];
402
403 strshare_unref(u->vhost);
404 u->vhost = strshare_get(p + 1);
405
406 mowgli_strlcpy(userbuf, parv[5+i], sizeof userbuf);
407
408 p = strchr(userbuf, '@');
409 if (p != NULL)
410 *p = '\0';
411
412 strshare_unref(u->user);
413 u->user = strshare_get(userbuf);
414 }
415 i++;
416 }
417 if (strchr(parv[5], 'f'))
418 {
419 strshare_unref(u->vhost);
420 u->vhost = strshare_get(parv[5 + i]);
421
422 i++;
423 }
424 if (strchr(parv[5], 'x'))
425 {
426 u->flags |= UF_HIDEHOSTREQ;
427 /* this must be after setting the account name */
428 check_hidehost(u);
429 }
430 }
431
432 handle_nickchange(u);
433 }
434 /* if it's only 2 then it's a nickname change */
435 else if (parc == 2)
436 {
437 if (!si->su)
438 {
439 slog(LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
440 return;
441 }
442
443 slog(LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
444
445 if (user_changenick(si->su, parv[0], atoi(parv[1])))
446 return;
447
448 handle_nickchange(si->su);
449 }
450 else
451 {
452 slog(LG_DEBUG, "m_nick(): got NICK with wrong (%d) number of params", parc);
453
454 for (i = 0; i < parc; i++)
455 slog(LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
456 }
457 }
458
m_mode(sourceinfo_t * si,int parc,char * parv[])459 static void m_mode(sourceinfo_t *si, int parc, char *parv[])
460 {
461 user_t *u;
462 char *p;
463
464 if (*parv[0] == '#')
465 channel_mode(NULL, channel_find(parv[0]), parc - 1, &parv[1]);
466 else
467 {
468 /* Yes this is a nick and not a UID -- jilles */
469 u = user_find_named(parv[0]);
470 if (u == NULL)
471 {
472 slog(LG_DEBUG, "m_mode(): user mode for unknown user %s", parv[0]);
473 return;
474 }
475 user_mode(u, parv[1]);
476 if (strchr(parv[1], 'x'))
477 {
478 u->flags |= UF_HIDEHOSTREQ;
479 check_hidehost(u);
480 }
481 if (strchr(parv[1], 'h'))
482 {
483 if (parc > 2)
484 {
485 /* assume +h */
486 p = strchr(parv[2], '@');
487 if (p == NULL)
488 {
489 strshare_unref(u->vhost);
490 u->vhost = strshare_get(parv[2]);
491 }
492 else
493 {
494 char userbuf[USERLEN];
495
496 strshare_unref(u->vhost);
497 u->vhost = strshare_get(p + 1);
498
499 mowgli_strlcpy(userbuf, parv[2], sizeof userbuf);
500 p = strchr(userbuf, '@');
501 if (p != NULL)
502 *p = '\0';
503
504 strshare_unref(u->user);
505 u->user = strshare_get(userbuf);
506 }
507 slog(LG_DEBUG, "m_mode(): user %s setting vhost %s@%s", u->nick, u->user, u->vhost);
508 }
509 else
510 {
511 /* must be -h */
512 /* XXX we don't know the original ident */
513 slog(LG_DEBUG, "m_mode(): user %s turning off vhost", u->nick);
514
515 strshare_unref(u->vhost);
516 u->vhost = strshare_get(u->host);
517
518 /* revert to +x vhost if applicable */
519 check_hidehost(u);
520 }
521 }
522 }
523 }
524
m_clearmode(sourceinfo_t * si,int parc,char * parv[])525 static void m_clearmode(sourceinfo_t *si, int parc, char *parv[])
526 {
527 channel_t *chan;
528 char *p, c;
529 mowgli_node_t *n, *tn;
530 chanuser_t *cu;
531 int i;
532
533 /* -> ABAAA CM # b */
534 /* Note: this is an IRCop command, do not enforce mode locks. */
535 chan = channel_find(parv[0]);
536 if (chan == NULL)
537 {
538 slog(LG_DEBUG, "m_clearmode(): unknown channel %s", parv[0]);
539 return;
540 }
541 p = parv[1];
542 while ((c = *p++))
543 {
544 if (c == 'b')
545 {
546 MOWGLI_ITER_FOREACH_SAFE(n, tn, chan->bans.head)
547 {
548 if (((chanban_t *)n->data)->type == 'b')
549 chanban_delete(n->data);
550 }
551 }
552 else if (c == 'e')
553 {
554 MOWGLI_ITER_FOREACH_SAFE(n, tn, chan->bans.head)
555 {
556 if (((chanban_t *)n->data)->type == 'e')
557 chanban_delete(n->data);
558 }
559 }
560 else if (c == 'k')
561 {
562 if (chan->key)
563 free(chan->key);
564 chan->key = NULL;
565 }
566 else if (c == 'l')
567 chan->limit = 0;
568 else if (c == 'o')
569 {
570 MOWGLI_ITER_FOREACH(n, chan->members.head)
571 {
572 cu = (chanuser_t *)n->data;
573 if (cu->user->server == me.me)
574 {
575 /* it's a service, reop */
576 sts("%s M %s +o %s", me.numeric,
577 chan->name,
578 cu->user->uid);
579 }
580 else
581 cu->modes &= ~CSTATUS_OP;
582 }
583 }
584 else if (c == 'h')
585 {
586 MOWGLI_ITER_FOREACH(n, chan->members.head)
587 {
588 cu = (chanuser_t *)n->data;
589 cu->modes &= ~CSTATUS_HALFOP;
590 }
591 }
592 else if (c == 'v')
593 {
594 MOWGLI_ITER_FOREACH(n, chan->members.head)
595 {
596 cu = (chanuser_t *)n->data;
597 cu->modes &= ~CSTATUS_VOICE;
598 }
599 }
600 else
601 for (i = 0; mode_list[i].mode != '\0'; i++)
602 {
603 if (c == mode_list[i].mode)
604 chan->modes &= ~mode_list[i].value;
605 }
606 }
607 }
608
m_account(sourceinfo_t * si,int parc,char * parv[])609 static void m_account(sourceinfo_t *si, int parc, char *parv[])
610 {
611 user_t *u;
612 static bool warned = false;
613
614 u = user_find(parv[0]);
615 if (u == NULL)
616 return;
617 if (strlen(parv[1]) != 1 || (parv[1][0] != 'U' && parc < 3))
618 {
619 if (!warned)
620 {
621 slog(LG_ERROR, "m_account(): got account with second parameter %s, %u parameters, Atheme requires F:EXTENDED_ACCOUNTS:TRUE", parv[1], parc);
622 wallops("Invalid ACCOUNT syntax, check F:EXTENDED_ACCOUNTS:TRUE");
623 warned = true;
624 }
625 return;
626 }
627 switch (parv[1][0])
628 {
629 case 'R':
630 handle_setlogin(si, u, parv[2], parc > 3 ? atol(parv[3]) : 0);
631 break;
632 case 'M':
633 if (!u->myuser)
634 slog(LG_INFO, "Account rename (%s) for not logged in user %s, processing anyway",
635 parv[2], u->nick);
636 handle_setlogin(si, u, parv[2], 0);
637 break;
638 case 'U':
639 handle_clearlogin(si, u);
640 break;
641 default:
642 slog(LG_INFO, "Unrecognized ACCOUNT type %s", parv[1]);
643 }
644 }
645
m_sasl(sourceinfo_t * si,int parc,char * parv[])646 static void m_sasl(sourceinfo_t *si, int parc, char *parv[])
647 {
648 sasl_message_t smsg;
649
650 if (parc < 4)
651 return;
652
653 smsg.uid = parv[1];
654 smsg.mode = *parv[2];
655 smsg.buf = parv[3];
656 smsg.ext = parc >= 4 ? parv[4] : NULL;
657 smsg.server = si->s ? si->s : NULL;
658
659 hook_call_sasl_input(&smsg);
660 }
661
check_hidehost(user_t * u)662 static void check_hidehost(user_t *u)
663 {
664 static bool warned = false;
665 char buf[HOSTLEN + 1];
666
667 /* do they qualify? */
668 if (!(u->flags & UF_HIDEHOSTREQ) || u->myuser == NULL || (u->myuser->flags & MU_WAITAUTH))
669 return;
670 /* don't use this if they have some other kind of vhost */
671 if (strcmp(u->host, u->vhost))
672 {
673 slog(LG_DEBUG, "check_hidehost(): +x overruled by other vhost for %s", u->nick);
674 return;
675 }
676 if (me.hidehostsuffix == NULL)
677 {
678 if (!warned)
679 {
680 wallops("Misconfiguration: serverinfo::hidehostsuffix not set");
681 warned = true;
682 }
683 return;
684 }
685
686 snprintf(buf, sizeof buf, "%s.%s", entity(u->myuser)->name, me.hidehostsuffix);
687
688 strshare_unref(u->vhost);
689 u->vhost = strshare_get(buf);
690
691 slog(LG_DEBUG, "check_hidehost(): %s -> %s", u->nick, u->vhost);
692 }
693
p10_kline_sts(const char * server,const char * user,const char * host,long duration,const char * reason)694 static void p10_kline_sts(const char *server, const char *user, const char *host, long duration, const char *reason)
695 {
696 /* hold permanent akills for four weeks -- jilles
697 * This was changed in Nefarious 2.
698 */
699 sts("%s GL * +%s@%s %ld %lu :%s", me.numeric, user, host, duration > 0 ? duration : 2419200, (unsigned long)CURRTIME, reason);
700 }
701
_modinit(module_t * m)702 void _modinit(module_t * m)
703 {
704 MODULE_TRY_REQUEST_DEPENDENCY(m, "protocol/p10-generic");
705
706 /* Symbol relocation voodoo. */
707 join_sts = &nefarious_join_sts;
708 kick = &nefarious_kick;
709 notice_channel_sts = &nefarious_notice_channel_sts;
710 topic_sts = &nefarious_topic_sts;
711 ircd_on_login = &nefarious_on_login;
712 ircd_on_logout = &nefarious_on_logout;
713 sasl_sts = &nefarious_sasl_sts;
714 sethost_sts = &nefarious_sethost_sts;
715 svslogin_sts = &nefarious_svslogin_sts;
716 quarantine_sts = &nefarious_quarantine_sts;
717 kline_sts = &p10_kline_sts;
718 mode_list = nefarious_mode_list;
719 ignore_mode_list = nefarious_ignore_mode_list;
720 status_mode_list = nefarious_status_mode_list;
721 prefix_mode_list = nefarious_prefix_mode_list;
722 user_mode_list = nefarious_user_mode_list;
723 ignore_mode_list_size = ARRAY_SIZE(nefarious_ignore_mode_list);
724
725 ircd = &Nefarious;
726
727 pcommand_add("SASL", m_sasl, 4, MSRC_SERVER);
728
729 /* override these */
730 pcommand_delete("B");
731 pcommand_delete("N");
732 pcommand_delete("M");
733 pcommand_delete("OM");
734 pcommand_delete("CM");
735 pcommand_delete("T");
736 pcommand_delete("AC");
737 pcommand_add("B", m_burst, 2, MSRC_SERVER);
738 pcommand_add("N", m_nick, 2, MSRC_USER | MSRC_SERVER);
739 pcommand_add("M", m_mode, 2, MSRC_USER | MSRC_SERVER);
740 pcommand_add("OM", m_mode, 2, MSRC_USER); /* OPMODE, treat as MODE */
741 pcommand_add("CM", m_clearmode, 2, MSRC_USER);
742 pcommand_add("T", m_topic, 2, MSRC_USER | MSRC_SERVER);
743 pcommand_add("AC", m_account, 2, MSRC_SERVER);
744
745 m->mflags = MODTYPE_CORE;
746
747 pmodule_loaded = true;
748 }
749
750 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
751 * vim:ts=8
752 * vim:sw=8
753 * vim:noexpandtab
754 */