]> jfr.im git - irc/evilnet/x3.git/blob - src/proto-p10.c
reverting the #1995 srvx merge until its a stable release. Commits after 1995 are...
[irc/evilnet/x3.git] / src / proto-p10.c
1 /* proto-p10.c - IRC protocol output
2 * Copyright 2000-2004 srvx Development Team
3 *
4 * This file is part of x3.
5 *
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
21 #include "nickserv.h"
22 #include "chanserv.h"
23 #include "hash.h"
24 #include "helpfile.h"
25 #include "hosthiding.h"
26 #include "proto-common.c"
27 #include "opserv.h"
28
29 /* Full commands. */
30 #define CMD_ACCOUNT "ACCOUNT"
31 #define CMD_ADMIN "ADMIN"
32 #define CMD_ALIST "ALIST"
33 #define CMD_ASLL "ASLL"
34 #define CMD_AWAY "AWAY"
35 #define CMD_BURST "BURST"
36 #define CMD_CLEARMODE "CLEARMODE"
37 #define CMD_CLOSE "CLOSE"
38 #define CMD_CNOTICE "CNOTICE"
39 #define CMD_CONNECT "CONNECT"
40 #define CMD_CPRIVMSG "CPRIVMSG"
41 #define CMD_CREATE "CREATE"
42 #define CMD_DESTRUCT "DESTRUCT"
43 #define CMD_DESYNCH "DESYNCH"
44 #define CMD_DIE "DIE"
45 #define CMD_DNS "DNS"
46 #define CMD_EOB "END_OF_BURST"
47 #define CMD_EOB_ACK "EOB_ACK"
48 #define CMD_ERROR "ERROR"
49 #define CMD_FAKEHOST "FAKE"
50 #define CMD_GET "GET"
51 #define CMD_GLINE "GLINE"
52 #define CMD_HASH "HASH"
53 #define CMD_HELP "HELP"
54 #define CMD_INFO "INFO"
55 #define CMD_INVITE "INVITE"
56 #define CMD_ISON "ISON"
57 #define CMD_JOIN "JOIN"
58 #define CMD_JUPE "JUPE"
59 #define CMD_KICK "KICK"
60 #define CMD_KILL "KILL"
61 #define CMD_LINKS "LINKS"
62 #define CMD_LIST "LIST"
63 #define CMD_LUSERS "LUSERS"
64 #define CMD_MAP "MAP"
65 #define CMD_MARK "MARK"
66 #define CMD_MODE "MODE"
67 #define CMD_MOTD "MOTD"
68 #define CMD_NAMES "NAMES"
69 #define CMD_NICK "NICK"
70 #define CMD_NOTICE "NOTICE"
71 #define CMD_OPER "OPER"
72 #define CMD_OPMODE "OPMODE"
73 #define CMD_PART "PART"
74 #define CMD_PASS "PASS"
75 #define CMD_PING "PING"
76 #define CMD_PONG "PONG"
77 #define CMD_POST "POST"
78 #define CMD_PRIVMSG "PRIVMSG"
79 #define CMD_PRIVS "PRIVS"
80 #define CMD_PROTO "PROTO"
81 #define CMD_QUIT "QUIT"
82 #define CMD_REHASH "REHASH"
83 #define CMD_RESET "RESET"
84 #define CMD_RESTART "RESTART"
85 #define CMD_RPING "RPING"
86 #define CMD_RPONG "RPONG"
87 #define CMD_SERVER "SERVER"
88 #define CMD_SERVLIST "SERVLIST"
89 #define CMD_SERVSET "SERVSET"
90 #define CMD_SET "SET"
91 #define CMD_SETTIME "SETTIME"
92 #define CMD_SHUN "SHUN"
93 #define CMD_SILENCE "SILENCE"
94 #define CMD_SQUERY "SQUERY"
95 #define CMD_SQUIT "SQUIT"
96 #define CMD_STATS "STATS"
97 #define CMD_SVSJOIN "SVSJOIN"
98 #define CMD_SVSNICK "SVSNICK"
99 #define CMD_SVSPART "SVSPART"
100 #define CMD_SWHOIS "SWHOIS"
101 #define CMD_TIME "TIME"
102 #define CMD_TOPIC "TOPIC"
103 #define CMD_TRACE "TRACE"
104 #define CMD_UPING "UPING"
105 #define CMD_USER "USER"
106 #define CMD_USERHOST "USERHOST"
107 #define CMD_USERIP "USERIP"
108 #define CMD_VERSION "VERSION"
109 #define CMD_WALLCHOPS "WALLCHOPS"
110 #define CMD_WALLOPS "WALLOPS"
111 #define CMD_WALLHOPS "WALLHOPS"
112 #define CMD_WALLUSERS "WALLUSERS"
113 #define CMD_WALLVOICES "WALLVOICES"
114 #define CMD_WALLHOPS "WALLHOPS"
115 #define CMD_WHO "WHO"
116 #define CMD_WHOIS "WHOIS"
117 #define CMD_WHOWAS "WHOWAS"
118
119 /* Tokenized commands. */
120 #define TOK_ACCOUNT "AC"
121 #define TOK_ADMIN "AD"
122 #define TOK_ALIST "AL"
123 #define TOK_ASLL "LL"
124 #define TOK_AWAY "A"
125 #define TOK_BURST "B"
126 #define TOK_CLEARMODE "CM"
127 #define TOK_CLOSE "CLOSE"
128 #define TOK_CNOTICE "CN"
129 #define TOK_CONNECT "CO"
130 #define TOK_CPRIVMSG "CP"
131 #define TOK_CREATE "C"
132 #define TOK_DESTRUCT "DE"
133 #define TOK_DESYNCH "DS"
134 #define TOK_DIE "DIE"
135 #define TOK_DNS "DNS"
136 #define TOK_EOB "EB"
137 #define TOK_EOB_ACK "EA"
138 #define TOK_ERROR "Y"
139 #define TOK_EXEMPT "EX"
140 #define TOK_FAKEHOST "FA"
141 #define TOK_GET "GET"
142 #define TOK_GLINE "GL"
143 #define TOK_HASH "HASH"
144 #define TOK_HELP "HELP"
145 #define TOK_INFO "F"
146 #define TOK_INVITE "I"
147 #define TOK_ISON "ISON"
148 #define TOK_JOIN "J"
149 #define TOK_JUPE "JU"
150 #define TOK_KICK "K"
151 #define TOK_KILL "D"
152 #define TOK_LINKS "LI"
153 #define TOK_LIST "LIST"
154 #define TOK_LUSERS "LU"
155 #define TOK_MAP "MAP"
156 #define TOK_MARK "MK"
157 #define TOK_MODE "M"
158 #define TOK_MOTD "MO"
159 #define TOK_NAMES "E"
160 #define TOK_NICK "N"
161 #define TOK_NOTICE "O"
162 #define TOK_OPER "OPER"
163 #define TOK_OPMODE "OM"
164 #define TOK_PART "L"
165 #define TOK_PASS "PA"
166 #define TOK_PING "G"
167 #define TOK_PONG "Z"
168 #define TOK_POST "POST"
169 #define TOK_PRIVMSG "P"
170 #define TOK_PRIVS "PRIVS"
171 #define TOK_PROTO "PROTO"
172 #define TOK_QUIT "Q"
173 #define TOK_REHASH "REHASH"
174 #define TOK_RESET "RESET"
175 #define TOK_RESTART "RESTART"
176 #define TOK_RPING "RI"
177 #define TOK_RPONG "RO"
178 #define TOK_SERVER "S"
179 #define TOK_SERVLIST "SERVSET"
180 #define TOK_SERVSET "SERVSET"
181 #define TOK_SET "SET"
182 #define TOK_SETTIME "SE"
183 #define TOK_SHUN "SU"
184 #define TOK_SILENCE "U"
185 #define TOK_SQUERY "SQUERY"
186 #define TOK_SQUIT "SQ"
187 #define TOK_STATS "R"
188 #define TOK_SVSJOIN "SJ"
189 #define TOK_SVSNICK "SN"
190 #define TOK_SVSPART "SP"
191 #define TOK_SWHOIS "SW"
192 #define TOK_TIME "TI"
193 #define TOK_TOPIC "T"
194 #define TOK_TRACE "TR"
195 #define TOK_UPING "UP"
196 #define TOK_USER "USER"
197 #define TOK_USERHOST "USERHOST"
198 #define TOK_USERIP "USERIP"
199 #define TOK_VERSION "V"
200 #define TOK_WALLCHOPS "WC"
201 #define TOK_WALLOPS "WA"
202 #define TOK_WALLHOPS "WH"
203 #define TOK_WALLUSERS "WU"
204 #define TOK_WALLVOICES "WV"
205 #define TOK_WALLHOPS "WH"
206 #define TOK_WHO "H"
207 #define TOK_WHOIS "W"
208 #define TOK_WHOWAS "X"
209
210 /* Protocol messages; aliased to full commands or tokens depending
211 on compile-time configuration. ircu prefers tokens WITH THE
212 EXCEPTION OF THE SERVER AND PASS COMMANDS, which cannot be
213 tokenized, because clients' (ie. a linking server) commands are
214 only checked against the full command list.
215 */
216 #if defined(ENABLE_TOKENS)
217 #define TYPE(NAME) TOK_ ## NAME
218 #else /* !ENABLE_TOKENS */
219 #define TYPE(NAME) CMD_ ## NAME
220 #endif /* ENABLE_TOKENS */
221
222 #define P10_ACCOUNT TYPE(ACCOUNT)
223 #define P10_ADMIN TYPE(ADMIN)
224 #define P10_ASLL TYPE(ASLL)
225 #define P10_AWAY TYPE(AWAY)
226 #define P10_BURST TYPE(BURST)
227 #define P10_CLEARMODE TYPE(CLEARMODE)
228 #define P10_CLOSE TYPE(CLOSE)
229 #define P10_CNOTICE TYPE(CNOTICE)
230 #define P10_CONNECT TYPE(CONNECT)
231 #define P10_CPRIVMSG TYPE(CPRIVMSG)
232 #define P10_CREATE TYPE(CREATE)
233 #define P10_DESTRUCT TYPE(DESTRUCT)
234 #define P10_DESYNCH TYPE(DESYNCH)
235 #define P10_DIE TYPE(DIE)
236 #define P10_DNS TYPE(DNS)
237 #define P10_EOB TYPE(EOB)
238 #define P10_EOB_ACK TYPE(EOB_ACK)
239 #define P10_ERROR TYPE(ERROR)
240 #define P10_FAKEHOST TYPE(FAKEHOST)
241 #define P10_GET TYPE(GET)
242 #define P10_GLINE TYPE(GLINE)
243 #define P10_HASH TYPE(HASH)
244 #define P10_HELP TYPE(HELP)
245 #define P10_INFO TYPE(INFO)
246 #define P10_INVITE TYPE(INVITE)
247 #define P10_ISON TYPE(ISON)
248 #define P10_JOIN TYPE(JOIN)
249 #define P10_JUPE TYPE(JUPE)
250 #define P10_KICK TYPE(KICK)
251 #define P10_KILL TYPE(KILL)
252 #define P10_LINKS TYPE(LINKS)
253 #define P10_LIST TYPE(LIST)
254 #define P10_LUSERS TYPE(LUSERS)
255 #define P10_MAP TYPE(MAP)
256 #define P10_MARK TYPE(MARK)
257 #define P10_MODE TYPE(MODE)
258 #define P10_MOTD TYPE(MOTD)
259 #define P10_NAMES TYPE(NAMES)
260 #define P10_NICK TYPE(NICK)
261 #define P10_NOTICE TYPE(NOTICE)
262 #define P10_OPER TYPE(OPER)
263 #define P10_OPMODE TYPE(OPMODE)
264 #define P10_PART TYPE(PART)
265 #define P10_PASS CMD_PASS
266 #define P10_PING TYPE(PING)
267 #define P10_PONG TYPE(PONG)
268 #define P10_POST TYPE(POST)
269 #define P10_PRIVMSG TYPE(PRIVMSG)
270 #define P10_PRIVS TYPE(PRIVS)
271 #define P10_PROTO TYPE(PROTO)
272 #define P10_QUIT TYPE(QUIT)
273 #define P10_REHASH TYPE(REHASH)
274 #define P10_RESET TYPE(RESET)
275 #define P10_RESTART TYPE(RESTART)
276 #define P10_RPING TYPE(RPING)
277 #define P10_RPONG TYPE(RPONG)
278 #define P10_SERVER CMD_SERVER
279 #define P10_SERVLIST TYPE(SERVLIST)
280 #define P10_SERVSET TYPE(SERVSET)
281 #define P10_SET TYPE(SET)
282 #define P10_SETTIME TYPE(SETTIME)
283 #define P10_SHUN TYPE(SHUN)
284 #define P10_SILENCE TYPE(SILENCE)
285 #define P10_SQUERY TYPE(SQUERY)
286 #define P10_SQUIT TYPE(SQUIT)
287 #define P10_STATS TYPE(STATS)
288 #define P10_SVSJOIN TYPE(SVSJOIN)
289 #define P10_SVSNICK TYPE(SVSNICK)
290 #define P10_SVSPART TYPE(SVSPART)
291 #define P10_SWHOIS TYPE(SWHOIS)
292 #define P10_TIME TYPE(TIME)
293 #define P10_TOPIC TYPE(TOPIC)
294 #define P10_TRACE TYPE(TRACE)
295 #define P10_UPING TYPE(UPING)
296 #define P10_USER TYPE(USER)
297 #define P10_USERHOST TYPE(USERHOST)
298 #define P10_USERIP TYPE(USERIP)
299 #define P10_VERSION TYPE(VERSION)
300 #define P10_WALLCHOPS TYPE(WALLCHOPS)
301 #define P10_WALLOPS TYPE(WALLOPS)
302 #define P10_WALLHOPS TYPE(WALLHOPS)
303 #define P10_WALLUSERS TYPE(WALLUSERS)
304 #define P10_WALLVOICES TYPE(WALLVOICES)
305 #define P10_WHO TYPE(WHO)
306 #define P10_WHOIS TYPE(WHOIS)
307 #define P10_WHOWAS TYPE(WHOWAS)
308 #define P10_EXEMPT TYPE(EXEMPT)
309
310 /* Servers claiming to have a boot or link time before PREHISTORY
311 * trigger errors to the log. We hope no server has been running
312 * constantly since September 1994. :)
313 */
314 #define PREHISTORY 780000000
315
316 #define MODELEN 40 + KEYLEN
317
318 static struct server *servers_num[64*64];
319 static privmsg_func_t *privmsg_funcs;
320 static unsigned int num_privmsg_funcs;
321 static privmsg_func_t *notice_funcs;
322 static unsigned int num_notice_funcs;
323 static struct dict *unbursted_channels;
324 static char *his_servername;
325 static char *his_servercomment;
326 static int extended_accounts;
327
328 static struct userNode *AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip);
329
330 extern int off_channel;
331 extern int DefConLevel;
332 extern int DefConTimeOut;
333 extern char *DefConChanModes;
334
335 static int parse_oplevel(char *str);
336
337 char privbuf[512] = "";
338
339 /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
340 * server and Y's indentifying the client on that server. */
341 struct server*
342 GetServerN(const char *numeric)
343 {
344 switch (strlen(numeric)) {
345 default:
346 return servers_num[base64toint(numeric, 2)];
347 case 4:
348 case 3:
349 case 1:
350 return servers_num[base64toint(numeric, 1)];
351 case 0:
352 return NULL;
353 }
354 }
355
356 struct userNode*
357 GetUserN(const char *numeric) /* using numeric */
358 {
359 struct userNode *un;
360 struct server *s;
361 int n, slen, ulen;
362
363 switch (strlen(numeric)) {
364 default:
365 log_module(MAIN_LOG, LOG_WARNING, "GetUserN(%s): numeric too long!", numeric);
366 return NULL;
367 case 5: slen = 2; ulen = 3; break;
368 case 4: slen = 1; ulen = 3; break;
369 case 3: slen = 1; ulen = 2; break;
370 case 2: case 1: case 0:
371 log_module(MAIN_LOG, LOG_WARNING, "GetUserN(%s): numeric too short!", numeric);
372 return NULL;
373 }
374 if (!(s = servers_num[base64toint(numeric, slen)])) {
375 log_module(MAIN_LOG, LOG_WARNING, "GetUserN(%s): couldn't find server (len=%d)!", numeric, slen);
376 return NULL;
377 }
378 n = base64toint(numeric+slen, ulen) & s->num_mask;
379 if (!(un = s->users[n])) {
380 log_module(MAIN_LOG, LOG_WARNING, "GetUserN(%s) couldn't find user!", numeric);
381 }
382 return un;
383 }
384
385 extern struct userNode *opserv;
386 static void
387 check_ctcp(struct userNode *user, struct userNode *bot, char *text, UNUSED_ARG(int server_qualified))
388 {
389 char *cmd;
390 /* if its a version reply, do an alert check (only alerts with version=something) */
391 if(bot == opserv) {
392 if(text[0] == '\001') {
393 text++;
394 cmd = mysep(&text, " ");
395 if(!irccasecmp(cmd, "VERSION")) {
396 char *version = mysep(&text, "\n");
397 if(!version)
398 version = "";
399 /* opserv_debug("Opserv got CTCP VERSION Notice from %s: %s", user->nick, version); */
400 /* TODO: setup a ctcp_funcs thing to handle this and other CTCPS properly */
401 user->version_reply = strdup(version);
402 /* TODO: put this in the db */
403 if(match_ircglob(version, "WebTV;*"))
404 user->no_notice = true; /* webbies cant see notices */
405 }
406 }
407 }
408 }
409
410
411 static void
412 privmsg_user_helper(struct userNode *un, void *data)
413 {
414 struct privmsg_desc *pd = data;
415 unsigned int num = un->num_local;
416 if (!pd->is_notice) {
417 if ((num < num_privmsg_funcs) && privmsg_funcs[num]) {
418 privmsg_funcs[num](pd->user, un, pd->text, pd->is_qualified);
419 }
420 } else {
421 if ((num < num_notice_funcs) && notice_funcs[num]) {
422 check_ctcp(pd->user, un, pd->text, pd->is_qualified);
423 notice_funcs[num](pd->user, un, pd->text, pd->is_qualified);
424 }
425 }
426 }
427
428 /* equiv to user doing /connect server port target */
429 void irc_connect(struct userNode *user, char *server, unsigned int port, struct server *target)
430 {
431 putsock("%s " P10_CONNECT " %s %d %s", user->numeric, server, port, target->numeric);
432 }
433
434 void
435 irc_squit_route(struct server *srv, const char *message, ...)
436 {
437 va_list arg_list;
438 char buffer[MAXLEN];
439 va_start(arg_list, message);
440 vsnprintf(buffer, MAXLEN-2, message, arg_list);
441 buffer[MAXLEN-1] = 0;
442
443 /* When would we squit ourselves exactly?? -Rubin */
444 if(srv == self && cManager.uplink->state == CONNECTED ) {
445 unsigned int i;
446
447 /* Quit all clients linked to me. */
448 for(i = 0; i <= self->num_mask; i++) {
449 if(!self->users[i])
450 continue;
451 irc_quit(self->users[i], buffer);
452 }
453 }
454
455 putsock("%s " P10_SQUIT " %s %d :%s", self->numeric, srv->name, 0, buffer);
456
457 if(srv == self) {
458 /* Force a reconnect to the currently selected server. */
459 cManager.uplink->tries = 0;
460 log_module(MAIN_LOG, LOG_INFO, "Squitting from uplink: %s", buffer);
461 close_socket();
462 }
463 }
464
465 void
466 irc_server(struct server *srv)
467 {
468 char extranum[COMBO_NUMERIC_LEN+1];
469
470 inttobase64(extranum, srv->num_mask, (srv->numeric[1] || (srv->num_mask >= 64*64)) ? 3 : 2);
471 if (srv == self) {
472 putsock(P10_SERVER " %s %d %li %li J10 %s%s +s6 :%s",
473 srv->name, srv->hops+1, srv->boot, srv->link, srv->numeric, extranum, srv->description);
474 } else {
475 putsock("%s " P10_SERVER " %s %d %li %li %c10 %s%s +s6 :%s",
476 self->numeric, srv->name, srv->hops+1, srv->boot, srv->link, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description);
477 }
478 }
479
480 static void
481 irc_p10_pton(irc_in_addr_t *ip, const char *input)
482 {
483 if (strlen(input) == 6) {
484 unsigned int value;
485 memset(ip, 0, 6 * sizeof(ip->in6[0]));
486 value = base64toint(input, 6);
487 if (value)
488 ip->in6[5] = htons(65535);
489 ip->in6[6] = htons(value >> 16);
490 ip->in6[7] = htons(value & 65535);
491 } else {
492 unsigned int pos = 0;
493 do {
494 if (*input == '_') {
495 unsigned int left;
496 for (left = (25 - strlen(input)) / 3; left; left--)
497 ip->in6[pos++] = 0;
498 input++;
499 } else {
500 ip->in6[pos++] = ntohs(base64toint(input, 3));
501 input += 3;
502 }
503 } while (pos < 8);
504 }
505 }
506
507 static void
508 irc_p10_ntop(char *output, const irc_in_addr_t *ip)
509 {
510 if (!irc_in_addr_is_valid(*ip)) {
511 strcpy(output, "AAAAAA");
512 } else if (irc_in_addr_is_ipv4(*ip)) {
513 unsigned int in4;
514 in4 = (ntohs(ip->in6[6]) << 16) | ntohs(ip->in6[7]);
515 inttobase64(output, in4, 6);
516 output[6] = '\0';
517 } else if (irc_in_addr_is_ipv6(*ip)) {
518 unsigned int max_start, max_zeros, curr_zeros, zero, ii;
519 /* Can start by printing out the leading non-zero parts. */
520 for (ii = 0; (ip->in6[ii]) && (ii < 8); ++ii) {
521 inttobase64(output, ntohs(ip->in6[ii]), 3);
522 output += 3;
523 }
524 /* Find the longest run of zeros. */
525 for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
526 if (!ip->in6[ii])
527 curr_zeros++;
528 else if (curr_zeros > max_zeros) {
529 max_start = ii - curr_zeros;
530 max_zeros = curr_zeros;
531 curr_zeros = 0;
532 }
533 }
534 if (curr_zeros > max_zeros) {
535 max_start = ii - curr_zeros;
536 max_zeros = curr_zeros;
537 curr_zeros = 0;
538 }
539 /* Print the rest of the address */
540 for (ii = zero; ii < 8; ) {
541 if ((ii == max_start) && max_zeros) {
542 *output++ = '_';
543 ii += max_zeros;
544 } else {
545 inttobase64(output, ntohs(ip->in6[ii]), 3);
546 output += 3;
547 }
548 }
549 *output = '\0';
550 } else {
551 strcpy(output, "???");
552 }
553 }
554
555 void
556 irc_user(struct userNode *user)
557 {
558 char b64ip[25];
559 if (!user)
560 return;
561 irc_p10_ntop(b64ip, &user->ip);
562 if (user->modes) {
563 int modelen;
564 char modes[32];
565
566 modelen = 0;
567 if (IsOper(user))
568 modes[modelen++] = 'o';
569 if (IsInvisible(user))
570 modes[modelen++] = 'i';
571 if (IsWallOp(user))
572 modes[modelen++] = 'w';
573 if (IsService(user))
574 modes[modelen++] = 'k';
575 if (IsServNotice(user))
576 modes[modelen++] = 's';
577 if (IsDeaf(user))
578 modes[modelen++] = 'd';
579 if (IsGlobal(user))
580 modes[modelen++] = 'g';
581 // sethost - reed/apples
582 // if (IsHelperIrcu(user))
583 if (IsSetHost(user))
584 modes[modelen++] = 'h';
585 if (IsFakeHost(user))
586 modes[modelen++] = 'f';
587 if (IsHiddenHost(user))
588 modes[modelen++] = 'x';
589 modes[modelen] = 0;
590
591 /* we don't need to put the + in modes because it's in the format string. */
592 putsock("%s " P10_NICK " %s %d %li %s %s +%s %s %s :%s",
593 user->uplink->numeric, user->nick, user->uplink->hops+1, user->timestamp, user->ident, user->hostname, modes, b64ip, user->numeric, user->info);
594 } else {
595 putsock("%s " P10_NICK " %s %d %li %s %s %s %s :%s",
596 user->uplink->numeric, user->nick, user->uplink->hops+1, user->timestamp, user->ident, user->hostname, b64ip, user->numeric, user->info);
597 }
598 }
599
600 void
601 irc_rename(struct userNode *user, const char *new_handle)
602 {
603 if(extended_accounts)
604 putsock("%s " P10_ACCOUNT " %s M %s", self->numeric, user->numeric, new_handle);
605 }
606
607 void
608 irc_delete(struct userNode *user)
609 {
610 if(extended_accounts)
611 putsock("%s " P10_ACCOUNT " %s U", self->numeric, user->numeric);
612 }
613
614 void
615 irc_account(struct userNode *user, const char *stamp, time_t timestamp)
616 {
617 if(extended_accounts)
618 putsock("%s " P10_ACCOUNT " %s R %s %lu", self->numeric, user->numeric, stamp, timestamp);
619 else
620 putsock("%s " P10_ACCOUNT " %s %s %lu", self->numeric, user->numeric, stamp, timestamp);
621 }
622
623 void
624 irc_fakehost(struct userNode *user, const char *host)
625 {
626 putsock("%s " P10_FAKEHOST " %s %s", self->numeric, user->numeric, host);
627 }
628
629 void
630 irc_regnick(UNUSED_ARG(struct userNode *user))
631 {
632 /* no operation here */
633 }
634
635 void
636 irc_nick(struct userNode *user, UNUSED_ARG(const char *old_nick))
637 {
638 putsock("%s " P10_NICK " %s "FMT_TIME_T, user->numeric, user->nick, now);
639 }
640
641 void
642 irc_fetchtopic(struct userNode *from, const char *to)
643 {
644 if (!from || !to)
645 return;
646 putsock("%s " P10_TOPIC " %s", from->numeric, to);
647 }
648
649 void
650 irc_squit(struct server *srv, const char *message, const char *service_message)
651 {
652 if (!service_message)
653 service_message = message;
654
655 /* Are we leaving the network? */
656 if (srv == self && cManager.uplink->state == CONNECTED) {
657 unsigned int i;
658
659 /* Quit all clients linked to me. */
660 for (i = 0; i <= self->num_mask; i++) {
661 if (!self->users[i])
662 continue;
663 irc_quit(self->users[i], service_message);
664 }
665 }
666
667 putsock("%s " P10_SQUIT " %s %d :%s", self->numeric, srv->name, 0, message);
668
669 if (srv == self) {
670 /* Force a reconnect to the currently selected server. */
671 cManager.uplink->tries = 0;
672 log_module(MAIN_LOG, LOG_INFO, "Squitting from uplink: %s", message);
673 close_socket();
674 }
675 }
676
677 void
678 irc_wallchops(struct userNode *from, const char *to, const char *message)
679 {
680 putsock("%s " P10_WALLCHOPS " %s :%s", from->numeric, to, message);
681 }
682
683 void
684 irc_wallops(const char *format, ...)
685 {
686 va_list arg_list;
687 char buffer[MAXLEN];
688 va_start(arg_list, format);
689 vsnprintf(buffer, MAXLEN-2, format, arg_list);
690 buffer[MAXLEN-1] = 0;
691 putsock("%s " P10_WALLOPS " :%s", self->numeric, buffer);
692 }
693
694
695 void
696 irc_notice(struct userNode *from, const char *to, const char *message)
697 {
698 putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message);
699 }
700
701 void
702 irc_notice_user(struct userNode *from, struct userNode *to, const char *message)
703 {
704 putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message);
705 }
706
707 void
708 irc_privmsg(struct userNode *from, const char *to, const char *message)
709 {
710 putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message);
711 }
712
713 void
714 irc_privmsg_user(struct userNode *from, struct userNode *to, const char *message)
715 {
716 putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to->numeric, message);
717 }
718
719 void
720 irc_version_user(struct userNode *from, struct userNode *to)
721 {
722 irc_privmsg_user(from, to, "\001VERSION\001");
723 }
724
725 void
726 irc_eob(void)
727 {
728 putsock("%s " P10_EOB, self->numeric);
729 }
730
731 void
732 irc_eob_ack(void)
733 {
734 putsock("%s " P10_EOB_ACK, self->numeric);
735
736 char *nick;
737 const char *str;
738 str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
739 nick = strdup(str);
740
741 if (nick && (DefConLevel < 5)) {
742 DefConProcess(GetUserH(nick));
743
744 if (DefConTimeOut > 0)
745 timeq_add(now + DefConTimeOut, defcon_timeout, NULL);
746 }
747 }
748
749 void
750 irc_rpong(const char *from1, const char *from2, const char *pingtime, const char *clientinfo)
751 {
752 putsock("%s " P10_RPONG " %s %s %s :%s", self->numeric, from1, from2, pingtime, clientinfo);
753 }
754
755 void
756 irc_ping(const char *payload)
757 {
758 putsock("%s " P10_PING " :%s", self->numeric, payload);
759 }
760
761 void
762 irc_pong(const char *who, const char *data)
763 {
764 putsock("%s " P10_PONG " %s :%s", self->numeric, who, data);
765 }
766
767 void
768 irc_pong_asll(const char *who, const char *orig_ts)
769 {
770 char *delim;
771 struct timeval orig;
772 struct timeval now;
773 int diff;
774
775 orig.tv_sec = strtoul(orig_ts, &delim, 10);
776 orig.tv_usec = (*delim == '.') ? strtoul(delim + 1, NULL, 10) : 0;
777 gettimeofday(&now, NULL);
778 diff = (now.tv_sec - orig.tv_sec) * 1000 + (now.tv_usec - orig.tv_usec) / 1000;
779 putsock("%s " P10_PONG " %s %s %d " FMT_TIME_T ".%06u", self->numeric, who, orig_ts, diff, now.tv_sec, (unsigned)now.tv_usec);
780 }
781
782 void
783 irc_pass(const char *passwd)
784 {
785 putsock(P10_PASS " :%s", passwd);
786 }
787
788 void
789 irc_introduce(const char *passwd)
790 {
791 void timed_send_ping(void *data);
792
793 self->self_burst = self->burst = 1;
794 irc_pass(passwd);
795 irc_server(self);
796 burst_length = 0;
797 timeq_add(now + ping_freq, timed_send_ping, 0);
798 }
799
800 void
801 irc_gline(struct server *srv, struct gline *gline, int silent)
802 {
803 putsock("%s " P10_GLINE " %s +%s %ld :%s<%s> %s",
804 self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, silent ? "AUTO " : "", gline->issuer, gline->reason);
805 }
806
807 void
808 irc_shun(struct server *srv, struct shun *shun)
809 {
810 putsock("%s " P10_SHUN " %s +%s %ld :<%s> %s",
811 self->numeric, (srv ? srv->numeric : "*"), shun->target, shun->expires-now, shun->issuer, shun->reason);
812 }
813
814 void
815 irc_settime(const char *srv_name_mask, time_t new_time)
816 {
817 ioset_set_time(new_time);
818 if (!strcmp(srv_name_mask, "*"))
819 srv_name_mask = "";
820 putsock("%s " P10_SETTIME " " FMT_TIME_T " %s", self->numeric, new_time, srv_name_mask);
821 }
822
823 void
824 irc_ungline(const char *mask)
825 {
826 putsock("%s " P10_GLINE " * -%s", self->numeric, mask);
827 }
828
829 void
830 irc_unshun(const char *mask)
831 {
832 putsock("%s " P10_SHUN " * -%s", self->numeric, mask);
833 }
834
835 static void
836 irc_burst(struct chanNode *chan)
837 {
838 char burst_line[512];
839 int pos, base_len, len;
840 struct modeNode *mn;
841 struct banNode *bn;
842 struct exemptNode *en;
843 long last_mode=-1;
844 unsigned int n;
845
846 base_len = sprintf(burst_line, "%s " P10_BURST " %s " FMT_TIME_T " ",
847 self->numeric, chan->name, chan->timestamp);
848 len = irc_make_chanmode(chan, burst_line+base_len);
849 pos = base_len + len;
850 if (len)
851 burst_line[pos++] = ' ';
852
853 if(chan->members.used < 1)
854 return; /* dont burst empty channels (created by discrims) */
855 /* dump the users */
856 for (n=0; n<chan->members.used; n++) {
857 mn = chan->members.list[n];
858 if (pos > 500) {
859 burst_line[pos-1] = 0; /* -1 to back up over the space or comma */
860 putsock("%s", burst_line);
861 pos = base_len;
862 last_mode = -1;
863 }
864
865 memcpy(burst_line+pos, mn->user->numeric, strlen(mn->user->numeric));
866 pos += strlen(mn->user->numeric);
867 if (mn->modes && (mn->modes != last_mode)) {
868 last_mode = mn->modes;
869 burst_line[pos++] = ':';
870 if (last_mode & MODE_CHANOP)
871 burst_line[pos++] = 'o';
872 if (last_mode & MODE_HALFOP)
873 burst_line[pos++] = 'h';
874 if (last_mode & MODE_VOICE)
875 burst_line[pos++] = 'v';
876 }
877 if ((n+1)<chan->members.used)
878 burst_line[pos++] = ',';
879 }
880 if (chan->banlist.used) {
881 /* dump the bans */
882 if (pos+2+strlen(chan->banlist.list[0]->ban) > 505) {
883 burst_line[pos-1] = 0;
884 putsock("%s", burst_line);
885 pos = base_len;
886 } else {
887 burst_line[pos++] = ' ';
888 }
889
890 burst_line[pos++] = ':';
891 burst_line[pos++] = '%';
892 base_len = pos;
893 for (n=0; n<chan->banlist.used; n++) {
894 bn = chan->banlist.list[n];
895 len = strlen(bn->ban);
896 if (pos+len+1 > 510) {
897 burst_line[pos-1] = 0; /* -1 to back up over the space or comma */
898 putsock("%s", burst_line);
899 pos = base_len;
900 }
901 memcpy(burst_line+pos, bn->ban, len);
902 pos += len;
903 burst_line[pos++] = ' ';
904 }
905 }
906 if (chan->exemptlist.used) {
907 /* dump the exempt */
908 if (pos+2+strlen(chan->exemptlist.list[0]->exempt) > 505) {
909 burst_line[pos-1] = 0;
910 putsock("%s", burst_line);
911 pos = base_len;
912 } else {
913 burst_line[pos++] = ' ';
914 }
915
916 burst_line[pos++] = ' ';
917 burst_line[pos++] = '~';
918 burst_line[pos++] = ' ';
919 base_len = pos;
920 for (n=0; n<chan->exemptlist.used; n++) {
921 en = chan->exemptlist.list[n];
922 len = strlen(en->exempt);
923 if (pos+len+1 > 510) {
924 burst_line[pos-1] = 0; /* -1 to back up over the space or comma */
925 putsock("%s", burst_line);
926 pos = base_len;
927 }
928 memcpy(burst_line+pos, en->exempt, len);
929 pos += len;
930 burst_line[pos++] = ' ';
931 }
932 }
933 /* print the last line */
934 burst_line[pos] = 0;
935 putsock("%s", burst_line);
936 }
937
938 void
939 irc_quit(struct userNode *user, const char *message)
940 {
941 putsock("%s " P10_QUIT " :%s", user->numeric, message);
942 }
943
944 void
945 irc_error(const char *to, const char *message)
946 {
947 if (to) {
948 putsock("%s " P10_ERROR " :%s", to, message);
949 } else {
950 putsock(":%s " P10_ERROR " :%s", self->name, message);
951 }
952 }
953
954 void
955 irc_kill(struct userNode *from, struct userNode *target, const char *message)
956 {
957 if (from) {
958 putsock("%s " P10_KILL " %s :%s!%s (%s)",
959 from->numeric, target->numeric, self->name, from->nick, message);
960 } else {
961 putsock("%s " P10_KILL " %s :%s (%s)",
962 self->numeric, target->numeric, self->name, message);
963 }
964 }
965
966 void
967 irc_mode(struct userNode *from, struct chanNode *target, const char *modes)
968 {
969 call_channel_mode_funcs(from, target, (char **)&modes, 0);
970 putsock("%s " P10_MODE " %s %s "FMT_TIME_T,
971 (from ? from->numeric : self->numeric),
972 target->name, modes, target->timestamp);
973 }
974
975 /* Added to allow services to mode users
976 2005 - 8 - 10 by Life4Christ
977 */
978 void
979 irc_umode(struct userNode *target, const char *modes)
980 {
981 putsock("%s " P10_MODE " %s %s ",self->numeric,target->nick, modes);
982 }
983
984
985 void
986 irc_invite(struct userNode *from, struct userNode *who, struct chanNode *to)
987 {
988 putsock("%s " P10_INVITE " %s %s", from->numeric, who->nick, to->name);
989 }
990
991 void
992 irc_silence(struct userNode *who, const char *mask, int add)
993 {
994 putsock("%s " P10_SILENCE " %s %s%s", self->numeric, who->numeric, add ? "+" : "-", mask);
995 }
996
997 void
998 irc_join(struct userNode *who, struct chanNode *what)
999 {
1000 if (what->members.used == 1) {
1001 putsock("%s " P10_CREATE " %s %lu",
1002 who->numeric, what->name, what->timestamp);
1003 } else {
1004 putsock("%s " P10_JOIN " %s %lu", who->numeric, what->name, what->timestamp);
1005 }
1006 }
1007
1008 void
1009 irc_svsjoin(struct userNode *from, struct userNode *who, struct chanNode *to)
1010 {
1011 putsock("%s " P10_SVSJOIN " %s %s "FMT_TIME_T, from->uplink->numeric, who->numeric, to->name, now);
1012 }
1013
1014 void
1015 irc_svspart(struct userNode *from, struct userNode *who, struct chanNode *to)
1016 {
1017 putsock("%s " P10_SVSPART " %s %s", from->uplink->numeric, who->numeric, to->name);
1018 }
1019
1020 void
1021 irc_kick(struct userNode *who, struct userNode *target, struct chanNode *channel, const char *msg)
1022 {
1023 const char *numeric;
1024 struct modeNode *mn = GetUserMode(channel, who);
1025 numeric = ((mn && (mn->modes & MODE_CHANOP)) || off_channel) ? who->numeric : self->numeric;
1026 putsock("%s " P10_KICK " %s %s :%s",
1027 numeric, channel->name, target->numeric, msg);
1028 }
1029
1030 void
1031 irc_stats(struct userNode *from, struct server *target, char type)
1032 {
1033 putsock("%s " P10_STATS " %c :%s", from->numeric, type, target->numeric);
1034 }
1035
1036 void
1037 irc_svsnick(struct userNode *from, struct userNode *target, const char *newnick)
1038 {
1039 putsock("%s " P10_SVSNICK " %s %s "FMT_TIME_T, from->uplink->numeric, target->numeric, newnick, now);
1040 }
1041
1042 void
1043 irc_swhois(struct userNode *from, struct userNode *target, const char *message)
1044 {
1045 putsock("%s " P10_SWHOIS " %s %s%s", from->uplink->numeric, target->numeric, message ? ":" : "",
1046 message ? message : "");
1047
1048 }
1049
1050 void
1051 irc_part(struct userNode *who, struct chanNode *what, const char *reason)
1052 {
1053 if (reason) {
1054 putsock("%s " P10_PART " %s :%s", who->numeric, what->name, reason);
1055 } else {
1056 putsock("%s " P10_PART " %s", who->numeric, what->name);
1057 }
1058 }
1059
1060 void
1061 irc_topic(struct userNode *service, struct userNode *who, struct chanNode *what, const char *topic)
1062 {
1063
1064 int type = 4;
1065 int host_in_topic = 0;
1066 const char *hstr, *tstr;
1067 char *host, *hostmask;
1068 char shost[MAXLEN];
1069 char sident[MAXLEN];
1070
1071 tstr = conf_get_data("server/type", RECDB_QSTRING);
1072 hstr = conf_get_data("server/host_in_topic", RECDB_QSTRING);
1073 if(tstr)
1074 type = atoi(tstr);
1075 else
1076 type = 4;/* default to 040 style topics */
1077
1078 if (hstr) {
1079 if (IsFakeHost(who))
1080 safestrncpy(shost, who->fakehost, sizeof(shost));
1081 else if (IsSetHost(who)) {
1082 hostmask = strdup(who->sethost);
1083 if ((host = (strrchr(hostmask, '@'))))
1084 *host++ = '\0';
1085 else
1086 host = hostmask;
1087
1088 safestrncpy(sident, hostmask, sizeof(shost));
1089 safestrncpy(shost, host, sizeof(shost));
1090 } else
1091 safestrncpy(shost, who->hostname, sizeof(shost));
1092
1093 host_in_topic = atoi(hstr);
1094 }
1095
1096 if (type >= 5) {
1097 putsock("%s " P10_TOPIC " %s %s%s%s%s%s " FMT_TIME_T " " FMT_TIME_T " :%s", service->numeric, what->name,
1098 who->nick, host_in_topic ? "!" : "", host_in_topic ? (IsSetHost(who) ? sident : who->ident) : "",
1099 host_in_topic ? "@" : "", host_in_topic ? shost : "", what->timestamp, now, topic);
1100 } else {
1101 who = service;
1102 putsock("%s " P10_TOPIC " %s :%s", who->numeric, what->name, topic);
1103 }
1104 }
1105
1106 void
1107 irc_raw(const char *what)
1108 {
1109 putsock("%s", what);
1110 }
1111
1112 void
1113 irc_numeric(struct userNode *user, unsigned int num, const char *format, ...)
1114 {
1115 va_list arg_list;
1116 char buffer[MAXLEN];
1117 va_start(arg_list, format);
1118 vsnprintf(buffer, MAXLEN-2, format, arg_list);
1119 buffer[MAXLEN-1] = 0;
1120 putsock(":%s %03d %s %s", self->name, num, user->nick, buffer);
1121 }
1122
1123 void
1124 irc_mark(struct userNode *user, char *mark)
1125 {
1126 char *host = user->hostname;
1127
1128 /* TODO: Allow mark overwrite. If they are marked, and their fakehost is oldmark.hostname, update it to newmark.hostname so mark can be called multiple times. Probably requires ircd modification also */
1129 if(user->mark)
1130 return;
1131
1132 /* if the mark will put us over the host length, clip some off the left hand side
1133 * to make room...
1134 */
1135 if(strlen(host) + 1 + strlen(mark) > HOSTLEN)
1136 host += 1 + ( (strlen(host) + 1 + strlen(mark)) - HOSTLEN );
1137 putsock("%s " CMD_MARK " %s DNSBL +m %s.%s", self->numeric, user->nick, mark, host);
1138 putsock("%s " CMD_MARK " %s DNSBL_DATA %s", self->numeric, user->nick, mark);
1139
1140 /* Save it in the user */
1141 user->mark = strdup(mark);
1142
1143 /* If they are not otherwise marked, mark their host with fakehost */
1144 if(!IsFakeHost(user) && !IsSetHost(user) && !(IsHiddenHost(user) && user->handle_info) )
1145 {
1146 struct modeNode *mn = NULL;
1147 char fakehost[HOSTLEN];
1148 unsigned int count = 0;
1149 unsigned int n = 0;
1150
1151 putsock("%s " CMD_FAKEHOST " %s %s.%s", self->numeric, user->numeric, mark, host);
1152 putsock("%s " CMD_MODE " %s +x", self->numeric, user->nick);
1153
1154 snprintf(fakehost, sizeof(fakehost), "%s.%s", mark, host);
1155 safestrncpy(user->fakehost, fakehost, sizeof(user->fakehost));
1156
1157 for (n=count=0; n<user->channels.used; n++) {
1158 mn = user->channels.list[n];
1159 if (strlen(mn->channel->name) >= 1) /* Sanity */
1160 check_bans(user, mn->channel->name);
1161 }
1162 }
1163 }
1164
1165 static void send_burst(void);
1166
1167 static void
1168 change_nicklen(int new_nicklen)
1169 {
1170 unsigned int nn;
1171 char new_nick[NICKLEN+1];
1172 struct userNode *user;
1173
1174 nicklen = new_nicklen;
1175 /* fix up any users we have here */
1176 for (nn=0; nn<=self->num_mask; nn++) {
1177 if (!(user = self->users[nn]))
1178 continue;
1179 safestrncpy(new_nick, user->nick, sizeof(new_nick));
1180 new_nick[nicklen] = 0;
1181 NickChange(user, new_nick, 1);
1182 }
1183 }
1184
1185 static CMD_FUNC(cmd_whois)
1186 {
1187 struct userNode *from;
1188 struct userNode *who;
1189
1190 if (argc < 3)
1191 return 0;
1192 if (!(from = GetUserH(origin))) {
1193 log_module(MAIN_LOG, LOG_ERROR, "Could not find WHOIS origin user %s", origin);
1194 return 0;
1195 }
1196 if(!(who = GetUserH(argv[2]))) {
1197 irc_numeric(from, ERR_NOSUCHNICK, "%s@%s :No such nick", argv[2], self->name);
1198 return 1;
1199 }
1200 if (IsHiddenHost(who) && !IsOper(from)) {
1201 /* Just stay quiet. */
1202 return 1;
1203 }
1204 irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info);
1205 if (his_servername && his_servercomment)
1206 irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment);
1207 else
1208 irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, who->uplink->name, who->uplink->description);
1209 if (IsOper(who))
1210 irc_numeric(from, RPL_WHOISOPERATOR, "%s :is a megalomaniacal power hungry tyrant", who->nick);
1211 irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick);
1212 return 1;
1213 }
1214
1215 static CMD_FUNC(cmd_server)
1216 {
1217 struct server *srv;
1218 const char *str;
1219
1220 if (argc < 8)
1221 return 0;
1222 if (self->uplink) {
1223 /* another server introduced us */
1224 srv = AddServer(GetServerH(origin), argv[1], atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), argv[6], argv[argc-1]);
1225 if (!srv)
1226 return 0;
1227 srv->self_burst = argv[5][0] == 'J';
1228 srv->burst = 1;
1229 } else {
1230 /* this must be our uplink */
1231 srv = self->uplink = AddServer(self, argv[1], atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), argv[6], argv[argc-1]);
1232 if (!srv)
1233 return 0;
1234 srv->self_burst = argv[5][0] == 'J';
1235 srv->burst = 1;
1236 if ((argv[7][0] == '+') && !force_n2k) {
1237 log_module(MAIN_LOG, LOG_WARNING, "Got Undernet-style SERVER message but \"force_n2k\" not on.");
1238 }
1239 send_burst();
1240 }
1241
1242 /* Fix up our timestamps if necessary. */
1243 if (srv->boot <= PREHISTORY) {
1244 /* Server from the mists of time.. */
1245 if (srv->hops == 1) {
1246 log_module(MAIN_LOG, LOG_ERROR, "Server %s claims to have booted at time "FMT_TIME_T". This is absurd.", srv->name, srv->boot);
1247 }
1248 } else if ((str = conf_get_data("server/reliable_clock", RECDB_QSTRING))
1249 && enabled_string(str)) {
1250 /* If we have a reliable clock, we just keep our current time. */
1251 } else {
1252 if (srv->boot <= self->boot) {
1253 /* The other server is older than us. Accept their timestamp.
1254 * Alternately, we are same age, but we accept their time
1255 * since we are linking to them. */
1256 self->boot = srv->boot;
1257 ioset_set_time(srv->link);
1258 }
1259 }
1260 if (srv == self->uplink) {
1261 extern time_t burst_begin;
1262 burst_begin = now;
1263 }
1264 return 1;
1265 }
1266
1267
1268 static CMD_FUNC(cmd_eob)
1269 {
1270 struct server *sender;
1271 dict_iterator_t it;
1272 unsigned int ii;
1273
1274 if (!(sender = GetServerH(origin)))
1275 return 0;
1276 if (sender == self->uplink) {
1277 cManager.uplink->state = CONNECTED;
1278 for (it = dict_first(unbursted_channels); it; it = iter_next(it))
1279 irc_burst(iter_data(it));
1280 dict_delete(unbursted_channels);
1281 unbursted_channels = NULL;
1282 irc_eob();
1283 irc_eob_ack();
1284
1285 /* now that we know who our uplink is,
1286 * we can center the routing map and activate auto-routing.
1287 */
1288 //activate_routing(NULL, NULL, NULL);
1289 routing_init();
1290 }
1291 sender->self_burst = 0;
1292 recalc_bursts(sender);
1293 for (ii=0; ii<slf_used; ii++)
1294 slf_list[ii](sender);
1295 /* let auto-routing figure out if we were
1296 * wating on this server to link a child to it */
1297 /* DONT call this if uplink is _US_ */
1298 if(sender->uplink != self)
1299 routing_handle_connect(sender->name, sender->uplink->name);
1300 return 1;
1301 }
1302
1303 static CMD_FUNC(cmd_eob_ack)
1304 {
1305 extern time_t burst_begin;
1306
1307 if (GetServerH(origin) == self->uplink) {
1308 burst_length = now - burst_begin;
1309 self->self_burst = self->burst = 0;
1310 }
1311 cManager.uplink->state = CONNECTED;
1312 return 1;
1313 }
1314
1315 static CMD_FUNC(cmd_rping)
1316 {
1317 struct server *dest;
1318
1319 if (!(dest = GetServerN(argv[1])))
1320 return 0;
1321
1322 if (dest == self)
1323 irc_rpong(argv[2], argv[3], argv[4], argv[5]);
1324
1325 return 1;
1326 }
1327
1328 static CMD_FUNC(cmd_ping)
1329 {
1330 struct server *srv;
1331 struct userNode *un;
1332
1333 if (argc > 3)
1334 irc_pong_asll(argv[2], argv[3]);
1335 else if ((srv = GetServerH(origin)))
1336 irc_pong(self->name, srv->numeric);
1337 else if ((un = GetUserH(origin)))
1338 irc_pong(self->name, un->numeric);
1339 else
1340 irc_pong(self->name, origin);
1341
1342 timeq_del(0, timed_send_ping, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
1343 timeq_del(0, timed_ping_timeout, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
1344 timeq_add(now + ping_freq, timed_send_ping, 0);
1345 received_ping();
1346 return 1;
1347 }
1348
1349 static CMD_FUNC(cmd_error_nick)
1350 {
1351 /* Go back to original IRC length .. and try to reconnect :/ */
1352 change_nicklen(9);
1353 irc_squit(self, "Got erroneous nickname, truncating nicks.", NULL);
1354 return 1;
1355 }
1356
1357 struct create_desc {
1358 struct userNode *user;
1359 time_t when;
1360 };
1361
1362 static void
1363 join_helper(struct chanNode *chan, void *data)
1364 {
1365 struct create_desc *cd = data;
1366 AddChannelUser(cd->user, chan);
1367 }
1368
1369 static void
1370 create_helper(char *name, void *data)
1371 {
1372 struct create_desc *cd = data;
1373
1374 if (!strcmp(name, "0")) {
1375 while (cd->user->channels.used > 0)
1376 DelChannelUser(cd->user, cd->user->channels.list[0]->channel, 0, 0);
1377 return;
1378 }
1379
1380 AddChannelUser(cd->user, AddChannel(name, cd->when, NULL, NULL, NULL));
1381 }
1382
1383 static CMD_FUNC(cmd_create)
1384 {
1385 struct create_desc cd;
1386 struct userNode *user;
1387
1388 if ((argc < 3) || !(user = GetUserH(origin)))
1389 return 0;
1390 cd.user = user;
1391 cd.when = atoi(argv[2]);
1392 parse_foreach(argv[1], join_helper, create_helper, NULL, NULL, &cd);
1393 return 1;
1394 }
1395
1396 static CMD_FUNC(cmd_join)
1397 {
1398 struct create_desc cd;
1399
1400 if (!(cd.user = GetUserH(origin)))
1401 return 0;
1402 if (argc < 2)
1403 return 0;
1404 else if (argc < 3)
1405 cd.when = now;
1406 else
1407 cd.when = atoi(argv[2]);
1408 parse_foreach(argv[1], join_helper, create_helper, NULL, NULL, &cd);
1409 return 1;
1410 }
1411
1412 static CMD_FUNC(cmd_svsjoin)
1413 {
1414 struct create_desc cd;
1415
1416 if (!(cd.user = GetUserH(argv[1])))
1417 return 0;
1418 if (argc < 3)
1419 return 0;
1420 else if (argc < 4)
1421 cd.when = now;
1422 else
1423 cd.when = atoi(argv[3]);
1424 parse_foreach(argv[2], join_helper, create_helper, NULL, NULL, &cd);
1425 return 1;
1426 }
1427
1428 static CMD_FUNC(cmd_pong)
1429 {
1430 if (argc < 3)
1431 return 0;
1432 if (!strcmp(argv[2], self->name)) {
1433 timeq_del(0, timed_send_ping, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
1434 timeq_del(0, timed_ping_timeout, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
1435 timeq_add(now + ping_freq, timed_send_ping, 0);
1436 received_ping();
1437 }
1438 return 1;
1439 }
1440
1441 static CMD_FUNC(cmd_nick)
1442 {
1443 struct userNode *user;
1444 if ((user = GetUserH(origin))) {
1445 /* nick change (since the source is a user numeric) */
1446 if (argc < 2)
1447 return 0;
1448 NickChange(user, argv[1], 1);
1449 } else {
1450 struct server *serv;
1451 struct userNode *nuser;
1452 char modes[MAXLEN];
1453 /* new nick */
1454 if (argc < 9)
1455 return 0;
1456 serv = GetServerH(origin);
1457 if (argc > 9)
1458 unsplit_string(argv+6, argc-9, modes);
1459 else
1460 strcpy(modes, "+");
1461 nuser = AddUser(serv, argv[1], argv[4], argv[5], modes, argv[argc-2], argv[argc-1], atoi(argv[3]), argv[argc-3]);
1462 }
1463 return 1;
1464 }
1465
1466 static CMD_FUNC(cmd_account)
1467 {
1468 struct userNode *user;
1469 struct server *server;
1470 struct handle_info *hi;
1471
1472 if ((argc < 3) || !origin || !(server = GetServerH(origin)))
1473 return 0; /* Origin must be server. */
1474
1475 /* This next line appears to tremple origin.. why? */
1476 user = GetUserN(argv[1]);
1477 if (!user)
1478 return 1; /* A QUIT probably passed the ACCOUNT. */
1479
1480 if(!extended_accounts) /* any need for this function without? */
1481 return 1;
1482
1483 if(!strcmp(argv[2],"C"))
1484 {
1485 if((hi = loc_auth(argv[4], argv[5])))
1486 {
1487 /* Return a AC A */
1488 putsock("%s " P10_ACCOUNT " %s A %s %lu", self->numeric, server->numeric , argv[3], hi->registered);
1489
1490 }
1491 else
1492 {
1493 /* Return a AC D */
1494 putsock("%s " P10_ACCOUNT " %s D %s", self->numeric, server->numeric , argv[3]);
1495 }
1496 return 1;
1497 }
1498 else if(!strcmp(argv[2],"R"))
1499 call_account_func(user, argv[3]);
1500 else
1501 call_account_func(user, argv[2]); /* For backward compatability */
1502 return 1;
1503 }
1504
1505 static CMD_FUNC(cmd_fakehost)
1506 {
1507 struct userNode *user;
1508
1509 if ((argc < 3) || !origin || !GetServerH(origin))
1510 return 0;
1511 if (!(user = GetUserN(argv[1])))
1512 return 1;
1513 assign_fakehost(user, argv[2], 0);
1514 return 1;
1515 }
1516
1517 static struct {
1518 char *name;
1519 unsigned int priv;
1520 } privtab[] = {
1521 #define P(priv) { #priv, PRIV_ ## priv }
1522 P(CHAN_LIMIT), P(MODE_LCHAN), P(WALK_LCHAN), P(DEOP_LCHAN),
1523 P(SHOW_INVIS), P(SHOW_ALL_INVIS), P(UNLIMIT_QUERY), P(KILL),
1524 P(LOCAL_KILL), P(REHASH), P(RESTART), P(DIE),
1525 P(GLINE), P(LOCAL_GLINE), P(JUPE), P(LOCAL_JUPE),
1526 P(OPMODE), P(LOCAL_OPMODE), P(SET), P(WHOX),
1527 P(BADCHAN), P(LOCAL_BADCHAN), P(SEE_CHAN), P(PROPAGATE),
1528 P(DISPLAY), P(SEE_OPERS), P(WIDE_GLINE), P(FORCE_OPMODE),
1529 P(FORCE_LOCAL_OPMODE), P(REMOTEREHASH), P(CHECK), P(SEE_SECRET_CHAN),
1530 P(SHUN), P(LOCAL_SHUN), P(WIDE_SHUN),
1531 #undef P
1532 { 0, 0 }
1533 };
1534
1535 char *client_report_privs(struct userNode *client)
1536 {
1537 int i;
1538
1539 privbuf[0] = '\0';
1540 for (i = 0; privtab[i].name; i++) {
1541 if (HasPriv(client, privtab[i].priv)) {
1542 strcat(privbuf, privtab[i].name);
1543 strcat(privbuf, " ");
1544 }
1545 }
1546
1547 privbuf[strlen(privbuf)] = 0;
1548
1549 return privbuf;
1550 }
1551
1552 int client_modify_priv_by_name(struct userNode *who, char *priv, int what) {
1553 int i = 0;
1554 assert(0 != priv);
1555 assert(0 != who);
1556
1557 for (i = 0; privtab[i].name; i++) {
1558 if (0 == strcmp(privtab[i].name, priv)) {
1559 if (what == PRIV_ADD)
1560 GrantPriv(who, privtab[i].priv);
1561 else if (what == PRIV_DEL) {
1562 RevokePriv(who, privtab[i].priv);
1563 }
1564 }
1565 }
1566 return 0;
1567 }
1568
1569 int check_priv(char *priv)
1570 {
1571 int i;
1572
1573 for (i = 0; privtab[i].name; i++) {
1574 if (0 == strcmp(privtab[i].name, priv)) {
1575 return 1;
1576 }
1577 }
1578 return 0;
1579 }
1580
1581 void
1582 irc_privs(struct userNode *target, char *flag, int add)
1583 {
1584 client_modify_priv_by_name(target, flag, add);
1585 putsock("%s " P10_PRIVS " %s %s%s", self->numeric, target->numeric, (add == PRIV_ADD) ? "+" : "-", flag);
1586 }
1587
1588 static CMD_FUNC(cmd_privs)
1589 {
1590 char *tstr = NULL;
1591 int type = 0;
1592
1593 tstr = conf_get_data("server/type", RECDB_QSTRING);
1594 if(tstr)
1595 type = atoi(tstr);
1596
1597 if (type < 6)
1598 return 1; /* silently ignore */
1599
1600 struct userNode *user = argc > 1 ? GetUserN(argv[1]) : NULL;
1601 char buf[512] = "";
1602 int what = PRIV_ADD;
1603 char *p = 0;
1604 char *tmp;
1605 unsigned int i;
1606
1607 if (argc < 3)
1608 return 0;
1609
1610 if (!user)
1611 return 0;
1612
1613 for (i=1; i<argc; i++) {
1614 strcat(buf, argv[i]);
1615 strcat(buf, " ");
1616 }
1617
1618 for (i = 2; i < argc; i++) {
1619 if (*argv[i] == '+') { what = PRIV_ADD; argv[i]++; }
1620 if (*argv[i] == '-') { what = PRIV_DEL; argv[i]++; }
1621 for (tmp = x3_strtok(&p, argv[i], ","); tmp;
1622 tmp = x3_strtok(&p, NULL, ",")) {
1623 client_modify_priv_by_name(user, tmp, what);
1624 }
1625 }
1626 return 1;
1627 }
1628
1629 static CMD_FUNC(cmd_burst)
1630 {
1631 extern int rel_age;
1632 char modes[MAXLEN], *members = "";
1633 static char exemptlist[MAXLEN], banlist[MAXLEN];
1634 unsigned int next = 3, res = 1;
1635 int ctype = 0, echeck = 0, bcheck = 0;
1636 struct chanNode *cNode;
1637 struct userNode *un;
1638 struct modeNode *mNode;
1639 long mode;
1640 int oplevel = -1;
1641 char *user, *end, sep;
1642 time_t in_timestamp;
1643 char* parm = NULL;
1644
1645 if (argc < 3)
1646 return 0;
1647 modes[0] = 0;
1648
1649 exemptlist[0] = 0;
1650 banlist[0] = 0;
1651
1652 while (next < argc) {
1653 switch (argv[next][0]) {
1654 case '+': {
1655 const char *pos;
1656 int n_modes;
1657 for (pos=argv[next], n_modes = 1; *pos; pos++)
1658 if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A')
1659 || (*pos == 'U'))
1660 n_modes++;
1661 unsplit_string(argv+next, n_modes, modes);
1662 next += n_modes;
1663 break;
1664 }
1665 case '%': {
1666 for(parm = mysep(&argv[next], " "); /* parm = first param */
1667 parm; /* While param is not null */
1668 parm = mysep(&argv[next], " ") /* parm = next param */
1669 )
1670 {
1671 switch (parm[0]) {
1672 case '%': {
1673 ctype = 1;
1674 break;
1675 }
1676 case '~': {
1677 ctype = 2;
1678 break;
1679 }
1680 default: {
1681 break;
1682 }
1683 }
1684 if (ctype == 1) {
1685 if (bcheck == 0) {
1686 /* strip % char off start of very first ban */
1687 if (strlen(parm) > 1) {
1688 strncat(banlist, strtok(parm, "%"), sizeof(banlist) - 1 - strlen(banlist));
1689 strncat(banlist, " ", sizeof(banlist) - 1 - strlen(banlist));
1690 }
1691 bcheck = 1;
1692 } else {
1693 strncat(banlist, parm, sizeof(banlist) - 1 - strlen(banlist));
1694 strncat(banlist, " ", sizeof(banlist) - 1 - strlen(banlist));
1695 }
1696 } else if (ctype == 2) {
1697 if (echeck == 0) {
1698 echeck = 1;
1699 } else {
1700 strncat(exemptlist, parm, sizeof(exemptlist) - 1 - strlen(exemptlist));
1701 strncat(exemptlist, " ", sizeof(exemptlist) - 1 - strlen(exemptlist));
1702 }
1703 }
1704 }
1705 next++;
1706 break;
1707 }
1708 default: members = argv[next++]; break;
1709 }
1710 }
1711
1712 in_timestamp = atoi(argv[2]);
1713 if ((cNode = dict_find(unbursted_channels, argv[1], NULL))) {
1714 cNode->timestamp = in_timestamp;
1715 dict_remove(unbursted_channels, cNode->name);
1716 irc_burst(cNode);
1717 }
1718 cNode = AddChannel(argv[1], in_timestamp, modes, banlist, exemptlist);
1719
1720 /* Burst channel members in now. */
1721 for (user = members, sep = *members, mode = 0; sep; user = end) {
1722 for (end = user + 3; isalnum(*end) || *end == '[' || *end == ']'; end++) ;
1723 sep = *end++; end[-1] = 0;
1724 if (sep == ':') {
1725 mode = 0;
1726 while ((sep = *end++)) {
1727 if (sep == 'o') {
1728 mode |= MODE_CHANOP;
1729 oplevel = -1;
1730 } else if (sep == 'h') {
1731 mode |= MODE_HALFOP;
1732 oplevel = -1;
1733 } else if (sep == 'v') {
1734 mode |= MODE_VOICE;
1735 oplevel = -1;
1736 } else if (isdigit(sep)) {
1737 mode |= MODE_CHANOP;
1738 if (oplevel >= 0)
1739 oplevel += parse_oplevel(end);
1740 else
1741 oplevel = parse_oplevel(end);
1742 while (isdigit(*end)) end++;
1743 } else
1744 break;
1745 }
1746 if (rel_age < 0)
1747 mode = 0;
1748 }
1749 if (!(un = GetUserN(user))) {
1750 res = 0;
1751 continue;
1752 }
1753 if ((mNode = AddChannelUser(un, cNode))) {
1754 mNode->modes = mode;
1755 mNode->oplevel = oplevel;
1756 }
1757 }
1758
1759 return res;
1760 }
1761
1762 /* TODO:
1763 * This is a stub that doesn't actually do anything. It should be completed
1764 * so that bans on *!*@markname.* match users as it does in nefarious
1765 */
1766 static CMD_FUNC(cmd_mark)
1767 {
1768 struct userNode *target;
1769 /*
1770 * log_module(MAIN_LOG, LOG_ERROR, "DEBUG: mark, user %s, type %s, arg %s", argv[1], argv[2], argv[3]);
1771 */
1772
1773 if(argc < 4)
1774 return 0;
1775 if(!strcasecmp(argv[2], "DNSBL")) {
1776 /* DNSBL <modes> */
1777 return 1;
1778 }
1779 else if(!strcasecmp(argv[2], "DNSBL_DATA")) {
1780 /* DNSBL_DATA name */
1781 target = GetUserH(argv[1]);
1782 if(!target) {
1783 log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose mark is changing.", argv[1]);
1784 return 0;
1785 }
1786 target->mark = strdup(argv[3]);
1787 return 1;
1788
1789 }
1790 /* unknown type of mark */
1791 return 1;
1792 }
1793
1794 static CMD_FUNC(cmd_mode)
1795 {
1796 struct chanNode *cn;
1797 struct userNode *un;
1798 char *sethost; // sethost - reed/apples
1799 int i; // sethost - reed/apples
1800
1801 if (argc < 3)
1802 return 0;
1803 if (!IsChannelName(argv[1])) {
1804 un = GetUserH(argv[1]);
1805 if (!un) {
1806 log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose mode is changing.", argv[1]);
1807 return 0;
1808 }
1809 // sethost - reed/apples
1810 if (argc == 3)
1811 mod_usermode(un, argv[2]);
1812 else {
1813 sethost = malloc(strlen(argv[2]) + 1 + strlen(argv[3]) + 1);
1814 i = 0;
1815 while((sethost[i++] = *argv[2]++));
1816 i--;
1817 sethost[i++] = ' ';
1818 while((sethost[i++] = *argv[3]++));
1819 mod_usermode(un, sethost); // sethost - reed/apples
1820 }
1821
1822 return 1;
1823 }
1824
1825 if (!(cn = GetChannel(argv[1]))) {
1826 log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s whose mode is changing.", argv[1]);
1827 return 0;
1828 }
1829 if ((un = GetUserH(origin))) {
1830 struct modeNode *mn;
1831 /* Update idle time for person setting the mode */
1832 if ((mn = GetUserMode(cn, un)))
1833 mn->idle_since = now;
1834 } else {
1835 /* If it came from a server, reset timestamp to re-sync. */
1836 cn->timestamp = atoi(argv[argc-1]);
1837 }
1838
1839 if (checkDefCon(DEFCON_NO_MODE_CHANGE) && !IsOper(un)) {
1840 const char *str;
1841 str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
1842 if (str) {
1843 char modes[MODELEN];
1844 struct userNode *opserv = GetUserH(str);
1845
1846 send_message_type(4, un, opserv, "Channel modes cannot be changed due to DefCon level %d in effect, please try again soon", DefConLevel);
1847 irc_make_chanmode(cn, modes);
1848 irc_mode(opserv, cn, modes);
1849 irc_mode(opserv, cn, DefConChanModes);
1850 }
1851 return 1;
1852 }
1853
1854
1855 return mod_chanmode(un, cn, argv+2, argc-2, MCP_ALLOW_OVB|MCP_FROM_SERVER|(un ? MC_NOTIFY : 0));
1856 }
1857
1858 static CMD_FUNC(cmd_opmode)
1859 {
1860 struct chanNode *cn;
1861 struct userNode *un;
1862
1863 if (argc < 3)
1864 return 0;
1865
1866 if (!(cn = GetChannel(argv[1]))) {
1867 log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s whose mode is changing.", argv[1]);
1868 return 0;
1869 }
1870 if (!(un = GetUserH(origin))) {
1871 log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s requesting OPMODE.", origin);
1872 return 0;
1873 }
1874 if (!IsOper(un)) {
1875 log_module(MAIN_LOG, LOG_ERROR, "Non-privileged user %s using OPMODE.", un->nick);
1876 return 0;
1877 }
1878
1879 return mod_chanmode(un, cn, argv+2, argc-2, MCP_ALLOW_OVB|MCP_FROM_SERVER); /* do NOT announce opmode locally */
1880 }
1881
1882 static int clear_chanmode(struct chanNode *channel, const char *modes);
1883
1884 static CMD_FUNC(cmd_clearmode)
1885 {
1886 struct chanNode *cn;
1887 struct userNode *un;
1888
1889 if (argc < 3)
1890 return 0;
1891
1892 if (!(cn = GetChannel(argv[1]))) {
1893 log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s whose mode is changing.", argv[1]);
1894 return 0;
1895 }
1896 if (!(un = GetUserH(origin))) {
1897 log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s requesting CLEARMODE.", origin);
1898 return 0;
1899 }
1900 if (!IsOper(un)) {
1901 log_module(MAIN_LOG, LOG_ERROR, "Non-privileged user %s using CLEARMODE.", un->nick);
1902 return 0;
1903 }
1904
1905 return clear_chanmode(cn, argv[2]);
1906 }
1907
1908 static CMD_FUNC(cmd_topic)
1909 {
1910 struct chanNode *cn;
1911 time_t chan_ts, topic_ts;
1912 struct userNode *user;
1913
1914 if (argc < 3)
1915 return 0;
1916 if (!(cn = GetChannel(argv[1]))) {
1917 log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s whose topic is being set", argv[1]);
1918 return 0;
1919 }
1920
1921
1922 if (argc == 5) { /* Asuka / Topic Bursting IRCu's */
1923 user = GetUserH(origin);
1924 chan_ts = atoi(argv[2]);
1925 topic_ts = atoi(argv[3]);
1926 } else if (argc >= 6) { /* Nefarious 0.5.0 */
1927 user = GetUserH(strtok(argv[2], "!"));
1928 chan_ts = atoi(argv[3]);
1929 topic_ts = atoi(argv[4]);
1930 } else { /* Regular IRCu (No Topic Bursting)*/
1931 user = GetUserH(origin);
1932 chan_ts = cn->timestamp;
1933 topic_ts = now;
1934 }
1935
1936 SetChannelTopic(cn, user, user, argv[argc-1], 0);
1937 cn->topic_time = topic_ts;
1938 return 1;
1939 }
1940
1941 static CMD_FUNC(cmd_num_topic)
1942 {
1943 struct chanNode *cn;
1944
1945 if (!argv[0])
1946 return 0; /* huh? */
1947 if (argv[2]) {
1948 cn = GetChannel(argv[2]);
1949 if (!cn) {
1950 log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s in topic reply", argv[2]);
1951 return 0;
1952 }
1953 } else
1954 return 0;
1955
1956 switch (atoi(argv[0])) {
1957 case 331:
1958 cn->topic_time = 0;
1959 break; /* no topic */
1960 case 332:
1961 if (argc < 4)
1962 return 0;
1963 safestrncpy(cn->topic, unsplit_string(argv+3, argc-3, NULL), sizeof(cn->topic));
1964 break;
1965 case 333:
1966 if (argc < 5)
1967 return 0;
1968 safestrncpy(cn->topic_nick, argv[3], sizeof(cn->topic_nick));
1969 cn->topic_time = atoi(argv[4]);
1970 break;
1971 default:
1972 return 0; /* should never happen */
1973 }
1974 return 1;
1975 }
1976
1977 static CMD_FUNC(cmd_num_gline)
1978 {
1979 if (argc < 6)
1980 return 0;
1981 gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0, 0);
1982 return 1;
1983 }
1984
1985 static CMD_FUNC(cmd_num_shun)
1986 {
1987 if (argc < 6)
1988 return 0;
1989 shun_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0);
1990 return 1;
1991 }
1992
1993 static CMD_FUNC(cmd_quit)
1994 {
1995 struct userNode *user;
1996 if (argc < 2)
1997 return 0;
1998 /* Sometimes we get a KILL then a QUIT or the like, so we don't want to
1999 * call DelUser unless we have the user in our grasp. */
2000 if ((user = GetUserH(origin)))
2001 DelUser(user, NULL, false, argv[1]);
2002 return 1;
2003 }
2004
2005 static CMD_FUNC(cmd_kill)
2006 {
2007 struct userNode *user;
2008 if (argc < 2)
2009 return 0;
2010 user = GetUserN(argv[1]);
2011 if (!user) {
2012 /* If we get a KILL for a non-existent user, it could be a
2013 * Ghost response to a KILL we sent out earlier. So we only
2014 * whine if the target is local.
2015 */
2016 if (!strncmp(argv[1], self->numeric, strlen(self->numeric)))
2017 log_module(MAIN_LOG, LOG_ERROR, "Unable to find kill victim %s", argv[1]);
2018 return 0;
2019 }
2020
2021 if (IsLocal(user) && IsService(user)) {
2022 /* TODO: rate limit this so silly things don't happen. */
2023 ReintroduceUser(user);
2024 return 1;
2025 }
2026
2027 DelUser(user, NULL, false, argv[2]);
2028 return 1;
2029 }
2030
2031 static CMD_FUNC(cmd_part)
2032 {
2033 struct userNode *user;
2034
2035 if (argc < 2)
2036 return 0;
2037 user = GetUserH(origin);
2038 if (!user)
2039 return 0;
2040 parse_foreach(argv[1], part_helper, NULL, NULL, NULL, user);
2041 return 1;
2042 }
2043
2044 static CMD_FUNC(cmd_svspart)
2045 {
2046 struct userNode *user;
2047
2048 if (argc < 3)
2049 return 0;
2050 user = GetUserN(argv[1]);
2051 if (!user)
2052 return 0;
2053 parse_foreach(argv[2], part_helper, NULL, NULL, NULL, user);
2054 return 1;
2055 }
2056
2057 static CMD_FUNC(cmd_silence)
2058 {
2059 struct userNode *user;
2060 char *mask;
2061 char *new_mask;
2062 unsigned int i;
2063
2064 if (argc < 2)
2065 return 0;
2066
2067 user = GetUserN(argv[1]);
2068
2069 /* Sanity, go nuts if this happens */
2070 if (!user)
2071 return 0;
2072
2073 /* We can safely ignore this if a user adding a silence is not
2074 * ignored. However this brings up a TODO. If a user logs in and
2075 * they have silences on the IRCd then we need to set them here
2076 * somehow
2077 */
2078 if (!user->handle_info)
2079 return 1;
2080
2081 mask = argv[2];
2082
2083 if (*mask == '-') {
2084 for (i=0; i<user->handle_info->ignores->used; i++) {
2085 if (!irccasecmp(mask+1, user->handle_info->ignores->list[i]))
2086 user->handle_info->ignores->list[i] = user->handle_info->ignores->list[--user->handle_info->ignores->used];
2087 }
2088 } else {
2089 for (i=0; i<user->handle_info->ignores->used; i++) {
2090 if (!strcmp(mask+1, user->handle_info->ignores->list[i]))
2091 return 1; /* Already on the users NickServ ignore list, safely ignore */
2092 }
2093
2094 new_mask = strdup(mask+1);
2095 string_list_append(user->handle_info->ignores, new_mask);
2096 }
2097 return 1;
2098 }
2099
2100 static CMD_FUNC(cmd_kick)
2101 {
2102 if (argc < 3)
2103 return 0;
2104 ChannelUserKicked(GetUserH(origin), GetUserN(argv[2]), GetChannel(argv[1]));
2105 return 1;
2106 }
2107
2108 static CMD_FUNC(cmd_squit)
2109 {
2110 struct server *server;
2111 char *uplink;
2112
2113 if (argc < 4)
2114 return 0;
2115 if (!(server = GetServerH(argv[1])))
2116 return 0;
2117
2118 if (server == self->uplink) {
2119 /* Force a reconnect to the currently selected server. */
2120 cManager.uplink->tries = 0;
2121 log_module(MAIN_LOG, LOG_INFO, "Squitting from uplink: %s", argv[3]);
2122 close_socket();
2123 return 1;
2124 }
2125
2126 uplink = strdup(server->uplink->name);
2127 DelServer(server, 0, argv[3]);
2128 /* if its a pingout and pingout connecting is enabled
2129 or its a read error and readerror connecting is enabled
2130 or were doing a "N" and i need to connect that server somewhere */
2131 routing_handle_squit(argv[1], uplink, argv[3]);
2132 free(uplink);
2133 return 1;
2134 }
2135
2136 static CMD_FUNC(cmd_privmsg)
2137 {
2138 struct privmsg_desc pd;
2139 if (argc != 3)
2140 return 0;
2141 pd.user = GetUserH(origin);
2142 if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user)))
2143 return 1;
2144
2145 if (checkDefCon(DEFCON_OPER_ONLY) && !IsOper(pd.user)) {
2146 const char *str;
2147 str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
2148 if (str)
2149 send_message_type(4, pd.user, GetUserH(str), "Services are currently not available, please try again soon");
2150 return 1;
2151 }
2152
2153 if (checkDefCon(DEFCON_SILENT_OPER_ONLY) && !IsOper(pd.user))
2154 return 1; /* Silently Ignore */
2155
2156 pd.is_notice = 0;
2157 pd.text = argv[2];
2158 parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
2159
2160 return 1;
2161 }
2162
2163 static CMD_FUNC(cmd_notice)
2164 {
2165 struct privmsg_desc pd;
2166 struct server *srv;
2167 int nuser = 0;
2168
2169 if (argc != 3)
2170 return 0;
2171
2172 pd.user = GetUserH(origin);
2173 if(!pd.user)
2174 nuser = 1;
2175 if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user))) {
2176 }
2177 else {
2178 pd.is_notice = 1;
2179 pd.text = argv[2];
2180 parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
2181 }
2182
2183 srv = GetServerH(origin);
2184 if(srv) {
2185 char *sargv[MAXNUMPARAMS];
2186 int sargc;
2187
2188 sargc = split_line(argv[2], true, MAXNUMPARAMS, sargv);
2189
2190 if(!strcasecmp(sargv[0], "Connect:")) {
2191 /* :Connect: Host shoe.loxxin.net not listed in ircd.conf */
2192 if(!strcasecmp(sargv[3], "not") && !strcasecmp(sargv[4], "listed")) {
2193 routing_handle_connect_failure(srv, sargv[2], unsplit_string(sargv+3, sargc-3, NULL));
2194 }
2195 }
2196 else if(!strcasecmp(sargv[0], "Link")) {
2197 /* :Link with mephisto.etheria.cx cancelled: Server mephisto.etheria.cx[216.46.33.71]
2198 *
2199 * :Link with laptop.afternet.org cancelled: Connection refused
2200 */
2201 if(!strcasecmp(sargv[3], "cancelled:")) {
2202 routing_handle_connect_failure(srv, sargv[2], unsplit_string(sargv+4, sargc-4, NULL));
2203 }
2204 }
2205 }
2206 return 1;
2207 }
2208
2209 static CMD_FUNC(cmd_away)
2210 {
2211 struct userNode *uNode;
2212
2213 uNode = GetUserH(origin);
2214 if (!uNode)
2215 return 1;
2216 if (argc < 2)
2217 uNode->modes &= ~FLAGS_AWAY;
2218 else
2219 uNode->modes |= FLAGS_AWAY;
2220 return 1;
2221 }
2222
2223 static CMD_FUNC(cmd_gline)
2224 {
2225 if (argc < 3)
2226 return 0;
2227 if (argv[2][0] == '+') {
2228 if (argc < 5)
2229 return 0;
2230 gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0, 0);
2231 return 1;
2232 } else if (argv[2][0] == '-') {
2233 gline_remove(argv[2]+1, 0);
2234 return 1;
2235 } else
2236 return 0;
2237 }
2238
2239 static CMD_FUNC(cmd_shun)
2240 {
2241 if (argc < 3)
2242 return 0;
2243 if (argv[2][0] == '+') {
2244 if (argc < 5)
2245 return 0;
2246 shun_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0);
2247 return 1;
2248 } else if (argv[2][0] == '-') {
2249 shun_remove(argv[2]+1, 0);
2250 return 1;
2251 } else
2252 return 0;
2253 }
2254
2255 static CMD_FUNC(cmd_svsnick)
2256 {
2257 struct userNode *target, *dest;
2258 if ((argc < 4)
2259 || !(target = GetUserN(argv[1]))
2260 || !IsLocal(target)
2261 || (dest = GetUserH(argv[2])))
2262 return 0;
2263 NickChange(target, argv[2], 0);
2264 return 1;
2265 }
2266
2267 static oper_func_t *of_list;
2268 static unsigned int of_size = 0, of_used = 0;
2269
2270 void
2271 free_user(struct userNode *user)
2272 {
2273 free(user->nick);
2274 free(user);
2275 }
2276
2277 static void
2278 parse_cleanup(void)
2279 {
2280 unsigned int nn;
2281 free(of_list);
2282 free(privmsg_funcs);
2283 free(notice_funcs);
2284 free(mcf_list);
2285 dict_delete(irc_func_dict);
2286 for (nn=0; nn<dead_users.used; nn++)
2287 free_user(dead_users.list[nn]);
2288 userList_clean(&dead_users);
2289 }
2290
2291 static void
2292 p10_conf_reload(void) {
2293 hidden_host_suffix = conf_get_data("server/hidden_host", RECDB_QSTRING);
2294 }
2295
2296 static void
2297 remove_unbursted_channel(struct chanNode *cNode) {
2298 if (unbursted_channels)
2299 dict_remove(unbursted_channels, cNode->name);
2300 }
2301
2302 void
2303 init_parse(void)
2304 {
2305 const char *str, *desc;
2306 int numnick, usermask, max_users;
2307 char numer[COMBO_NUMERIC_LEN+1];
2308
2309 /* read config items */
2310 str = conf_get_data("server/extended_accounts", RECDB_QSTRING);
2311 extended_accounts = str ? enabled_string(str) : 1;
2312 str = conf_get_data("server/ping_freq", RECDB_QSTRING);
2313 ping_freq = str ? ParseInterval(str) : 120;
2314 str = conf_get_data("server/ping_timeout", RECDB_QSTRING);
2315 ping_timeout = str ? ParseInterval(str) : 30;
2316 str = conf_get_data("server/force_n2k", RECDB_QSTRING);
2317 force_n2k = str ? enabled_string(str) : 1;
2318 str = conf_get_data("server/numeric", RECDB_QSTRING);
2319 if (!str) {
2320 log_module(MAIN_LOG, LOG_ERROR, "No server/numeric entry in config file.");
2321 exit(1);
2322 }
2323 numnick = atoi(str);
2324 str = conf_get_data("server/max_users", RECDB_QSTRING);
2325 max_users = str ? atoi(str) : 4096;
2326 for (usermask = 4; usermask < max_users; usermask <<= 1) ;
2327 usermask--;
2328 if ((numnick < 64) && (usermask < 4096) && !force_n2k)
2329 inttobase64(numer, (numnick << 12) + (usermask & 0x00fff), 3);
2330 else
2331 inttobase64(numer, (numnick << 18) + (usermask & 0x3ffff), 5);
2332
2333 str = conf_get_data("server/his_servername", RECDB_QSTRING);
2334 his_servername = str ? strdup(str) : NULL;
2335 str = conf_get_data("server/his_servercomment", RECDB_QSTRING);
2336 his_servercomment = str ? strdup(str) : NULL;
2337
2338 str = conf_get_data("server/hostname", RECDB_QSTRING);
2339 desc = conf_get_data("server/description", RECDB_QSTRING);
2340 if (!str || !desc) {
2341 log_module(MAIN_LOG, LOG_ERROR, "No server/hostname entry in config file.");
2342 exit(1);
2343 }
2344 self = AddServer(NULL, str, 0, boot_time, now, numer, desc);
2345 conf_register_reload(p10_conf_reload);
2346
2347 irc_func_dict = dict_new();
2348 dict_insert(irc_func_dict, CMD_BURST, cmd_burst);
2349 dict_insert(irc_func_dict, TOK_BURST, cmd_burst);
2350 dict_insert(irc_func_dict, CMD_CREATE, cmd_create);
2351 dict_insert(irc_func_dict, TOK_CREATE, cmd_create);
2352 dict_insert(irc_func_dict, CMD_EOB, cmd_eob);
2353 dict_insert(irc_func_dict, TOK_EOB, cmd_eob);
2354 dict_insert(irc_func_dict, CMD_EOB_ACK, cmd_eob_ack);
2355 dict_insert(irc_func_dict, TOK_EOB_ACK, cmd_eob_ack);
2356 dict_insert(irc_func_dict, CMD_MODE, cmd_mode);
2357 dict_insert(irc_func_dict, TOK_MODE, cmd_mode);
2358 dict_insert(irc_func_dict, CMD_MARK, cmd_mark);
2359 dict_insert(irc_func_dict, TOK_MARK, cmd_mark);
2360 dict_insert(irc_func_dict, CMD_NICK, cmd_nick);
2361 dict_insert(irc_func_dict, TOK_NICK, cmd_nick);
2362 dict_insert(irc_func_dict, CMD_ACCOUNT, cmd_account);
2363 dict_insert(irc_func_dict, TOK_ACCOUNT, cmd_account);
2364 dict_insert(irc_func_dict, CMD_FAKEHOST, cmd_fakehost);
2365 dict_insert(irc_func_dict, TOK_FAKEHOST, cmd_fakehost);
2366 dict_insert(irc_func_dict, CMD_PASS, cmd_pass);
2367 dict_insert(irc_func_dict, TOK_PASS, cmd_pass);
2368 dict_insert(irc_func_dict, CMD_PING, cmd_ping);
2369 dict_insert(irc_func_dict, TOK_PING, cmd_ping);
2370 dict_insert(irc_func_dict, CMD_PRIVMSG, cmd_privmsg);
2371 dict_insert(irc_func_dict, TOK_PRIVMSG, cmd_privmsg);
2372 dict_insert(irc_func_dict, CMD_PONG, cmd_pong);
2373 dict_insert(irc_func_dict, TOK_PONG, cmd_pong);
2374 dict_insert(irc_func_dict, CMD_QUIT, cmd_quit);
2375 dict_insert(irc_func_dict, TOK_QUIT, cmd_quit);
2376 dict_insert(irc_func_dict, CMD_SERVER, cmd_server);
2377 dict_insert(irc_func_dict, TOK_SERVER, cmd_server);
2378 dict_insert(irc_func_dict, CMD_JOIN, cmd_join);
2379 dict_insert(irc_func_dict, TOK_JOIN, cmd_join);
2380 dict_insert(irc_func_dict, CMD_PART, cmd_part);
2381 dict_insert(irc_func_dict, TOK_PART, cmd_part);
2382 dict_insert(irc_func_dict, CMD_ERROR, cmd_error);
2383 dict_insert(irc_func_dict, TOK_ERROR, cmd_error);
2384 dict_insert(irc_func_dict, CMD_TOPIC, cmd_topic);
2385 dict_insert(irc_func_dict, TOK_TOPIC, cmd_topic);
2386 dict_insert(irc_func_dict, CMD_AWAY, cmd_away);
2387 dict_insert(irc_func_dict, TOK_AWAY, cmd_away);
2388 dict_insert(irc_func_dict, CMD_SILENCE, cmd_silence);
2389 dict_insert(irc_func_dict, TOK_SILENCE, cmd_silence);
2390 dict_insert(irc_func_dict, CMD_KICK, cmd_kick);
2391 dict_insert(irc_func_dict, TOK_KICK, cmd_kick);
2392 dict_insert(irc_func_dict, CMD_SQUIT, cmd_squit);
2393 dict_insert(irc_func_dict, TOK_SQUIT, cmd_squit);
2394 dict_insert(irc_func_dict, CMD_KILL, cmd_kill);
2395 dict_insert(irc_func_dict, TOK_KILL, cmd_kill);
2396 dict_insert(irc_func_dict, CMD_NOTICE, cmd_notice);
2397 dict_insert(irc_func_dict, TOK_NOTICE, cmd_notice);
2398 dict_insert(irc_func_dict, CMD_STATS, cmd_stats);
2399 dict_insert(irc_func_dict, TOK_STATS, cmd_stats);
2400 dict_insert(irc_func_dict, CMD_SVSJOIN, cmd_svsjoin);
2401 dict_insert(irc_func_dict, TOK_SVSJOIN, cmd_svsjoin);
2402 dict_insert(irc_func_dict, CMD_SVSNICK, cmd_svsnick);
2403 dict_insert(irc_func_dict, TOK_SVSNICK, cmd_svsnick);
2404 dict_insert(irc_func_dict, CMD_SVSPART, cmd_svspart);
2405 dict_insert(irc_func_dict, TOK_SVSPART, cmd_svspart);
2406 dict_insert(irc_func_dict, CMD_SWHOIS, cmd_dummy);
2407 dict_insert(irc_func_dict, TOK_SWHOIS, cmd_dummy);
2408 dict_insert(irc_func_dict, CMD_WHOIS, cmd_whois);
2409 dict_insert(irc_func_dict, TOK_WHOIS, cmd_whois);
2410 dict_insert(irc_func_dict, CMD_GLINE, cmd_gline);
2411 dict_insert(irc_func_dict, TOK_GLINE, cmd_gline);
2412 dict_insert(irc_func_dict, CMD_SHUN, cmd_shun);
2413 dict_insert(irc_func_dict, TOK_SHUN, cmd_shun);
2414 dict_insert(irc_func_dict, CMD_OPMODE, cmd_opmode);
2415 dict_insert(irc_func_dict, TOK_OPMODE, cmd_opmode);
2416 dict_insert(irc_func_dict, CMD_CLEARMODE, cmd_clearmode);
2417 dict_insert(irc_func_dict, TOK_CLEARMODE, cmd_clearmode);
2418 dict_insert(irc_func_dict, CMD_VERSION, cmd_version);
2419 dict_insert(irc_func_dict, TOK_VERSION, cmd_version);
2420 dict_insert(irc_func_dict, CMD_ADMIN, cmd_admin);
2421 dict_insert(irc_func_dict, TOK_ADMIN, cmd_admin);
2422
2423 dict_insert(irc_func_dict, CMD_RPING, cmd_rping);
2424 dict_insert(irc_func_dict, TOK_RPING, cmd_rping);
2425 dict_insert(irc_func_dict, CMD_RPONG, cmd_dummy);
2426 dict_insert(irc_func_dict, TOK_RPONG, cmd_dummy);
2427
2428 /* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
2429 * Apparently to obliterate channels from any servers that think they
2430 * exist?
2431 */
2432 dict_insert(irc_func_dict, CMD_DESTRUCT, cmd_dummy);
2433 dict_insert(irc_func_dict, TOK_DESTRUCT, cmd_dummy);
2434 /* Ignore invites */
2435 dict_insert(irc_func_dict, CMD_INVITE, cmd_dummy);
2436 dict_insert(irc_func_dict, TOK_INVITE, cmd_dummy);
2437 /* DESYNCH is just informational, so ignore it */
2438 dict_insert(irc_func_dict, CMD_DESYNCH, cmd_dummy);
2439 dict_insert(irc_func_dict, TOK_DESYNCH, cmd_dummy);
2440 /* Ignore channel operator notices. */
2441 dict_insert(irc_func_dict, CMD_WALLCHOPS, cmd_dummy);
2442 dict_insert(irc_func_dict, TOK_WALLCHOPS, cmd_dummy);
2443 dict_insert(irc_func_dict, CMD_WALLVOICES, cmd_dummy);
2444 dict_insert(irc_func_dict, TOK_WALLVOICES, cmd_dummy);
2445 dict_insert(irc_func_dict, CMD_WALLHOPS, cmd_dummy);
2446 dict_insert(irc_func_dict, TOK_WALLHOPS, cmd_dummy);
2447 /* Ignore opers being silly. */
2448 dict_insert(irc_func_dict, CMD_WALLOPS, cmd_dummy);
2449 dict_insert(irc_func_dict, TOK_WALLOPS, cmd_dummy);
2450 dict_insert(irc_func_dict, CMD_WALLHOPS, cmd_dummy);
2451 dict_insert(irc_func_dict, TOK_WALLHOPS, cmd_dummy);
2452 dict_insert(irc_func_dict, TOK_WALLUSERS, cmd_dummy);
2453 /* Ignore dnsbl exemptions */
2454 dict_insert(irc_func_dict, TOK_EXEMPT, cmd_dummy);
2455 dict_insert(irc_func_dict, CMD_PRIVS, cmd_privs);
2456 dict_insert(irc_func_dict, TOK_PRIVS, cmd_privs);
2457 /* ignore ALIST for now */
2458 dict_insert(irc_func_dict, TOK_ALIST, cmd_dummy);
2459 dict_insert(irc_func_dict, CMD_ALIST, cmd_dummy);
2460 /* Ignore remote luser */
2461 dict_insert(irc_func_dict, TOK_LUSERS, cmd_dummy);
2462 /* We have reliable clock! Always! Wraaa! */
2463 dict_insert(irc_func_dict, CMD_SETTIME, cmd_dummy);
2464 dict_insert(irc_func_dict, TOK_SETTIME, cmd_dummy);
2465
2466 /* ignore /trace and /motd commands targetted at us */
2467 dict_insert(irc_func_dict, TOK_TRACE, cmd_dummy);
2468 dict_insert(irc_func_dict, TOK_MOTD, cmd_dummy);
2469
2470 /* handle topics */
2471 dict_insert(irc_func_dict, "331", cmd_num_topic);
2472 dict_insert(irc_func_dict, "332", cmd_num_topic);
2473 dict_insert(irc_func_dict, "333", cmd_num_topic);
2474 dict_insert(irc_func_dict, "345", cmd_dummy); /* blah has been invited to blah */
2475 dict_insert(irc_func_dict, "432", cmd_error_nick); /* Erroneus [sic] nickname */
2476 /* ban list resetting */
2477 /* "stats g" responses */
2478 dict_insert(irc_func_dict, "247", cmd_num_gline);
2479 dict_insert(irc_func_dict, "542", cmd_num_shun);
2480 dict_insert(irc_func_dict, "219", cmd_dummy); /* "End of /STATS report" */
2481 /* other numeric responses we might get */
2482 dict_insert(irc_func_dict, "401", cmd_dummy); /* target left network */
2483 dict_insert(irc_func_dict, "403", cmd_dummy); /* no such channel */
2484 dict_insert(irc_func_dict, "404", cmd_dummy); /* cannot send to channel */
2485 dict_insert(irc_func_dict, "439", cmd_dummy); /* target change too fast */
2486 dict_insert(irc_func_dict, "441", cmd_dummy); /* target isn't on that channel */
2487 dict_insert(irc_func_dict, "442", cmd_dummy); /* you aren't on that channel */
2488 dict_insert(irc_func_dict, "443", cmd_dummy); /* is already on channel (after invite?) */
2489 dict_insert(irc_func_dict, "461", cmd_dummy); /* Not enough parameters (after TOPIC w/ 0 args) */
2490 dict_insert(irc_func_dict, "467", cmd_dummy); /* Channel key already set */
2491
2492 num_privmsg_funcs = 16;
2493 privmsg_funcs = malloc(sizeof(privmsg_func_t)*num_privmsg_funcs);
2494 memset(privmsg_funcs, 0, sizeof(privmsg_func_t)*num_privmsg_funcs);
2495
2496 num_notice_funcs = 16;
2497 notice_funcs = malloc(sizeof(privmsg_func_t)*num_notice_funcs);
2498 memset(notice_funcs, 0, sizeof(privmsg_func_t)*num_notice_funcs);
2499
2500 userList_init(&dead_users);
2501 reg_del_channel_func(remove_unbursted_channel);
2502 reg_exit_func(parse_cleanup);
2503 // reg_notice_func(opserv, check_ctcp);
2504 }
2505
2506 int
2507 parse_line(char *line, int recursive)
2508 {
2509 char *argv[MAXNUMPARAMS], *origin;
2510 int argc, cmd, res=0;
2511 cmd_func_t *func;
2512
2513 argc = split_line(line, true, MAXNUMPARAMS, argv);
2514 cmd = self->uplink || !argv[0][1] || !argv[0][2];
2515 if (argc > cmd) {
2516 if (cmd) {
2517 if (argv[0][0] == ':') {
2518 origin = argv[0]+1;
2519 } else if (!argv[0][1] || !argv[0][2]) {
2520 struct server *sNode = GetServerN(argv[0]);
2521 origin = sNode ? sNode->name : 0;
2522 } else {
2523 struct userNode *uNode = GetUserN(argv[0]);
2524 origin = uNode ? uNode->nick : 0;
2525 }
2526 } else
2527 origin = 0;
2528 if ((func = dict_find(irc_func_dict, argv[cmd], NULL)))
2529 res = func(origin, argc-cmd, argv+cmd);
2530 }
2531 if (!res) {
2532 log_module(MAIN_LOG, LOG_ERROR, "PARSE ERROR on line: %s", unsplit_string(argv, argc, NULL));
2533 } else if (!recursive) {
2534 unsigned int i;
2535 for (i=0; i<dead_users.used; i++)
2536 free_user(dead_users.list[i]);
2537 dead_users.used = 0;
2538 }
2539 return res;
2540 }
2541
2542 static void
2543 parse_foreach(char *target_list, foreach_chanfunc cf, foreach_nonchan nc, foreach_userfunc uf, foreach_nonuser nu, void *data)
2544 {
2545 char *j, old;
2546
2547 do {
2548 j = target_list;
2549 while (*j != 0 && *j != ',')
2550 j++;
2551 old = *j;
2552 *j = 0;
2553
2554 if (IsChannelName(target_list)
2555 || (target_list[0] == '0' && target_list[1] == '\0')) {
2556 struct chanNode *chan = GetChannel(target_list);
2557
2558 if (chan) {
2559 if (cf)
2560 cf(chan, data);
2561 } else {
2562 if (nc)
2563 nc(target_list, data);
2564 }
2565 } else {
2566 struct userNode *user;
2567 struct privmsg_desc *pd = data;
2568
2569 pd->is_qualified = 0;
2570 if (*target_list == '@') {
2571 user = NULL;
2572 } else if (strchr(target_list, '@')) {
2573 struct server *server;
2574
2575 pd->is_qualified = 1;
2576 user = GetUserH(strtok(target_list, "@"));
2577 server = GetServerH(strtok(NULL, "@"));
2578
2579 if (user && (user->uplink != server)) {
2580 /* Don't attempt to index into any arrays
2581 using a user's numeric on another server. */
2582 user = NULL;
2583 }
2584 } else {
2585 user = GetUserN(target_list);
2586 }
2587
2588 if (user) {
2589 if (uf)
2590 uf(user, data);
2591 } else {
2592 if (nu)
2593 nu(target_list, data);
2594 }
2595 }
2596 target_list = j+1;
2597 } while (old == ',');
2598 }
2599
2600 static int
2601 get_local_numeric(void)
2602 {
2603 static unsigned int next_numeric = 0;
2604 if (self->clients > self->num_mask)
2605 return -1;
2606 while (self->users[next_numeric])
2607 if (++next_numeric > self->num_mask)
2608 next_numeric = 0;
2609 return next_numeric;
2610 }
2611
2612 static void
2613 make_numeric(struct server *svr, int local_num, char *outbuf)
2614 {
2615 int slen, llen;
2616
2617 if (force_n2k || svr->numeric[1]) {
2618 slen = 2;
2619 llen = 3;
2620 } else {
2621 slen = 1;
2622 llen = (local_num < 64*64) ? 2 : 3;
2623 }
2624 strncpy(outbuf, svr->numeric, slen);
2625 inttobase64(outbuf+slen, local_num, llen);
2626 outbuf[slen+llen] = 0;
2627 }
2628
2629 struct server *
2630 AddServer(struct server *uplink, const char *name, int hops, time_t boot, time_t link, const char *numeric, const char *description)
2631 {
2632 struct server* sNode;
2633 int slen, mlen;
2634
2635 if ((sNode = GetServerN(numeric))) {
2636 /* This means we're trying to re-add an existant server.
2637 * To be safe, we should forget the previous incarnation.
2638 * (And all its linked servers.)
2639 *
2640 * It usually only happens in replays when the original
2641 * had a ping timeout and the replay didn't (because
2642 * replaying a ping timeout invariably gets things wrong).
2643 */
2644 DelServer(sNode, 0, NULL);
2645 }
2646
2647 switch (strlen(numeric)) {
2648 case 5: slen = 2; mlen = 3; break;
2649 case 4: slen = 1; mlen = 3; break;
2650 case 3: slen = 1; mlen = 2; break;
2651 default:
2652 log_module(MAIN_LOG, LOG_ERROR, "AddServer(\"%s\", \"%s\", ...): Numeric %s has invalid length.", uplink->name, name, numeric);
2653 return NULL;
2654 }
2655
2656 sNode = calloc(1, sizeof(*sNode));
2657 sNode->uplink = uplink;
2658 safestrncpy(sNode->name, name, sizeof(sNode->name));
2659 sNode->num_mask = base64toint(numeric+slen, mlen);
2660 sNode->hops = hops;
2661 sNode->boot = boot;
2662 sNode->link = link;
2663 strncpy(sNode->numeric, numeric, slen);
2664 safestrncpy(sNode->description, description, sizeof(sNode->description));
2665 sNode->users = calloc(sNode->num_mask+1, sizeof(*sNode->users));
2666 serverList_init(&sNode->children);
2667 if (sNode->uplink) {
2668 /* uplink may be NULL if we're just building ourself */
2669 serverList_append(&sNode->uplink->children, sNode);
2670 }
2671 servers_num[base64toint(numeric, slen)] = sNode;
2672 dict_insert(servers, sNode->name, sNode);
2673 return sNode;
2674 }
2675
2676 void DelServer(struct server* serv, int announce, const char *message)
2677 {
2678 unsigned int i;
2679
2680 /* If we receive an ERROR command before the SERVER
2681 * command a NULL server can be passed */
2682 if (!serv)
2683 return;
2684
2685 /* Hrm, what's the right way to SQUIT some other server?
2686 * (This code is only to handle killing juped servers.) */
2687 if (announce && (serv->uplink == self) && (serv != self->uplink))
2688 irc_squit(serv, message, NULL);
2689
2690 /* must recursively remove servers linked to this one first */
2691 for (i=serv->children.used;i>0;)
2692 if (serv->children.list[--i] != self)
2693 DelServer(serv->children.list[i], false, NULL);
2694
2695 /* clean up server's user hash tables */
2696 for (i=0;i<=serv->num_mask;i++)
2697 if (serv->users[i])
2698 DelUser(serv->users[i], NULL, false, "server delinked");
2699
2700 /* delete server */
2701 if (serv->uplink)
2702 serverList_remove(&serv->uplink->children, serv);
2703 if (serv == self->uplink)
2704 self->uplink = NULL;
2705 servers_num[base64toint(serv->numeric, strlen(serv->numeric))] = NULL;
2706 dict_remove(servers, serv->name);
2707 serverList_clean(&serv->children);
2708 free(serv->users);
2709 free(serv);
2710 }
2711
2712 struct userNode *
2713 AddService(const char *nick, const char *modes, const char *desc, const char *hostname)
2714 {
2715 char numeric[COMBO_NUMERIC_LEN+1];
2716 int local_num = get_local_numeric();
2717 time_t timestamp = now;
2718 struct userNode *old_user = GetUserH(nick);
2719
2720 if (old_user) {
2721 if (IsLocal(old_user))
2722 return old_user;
2723 timestamp = old_user->timestamp - 1;
2724 }
2725 if (local_num == -1) {
2726 log_module(MAIN_LOG, LOG_ERROR, "Unable to allocate numnick for service %s", nick);
2727 return 0;
2728 }
2729 if (!hostname)
2730 hostname = self->name;
2731 make_numeric(self, local_num, numeric);
2732 /* TODO: Make these modes part of the conf file */
2733 return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA");
2734 }
2735
2736 struct userNode *
2737 AddClone(const char *nick, const char *ident, const char *hostname, const char *desc)
2738 {
2739 char numeric[COMBO_NUMERIC_LEN+1];
2740 int local_num = get_local_numeric();
2741 time_t timestamp = now;
2742 struct userNode *old_user = GetUserH(nick);
2743
2744 if (old_user) {
2745 if (IsLocal(old_user))
2746 return old_user;
2747 timestamp = old_user->timestamp - 1;
2748 }
2749 if (local_num == -1) {
2750 log_module(MAIN_LOG, LOG_ERROR, "Unable to allocate numnick for clone %s", nick);
2751 return 0;
2752 }
2753 make_numeric(self, local_num, numeric);
2754 return AddUser(self, nick, ident, hostname, "+i", numeric, desc, timestamp, "AAAAAA");
2755 }
2756
2757 int
2758 is_valid_nick(const char *nick) {
2759 unsigned int ii;
2760 /* IRC has some of The Most Fucked-Up ideas about character sets
2761 * in the world.. */
2762 if (!isalpha(*nick) && !strchr("{|}~[\\]^_`", *nick))
2763 return 0;
2764 for (ii = 0; nick[ii]; ++ii)
2765 if (!isalnum(nick[ii]) && !strchr("{|}~[\\]^-_`", nick[ii]))
2766 return 0;
2767 if (strlen(nick) > nicklen)
2768 return 0;
2769 return 1;
2770 }
2771
2772 static struct userNode*
2773 AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip)
2774 {
2775 struct userNode *oldUser, *uNode;
2776 unsigned int n, ignore_user;
2777
2778 if ((strlen(numeric) < 3) || (strlen(numeric) > 5)) {
2779 log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): numeric %s wrong length!", uplink, nick, numeric);
2780 return NULL;
2781 }
2782
2783 if (!uplink) {
2784 log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s doesn't exist!", uplink, nick, numeric);
2785 return NULL;
2786 }
2787
2788 if (uplink != GetServerN(numeric)) {
2789 log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s differs from nominal uplink %s.", uplink, nick, numeric, uplink->name);
2790 return NULL;
2791 }
2792
2793 if (!is_valid_nick(nick)) {
2794 log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", uplink, nick);
2795 return NULL;
2796 }
2797
2798 ignore_user = 0;
2799 if ((oldUser = GetUserH(nick))) {
2800 if (IsLocal(oldUser) && (IsService(oldUser) || IsPersistent(oldUser))) {
2801 /* The service should collide the new user off. */
2802 oldUser->timestamp = timestamp - 1;
2803 irc_user(oldUser);
2804 }
2805 if (oldUser->timestamp > timestamp) {
2806 /* "Old" user is really newer; remove them */
2807 DelUser(oldUser, 0, 1, "Overruled by older nick");
2808 } else {
2809 /* User being added is too new; do not add them to
2810 * clients, but do add them to the server's list, since it
2811 * will send a KILL and QUIT soon. */
2812 ignore_user = 1;
2813 }
2814 }
2815
2816 /* create new usernode and set all values */
2817 uNode = calloc(1, sizeof(*uNode));
2818 uNode->nick = strdup(nick);
2819 safestrncpy(uNode->ident, ident, sizeof(uNode->ident));
2820 safestrncpy(uNode->info, userinfo, sizeof(uNode->info));
2821 safestrncpy(uNode->hostname, hostname, sizeof(uNode->hostname));
2822 safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric));
2823 irc_p10_pton(&uNode->ip, realip);
2824
2825 if (irc_in_addr_is_ipv4(uNode->ip)) {
2826 make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip);
2827 make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
2828 } else if (irc_in_addr_is_ipv6(uNode->ip)) {
2829 make_ipv6virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
2830 }
2831
2832 if (!uNode->crypthost && uNode->cryptip)
2833 snprintf(uNode->crypthost, sizeof(uNode->crypthost), "%s", strdup(uNode->cryptip));
2834
2835 uNode->timestamp = timestamp;
2836 modeList_init(&uNode->channels);
2837 uNode->uplink = uplink;
2838 if (++uNode->uplink->clients > uNode->uplink->max_clients) {
2839 uNode->uplink->max_clients = uNode->uplink->clients;
2840 }
2841 uNode->num_local = base64toint(numeric+strlen(uNode->uplink->numeric), 3) & uNode->uplink->num_mask;
2842 uNode->uplink->users[uNode->num_local] = uNode;
2843 mod_usermode(uNode, modes);
2844
2845 set_geoip_info(uNode);
2846
2847 if (ignore_user)
2848 return uNode;
2849
2850 dict_insert(clients, uNode->nick, uNode);
2851 if (dict_size(clients) > max_clients) {
2852 max_clients = dict_size(clients);
2853 max_clients_time = now;
2854 }
2855 if (IsLocal(uNode))
2856 irc_user(uNode);
2857 for (n=0; n<nuf_used; n++)
2858 if (nuf_list[n](uNode))
2859 break;
2860
2861 if ((uNode->loc == 1) && (uNode->handle_info))
2862 send_func_list(uNode);
2863
2864 return uNode;
2865 }
2866
2867 /* removes user from it's server's hash table and nick hash table */
2868 void
2869 DelUser(struct userNode* user, struct userNode *killer, int announce, const char *why)
2870 {
2871 unsigned int n;
2872
2873 verify(user);
2874
2875 /* mark them as dead, in case anybody cares */
2876 user->dead = 1;
2877
2878 /* remove pending adduser commands */
2879 wipe_adduser_pending(NULL, user);
2880
2881 /* remove user from all channels */
2882 while (user->channels.used > 0)
2883 DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, false, 0);
2884
2885 /* Call these in reverse order so ChanServ can update presence
2886 information before NickServ nukes the handle_info. */
2887 for (n = duf_used; n > 0; )
2888 duf_list[--n](user, killer, why);
2889
2890 user->uplink->clients--;
2891 user->uplink->users[user->num_local] = NULL;
2892 if (IsOper(user))
2893 userList_remove(&curr_opers, user);
2894 /* remove from global dictionary, but not if after a collide */
2895 if (user == dict_find(clients, user->nick, NULL))
2896 dict_remove(clients, user->nick);
2897
2898 if (IsInvisible(user))
2899 invis_clients--;
2900
2901 if (announce) {
2902 if (IsLocal(user))
2903 irc_quit(user, why);
2904 else
2905 irc_kill(killer, user, why);
2906 }
2907
2908 modeList_clean(&user->channels);
2909
2910 /* Clean up version data */
2911 if(user->version_reply) {
2912 free(user->version_reply);
2913 user->version_reply = NULL;
2914 }
2915
2916 /* clean up mark */
2917 if(user->mark) {
2918 free(user->mark);
2919 user->mark = NULL;
2920 }
2921
2922 /* clean up geoip data if any */
2923 if(user->country_code) free(user->country_code);
2924 if(user->city) free(user->city);
2925 if(user->region) free(user->region);
2926 if(user->postal_code) free(user->postal_code);
2927
2928 /* We don't free them, in case we try to privmsg them or something
2929 * (like when a stupid oper kills themself). We just put them onto
2930 * a list of clients that get freed after processing each line.
2931 */
2932 if (dead_users.size)
2933 userList_append(&dead_users, user);
2934 else
2935 free_user(user);
2936 }
2937
2938 static void call_oper_funcs(struct userNode *user);
2939
2940 void mod_usermode(struct userNode *user, const char *mode_change) {
2941 int add = 1;
2942 const char *word = mode_change;
2943
2944 if (!user || !mode_change)
2945 return;
2946
2947 call_user_mode_funcs(user, mode_change);
2948
2949 while (*word != ' ' && *word) word++;
2950 while (*word == ' ') word++;
2951 while (1) {
2952 #define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
2953 switch (*mode_change++) {
2954 case 0: case ' ': return;
2955 case '+': add = 1; break;
2956 case '-': add = 0; break;
2957 case 'o':
2958 if (add) {
2959 if(!IsOper(user)) { /* Dont re-oper an oper */
2960 userList_append(&curr_opers, user);
2961 call_oper_funcs(user);
2962 }
2963 } else {
2964 userList_remove(&curr_opers, user);
2965 }
2966 do_user_mode(FLAGS_OPER);
2967 break;
2968 case 'O': do_user_mode(FLAGS_LOCOP); break;
2969 case 'i': do_user_mode(FLAGS_INVISIBLE);
2970 if (add)
2971 invis_clients++;
2972 else
2973 invis_clients--;
2974 break;
2975 case 'w': do_user_mode(FLAGS_WALLOP); break;
2976 case 's': do_user_mode(FLAGS_SERVNOTICE); break;
2977 case 'd': do_user_mode(FLAGS_DEAF); break;
2978 case 'k': do_user_mode(FLAGS_SERVICE); break;
2979 case 'g': do_user_mode(FLAGS_GLOBAL); break;
2980 // sethost - reed/apples
2981 // case 'h': do_user_mode(FLAGS_HELPER); break;
2982 // I check if there's an 'h' in the first part, and if there,
2983 // then everything after the space becomes their new host.
2984 case 'h': do_user_mode(FLAGS_SETHOST);
2985 if (*word) {
2986 char sethost[MAXLEN];
2987 unsigned int ii;
2988 for (ii=0; (*word != ' ') && (*word != '\0'); )
2989 sethost[ii++] = *word++;
2990 sethost[ii] = 0;
2991 while (*word == ' ')
2992 word++;
2993 safestrncpy(user->sethost, sethost, sizeof(user->sethost));
2994 }
2995 break;
2996 case 'x': do_user_mode(FLAGS_HIDDEN_HOST); break;
2997 case 'r':
2998 if (*word) {
2999 char tag[MAXLEN];
3000 unsigned int ii;
3001 for (ii=0; (*word != ' ') && (*word != '\0'); )
3002 tag[ii++] = *word++;
3003 tag[ii] = 0;
3004 while (*word == ' ')
3005 word++;
3006 call_account_func(user, tag);
3007 }
3008 break;
3009 case 'f':
3010 if (*word) {
3011 char host[MAXLEN];
3012 unsigned int ii;
3013 for (ii=0; (*word != ' ') && (*word != '\0'); )
3014 host[ii++] = *word++;
3015 host[ii] = 0;
3016 while (*word == ' ')
3017 word++;
3018 assign_fakehost(user, host, 0);
3019 }
3020 break;
3021 }
3022 #undef do_user_mode
3023 }
3024 }
3025
3026 struct mod_chanmode *
3027 mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags, short base_oplevel)
3028 {
3029 struct mod_chanmode *change;
3030 unsigned int ii, in_arg, ch_arg, add;
3031
3032 if (argc == 0)
3033 return NULL;
3034 if (!(change = mod_chanmode_alloc(argc - 1)))
3035 return NULL;
3036
3037 for (ii = ch_arg = 0, in_arg = add = 1;
3038 (modes[0][ii] != '\0') && (modes[0][ii] != ' ');
3039 ++ii) {
3040 switch (modes[0][ii]) {
3041 case '+':
3042 add = 1;
3043 break;
3044 case '-':
3045 add = 0;
3046 break;
3047 #define do_chan_mode(FLAG) do { if (add) change->modes_set |= (FLAG), change->modes_clear &= ~(FLAG); else change->modes_clear |= (FLAG), change->modes_set &= ~(FLAG); } while(0)
3048 case 'C': do_chan_mode(MODE_NOCTCPS); break;
3049 case 'D': do_chan_mode(MODE_DELAYJOINS); break;
3050 case 'c': do_chan_mode(MODE_NOCOLORS); break;
3051 case 'i': do_chan_mode(MODE_INVITEONLY); break;
3052 case 'm': do_chan_mode(MODE_MODERATED); break;
3053 case 'n': do_chan_mode(MODE_NOPRIVMSGS); break;
3054 case 'p': do_chan_mode(MODE_PRIVATE); break;
3055 case 'r': do_chan_mode(MODE_REGONLY); break;
3056 case 's': do_chan_mode(MODE_SECRET); break;
3057 case 't': do_chan_mode(MODE_TOPICLIMIT); break;
3058 case 'S': do_chan_mode(MODE_STRIPCOLOR); break;
3059 case 'M': do_chan_mode(MODE_MODUNREG); break;
3060 case 'N': do_chan_mode(MODE_NONOTICE); break;
3061 case 'Q': do_chan_mode(MODE_NOQUITMSGS); break;
3062 case 'T': do_chan_mode(MODE_NOAMSG); break;
3063 case 'O': do_chan_mode(MODE_OPERSONLY); break;
3064 case 'Z': do_chan_mode(MODE_SSLONLY); break;
3065 case 'L': do_chan_mode(MODE_HIDEMODE); break;
3066 case 'z':
3067 if (!(flags & MCP_REGISTERED)) {
3068 do_chan_mode(MODE_REGISTERED);
3069 } else {
3070 mod_chanmode_free(change);
3071 return NULL;
3072 }
3073 break;
3074 #undef do_chan_mode
3075 case 'l':
3076 if (add) {
3077 if (in_arg >= argc)
3078 goto error;
3079 change->modes_set |= MODE_LIMIT;
3080 change->new_limit = atoi(modes[in_arg++]);
3081 } else {
3082 change->modes_set &= ~MODE_LIMIT;
3083 change->modes_clear |= MODE_LIMIT;
3084 }
3085 break;
3086 case 'k':
3087 if (add) {
3088 if (in_arg >= argc)
3089 goto error;
3090 change->modes_set |= MODE_KEY;
3091 safestrncpy(change->new_key, modes[in_arg++], sizeof(change->new_key));
3092 } else {
3093 change->modes_clear |= MODE_KEY;
3094 if (!(flags & MCP_KEY_FREE)) {
3095 if (in_arg >= argc)
3096 goto error;
3097 in_arg++;
3098 }
3099 }
3100 break;
3101 case 'U':
3102 if (add)
3103 {
3104 if (in_arg >= argc)
3105 goto error;
3106 change->modes_set |= MODE_UPASS;
3107 safestrncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass));
3108 } else {
3109 change->modes_clear |= MODE_UPASS;
3110 if (!(flags & MCP_UPASS_FREE)) {
3111 if (in_arg >= argc)
3112 goto error;
3113 in_arg++;
3114 }
3115 }
3116 break;
3117 case 'A':
3118 if (add) {
3119 if (in_arg >= argc)
3120 goto error;
3121 change->modes_set |= MODE_APASS;
3122 safestrncpy(change->new_apass, modes[in_arg++], sizeof(change->new_apass));
3123 } else {
3124 change->modes_clear |= MODE_APASS;
3125 if (!(flags & MCP_APASS_FREE)) {
3126 if (in_arg >= argc)
3127 goto error;
3128 in_arg++;
3129 }
3130 }
3131 break;
3132 case 'b':
3133 if (!(flags & MCP_ALLOW_OVB))
3134 goto error;
3135 if (in_arg >= argc)
3136 goto error;
3137 change->args[ch_arg].mode = MODE_BAN;
3138 if (!add)
3139 change->args[ch_arg].mode |= MODE_REMOVE;
3140 change->args[ch_arg++].u.hostmask = modes[in_arg++];
3141 break;
3142 case 'e':
3143 if (!(flags & MCP_ALLOW_OVB))
3144 goto error;
3145 if (in_arg >= argc)
3146 goto error;
3147 change->args[ch_arg].mode = MODE_EXEMPT;
3148 if (!add)
3149 change->args[ch_arg].mode |= MODE_REMOVE;
3150 change->args[ch_arg++].u.hostmask = modes[in_arg++];
3151 break;
3152 case 'o': case 'h': case 'v':
3153 {
3154 struct userNode *victim;
3155 char *oplevel_str;
3156 int oplevel;
3157
3158 if (in_arg >= argc)
3159 goto error;
3160 oplevel_str = strchr(modes[in_arg], ':');
3161 if (oplevel_str)
3162 {
3163 /* XXYYY M #channel +o XXYYY:<oplevel> */
3164 *oplevel_str++ = '\0';
3165 oplevel = parse_oplevel(oplevel_str);
3166 if (oplevel <= base_oplevel && !(flags & MCP_FROM_SERVER))
3167 oplevel = base_oplevel + 1;
3168 }
3169 else if (channel->modes & MODE_UPASS)
3170 oplevel = base_oplevel + 1;
3171 else
3172 oplevel = -1;
3173
3174 /* Check that oplevel is within bounds. */
3175 if (oplevel > MAXOPLEVEL)
3176 oplevel = MAXOPLEVEL;
3177
3178 if (!(flags & MCP_ALLOW_OVB))
3179 goto error;
3180 if (in_arg >= argc)
3181 goto error;
3182
3183 if (modes[0][ii] == 'o')
3184 change->args[ch_arg].mode = MODE_CHANOP;
3185 else if (modes[0][ii] == 'h')
3186 change->args[ch_arg].mode = MODE_HALFOP;
3187 else if (modes[0][ii] == 'v')
3188 change->args[ch_arg].mode = MODE_VOICE;
3189
3190 if (!add)
3191 change->args[ch_arg].mode |= MODE_REMOVE;
3192 if (flags & MCP_FROM_SERVER)
3193 victim = GetUserN(modes[in_arg++]);
3194 else
3195 victim = GetUserH(modes[in_arg++]);
3196 if (!victim)
3197 continue;
3198 if ((change->args[ch_arg].u.member = GetUserMode(channel, victim)))
3199 {
3200 /* Apply the oplevel change */
3201 change->args[ch_arg].u.member->oplevel = oplevel;
3202 ch_arg++;
3203 }
3204 break;
3205 }
3206 default:
3207 if (!(flags & MCP_FROM_SERVER))
3208 goto error;
3209 break;
3210 }
3211 }
3212 change->argc = ch_arg; /* in case any turned out to be ignored */
3213 if (change->modes_set & MODE_SECRET) {
3214 change->modes_set &= ~(MODE_PRIVATE);
3215 change->modes_clear |= MODE_PRIVATE;
3216 } else if (change->modes_set & MODE_PRIVATE) {
3217 change->modes_set &= ~(MODE_SECRET);
3218 change->modes_clear |= MODE_SECRET;
3219 }
3220 return change;
3221 error:
3222 mod_chanmode_free(change);
3223 return NULL;
3224 }
3225
3226 struct chanmode_buffer {
3227 char modes[MAXLEN];
3228 char args[MAXLEN];
3229 struct chanNode *channel;
3230 struct userNode *actor;
3231 unsigned int modes_used;
3232 unsigned int args_used;
3233 size_t chname_len;
3234 unsigned int is_add : 1;
3235 unsigned int is_chanop : 1;
3236 };
3237
3238 static void
3239 mod_chanmode_append(struct chanmode_buffer *buf, char ch, const char *arg)
3240 {
3241 size_t arg_len = strlen(arg);
3242 if (buf->modes_used > (MAXMODEPARAMS) ||
3243 buf->modes_used + buf->args_used + buf->chname_len + arg_len > 450) {
3244 memcpy(buf->modes + buf->modes_used, buf->args, buf->args_used);
3245 buf->modes[buf->modes_used + buf->args_used] = '\0';
3246 irc_mode((buf->is_chanop ? buf->actor : NULL), buf->channel, buf->modes);
3247 buf->modes[0] = buf->is_add ? '+' : '-';
3248 buf->modes_used = 1;
3249 buf->args_used = 0;
3250 }
3251 buf->modes[buf->modes_used++] = ch;
3252 buf->args[buf->args_used++] = ' ';
3253 memcpy(buf->args + buf->args_used, arg, arg_len);
3254 buf->args_used += arg_len;
3255 }
3256
3257 void
3258 mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod_chanmode *change)
3259 {
3260 struct chanmode_buffer chbuf;
3261 unsigned int arg;
3262 struct modeNode *mn;
3263 char int_buff[32], mode = '\0';
3264
3265 assert(change->argc <= change->alloc_argc);
3266 memset(&chbuf, 0, sizeof(chbuf));
3267 chbuf.channel = channel;
3268 chbuf.actor = who;
3269 chbuf.chname_len = strlen(channel->name);
3270
3271 mn = GetUserMode(channel, who);
3272 if ((mn && (mn->modes & MODE_CHANOP)) || off_channel)
3273 chbuf.is_chanop = 1;
3274
3275 /* First remove modes */
3276 chbuf.is_add = 0;
3277 if (change->modes_clear) {
3278 if (mode != '-')
3279 chbuf.modes[chbuf.modes_used++] = mode = '-';
3280 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) chbuf.modes[chbuf.modes_used++] = CHAR
3281 DO_MODE_CHAR(PRIVATE, 'p');
3282 DO_MODE_CHAR(SECRET, 's');
3283 DO_MODE_CHAR(MODERATED, 'm');
3284 DO_MODE_CHAR(TOPICLIMIT, 't');
3285 DO_MODE_CHAR(INVITEONLY, 'i');
3286 DO_MODE_CHAR(NOPRIVMSGS, 'n');
3287 DO_MODE_CHAR(LIMIT, 'l');
3288 DO_MODE_CHAR(DELAYJOINS, 'D');
3289 DO_MODE_CHAR(REGONLY, 'r');
3290 DO_MODE_CHAR(NOCOLORS, 'c');
3291 DO_MODE_CHAR(NOCTCPS, 'C');
3292 DO_MODE_CHAR(STRIPCOLOR, 'S');
3293 DO_MODE_CHAR(MODUNREG, 'M');
3294 DO_MODE_CHAR(NONOTICE, 'N');
3295 DO_MODE_CHAR(NOQUITMSGS, 'Q');
3296 DO_MODE_CHAR(NOAMSG, 'T');
3297 DO_MODE_CHAR(OPERSONLY, 'O');
3298 DO_MODE_CHAR(REGISTERED, 'z');
3299 DO_MODE_CHAR(SSLONLY, 'Z');
3300 DO_MODE_CHAR(HIDEMODE, 'L');
3301 #undef DO_MODE_CHAR
3302 if (change->modes_clear & channel->modes & MODE_KEY)
3303 mod_chanmode_append(&chbuf, 'k', channel->key);
3304 if (change->modes_clear & channel->modes & MODE_UPASS)
3305 mod_chanmode_append(&chbuf, 'U', channel->upass);
3306 if (change->modes_clear * channel->modes & MODE_APASS)
3307 mod_chanmode_append(&chbuf, 'A', channel->apass);
3308 }
3309 for (arg = 0; arg < change->argc; ++arg) {
3310 if (!(change->args[arg].mode & MODE_REMOVE))
3311 continue;
3312 if (mode != '-')
3313 chbuf.modes[chbuf.modes_used++] = mode = '-';
3314 switch (change->args[arg].mode & ~MODE_REMOVE) {
3315 case MODE_BAN:
3316 mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask);
3317 break;
3318 case MODE_EXEMPT:
3319 mod_chanmode_append(&chbuf, 'e', change->args[arg].u.hostmask);
3320 break;
3321 default:
3322 if (change->args[arg].mode & MODE_CHANOP)
3323 mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric);
3324 if (change->args[arg].mode & MODE_HALFOP)
3325 mod_chanmode_append(&chbuf, 'h', change->args[arg].u.member->user->numeric);
3326 if (change->args[arg].mode & MODE_VOICE)
3327 mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric);
3328 break;
3329 }
3330 }
3331
3332 /* Then set them */
3333 chbuf.is_add = 1;
3334 if (change->modes_set) {
3335 if (mode != '+')
3336 chbuf.modes[chbuf.modes_used++] = mode = '+';
3337 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_set & MODE_##BIT) chbuf.modes[chbuf.modes_used++] = CHAR
3338 DO_MODE_CHAR(PRIVATE, 'p');
3339 DO_MODE_CHAR(SECRET, 's');
3340 DO_MODE_CHAR(MODERATED, 'm');
3341 DO_MODE_CHAR(TOPICLIMIT, 't');
3342 DO_MODE_CHAR(INVITEONLY, 'i');
3343 DO_MODE_CHAR(NOPRIVMSGS, 'n');
3344 DO_MODE_CHAR(DELAYJOINS, 'D');
3345 DO_MODE_CHAR(REGONLY, 'r');
3346 DO_MODE_CHAR(NOCOLORS, 'c');
3347 DO_MODE_CHAR(NOCTCPS, 'C');
3348 DO_MODE_CHAR(STRIPCOLOR, 'S');
3349 DO_MODE_CHAR(MODUNREG, 'M');
3350 DO_MODE_CHAR(NONOTICE, 'N');
3351 DO_MODE_CHAR(NOQUITMSGS, 'Q');
3352 DO_MODE_CHAR(NOAMSG, 'T');
3353 DO_MODE_CHAR(OPERSONLY, 'O');
3354 DO_MODE_CHAR(REGISTERED, 'z');
3355 DO_MODE_CHAR(SSLONLY, 'Z');
3356 DO_MODE_CHAR(HIDEMODE, 'L');
3357 #undef DO_MODE_CHAR
3358 if(change->modes_set & MODE_KEY)
3359 mod_chanmode_append(&chbuf, 'k', change->new_key);
3360 if (change->modes_set & MODE_UPASS)
3361 mod_chanmode_append(&chbuf, 'U', change->new_upass);
3362 if (change->modes_set & MODE_APASS)
3363 mod_chanmode_append(&chbuf, 'A', change->new_apass);
3364 if(change->modes_set & MODE_LIMIT) {
3365 sprintf(int_buff, "%d", change->new_limit);
3366 mod_chanmode_append(&chbuf, 'l', int_buff);
3367 }
3368 }
3369 for (arg = 0; arg < change->argc; ++arg) {
3370 if (change->args[arg].mode & MODE_REMOVE)
3371 continue;
3372 if (mode != '+')
3373 chbuf.modes[chbuf.modes_used++] = mode = '+';
3374 switch (change->args[arg].mode) {
3375 case MODE_BAN:
3376 mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask);
3377 break;
3378 case MODE_EXEMPT:
3379 mod_chanmode_append(&chbuf, 'e', change->args[arg].u.hostmask);
3380 break;
3381 default:
3382 if (change->args[arg].mode & MODE_CHANOP)
3383 mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric);
3384 if (change->args[arg].mode & MODE_HALFOP)
3385 mod_chanmode_append(&chbuf, 'h', change->args[arg].u.member->user->numeric);
3386 if (change->args[arg].mode & MODE_VOICE)
3387 mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric);
3388 break;
3389 }
3390 }
3391
3392 /* Flush the buffer and apply changes locally */
3393 if (chbuf.modes_used > 0) {
3394 memcpy(chbuf.modes + chbuf.modes_used, chbuf.args, chbuf.args_used);
3395 chbuf.modes[chbuf.modes_used + chbuf.args_used] = '\0';
3396 irc_mode((chbuf.is_chanop ? chbuf.actor : NULL), chbuf.channel, chbuf.modes);
3397 }
3398 mod_chanmode_apply(who, channel, change);
3399 }
3400
3401 char *
3402 mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
3403 {
3404 unsigned int used = 0;
3405 assert(change->argc <= change->alloc_argc);
3406 if (change->modes_clear) {
3407 outbuff[used++] = '-';
3408 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) outbuff[used++] = CHAR
3409 DO_MODE_CHAR(PRIVATE, 'p');
3410 DO_MODE_CHAR(SECRET, 's');
3411 DO_MODE_CHAR(MODERATED, 'm');
3412 DO_MODE_CHAR(TOPICLIMIT, 't');
3413 DO_MODE_CHAR(INVITEONLY, 'i');
3414 DO_MODE_CHAR(NOPRIVMSGS, 'n');
3415 DO_MODE_CHAR(LIMIT, 'l');
3416 DO_MODE_CHAR(KEY, 'k');
3417 DO_MODE_CHAR(UPASS, 'U');
3418 DO_MODE_CHAR(APASS, 'A');
3419 DO_MODE_CHAR(DELAYJOINS, 'D');
3420 DO_MODE_CHAR(REGONLY, 'r');
3421 DO_MODE_CHAR(NOCOLORS, 'c');
3422 DO_MODE_CHAR(NOCTCPS, 'C');
3423 DO_MODE_CHAR(STRIPCOLOR, 'S');
3424 DO_MODE_CHAR(MODUNREG, 'M');
3425 DO_MODE_CHAR(NONOTICE, 'N');
3426 DO_MODE_CHAR(NOQUITMSGS, 'Q');
3427 DO_MODE_CHAR(NOAMSG, 'T');
3428 DO_MODE_CHAR(OPERSONLY, 'O');
3429 DO_MODE_CHAR(REGISTERED, 'z');
3430 DO_MODE_CHAR(SSLONLY, 'Z');
3431 DO_MODE_CHAR(HIDEMODE, 'L');
3432 #undef DO_MODE_CHAR
3433 }
3434 if (change->modes_set) {
3435 outbuff[used++] = '+';
3436 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_set & MODE_##BIT) outbuff[used++] = CHAR
3437 DO_MODE_CHAR(PRIVATE, 'p');
3438 DO_MODE_CHAR(SECRET, 's');
3439 DO_MODE_CHAR(MODERATED, 'm');
3440 DO_MODE_CHAR(TOPICLIMIT, 't');
3441 DO_MODE_CHAR(INVITEONLY, 'i');
3442 DO_MODE_CHAR(NOPRIVMSGS, 'n');
3443 DO_MODE_CHAR(DELAYJOINS, 'D');
3444 DO_MODE_CHAR(REGONLY, 'r');
3445 DO_MODE_CHAR(NOCOLORS, 'c');
3446 DO_MODE_CHAR(NOCTCPS, 'C');
3447 DO_MODE_CHAR(STRIPCOLOR, 'S');
3448 DO_MODE_CHAR(MODUNREG, 'M');
3449 DO_MODE_CHAR(NONOTICE, 'N');
3450 DO_MODE_CHAR(NOQUITMSGS, 'Q');
3451 DO_MODE_CHAR(NOAMSG, 'T');
3452 DO_MODE_CHAR(OPERSONLY, 'O');
3453 DO_MODE_CHAR(REGISTERED, 'z');
3454 DO_MODE_CHAR(SSLONLY, 'Z');
3455 DO_MODE_CHAR(HIDEMODE, 'L');
3456 #undef DO_MODE_CHAR
3457 switch (change->modes_set & (MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS)) {
3458 /* Doing this implementation has been a pain in the arse, I hope I didn't forget a possible combination */
3459 case MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS:
3460 used += sprintf(outbuff+used, "lkAU %d %s %s %s", change->new_limit, change->new_key,change->new_apass, change->new_upass);
3461 break;
3462
3463 case MODE_KEY|MODE_LIMIT|MODE_APASS:
3464 used += sprintf(outbuff+used, "lkA %d %s %s", change->new_limit, change->new_key, change->new_apass);
3465 break;
3466 case MODE_KEY|MODE_LIMIT|MODE_UPASS:
3467 used += sprintf(outbuff+used, "lkU %d %s %s", change->new_limit, change->new_key, change->new_upass);
3468 break;
3469 case MODE_KEY|MODE_APASS|MODE_UPASS:
3470 used += sprintf(outbuff+used, "kAU %s %s %s", change->new_key, change->new_apass, change->new_upass);
3471 break;
3472
3473 case MODE_KEY|MODE_APASS:
3474 used += sprintf(outbuff+used, "kA %s %s", change->new_key, change->new_apass);
3475 break;
3476 case MODE_KEY|MODE_UPASS:
3477 used += sprintf(outbuff+used, "kU %s %s", change->new_key, change->new_upass);
3478 break;
3479 case MODE_KEY|MODE_LIMIT:
3480 used += sprintf(outbuff+used, "lk %d %s", change->new_limit, change->new_key);
3481 break;
3482
3483 case MODE_LIMIT|MODE_UPASS:
3484 used += sprintf(outbuff+used, "lU %d %s", change->new_limit, change->new_upass);
3485 break;
3486 case MODE_LIMIT|MODE_APASS:
3487 used += sprintf(outbuff+used, "lA %d %s", change->new_limit, change->new_apass);
3488 break;
3489 case MODE_APASS|MODE_UPASS:
3490 used += sprintf(outbuff+used, "AU %s %s", change->new_apass, change->new_upass);
3491
3492 case MODE_LIMIT|MODE_APASS|MODE_UPASS:
3493 used += sprintf(outbuff+used, "lAU %d %s %s", change->new_limit, change->new_apass, change->new_upass);
3494 break;
3495
3496 case MODE_APASS:
3497 used += sprintf(outbuff+used, "A %s", change->new_apass);
3498 break;
3499 case MODE_UPASS:
3500 used += sprintf(outbuff+used, "U %s", change->new_upass);
3501 break;
3502 case MODE_KEY:
3503 used += sprintf(outbuff+used, "k %s", change->new_key);
3504 break;
3505 case MODE_LIMIT:
3506 used += sprintf(outbuff+used, "l %d", change->new_limit);
3507 break;
3508 }
3509 }
3510 outbuff[used] = 0;
3511 return outbuff;
3512 }
3513
3514 static int
3515 clear_chanmode(struct chanNode *channel, const char *modes)
3516 {
3517 unsigned int remove;
3518
3519 for (remove = 0; *modes; modes++) {
3520 switch (*modes) {
3521 case 'o': remove |= MODE_CHANOP; break;
3522 case 'h': remove |= MODE_HALFOP; break;
3523 case 'v': remove |= MODE_VOICE; break;
3524 case 'p': remove |= MODE_PRIVATE; break;
3525 case 's': remove |= MODE_SECRET; break;
3526 case 'm': remove |= MODE_MODERATED; break;
3527 case 't': remove |= MODE_TOPICLIMIT; break;
3528 case 'i': remove |= MODE_INVITEONLY; break;
3529 case 'n': remove |= MODE_NOPRIVMSGS; break;
3530 case 'k':
3531 remove |= MODE_KEY;
3532 channel->key[0] = '\0';
3533 break;
3534 case 'A':
3535 remove |= MODE_APASS;
3536 channel->apass[0] = '\0';
3537 break;
3538 case 'U':
3539 remove |= MODE_UPASS;
3540 channel->upass[0] = '\0';
3541 break;
3542 case 'l':
3543 remove |= MODE_LIMIT;
3544 channel->limit = 0;
3545 break;
3546 case 'b': remove |= MODE_BAN; break;
3547 case 'e': remove |= MODE_EXEMPT; break;
3548 case 'D': remove |= MODE_DELAYJOINS; break;
3549 case 'r': remove |= MODE_REGONLY; break;
3550 case 'c': remove |= MODE_NOCOLORS; break;
3551 case 'C': remove |= MODE_NOCTCPS; break;
3552 case 'S': remove |= MODE_STRIPCOLOR; break;
3553 case 'M': remove |= MODE_MODUNREG; break;
3554 case 'N': remove |= MODE_NONOTICE; break;
3555 case 'Q': remove |= MODE_NOQUITMSGS; break;
3556 case 'T': remove |= MODE_NOAMSG; break;
3557 case 'O': remove |= MODE_OPERSONLY; break;
3558 case 'z': remove |= MODE_REGISTERED; break;
3559 case 'Z': remove |= MODE_SSLONLY; break;
3560 case 'L': remove |= MODE_HIDEMODE; break;
3561 }
3562 }
3563
3564 if (!remove)
3565 return 1;
3566
3567 /* Remove simple modes. */
3568 channel->modes &= ~remove;
3569
3570 /* If removing bans, kill 'em all. */
3571 if ((remove & MODE_BAN) && channel->banlist.used) {
3572 unsigned int i;
3573 for (i=0; i<channel->banlist.used; i++)
3574 free(channel->banlist.list[i]);
3575 channel->banlist.used = 0;
3576 }
3577
3578 /* If removing exempts, kill 'em all. */
3579 if ((remove & MODE_EXEMPT) && channel->exemptlist.used) {
3580 unsigned int i;
3581 for (i=0; i<channel->exemptlist.used; i++)
3582 free(channel->exemptlist.list[i]);
3583 channel->exemptlist.used = 0;
3584 }
3585
3586 /* Remove member modes. */
3587 if ((remove & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) && channel->members.used) {
3588 int mask = ~(remove & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE));
3589 unsigned int i;
3590
3591 for (i = 0; i < channel->members.used; i++)
3592 channel->members.list[i]->modes &= mask;
3593 }
3594
3595 return 1;
3596 }
3597
3598 void
3599 reg_privmsg_func(struct userNode *user, privmsg_func_t handler)
3600 {
3601 unsigned int numeric = user->num_local;
3602 if (numeric >= num_privmsg_funcs) {
3603 int newnum = numeric + 8;
3604 privmsg_funcs = realloc(privmsg_funcs, newnum*sizeof(privmsg_func_t));
3605 memset(privmsg_funcs+num_privmsg_funcs, 0, (newnum-num_privmsg_funcs)*sizeof(privmsg_func_t));
3606 num_privmsg_funcs = newnum;
3607 }
3608 if (privmsg_funcs[numeric])
3609 log_module(MAIN_LOG, LOG_WARNING, "re-registering new privmsg handler for numeric %d", numeric);
3610 privmsg_funcs[numeric] = handler;
3611 }
3612
3613 void
3614 unreg_privmsg_func(struct userNode *user, privmsg_func_t handler)
3615 {
3616 unsigned int x;
3617
3618 if (!user || handler)
3619 return; /* this really only works with users */
3620
3621 memset(privmsg_funcs+user->num_local, 0, sizeof(privmsg_func_t));
3622
3623 for (x = user->num_local+1; x < num_privmsg_funcs; x++)
3624 memmove(privmsg_funcs+x-1, privmsg_funcs+x, sizeof(privmsg_func_t));
3625
3626 privmsg_funcs = realloc(privmsg_funcs, num_privmsg_funcs*sizeof(privmsg_func_t));
3627 num_privmsg_funcs--;
3628 }
3629
3630
3631 void
3632 reg_notice_func(struct userNode *user, privmsg_func_t handler)
3633 {
3634 unsigned int numeric = user->num_local;
3635 if (numeric >= num_notice_funcs) {
3636 int newnum = numeric + 8;
3637 notice_funcs = realloc(notice_funcs, newnum*sizeof(privmsg_func_t));
3638 memset(notice_funcs+num_notice_funcs, 0, (newnum-num_notice_funcs)*sizeof(privmsg_func_t));
3639 num_notice_funcs = newnum;
3640 }
3641 if (notice_funcs[numeric])
3642 log_module(MAIN_LOG, LOG_WARNING, "re-registering new notice handler for numeric %d", numeric);
3643 notice_funcs[numeric] = handler;
3644 }
3645
3646 void
3647 unreg_notice_func(struct userNode *user, privmsg_func_t handler)
3648 {
3649 unsigned int x;
3650
3651 if (!user || handler)
3652 return; /* this really only works with users */
3653
3654 memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t));
3655
3656 for (x = user->num_local+1; x < num_notice_funcs; x++)
3657 memmove(notice_funcs+x-1, notice_funcs+x, sizeof(privmsg_func_t));
3658
3659 memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t));
3660 notice_funcs = realloc(notice_funcs, num_notice_funcs*sizeof(privmsg_func_t));
3661 num_notice_funcs--;
3662 }
3663
3664 void
3665 reg_oper_func(oper_func_t handler)
3666 {
3667 if (of_used == of_size) {
3668 if (of_size) {
3669 of_size <<= 1;
3670 of_list = realloc(of_list, of_size*sizeof(oper_func_t));
3671 } else {
3672 of_size = 8;
3673 of_list = malloc(of_size*sizeof(oper_func_t));
3674 }
3675 }
3676 of_list[of_used++] = handler;
3677 }
3678
3679 static void
3680 call_oper_funcs(struct userNode *user)
3681 {
3682 unsigned int n;
3683 if (IsLocal(user))
3684 return;
3685 for (n=0; n<of_used; n++)
3686 of_list[n](user);
3687 }
3688
3689 static void
3690 send_burst(void)
3691 {
3692 unsigned int i, hop, max_hop=1;
3693 dict_iterator_t it;
3694
3695 /* burst (juped) servers, closest first (except self, which is sent already) */
3696 for (i=0; i<ArrayLength(servers_num); i++)
3697 if (servers_num[i] && servers_num[i]->hops > max_hop)
3698 max_hop = servers_num[i]->hops;
3699 for (hop=1; hop<=max_hop; hop++) {
3700 for (i=0;i<ArrayLength(servers_num);i++) {
3701 if (servers_num[i]
3702 && (servers_num[i]->hops == hop)
3703 && (servers_num[i] != self->uplink))
3704 irc_server(servers_num[i]);
3705 }
3706 }
3707
3708 /* burst local nicks */
3709 for (i=0; i<=self->num_mask; i++)
3710 if (self->users[i])
3711 irc_user(self->users[i]);
3712
3713 /* build dict of unbursted channel names (just copy existing channels) */
3714 unbursted_channels = dict_new();
3715 for (it = dict_first(channels); it; it = iter_next(it))
3716 dict_insert(unbursted_channels, iter_key(it), iter_data(it));
3717 }
3718
3719 /*
3720 * Oplevel parsing
3721 */
3722 static int
3723 parse_oplevel(char *str)
3724 {
3725 int oplevel = 0;
3726 while (isdigit(*str))
3727 oplevel = oplevel * 10 + *str++ - '0';
3728 return oplevel;
3729 }
3730