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