]>
jfr.im git - irc/evilnet/x3.git/blob - src/proto-p10.c
1 /* proto-p10.c - IRC protocol output
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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.
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.
25 #include "hosthiding.h"
26 #include "proto-common.c"
30 #define CMD_ACCOUNT "ACCOUNT"
31 #define CMD_ADMIN "ADMIN"
32 #define CMD_ASLL "ASLL"
33 #define CMD_AWAY "AWAY"
34 #define CMD_BURST "BURST"
35 #define CMD_CLEARMODE "CLEARMODE"
36 #define CMD_CLOSE "CLOSE"
37 #define CMD_CNOTICE "CNOTICE"
38 #define CMD_CONNECT "CONNECT"
39 #define CMD_CPRIVMSG "CPRIVMSG"
40 #define CMD_CREATE "CREATE"
41 #define CMD_DESTRUCT "DESTRUCT"
42 #define CMD_DESYNCH "DESYNCH"
45 #define CMD_EOB "END_OF_BURST"
46 #define CMD_EOB_ACK "EOB_ACK"
47 #define CMD_ERROR "ERROR"
48 #define CMD_FAKEHOST "FAKE"
50 #define CMD_GLINE "GLINE"
51 #define CMD_HASH "HASH"
52 #define CMD_HELP "HELP"
53 #define CMD_INFO "INFO"
54 #define CMD_INVITE "INVITE"
55 #define CMD_ISON "ISON"
56 #define CMD_JOIN "JOIN"
57 #define CMD_JUPE "JUPE"
58 #define CMD_KICK "KICK"
59 #define CMD_KILL "KILL"
60 #define CMD_LINKS "LINKS"
61 #define CMD_LIST "LIST"
62 #define CMD_LUSERS "LUSERS"
64 #define CMD_MARK "MARK"
65 #define CMD_MODE "MODE"
66 #define CMD_MOTD "MOTD"
67 #define CMD_NAMES "NAMES"
68 #define CMD_NICK "NICK"
69 #define CMD_NOTICE "NOTICE"
70 #define CMD_OPER "OPER"
71 #define CMD_OPMODE "OPMODE"
72 #define CMD_PART "PART"
73 #define CMD_PASS "PASS"
74 #define CMD_PING "PING"
75 #define CMD_PONG "PONG"
76 #define CMD_POST "POST"
77 #define CMD_PRIVMSG "PRIVMSG"
78 #define CMD_PRIVS "PRIVS"
79 #define CMD_PROTO "PROTO"
80 #define CMD_QUIT "QUIT"
81 #define CMD_REHASH "REHASH"
82 #define CMD_RESET "RESET"
83 #define CMD_RESTART "RESTART"
84 #define CMD_RPING "RPING"
85 #define CMD_RPONG "RPONG"
86 #define CMD_SERVER "SERVER"
87 #define CMD_SERVLIST "SERVLIST"
88 #define CMD_SERVSET "SERVSET"
90 #define CMD_SETTIME "SETTIME"
91 #define CMD_SHUN "SHUN"
92 #define CMD_SILENCE "SILENCE"
93 #define CMD_SQUERY "SQUERY"
94 #define CMD_SQUIT "SQUIT"
95 #define CMD_STATS "STATS"
96 #define CMD_SVSJOIN "SVSJOIN"
97 #define CMD_SVSNICK "SVSNICK"
98 #define CMD_SVSPART "SVSPART"
99 #define CMD_SWHOIS "SWHOIS"
100 #define CMD_TIME "TIME"
101 #define CMD_TOPIC "TOPIC"
102 #define CMD_TRACE "TRACE"
103 #define CMD_UPING "UPING"
104 #define CMD_USER "USER"
105 #define CMD_USERHOST "USERHOST"
106 #define CMD_USERIP "USERIP"
107 #define CMD_VERSION "VERSION"
108 #define CMD_WALLCHOPS "WALLCHOPS"
109 #define CMD_WALLOPS "WALLOPS"
110 #define CMD_WALLHOPS "WALLHOPS"
111 #define CMD_WALLUSERS "WALLUSERS"
112 #define CMD_WALLVOICES "WALLVOICES"
113 #define CMD_WALLHOPS "WALLHOPS"
114 #define CMD_WHO "WHO"
115 #define CMD_WHOIS "WHOIS"
116 #define CMD_WHOWAS "WHOWAS"
118 /* Tokenized commands. */
119 #define TOK_ACCOUNT "AC"
120 #define TOK_ADMIN "AD"
121 #define TOK_ASLL "LL"
123 #define TOK_BURST "B"
124 #define TOK_CLEARMODE "CM"
125 #define TOK_CLOSE "CLOSE"
126 #define TOK_CNOTICE "CN"
127 #define TOK_CONNECT "CO"
128 #define TOK_CPRIVMSG "CP"
129 #define TOK_CREATE "C"
130 #define TOK_DESTRUCT "DE"
131 #define TOK_DESYNCH "DS"
132 #define TOK_DIE "DIE"
133 #define TOK_DNS "DNS"
135 #define TOK_EOB_ACK "EA"
136 #define TOK_ERROR "Y"
137 #define TOK_EXEMPT "EX"
138 #define TOK_FAKEHOST "FA"
139 #define TOK_GET "GET"
140 #define TOK_GLINE "GL"
141 #define TOK_HASH "HASH"
142 #define TOK_HELP "HELP"
144 #define TOK_INVITE "I"
145 #define TOK_ISON "ISON"
147 #define TOK_JUPE "JU"
150 #define TOK_LINKS "LI"
151 #define TOK_LIST "LIST"
152 #define TOK_LUSERS "LU"
153 #define TOK_MAP "MAP"
154 #define TOK_MARK "MK"
156 #define TOK_MOTD "MO"
157 #define TOK_NAMES "E"
159 #define TOK_NOTICE "O"
160 #define TOK_OPER "OPER"
161 #define TOK_OPMODE "OM"
163 #define TOK_PASS "PA"
166 #define TOK_POST "POST"
167 #define TOK_PRIVMSG "P"
168 #define TOK_PRIVS "PRIVS"
169 #define TOK_PROTO "PROTO"
171 #define TOK_REHASH "REHASH"
172 #define TOK_RESET "RESET"
173 #define TOK_RESTART "RESTART"
174 #define TOK_RPING "RI"
175 #define TOK_RPONG "RO"
176 #define TOK_SERVER "S"
177 #define TOK_SERVLIST "SERVSET"
178 #define TOK_SERVSET "SERVSET"
179 #define TOK_SET "SET"
180 #define TOK_SETTIME "SE"
181 #define TOK_SHUN "SU"
182 #define TOK_SILENCE "U"
183 #define TOK_SQUERY "SQUERY"
184 #define TOK_SQUIT "SQ"
185 #define TOK_STATS "R"
186 #define TOK_SVSJOIN "SJ"
187 #define TOK_SVSNICK "SN"
188 #define TOK_SVSPART "SP"
189 #define TOK_SWHOIS "SW"
190 #define TOK_TIME "TI"
191 #define TOK_TOPIC "T"
192 #define TOK_TRACE "TR"
193 #define TOK_UPING "UP"
194 #define TOK_USER "USER"
195 #define TOK_USERHOST "USERHOST"
196 #define TOK_USERIP "USERIP"
197 #define TOK_VERSION "V"
198 #define TOK_WALLCHOPS "WC"
199 #define TOK_WALLOPS "WA"
200 #define TOK_WALLHOPS "WH"
201 #define TOK_WALLUSERS "WU"
202 #define TOK_WALLVOICES "WV"
203 #define TOK_WALLHOPS "WH"
205 #define TOK_WHOIS "W"
206 #define TOK_WHOWAS "X"
208 /* Protocol messages; aliased to full commands or tokens depending
209 on compile-time configuration. ircu prefers tokens WITH THE
210 EXCEPTION OF THE SERVER AND PASS COMMANDS, which cannot be
211 tokenized, because clients' (ie. a linking server) commands are
212 only checked against the full command list.
214 #if defined(ENABLE_TOKENS)
215 #define TYPE(NAME) TOK_ ## NAME
216 #else /* !ENABLE_TOKENS */
217 #define TYPE(NAME) CMD_ ## NAME
218 #endif /* ENABLE_TOKENS */
220 #define P10_ACCOUNT TYPE(ACCOUNT)
221 #define P10_ADMIN TYPE(ADMIN)
222 #define P10_ASLL TYPE(ASLL)
223 #define P10_AWAY TYPE(AWAY)
224 #define P10_BURST TYPE(BURST)
225 #define P10_CLEARMODE TYPE(CLEARMODE)
226 #define P10_CLOSE TYPE(CLOSE)
227 #define P10_CNOTICE TYPE(CNOTICE)
228 #define P10_CONNECT TYPE(CONNECT)
229 #define P10_CPRIVMSG TYPE(CPRIVMSG)
230 #define P10_CREATE TYPE(CREATE)
231 #define P10_DESTRUCT TYPE(DESTRUCT)
232 #define P10_DESYNCH TYPE(DESYNCH)
233 #define P10_DIE TYPE(DIE)
234 #define P10_DNS TYPE(DNS)
235 #define P10_EOB TYPE(EOB)
236 #define P10_EOB_ACK TYPE(EOB_ACK)
237 #define P10_ERROR TYPE(ERROR)
238 #define P10_FAKEHOST TYPE(FAKEHOST)
239 #define P10_GET TYPE(GET)
240 #define P10_GLINE TYPE(GLINE)
241 #define P10_HASH TYPE(HASH)
242 #define P10_HELP TYPE(HELP)
243 #define P10_INFO TYPE(INFO)
244 #define P10_INVITE TYPE(INVITE)
245 #define P10_ISON TYPE(ISON)
246 #define P10_JOIN TYPE(JOIN)
247 #define P10_JUPE TYPE(JUPE)
248 #define P10_KICK TYPE(KICK)
249 #define P10_KILL TYPE(KILL)
250 #define P10_LINKS TYPE(LINKS)
251 #define P10_LIST TYPE(LIST)
252 #define P10_LUSERS TYPE(LUSERS)
253 #define P10_MAP TYPE(MAP)
254 #define P10_MARK TYPE(MARK)
255 #define P10_MODE TYPE(MODE)
256 #define P10_MOTD TYPE(MOTD)
257 #define P10_NAMES TYPE(NAMES)
258 #define P10_NICK TYPE(NICK)
259 #define P10_NOTICE TYPE(NOTICE)
260 #define P10_OPER TYPE(OPER)
261 #define P10_OPMODE TYPE(OPMODE)
262 #define P10_PART TYPE(PART)
263 #define P10_PASS CMD_PASS
264 #define P10_PING TYPE(PING)
265 #define P10_PONG TYPE(PONG)
266 #define P10_POST TYPE(POST)
267 #define P10_PRIVMSG TYPE(PRIVMSG)
268 #define P10_PRIVS TYPE(PRIVS)
269 #define P10_PROTO TYPE(PROTO)
270 #define P10_QUIT TYPE(QUIT)
271 #define P10_REHASH TYPE(REHASH)
272 #define P10_RESET TYPE(RESET)
273 #define P10_RESTART TYPE(RESTART)
274 #define P10_RPING TYPE(RPING)
275 #define P10_RPONG TYPE(RPONG)
276 #define P10_SERVER CMD_SERVER
277 #define P10_SERVLIST TYPE(SERVLIST)
278 #define P10_SERVSET TYPE(SERVSET)
279 #define P10_SET TYPE(SET)
280 #define P10_SETTIME TYPE(SETTIME)
281 #define P10_SHUN TYPE(SHUN)
282 #define P10_SILENCE TYPE(SILENCE)
283 #define P10_SQUERY TYPE(SQUERY)
284 #define P10_SQUIT TYPE(SQUIT)
285 #define P10_STATS TYPE(STATS)
286 #define P10_SVSJOIN TYPE(SVSJOIN)
287 #define P10_SVSNICK TYPE(SVSNICK)
288 #define P10_SVSPART TYPE(SVSPART)
289 #define P10_SWHOIS TYPE(SWHOIS)
290 #define P10_TIME TYPE(TIME)
291 #define P10_TOPIC TYPE(TOPIC)
292 #define P10_TRACE TYPE(TRACE)
293 #define P10_UPING TYPE(UPING)
294 #define P10_USER TYPE(USER)
295 #define P10_USERHOST TYPE(USERHOST)
296 #define P10_USERIP TYPE(USERIP)
297 #define P10_VERSION TYPE(VERSION)
298 #define P10_WALLCHOPS TYPE(WALLCHOPS)
299 #define P10_WALLOPS TYPE(WALLOPS)
300 #define P10_WALLHOPS TYPE(WALLHOPS)
301 #define P10_WALLUSERS TYPE(WALLUSERS)
302 #define P10_WALLVOICES TYPE(WALLVOICES)
303 #define P10_WHO TYPE(WHO)
304 #define P10_WHOIS TYPE(WHOIS)
305 #define P10_WHOWAS TYPE(WHOWAS)
306 #define P10_EXEMPT TYPE(EXEMPT)
308 /* Servers claiming to have a boot or link time before PREHISTORY
309 * trigger errors to the log. We hope no server has been running
310 * constantly since September 1994. :)
312 #define PREHISTORY 780000000
314 #define MODELEN 40 + KEYLEN
316 static struct server
*servers_num
[64*64];
317 static privmsg_func_t
*privmsg_funcs
;
318 static unsigned int num_privmsg_funcs
;
319 static privmsg_func_t
*notice_funcs
;
320 static unsigned int num_notice_funcs
;
321 static struct dict
*unbursted_channels
;
322 static char *his_servername
;
323 static char *his_servercomment
;
324 static int extended_accounts
;
326 static struct userNode
*AddUser(struct server
* uplink
, const char *nick
, const char *ident
, const char *hostname
, const char *modes
, const char *numeric
, const char *userinfo
, time_t timestamp
, const char *realip
);
328 extern int off_channel
;
329 extern int DefConLevel
;
330 extern int DefConTimeOut
;
331 extern char *DefConChanModes
;
333 static int parse_oplevel(char *str
);
335 char privbuf
[512] = "";
337 /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
338 * server and Y's indentifying the client on that server. */
340 GetServerN(const char *numeric
)
342 switch (strlen(numeric
)) {
344 return servers_num
[base64toint(numeric
, 2)];
348 return servers_num
[base64toint(numeric
, 1)];
355 GetUserN(const char *numeric
) /* using numeric */
361 switch (strlen(numeric
)) {
363 log_module(MAIN_LOG
, LOG_WARNING
, "GetUserN(%s): numeric too long!", numeric
);
365 case 5: slen
= 2; ulen
= 3; break;
366 case 4: slen
= 1; ulen
= 3; break;
367 case 3: slen
= 1; ulen
= 2; break;
368 case 2: case 1: case 0:
369 log_module(MAIN_LOG
, LOG_WARNING
, "GetUserN(%s): numeric too short!", numeric
);
372 if (!(s
= servers_num
[base64toint(numeric
, slen
)])) {
373 log_module(MAIN_LOG
, LOG_WARNING
, "GetUserN(%s): couldn't find server (len=%d)!", numeric
, slen
);
376 n
= base64toint(numeric
+slen
, ulen
) & s
->num_mask
;
377 if (!(un
= s
->users
[n
])) {
378 log_module(MAIN_LOG
, LOG_WARNING
, "GetUserN(%s) couldn't find user!", numeric
);
384 privmsg_user_helper(struct userNode
*un
, void *data
)
386 struct privmsg_desc
*pd
= data
;
387 unsigned int num
= un
->num_local
;
388 if (!pd
->is_notice
) {
389 if ((num
< num_privmsg_funcs
) && privmsg_funcs
[num
]) {
390 privmsg_funcs
[num
](pd
->user
, un
, pd
->text
, pd
->is_qualified
);
393 if ((num
< num_notice_funcs
) && notice_funcs
[num
]) {
394 notice_funcs
[num
](pd
->user
, un
, pd
->text
, pd
->is_qualified
);
399 /* equiv to user doing /connect server port target */
400 void irc_connect(struct userNode
*user
, char *server
, unsigned int port
, struct server
*target
)
402 putsock("%s " P10_CONNECT
" %s %d %s", user
->numeric
, server
, port
, target
->numeric
);
406 irc_squit_route(struct server
*srv
, const char *message
, ...)
410 va_start(arg_list
, message
);
411 vsnprintf(buffer
, MAXLEN
-2, message
, arg_list
);
412 buffer
[MAXLEN
-1] = 0;
414 /* When would we squit ourselves exactly?? -Rubin */
415 if(srv
== self
&& cManager
.uplink
->state
== CONNECTED
) {
418 /* Quit all clients linked to me. */
419 for(i
= 0; i
<= self
->num_mask
; i
++) {
422 irc_quit(self
->users
[i
], buffer
);
426 putsock("%s " P10_SQUIT
" %s %d :%s", self
->numeric
, srv
->name
, 0, buffer
);
429 /* Force a reconnect to the currently selected server. */
430 cManager
.uplink
->tries
= 0;
431 log_module(MAIN_LOG
, LOG_INFO
, "Squitting from uplink: %s", buffer
);
437 irc_server(struct server
*srv
)
439 char extranum
[COMBO_NUMERIC_LEN
+1];
441 inttobase64(extranum
, srv
->num_mask
, (srv
->numeric
[1] || (srv
->num_mask
>= 64*64)) ? 3 : 2);
443 putsock(P10_SERVER
" %s %d %li %li J10 %s%s +s6 :%s",
444 srv
->name
, srv
->hops
+1, srv
->boot
, srv
->link
, srv
->numeric
, extranum
, srv
->description
);
446 putsock("%s " P10_SERVER
" %s %d %li %li %c10 %s%s +s6 :%s",
447 self
->numeric
, srv
->name
, srv
->hops
+1, srv
->boot
, srv
->link
, (srv
->self_burst
? 'J' : 'P'), srv
->numeric
, extranum
, srv
->description
);
452 irc_p10_pton(irc_in_addr_t
*ip
, const char *input
)
454 if (strlen(input
) == 6) {
456 memset(ip
, 0, 6 * sizeof(ip
->in6
[0]));
457 value
= base64toint(input
, 6);
459 ip
->in6
[5] = htons(65535);
460 ip
->in6
[6] = htons(value
>> 16);
461 ip
->in6
[7] = htons(value
& 65535);
463 unsigned int pos
= 0;
467 for (left
= (25 - strlen(input
)) / 3; left
; left
--)
471 ip
->in6
[pos
++] = ntohs(base64toint(input
, 3));
479 irc_p10_ntop(char *output
, const irc_in_addr_t
*ip
)
481 if (!irc_in_addr_is_valid(*ip
)) {
482 strcpy(output
, "AAAAAA");
483 } else if (irc_in_addr_is_ipv4(*ip
)) {
485 in4
= (ntohs(ip
->in6
[6]) << 16) | ntohs(ip
->in6
[7]);
486 inttobase64(output
, in4
, 6);
488 } else if (irc_in_addr_is_ipv6(*ip
)) {
489 unsigned int max_start
, max_zeros
, curr_zeros
, zero
, ii
;
490 /* Can start by printing out the leading non-zero parts. */
491 for (ii
= 0; (ip
->in6
[ii
]) && (ii
< 8); ++ii
) {
492 inttobase64(output
, ntohs(ip
->in6
[ii
]), 3);
495 /* Find the longest run of zeros. */
496 for (max_start
= zero
= ii
, max_zeros
= curr_zeros
= 0; ii
< 8; ++ii
) {
499 else if (curr_zeros
> max_zeros
) {
500 max_start
= ii
- curr_zeros
;
501 max_zeros
= curr_zeros
;
505 if (curr_zeros
> max_zeros
) {
506 max_start
= ii
- curr_zeros
;
507 max_zeros
= curr_zeros
;
510 /* Print the rest of the address */
511 for (ii
= zero
; ii
< 8; ) {
512 if ((ii
== max_start
) && max_zeros
) {
516 inttobase64(output
, ntohs(ip
->in6
[ii
]), 3);
522 strcpy(output
, "???");
527 irc_user(struct userNode
*user
)
532 irc_p10_ntop(b64ip
, &user
->ip
);
539 modes
[modelen
++] = 'o';
540 if (IsInvisible(user
))
541 modes
[modelen
++] = 'i';
543 modes
[modelen
++] = 'w';
545 modes
[modelen
++] = 'k';
546 if (IsServNotice(user
))
547 modes
[modelen
++] = 's';
549 modes
[modelen
++] = 'd';
551 modes
[modelen
++] = 'g';
552 // sethost - reed/apples
553 // if (IsHelperIrcu(user))
555 modes
[modelen
++] = 'h';
556 if (IsFakeHost(user
))
557 modes
[modelen
++] = 'f';
558 if (IsHiddenHost(user
))
559 modes
[modelen
++] = 'x';
562 /* we don't need to put the + in modes because it's in the format string. */
563 putsock("%s " P10_NICK
" %s %d %li %s %s +%s %s %s :%s",
564 user
->uplink
->numeric
, user
->nick
, user
->uplink
->hops
+1, user
->timestamp
, user
->ident
, user
->hostname
, modes
, b64ip
, user
->numeric
, user
->info
);
566 putsock("%s " P10_NICK
" %s %d %li %s %s %s %s :%s",
567 user
->uplink
->numeric
, user
->nick
, user
->uplink
->hops
+1, user
->timestamp
, user
->ident
, user
->hostname
, b64ip
, user
->numeric
, user
->info
);
572 irc_rename(struct userNode
*user
, const char *new_handle
)
574 if(extended_accounts
)
575 putsock("%s " P10_ACCOUNT
" %s M %s", self
->numeric
, user
->numeric
, new_handle
);
579 irc_delete(struct userNode
*user
)
581 if(extended_accounts
)
582 putsock("%s " P10_ACCOUNT
" %s U", self
->numeric
, user
->numeric
);
586 irc_account(struct userNode
*user
, const char *stamp
, time_t timestamp
)
588 if(extended_accounts
)
589 putsock("%s " P10_ACCOUNT
" %s R %s %lu", self
->numeric
, user
->numeric
, stamp
, timestamp
);
591 putsock("%s " P10_ACCOUNT
" %s %s %lu", self
->numeric
, user
->numeric
, stamp
, timestamp
);
595 irc_fakehost(struct userNode
*user
, const char *host
)
597 putsock("%s " P10_FAKEHOST
" %s %s", self
->numeric
, user
->numeric
, host
);
601 irc_regnick(UNUSED_ARG(struct userNode
*user
))
603 /* no operation here */
607 irc_nick(struct userNode
*user
, UNUSED_ARG(const char *old_nick
))
609 putsock("%s " P10_NICK
" %s "FMT_TIME_T
, user
->numeric
, user
->nick
, now
);
613 irc_fetchtopic(struct userNode
*from
, const char *to
)
617 putsock("%s " P10_TOPIC
" %s", from
->numeric
, to
);
621 irc_squit(struct server
*srv
, const char *message
, const char *service_message
)
623 if (!service_message
)
624 service_message
= message
;
626 /* Are we leaving the network? */
627 if (srv
== self
&& cManager
.uplink
->state
== CONNECTED
) {
630 /* Quit all clients linked to me. */
631 for (i
= 0; i
<= self
->num_mask
; i
++) {
634 irc_quit(self
->users
[i
], service_message
);
638 putsock("%s " P10_SQUIT
" %s %d :%s", self
->numeric
, srv
->name
, 0, message
);
641 /* Force a reconnect to the currently selected server. */
642 cManager
.uplink
->tries
= 0;
643 log_module(MAIN_LOG
, LOG_INFO
, "Squitting from uplink: %s", message
);
649 irc_wallchops(struct userNode
*from
, const char *to
, const char *message
)
651 putsock("%s " P10_WALLCHOPS
" %s :%s", from
->numeric
, to
, message
);
655 irc_wallops(const char *format
, ...)
659 va_start(arg_list
, format
);
660 vsnprintf(buffer
, MAXLEN
-2, format
, arg_list
);
661 buffer
[MAXLEN
-1] = 0;
662 putsock("%s " P10_WALLOPS
" :%s", self
->numeric
, buffer
);
667 irc_notice(struct userNode
*from
, const char *to
, const char *message
)
669 putsock("%s " P10_NOTICE
" %s :%s", from
->numeric
, to
, message
);
673 irc_notice_user(struct userNode
*from
, struct userNode
*to
, const char *message
)
675 putsock("%s " P10_NOTICE
" %s :%s", from
->numeric
, to
->numeric
, message
);
679 irc_privmsg(struct userNode
*from
, const char *to
, const char *message
)
681 putsock("%s " P10_PRIVMSG
" %s :%s", from
->numeric
, to
, message
);
685 irc_privmsg_user(struct userNode
*from
, struct userNode
*to
, const char *message
)
687 putsock("%s " P10_PRIVMSG
" %s :%s", from
->numeric
, to
->numeric
, message
);
691 irc_version_user(struct userNode
*from
, struct userNode
*to
)
693 irc_privmsg_user(from
, to
, "\001VERSION\001");
699 putsock("%s " P10_EOB
, self
->numeric
);
705 putsock("%s " P10_EOB_ACK
, self
->numeric
);
709 str
= conf_get_data("services/opserv/nick", RECDB_QSTRING
);
712 if (nick
&& (DefConLevel
< 5)) {
713 DefConProcess(GetUserH(nick
));
715 if (DefConTimeOut
> 0)
716 timeq_add(now
+ DefConTimeOut
, defcon_timeout
, NULL
);
721 irc_ping(const char *payload
)
723 putsock("%s " P10_PING
" :%s", self
->numeric
, payload
);
727 irc_pong(const char *who
, const char *data
)
729 putsock("%s " P10_PONG
" %s :%s", self
->numeric
, who
, data
);
733 irc_pong_asll(const char *who
, const char *orig_ts
)
740 orig
.tv_sec
= strtoul(orig_ts
, &delim
, 10);
741 orig
.tv_usec
= (*delim
== '.') ? strtoul(delim
+ 1, NULL
, 10) : 0;
742 gettimeofday(&now
, NULL
);
743 diff
= (now
.tv_sec
- orig
.tv_sec
) * 1000 + (now
.tv_usec
- orig
.tv_usec
) / 1000;
744 putsock("%s " P10_PONG
" %s %s %d " FMT_TIME_T
".%06u", self
->numeric
, who
, orig_ts
, diff
, now
.tv_sec
, (unsigned)now
.tv_usec
);
748 irc_pass(const char *passwd
)
750 putsock(P10_PASS
" :%s", passwd
);
754 irc_introduce(const char *passwd
)
756 void timed_send_ping(void *data
);
758 self
->self_burst
= self
->burst
= 1;
762 timeq_add(now
+ ping_freq
, timed_send_ping
, 0);
766 irc_gline(struct server
*srv
, struct gline
*gline
, int silent
)
768 putsock("%s " P10_GLINE
" %s +%s %ld :%s<%s> %s",
769 self
->numeric
, (srv
? srv
->numeric
: "*"), gline
->target
, gline
->expires
-now
, silent
? "AUTO " : "", gline
->issuer
, gline
->reason
);
773 irc_shun(struct server
*srv
, struct shun
*shun
)
775 putsock("%s " P10_SHUN
" %s +%s %ld :<%s> %s",
776 self
->numeric
, (srv
? srv
->numeric
: "*"), shun
->target
, shun
->expires
-now
, shun
->issuer
, shun
->reason
);
780 irc_settime(const char *srv_name_mask
, time_t new_time
)
782 ioset_set_time(new_time
);
783 if (!strcmp(srv_name_mask
, "*"))
785 putsock("%s " P10_SETTIME
" " FMT_TIME_T
" %s", self
->numeric
, new_time
, srv_name_mask
);
789 irc_ungline(const char *mask
)
791 putsock("%s " P10_GLINE
" * -%s", self
->numeric
, mask
);
795 irc_unshun(const char *mask
)
797 putsock("%s " P10_SHUN
" * -%s", self
->numeric
, mask
);
801 irc_burst(struct chanNode
*chan
)
803 char burst_line
[512];
804 int pos
, base_len
, len
;
807 struct exemptNode
*en
;
811 base_len
= sprintf(burst_line
, "%s " P10_BURST
" %s " FMT_TIME_T
" ",
812 self
->numeric
, chan
->name
, chan
->timestamp
);
813 len
= irc_make_chanmode(chan
, burst_line
+base_len
);
814 pos
= base_len
+ len
;
816 burst_line
[pos
++] = ' ';
818 if(chan
->members
.used
< 1)
819 return; /* dont burst empty channels (created by discrims) */
821 for (n
=0; n
<chan
->members
.used
; n
++) {
822 mn
= chan
->members
.list
[n
];
824 burst_line
[pos
-1] = 0; /* -1 to back up over the space or comma */
825 putsock("%s", burst_line
);
829 memcpy(burst_line
+pos
, mn
->user
->numeric
, strlen(mn
->user
->numeric
));
830 pos
+= strlen(mn
->user
->numeric
);
831 if (mn
->modes
&& (mn
->modes
!= last_mode
)) {
832 last_mode
= mn
->modes
;
833 burst_line
[pos
++] = ':';
834 if (last_mode
& MODE_CHANOP
)
835 burst_line
[pos
++] = 'o';
836 if (last_mode
& MODE_HALFOP
)
837 burst_line
[pos
++] = 'h';
838 if (last_mode
& MODE_VOICE
)
839 burst_line
[pos
++] = 'v';
841 if ((n
+1)<chan
->members
.used
)
842 burst_line
[pos
++] = ',';
844 if (chan
->banlist
.used
) {
846 if (pos
+2+strlen(chan
->banlist
.list
[0]->ban
) > 505) {
847 burst_line
[pos
-1] = 0;
848 putsock("%s", burst_line
);
851 burst_line
[pos
++] = ' ';
854 burst_line
[pos
++] = ':';
855 burst_line
[pos
++] = '%';
857 for (n
=0; n
<chan
->banlist
.used
; n
++) {
858 bn
= chan
->banlist
.list
[n
];
859 len
= strlen(bn
->ban
);
860 if (pos
+len
+1 > 510) {
861 burst_line
[pos
-1] = 0; /* -1 to back up over the space or comma */
862 putsock("%s", burst_line
);
865 memcpy(burst_line
+pos
, bn
->ban
, len
);
867 burst_line
[pos
++] = ' ';
870 if (chan
->exemptlist
.used
) {
871 /* dump the exempt */
872 if (pos
+2+strlen(chan
->exemptlist
.list
[0]->exempt
) > 505) {
873 burst_line
[pos
-1] = 0;
874 putsock("%s", burst_line
);
877 burst_line
[pos
++] = ' ';
880 burst_line
[pos
++] = ' ';
881 burst_line
[pos
++] = '~';
882 burst_line
[pos
++] = ' ';
884 for (n
=0; n
<chan
->exemptlist
.used
; n
++) {
885 en
= chan
->exemptlist
.list
[n
];
886 len
= strlen(en
->exempt
);
887 if (pos
+len
+1 > 510) {
888 burst_line
[pos
-1] = 0; /* -1 to back up over the space or comma */
889 putsock("%s", burst_line
);
892 memcpy(burst_line
+pos
, en
->exempt
, len
);
894 burst_line
[pos
++] = ' ';
897 /* print the last line */
899 putsock("%s", burst_line
);
903 irc_quit(struct userNode
*user
, const char *message
)
905 putsock("%s " P10_QUIT
" :%s", user
->numeric
, message
);
909 irc_error(const char *to
, const char *message
)
912 putsock("%s " P10_ERROR
" :%s", to
, message
);
914 putsock(":%s " P10_ERROR
" :%s", self
->name
, message
);
919 irc_kill(struct userNode
*from
, struct userNode
*target
, const char *message
)
922 putsock("%s " P10_KILL
" %s :%s!%s (%s)",
923 from
->numeric
, target
->numeric
, self
->name
, from
->nick
, message
);
925 putsock("%s " P10_KILL
" %s :%s (%s)",
926 self
->numeric
, target
->numeric
, self
->name
, message
);
931 irc_mode(struct userNode
*from
, struct chanNode
*target
, const char *modes
)
933 call_channel_mode_funcs(from
, target
, (char **)&modes
, 0);
934 putsock("%s " P10_MODE
" %s %s "FMT_TIME_T
,
935 (from
? from
->numeric
: self
->numeric
),
936 target
->name
, modes
, target
->timestamp
);
939 /* Added to allow services to mode users
940 2005 - 8 - 10 by Life4Christ
943 irc_umode(struct userNode
*target
, const char *modes
)
945 putsock("%s " P10_MODE
" %s %s ",self
->numeric
,target
->nick
, modes
);
950 irc_invite(struct userNode
*from
, struct userNode
*who
, struct chanNode
*to
)
952 putsock("%s " P10_INVITE
" %s %s", from
->numeric
, who
->nick
, to
->name
);
956 irc_silence(struct userNode
*who
, const char *mask
, int add
)
958 putsock("%s " P10_SILENCE
" %s %s%s", self
->numeric
, who
->numeric
, add
? "+" : "-", mask
);
962 irc_join(struct userNode
*who
, struct chanNode
*what
)
964 if (what
->members
.used
== 1) {
965 putsock("%s " P10_CREATE
" %s %lu",
966 who
->numeric
, what
->name
, what
->timestamp
);
968 putsock("%s " P10_JOIN
" %s %lu", who
->numeric
, what
->name
, what
->timestamp
);
973 irc_svsjoin(struct userNode
*from
, struct userNode
*who
, struct chanNode
*to
)
975 putsock("%s " P10_SVSJOIN
" %s %s "FMT_TIME_T
, from
->uplink
->numeric
, who
->numeric
, to
->name
, now
);
979 irc_svspart(struct userNode
*from
, struct userNode
*who
, struct chanNode
*to
)
981 putsock("%s " P10_SVSPART
" %s %s", from
->uplink
->numeric
, who
->numeric
, to
->name
);
985 irc_kick(struct userNode
*who
, struct userNode
*target
, struct chanNode
*channel
, const char *msg
)
988 struct modeNode
*mn
= GetUserMode(channel
, who
);
989 numeric
= ((mn
&& (mn
->modes
& MODE_CHANOP
)) || off_channel
) ? who
->numeric
: self
->numeric
;
990 putsock("%s " P10_KICK
" %s %s :%s",
991 numeric
, channel
->name
, target
->numeric
, msg
);
995 irc_stats(struct userNode
*from
, struct server
*target
, char type
)
997 putsock("%s " P10_STATS
" %c :%s", from
->numeric
, type
, target
->numeric
);
1001 irc_svsnick(struct userNode
*from
, struct userNode
*target
, const char *newnick
)
1003 putsock("%s " P10_SVSNICK
" %s %s "FMT_TIME_T
, from
->uplink
->numeric
, target
->numeric
, newnick
, now
);
1007 irc_swhois(struct userNode
*from
, struct userNode
*target
, const char *message
)
1009 putsock("%s " P10_SWHOIS
" %s %s%s", from
->uplink
->numeric
, target
->numeric
, message
? ":" : "",
1010 message
? message
: "");
1015 irc_part(struct userNode
*who
, struct chanNode
*what
, const char *reason
)
1018 putsock("%s " P10_PART
" %s :%s", who
->numeric
, what
->name
, reason
);
1020 putsock("%s " P10_PART
" %s", who
->numeric
, what
->name
);
1025 irc_topic(struct userNode
*service
, struct userNode
*who
, struct chanNode
*what
, const char *topic
)
1029 int host_in_topic
= 0;
1030 const char *hstr
, *tstr
;
1031 char *host
, *hostmask
;
1033 char sident
[MAXLEN
];
1035 tstr
= conf_get_data("server/type", RECDB_QSTRING
);
1036 hstr
= conf_get_data("server/host_in_topic", RECDB_QSTRING
);
1040 type
= 4;/* default to 040 style topics */
1043 if (IsFakeHost(who
))
1044 safestrncpy(shost
, who
->fakehost
, sizeof(shost
));
1045 else if (IsSetHost(who
)) {
1046 hostmask
= strdup(who
->sethost
);
1047 if ((host
= (strrchr(hostmask
, '@'))))
1052 safestrncpy(sident
, hostmask
, sizeof(shost
));
1053 safestrncpy(shost
, host
, sizeof(shost
));
1055 safestrncpy(shost
, who
->hostname
, sizeof(shost
));
1057 host_in_topic
= atoi(hstr
);
1061 putsock("%s " P10_TOPIC
" %s %s%s%s%s%s " FMT_TIME_T
" " FMT_TIME_T
" :%s", service
->numeric
, what
->name
,
1062 who
->nick
, host_in_topic
? "!" : "", host_in_topic
? (IsSetHost(who
) ? sident
: who
->ident
) : "",
1063 host_in_topic
? "@" : "", host_in_topic
? shost
: "", what
->timestamp
, now
, topic
);
1066 putsock("%s " P10_TOPIC
" %s :%s", who
->numeric
, what
->name
, topic
);
1071 irc_raw(const char *what
)
1073 putsock("%s", what
);
1077 irc_numeric(struct userNode
*user
, unsigned int num
, const char *format
, ...)
1080 char buffer
[MAXLEN
];
1081 va_start(arg_list
, format
);
1082 vsnprintf(buffer
, MAXLEN
-2, format
, arg_list
);
1083 buffer
[MAXLEN
-1] = 0;
1084 putsock(":%s %03d %s %s", self
->name
, num
, user
->nick
, buffer
);
1087 static void send_burst(void);
1090 change_nicklen(int new_nicklen
)
1093 char new_nick
[NICKLEN
+1];
1094 struct userNode
*user
;
1096 nicklen
= new_nicklen
;
1097 /* fix up any users we have here */
1098 for (nn
=0; nn
<=self
->num_mask
; nn
++) {
1099 if (!(user
= self
->users
[nn
]))
1101 safestrncpy(new_nick
, user
->nick
, sizeof(new_nick
));
1102 new_nick
[nicklen
] = 0;
1103 NickChange(user
, new_nick
, 1);
1107 static CMD_FUNC(cmd_whois
)
1109 struct userNode
*from
;
1110 struct userNode
*who
;
1114 if (!(from
= GetUserH(origin
))) {
1115 log_module(MAIN_LOG
, LOG_ERROR
, "Could not find WHOIS origin user %s", origin
);
1118 if(!(who
= GetUserH(argv
[2]))) {
1119 irc_numeric(from
, ERR_NOSUCHNICK
, "%s@%s :No such nick", argv
[2], self
->name
);
1122 if (IsHiddenHost(who
) && !IsOper(from
)) {
1123 /* Just stay quiet. */
1126 irc_numeric(from
, RPL_WHOISUSER
, "%s %s %s * :%s", who
->nick
, who
->ident
, who
->hostname
, who
->info
);
1127 if (his_servername
&& his_servercomment
)
1128 irc_numeric(from
, RPL_WHOISSERVER
, "%s %s :%s", who
->nick
, his_servername
, his_servercomment
);
1130 irc_numeric(from
, RPL_WHOISSERVER
, "%s %s :%s", who
->nick
, who
->uplink
->name
, who
->uplink
->description
);
1132 irc_numeric(from
, RPL_WHOISOPERATOR
, "%s :is a megalomaniacal power hungry tyrant", who
->nick
);
1133 irc_numeric(from
, RPL_ENDOFWHOIS
, "%s :End of /WHOIS list", who
->nick
);
1137 static CMD_FUNC(cmd_server
)
1145 /* another server introduced us */
1146 srv
= AddServer(GetServerH(origin
), argv
[1], atoi(argv
[2]), atoi(argv
[3]), atoi(argv
[4]), argv
[6], argv
[argc
-1]);
1149 srv
->self_burst
= argv
[5][0] == 'J';
1152 /* this must be our uplink */
1153 srv
= self
->uplink
= AddServer(self
, argv
[1], atoi(argv
[2]), atoi(argv
[3]), atoi(argv
[4]), argv
[6], argv
[argc
-1]);
1156 srv
->self_burst
= argv
[5][0] == 'J';
1158 if ((argv
[7][0] == '+') && !force_n2k
) {
1159 log_module(MAIN_LOG
, LOG_WARNING
, "Got Undernet-style SERVER message but \"force_n2k\" not on.");
1164 /* Fix up our timestamps if necessary. */
1165 if (srv
->boot
<= PREHISTORY
) {
1166 /* Server from the mists of time.. */
1167 if (srv
->hops
== 1) {
1168 log_module(MAIN_LOG
, LOG_ERROR
, "Server %s claims to have booted at time "FMT_TIME_T
". This is absurd.", srv
->name
, srv
->boot
);
1170 } else if ((str
= conf_get_data("server/reliable_clock", RECDB_QSTRING
))
1171 && enabled_string(str
)) {
1172 /* If we have a reliable clock, we just keep our current time. */
1174 if (srv
->boot
<= self
->boot
) {
1175 /* The other server is older than us. Accept their timestamp.
1176 * Alternately, we are same age, but we accept their time
1177 * since we are linking to them. */
1178 self
->boot
= srv
->boot
;
1179 ioset_set_time(srv
->link
);
1182 if (srv
== self
->uplink
) {
1183 extern time_t burst_begin
;
1190 static CMD_FUNC(cmd_eob
)
1192 struct server
*sender
;
1196 if (!(sender
= GetServerH(origin
)))
1198 if (sender
== self
->uplink
) {
1199 cManager
.uplink
->state
= CONNECTED
;
1200 for (it
= dict_first(unbursted_channels
); it
; it
= iter_next(it
))
1201 irc_burst(iter_data(it
));
1202 dict_delete(unbursted_channels
);
1203 unbursted_channels
= NULL
;
1207 /* now that we know who our uplink is,
1208 * we can center the routing map and activate auto-routing.
1210 activate_routing(NULL
, NULL
, NULL
);
1212 sender
->self_burst
= 0;
1213 recalc_bursts(sender
);
1214 for (ii
=0; ii
<slf_used
; ii
++)
1215 slf_list
[ii
](sender
);
1216 /* let auto-routing figure out if we were
1217 * wating on this server to link a child to it */
1218 /* DONT call this if uplink is _US_ */
1219 if(sender
->uplink
!= self
)
1220 routing_handle_connect(sender
->name
, sender
->uplink
->name
);
1224 static CMD_FUNC(cmd_eob_ack
)
1226 extern time_t burst_begin
;
1228 if (GetServerH(origin
) == self
->uplink
) {
1229 burst_length
= now
- burst_begin
;
1230 self
->self_burst
= self
->burst
= 0;
1232 cManager
.uplink
->state
= CONNECTED
;
1236 static CMD_FUNC(cmd_ping
)
1239 struct userNode
*un
;
1242 irc_pong_asll(argv
[2], argv
[3]);
1243 else if ((srv
= GetServerH(origin
)))
1244 irc_pong(self
->name
, srv
->numeric
);
1245 else if ((un
= GetUserH(origin
)))
1246 irc_pong(self
->name
, un
->numeric
);
1248 irc_pong(self
->name
, origin
);
1250 timeq_del(0, timed_send_ping
, 0, TIMEQ_IGNORE_WHEN
|TIMEQ_IGNORE_DATA
);
1251 timeq_del(0, timed_ping_timeout
, 0, TIMEQ_IGNORE_WHEN
|TIMEQ_IGNORE_DATA
);
1252 timeq_add(now
+ ping_freq
, timed_send_ping
, 0);
1257 static CMD_FUNC(cmd_error_nick
)
1259 /* Go back to original IRC length .. and try to reconnect :/ */
1261 irc_squit(self
, "Got erroneous nickname, truncating nicks.", NULL
);
1265 struct create_desc
{
1266 struct userNode
*user
;
1271 join_helper(struct chanNode
*chan
, void *data
)
1273 struct create_desc
*cd
= data
;
1274 AddChannelUser(cd
->user
, chan
);
1278 create_helper(char *name
, void *data
)
1280 struct create_desc
*cd
= data
;
1282 if (!strcmp(name
, "0")) {
1283 while (cd
->user
->channels
.used
> 0)
1284 DelChannelUser(cd
->user
, cd
->user
->channels
.list
[0]->channel
, 0, 0);
1288 AddChannelUser(cd
->user
, AddChannel(name
, cd
->when
, NULL
, NULL
, NULL
));
1291 static CMD_FUNC(cmd_create
)
1293 struct create_desc cd
;
1294 struct userNode
*user
;
1296 if ((argc
< 3) || !(user
= GetUserH(origin
)))
1299 cd
.when
= atoi(argv
[2]);
1300 parse_foreach(argv
[1], join_helper
, create_helper
, NULL
, NULL
, &cd
);
1304 static CMD_FUNC(cmd_join
)
1306 struct create_desc cd
;
1308 if (!(cd
.user
= GetUserH(origin
)))
1315 cd
.when
= atoi(argv
[2]);
1316 parse_foreach(argv
[1], join_helper
, create_helper
, NULL
, NULL
, &cd
);
1320 static CMD_FUNC(cmd_svsjoin
)
1322 struct create_desc cd
;
1324 if (!(cd
.user
= GetUserH(argv
[1])))
1331 cd
.when
= atoi(argv
[3]);
1332 parse_foreach(argv
[2], join_helper
, create_helper
, NULL
, NULL
, &cd
);
1336 static CMD_FUNC(cmd_pong
)
1340 if (!strcmp(argv
[2], self
->name
)) {
1341 timeq_del(0, timed_send_ping
, 0, TIMEQ_IGNORE_WHEN
|TIMEQ_IGNORE_DATA
);
1342 timeq_del(0, timed_ping_timeout
, 0, TIMEQ_IGNORE_WHEN
|TIMEQ_IGNORE_DATA
);
1343 timeq_add(now
+ ping_freq
, timed_send_ping
, 0);
1349 static CMD_FUNC(cmd_nick
)
1351 struct userNode
*user
;
1352 if ((user
= GetUserH(origin
))) {
1353 /* nick change (since the source is a user numeric) */
1356 NickChange(user
, argv
[1], 1);
1358 struct server
*serv
;
1359 struct userNode
*nuser
;
1364 serv
= GetServerH(origin
);
1366 unsplit_string(argv
+6, argc
-9, modes
);
1369 nuser
= AddUser(serv
, argv
[1], argv
[4], argv
[5], modes
, argv
[argc
-2], argv
[argc
-1], atoi(argv
[3]), argv
[argc
-3]);
1374 static CMD_FUNC(cmd_account
)
1376 struct userNode
*user
;
1377 struct server
*server
;
1378 struct handle_info
*hi
;
1380 if ((argc
< 3) || !origin
|| !(server
= GetServerH(origin
)))
1381 return 0; /* Origin must be server. */
1383 /* This next line appears to tremple origin.. why? */
1384 user
= GetUserN(argv
[1]);
1386 return 1; /* A QUIT probably passed the ACCOUNT. */
1388 if(!extended_accounts
) /* any need for this function without? */
1391 if(!strcmp(argv
[2],"C"))
1393 if((hi
= loc_auth(argv
[4], argv
[5])))
1396 putsock("%s " P10_ACCOUNT
" %s A %s %lu", self
->numeric
, server
->numeric
, argv
[3], hi
->registered
);
1402 putsock("%s " P10_ACCOUNT
" %s D %s", self
->numeric
, server
->numeric
, argv
[3]);
1406 else if(!strcmp(argv
[2],"R"))
1407 call_account_func(user
, argv
[3]);
1409 call_account_func(user
, argv
[2]); /* For backward compatability */
1413 static CMD_FUNC(cmd_fakehost
)
1415 struct userNode
*user
;
1417 if ((argc
< 3) || !origin
|| !GetServerH(origin
))
1419 if (!(user
= GetUserN(argv
[1])))
1421 assign_fakehost(user
, argv
[2], 0);
1429 #define P(priv) { #priv, PRIV_ ## priv }
1430 P(CHAN_LIMIT
), P(MODE_LCHAN
), P(WALK_LCHAN
), P(DEOP_LCHAN
),
1431 P(SHOW_INVIS
), P(SHOW_ALL_INVIS
), P(UNLIMIT_QUERY
), P(KILL
),
1432 P(LOCAL_KILL
), P(REHASH
), P(RESTART
), P(DIE
),
1433 P(GLINE
), P(LOCAL_GLINE
), P(JUPE
), P(LOCAL_JUPE
),
1434 P(OPMODE
), P(LOCAL_OPMODE
), P(SET
), P(WHOX
),
1435 P(BADCHAN
), P(LOCAL_BADCHAN
), P(SEE_CHAN
), P(PROPAGATE
),
1436 P(DISPLAY
), P(SEE_OPERS
), P(WIDE_GLINE
), P(FORCE_OPMODE
),
1437 P(FORCE_LOCAL_OPMODE
), P(REMOTEREHASH
), P(CHECK
), P(SEE_SECRET_CHAN
),
1438 P(SHUN
), P(LOCAL_SHUN
), P(WIDE_SHUN
),
1443 char *client_report_privs(struct userNode
*client
)
1448 for (i
= 0; privtab
[i
].name
; i
++) {
1449 if (HasPriv(client
, privtab
[i
].priv
)) {
1450 strcat(privbuf
, privtab
[i
].name
);
1451 strcat(privbuf
, " ");
1455 privbuf
[strlen(privbuf
)] = 0;
1460 int client_modify_priv_by_name(struct userNode
*who
, char *priv
, int what
) {
1465 for (i
= 0; privtab
[i
].name
; i
++) {
1466 if (0 == strcmp(privtab
[i
].name
, priv
)) {
1467 if (what
== PRIV_ADD
)
1468 GrantPriv(who
, privtab
[i
].priv
);
1469 else if (what
== PRIV_DEL
) {
1470 RevokePriv(who
, privtab
[i
].priv
);
1477 int check_priv(char *priv
)
1481 for (i
= 0; privtab
[i
].name
; i
++) {
1482 if (0 == strcmp(privtab
[i
].name
, priv
)) {
1490 irc_privs(struct userNode
*target
, char *flag
, int add
)
1492 client_modify_priv_by_name(target
, flag
, add
);
1493 putsock("%s " P10_PRIVS
" %s %s%s", self
->numeric
, target
->numeric
, (add
== PRIV_ADD
) ? "+" : "-", flag
);
1496 static CMD_FUNC(cmd_privs
)
1501 tstr
= conf_get_data("server/type", RECDB_QSTRING
);
1506 return 1; /* silently ignore */
1508 struct userNode
*user
= argc
> 1 ? GetUserN(argv
[1]) : NULL
;
1510 int what
= PRIV_ADD
;
1521 for (i
=1; i
<argc
; i
++) {
1522 strcat(buf
, argv
[i
]);
1526 for (i
= 2; i
< argc
; i
++) {
1527 if (*argv
[i
] == '+') { what
= PRIV_ADD
; argv
[i
]++; }
1528 if (*argv
[i
] == '-') { what
= PRIV_DEL
; argv
[i
]++; }
1529 for (tmp
= x3_strtok(&p
, argv
[i
], ","); tmp
;
1530 tmp
= x3_strtok(&p
, NULL
, ",")) {
1531 client_modify_priv_by_name(user
, tmp
, what
);
1537 static CMD_FUNC(cmd_burst
)
1540 char modes
[MAXLEN
], *members
= "";
1541 static char exemptlist
[MAXLEN
], banlist
[MAXLEN
];
1542 unsigned int next
= 3, res
= 1;
1543 int ctype
= 0, echeck
= 0, bcheck
= 0;
1544 struct chanNode
*cNode
;
1545 struct userNode
*un
;
1546 struct modeNode
*mNode
;
1549 char *user
, *end
, sep
;
1550 time_t in_timestamp
;
1560 while (next
< argc
) {
1561 switch (argv
[next
][0]) {
1565 for (pos
=argv
[next
], n_modes
= 1; *pos
; pos
++)
1566 if ((*pos
== 'k') || (*pos
== 'l') || (*pos
== 'A')
1569 unsplit_string(argv
+next
, n_modes
, modes
);
1574 for(parm
= mysep(&argv
[next
], " "); /* parm = first param */
1575 parm
; /* While param is not null */
1576 parm
= mysep(&argv
[next
], " ") /* parm = next param */
1594 /* strip % char off start of very first ban */
1595 if (strlen(parm
) > 1) {
1596 strncat(banlist
, strtok(parm
, "%"), sizeof(banlist
) - 1 - strlen(banlist
));
1597 strncat(banlist
, " ", sizeof(banlist
) - 1 - strlen(banlist
));
1601 strncat(banlist
, parm
, sizeof(banlist
) - 1 - strlen(banlist
));
1602 strncat(banlist
, " ", sizeof(banlist
) - 1 - strlen(banlist
));
1604 } else if (ctype
== 2) {
1608 strncat(exemptlist
, parm
, sizeof(exemptlist
) - 1 - strlen(exemptlist
));
1609 strncat(exemptlist
, " ", sizeof(exemptlist
) - 1 - strlen(exemptlist
));
1616 default: members
= argv
[next
++]; break;
1620 in_timestamp
= atoi(argv
[2]);
1621 if ((cNode
= dict_find(unbursted_channels
, argv
[1], NULL
))) {
1622 cNode
->timestamp
= in_timestamp
;
1623 dict_remove(unbursted_channels
, cNode
->name
);
1626 cNode
= AddChannel(argv
[1], in_timestamp
, modes
, banlist
, exemptlist
);
1628 /* Burst channel members in now. */
1629 for (user
= members
, sep
= *members
, mode
= 0; sep
; user
= end
) {
1630 for (end
= user
+ 3; isalnum(*end
) || *end
== '[' || *end
== ']'; end
++) ;
1631 sep
= *end
++; end
[-1] = 0;
1634 while ((sep
= *end
++)) {
1636 mode
|= MODE_CHANOP
;
1638 } else if (sep
== 'h') {
1639 mode
|= MODE_HALFOP
;
1641 } else if (sep
== 'v') {
1644 } else if (isdigit(sep
)) {
1645 mode
|= MODE_CHANOP
;
1647 oplevel
+= parse_oplevel(end
);
1649 oplevel
= parse_oplevel(end
);
1650 while (isdigit(*end
)) end
++;
1657 if (!(un
= GetUserN(user
))) {
1661 if ((mNode
= AddChannelUser(un
, cNode
))) {
1662 mNode
->modes
= mode
;
1663 mNode
->oplevel
= oplevel
;
1670 static CMD_FUNC(cmd_mode
)
1672 struct chanNode
*cn
;
1673 struct userNode
*un
;
1674 char *sethost
; // sethost - reed/apples
1675 int i
; // sethost - reed/apples
1679 if (!IsChannelName(argv
[1])) {
1680 un
= GetUserH(argv
[1]);
1682 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find user %s whose mode is changing.", argv
[1]);
1685 // sethost - reed/apples
1687 mod_usermode(un
, argv
[2]);
1689 sethost
= malloc(strlen(argv
[2]) + 1 + strlen(argv
[3]) + 1);
1691 while((sethost
[i
++] = *argv
[2]++));
1694 while((sethost
[i
++] = *argv
[3]++));
1695 mod_usermode(un
, sethost
); // sethost - reed/apples
1701 if (!(cn
= GetChannel(argv
[1]))) {
1702 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing.", argv
[1]);
1705 if ((un
= GetUserH(origin
))) {
1706 struct modeNode
*mn
;
1707 /* Update idle time for person setting the mode */
1708 if ((mn
= GetUserMode(cn
, un
)))
1709 mn
->idle_since
= now
;
1711 /* If it came from a server, reset timestamp to re-sync. */
1712 cn
->timestamp
= atoi(argv
[argc
-1]);
1715 if (checkDefCon(DEFCON_NO_MODE_CHANGE
) && !IsOper(un
)) {
1717 str
= conf_get_data("services/opserv/nick", RECDB_QSTRING
);
1719 char modes
[MODELEN
];
1720 struct userNode
*opserv
= GetUserH(str
);
1722 send_message_type(4, un
, opserv
, "Channel modes cannot be changed due to DefCon level %d in effect, please try again soon", DefConLevel
);
1723 irc_make_chanmode(cn
, modes
);
1724 irc_mode(opserv
, cn
, modes
);
1725 irc_mode(opserv
, cn
, DefConChanModes
);
1731 return mod_chanmode(un
, cn
, argv
+2, argc
-2, MCP_ALLOW_OVB
|MCP_FROM_SERVER
|(un
? MC_NOTIFY
: 0));
1734 static CMD_FUNC(cmd_opmode
)
1736 struct chanNode
*cn
;
1737 struct userNode
*un
;
1742 if (!(cn
= GetChannel(argv
[1]))) {
1743 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing.", argv
[1]);
1746 if (!(un
= GetUserH(origin
))) {
1747 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find user %s requesting OPMODE.", origin
);
1751 log_module(MAIN_LOG
, LOG_ERROR
, "Non-privileged user %s using OPMODE.", un
->nick
);
1755 return mod_chanmode(un
, cn
, argv
+2, argc
-2, MCP_ALLOW_OVB
|MCP_FROM_SERVER
); /* do NOT announce opmode locally */
1758 static int clear_chanmode(struct chanNode
*channel
, const char *modes
);
1760 static CMD_FUNC(cmd_clearmode
)
1762 struct chanNode
*cn
;
1763 struct userNode
*un
;
1768 if (!(cn
= GetChannel(argv
[1]))) {
1769 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing.", argv
[1]);
1772 if (!(un
= GetUserH(origin
))) {
1773 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find user %s requesting CLEARMODE.", origin
);
1777 log_module(MAIN_LOG
, LOG_ERROR
, "Non-privileged user %s using CLEARMODE.", un
->nick
);
1781 return clear_chanmode(cn
, argv
[2]);
1784 static CMD_FUNC(cmd_topic
)
1786 struct chanNode
*cn
;
1787 time_t chan_ts
, topic_ts
;
1788 struct userNode
*user
;
1792 if (!(cn
= GetChannel(argv
[1]))) {
1793 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose topic is being set", argv
[1]);
1798 if (argc
== 5) { /* Asuka / Topic Bursting IRCu's */
1799 user
= GetUserH(origin
);
1800 chan_ts
= atoi(argv
[2]);
1801 topic_ts
= atoi(argv
[3]);
1802 } else if (argc
>= 6) { /* Nefarious 0.5.0 */
1803 user
= GetUserH(strtok(argv
[2], "!"));
1804 chan_ts
= atoi(argv
[3]);
1805 topic_ts
= atoi(argv
[4]);
1806 } else { /* Regular IRCu (No Topic Bursting)*/
1807 user
= GetUserH(origin
);
1808 chan_ts
= cn
->timestamp
;
1812 SetChannelTopic(cn
, user
, user
, argv
[argc
-1], 0);
1813 cn
->topic_time
= topic_ts
;
1817 static CMD_FUNC(cmd_num_topic
)
1819 struct chanNode
*cn
;
1822 return 0; /* huh? */
1824 cn
= GetChannel(argv
[2]);
1826 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s in topic reply", argv
[2]);
1832 switch (atoi(argv
[0])) {
1835 break; /* no topic */
1839 safestrncpy(cn
->topic
, unsplit_string(argv
+3, argc
-3, NULL
), sizeof(cn
->topic
));
1844 safestrncpy(cn
->topic_nick
, argv
[3], sizeof(cn
->topic_nick
));
1845 cn
->topic_time
= atoi(argv
[4]);
1848 return 0; /* should never happen */
1853 static CMD_FUNC(cmd_num_gline
)
1857 gline_add(origin
, argv
[3], atoi(argv
[4])-now
, argv
[5], now
, 0, 0);
1861 static CMD_FUNC(cmd_num_shun
)
1865 shun_add(origin
, argv
[3], atoi(argv
[4])-now
, argv
[5], now
, 0);
1869 static CMD_FUNC(cmd_quit
)
1871 struct userNode
*user
;
1874 /* Sometimes we get a KILL then a QUIT or the like, so we don't want to
1875 * call DelUser unless we have the user in our grasp. */
1876 if ((user
= GetUserH(origin
)))
1877 DelUser(user
, NULL
, false, argv
[1]);
1881 static CMD_FUNC(cmd_kill
)
1883 struct userNode
*user
;
1886 user
= GetUserN(argv
[1]);
1888 /* If we get a KILL for a non-existent user, it could be a
1889 * Ghost response to a KILL we sent out earlier. So we only
1890 * whine if the target is local.
1892 if (!strncmp(argv
[1], self
->numeric
, strlen(self
->numeric
)))
1893 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find kill victim %s", argv
[1]);
1897 if (IsLocal(user
) && IsService(user
)) {
1898 /* TODO: rate limit this so silly things don't happen. */
1899 ReintroduceUser(user
);
1903 DelUser(user
, NULL
, false, argv
[2]);
1907 static CMD_FUNC(cmd_part
)
1909 struct userNode
*user
;
1913 user
= GetUserH(origin
);
1916 parse_foreach(argv
[1], part_helper
, NULL
, NULL
, NULL
, user
);
1920 static CMD_FUNC(cmd_svspart
)
1922 struct userNode
*user
;
1926 user
= GetUserH(argv
[1]);
1929 parse_foreach(argv
[2], part_helper
, NULL
, NULL
, NULL
, user
);
1933 static CMD_FUNC(cmd_silence
)
1935 struct userNode
*user
;
1943 user
= GetUserN(argv
[1]);
1945 /* Sanity, go nuts if this happens */
1949 /* We can safely ignore this if a user adding a silence is not
1950 * ignored. However this brings up a TODO. If a user logs in and
1951 * they have silences on the IRCd then we need to set them here
1954 if (!user
->handle_info
)
1960 for (i
=0; i
<user
->handle_info
->ignores
->used
; i
++) {
1961 if (!irccasecmp(mask
+1, user
->handle_info
->ignores
->list
[i
]))
1962 user
->handle_info
->ignores
->list
[i
] = user
->handle_info
->ignores
->list
[--user
->handle_info
->ignores
->used
];
1965 for (i
=0; i
<user
->handle_info
->ignores
->used
; i
++) {
1966 if (!strcmp(mask
+1, user
->handle_info
->ignores
->list
[i
]))
1967 return 1; /* Already on the users NickServ ignore list, safely ignore */
1970 new_mask
= strdup(mask
+1);
1971 string_list_append(user
->handle_info
->ignores
, new_mask
);
1976 static CMD_FUNC(cmd_kick
)
1980 ChannelUserKicked(GetUserH(origin
), GetUserN(argv
[2]), GetChannel(argv
[1]));
1984 static CMD_FUNC(cmd_squit
)
1986 struct server
*server
;
1991 if (!(server
= GetServerH(argv
[1])))
1994 if (server
== self
->uplink
) {
1995 /* Force a reconnect to the currently selected server. */
1996 cManager
.uplink
->tries
= 0;
1997 log_module(MAIN_LOG
, LOG_INFO
, "Squitting from uplink: %s", argv
[3]);
2002 uplink
= strdup(server
->uplink
->name
);
2003 DelServer(server
, 0, argv
[3]);
2004 /* if its a pingout and pingout connecting is enabled
2005 or its a read error and readerror connecting is enabled
2006 or were doing a "N" and i need to connect that server somewhere */
2007 routing_handle_squit(argv
[1], uplink
, argv
[3]);
2012 static CMD_FUNC(cmd_privmsg
)
2014 struct privmsg_desc pd
;
2017 pd
.user
= GetUserH(origin
);
2018 if (!pd
.user
|| (IsGagged(pd
.user
) && !IsOper(pd
.user
)))
2021 if (checkDefCon(DEFCON_OPER_ONLY
) && !IsOper(pd
.user
)) {
2023 str
= conf_get_data("services/opserv/nick", RECDB_QSTRING
);
2025 send_message_type(4, pd
.user
, GetUserH(str
), "Services are currently not available, please try again soon");
2029 if (checkDefCon(DEFCON_SILENT_OPER_ONLY
) && !IsOper(pd
.user
))
2030 return 1; /* Silently Ignore */
2034 parse_foreach(argv
[1], privmsg_chan_helper
, NULL
, privmsg_user_helper
, privmsg_invalid
, &pd
);
2038 static CMD_FUNC(cmd_notice
)
2040 struct privmsg_desc pd
;
2047 pd
.user
= GetUserH(origin
);
2050 if (!pd
.user
|| (IsGagged(pd
.user
) && !IsOper(pd
.user
))) {
2055 parse_foreach(argv
[1], privmsg_chan_helper
, NULL
, privmsg_user_helper
, privmsg_invalid
, &pd
);
2058 srv
= GetServerH(origin
);
2060 char *sargv
[MAXNUMPARAMS
];
2063 sargc
= split_line(argv
[2], true, MAXNUMPARAMS
, sargv
);
2065 if(!strcasecmp(sargv
[0], "Connect:")) {
2066 /* :Connect: Host shoe.loxxin.net not listed in ircd.conf */
2067 if(!strcasecmp(sargv
[3], "not") && !strcasecmp(sargv
[4], "listed")) {
2068 routing_handle_connect_failure(srv
, sargv
[2], unsplit_string(sargv
+3, sargc
-3, NULL
));
2071 else if(!strcasecmp(sargv
[0], "Link")) {
2072 /* :Link with mephisto.etheria.cx cancelled: Server mephisto.etheria.cx[216.46.33.71]
2074 * :Link with laptop.afternet.org cancelled: Connection refused
2076 if(!strcasecmp(sargv
[3], "cancelled:")) {
2077 routing_handle_connect_failure(srv
, sargv
[2], unsplit_string(sargv
+4, sargc
-4, NULL
));
2084 static CMD_FUNC(cmd_away
)
2086 struct userNode
*uNode
;
2088 uNode
= GetUserH(origin
);
2092 uNode
->modes
&= ~FLAGS_AWAY
;
2094 uNode
->modes
|= FLAGS_AWAY
;
2098 static CMD_FUNC(cmd_gline
)
2102 if (argv
[2][0] == '+') {
2105 gline_add(origin
, argv
[2]+1, strtoul(argv
[3], NULL
, 0), argv
[argc
-1], now
, 0, 0);
2107 } else if (argv
[2][0] == '-') {
2108 gline_remove(argv
[2]+1, 0);
2114 static CMD_FUNC(cmd_shun
)
2118 if (argv
[2][0] == '+') {
2121 shun_add(origin
, argv
[2]+1, strtoul(argv
[3], NULL
, 0), argv
[argc
-1], now
, 0);
2123 } else if (argv
[2][0] == '-') {
2124 shun_remove(argv
[2]+1, 0);
2130 static CMD_FUNC(cmd_svsnick
)
2132 struct userNode
*target
, *dest
;
2134 || !(target
= GetUserN(argv
[1]))
2136 || (dest
= GetUserH(argv
[2])))
2138 NickChange(target
, argv
[2], 0);
2142 static oper_func_t
*of_list
;
2143 static unsigned int of_size
= 0, of_used
= 0;
2146 free_user(struct userNode
*user
)
2157 free(privmsg_funcs
);
2160 dict_delete(irc_func_dict
);
2161 for (nn
=0; nn
<dead_users
.used
; nn
++)
2162 free_user(dead_users
.list
[nn
]);
2163 userList_clean(&dead_users
);
2167 p10_conf_reload(void) {
2168 hidden_host_suffix
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
2172 remove_unbursted_channel(struct chanNode
*cNode
) {
2173 if (unbursted_channels
)
2174 dict_remove(unbursted_channels
, cNode
->name
);
2180 const char *str
, *desc
;
2181 int numnick
, usermask
, max_users
;
2182 char numer
[COMBO_NUMERIC_LEN
+1];
2184 /* read config items */
2185 str
= conf_get_data("server/extended_accounts", RECDB_QSTRING
);
2186 extended_accounts
= str
? enabled_string(str
) : 1;
2187 str
= conf_get_data("server/ping_freq", RECDB_QSTRING
);
2188 ping_freq
= str
? ParseInterval(str
) : 120;
2189 str
= conf_get_data("server/ping_timeout", RECDB_QSTRING
);
2190 ping_timeout
= str
? ParseInterval(str
) : 30;
2191 str
= conf_get_data("server/force_n2k", RECDB_QSTRING
);
2192 force_n2k
= str
? enabled_string(str
) : 1;
2193 str
= conf_get_data("server/numeric", RECDB_QSTRING
);
2195 log_module(MAIN_LOG
, LOG_ERROR
, "No server/numeric entry in config file.");
2198 numnick
= atoi(str
);
2199 str
= conf_get_data("server/max_users", RECDB_QSTRING
);
2200 max_users
= str
? atoi(str
) : 4096;
2201 for (usermask
= 4; usermask
< max_users
; usermask
<<= 1) ;
2203 if ((numnick
< 64) && (usermask
< 4096) && !force_n2k
)
2204 inttobase64(numer
, (numnick
<< 12) + (usermask
& 0x00fff), 3);
2206 inttobase64(numer
, (numnick
<< 18) + (usermask
& 0x3ffff), 5);
2208 str
= conf_get_data("server/his_servername", RECDB_QSTRING
);
2209 his_servername
= str
? strdup(str
) : NULL
;
2210 str
= conf_get_data("server/his_servercomment", RECDB_QSTRING
);
2211 his_servercomment
= str
? strdup(str
) : NULL
;
2213 str
= conf_get_data("server/hostname", RECDB_QSTRING
);
2214 desc
= conf_get_data("server/description", RECDB_QSTRING
);
2215 if (!str
|| !desc
) {
2216 log_module(MAIN_LOG
, LOG_ERROR
, "No server/hostname entry in config file.");
2219 self
= AddServer(NULL
, str
, 0, boot_time
, now
, numer
, desc
);
2220 conf_register_reload(p10_conf_reload
);
2222 irc_func_dict
= dict_new();
2223 dict_insert(irc_func_dict
, CMD_BURST
, cmd_burst
);
2224 dict_insert(irc_func_dict
, TOK_BURST
, cmd_burst
);
2225 dict_insert(irc_func_dict
, CMD_CREATE
, cmd_create
);
2226 dict_insert(irc_func_dict
, TOK_CREATE
, cmd_create
);
2227 dict_insert(irc_func_dict
, CMD_EOB
, cmd_eob
);
2228 dict_insert(irc_func_dict
, TOK_EOB
, cmd_eob
);
2229 dict_insert(irc_func_dict
, CMD_EOB_ACK
, cmd_eob_ack
);
2230 dict_insert(irc_func_dict
, TOK_EOB_ACK
, cmd_eob_ack
);
2231 dict_insert(irc_func_dict
, CMD_MODE
, cmd_mode
);
2232 dict_insert(irc_func_dict
, TOK_MODE
, cmd_mode
);
2233 dict_insert(irc_func_dict
, CMD_NICK
, cmd_nick
);
2234 dict_insert(irc_func_dict
, TOK_NICK
, cmd_nick
);
2235 dict_insert(irc_func_dict
, CMD_ACCOUNT
, cmd_account
);
2236 dict_insert(irc_func_dict
, TOK_ACCOUNT
, cmd_account
);
2237 dict_insert(irc_func_dict
, CMD_FAKEHOST
, cmd_fakehost
);
2238 dict_insert(irc_func_dict
, TOK_FAKEHOST
, cmd_fakehost
);
2239 dict_insert(irc_func_dict
, CMD_PASS
, cmd_pass
);
2240 dict_insert(irc_func_dict
, TOK_PASS
, cmd_pass
);
2241 dict_insert(irc_func_dict
, CMD_PING
, cmd_ping
);
2242 dict_insert(irc_func_dict
, TOK_PING
, cmd_ping
);
2243 dict_insert(irc_func_dict
, CMD_PRIVMSG
, cmd_privmsg
);
2244 dict_insert(irc_func_dict
, TOK_PRIVMSG
, cmd_privmsg
);
2245 dict_insert(irc_func_dict
, CMD_PONG
, cmd_pong
);
2246 dict_insert(irc_func_dict
, TOK_PONG
, cmd_pong
);
2247 dict_insert(irc_func_dict
, CMD_QUIT
, cmd_quit
);
2248 dict_insert(irc_func_dict
, TOK_QUIT
, cmd_quit
);
2249 dict_insert(irc_func_dict
, CMD_SERVER
, cmd_server
);
2250 dict_insert(irc_func_dict
, TOK_SERVER
, cmd_server
);
2251 dict_insert(irc_func_dict
, CMD_JOIN
, cmd_join
);
2252 dict_insert(irc_func_dict
, TOK_JOIN
, cmd_join
);
2253 dict_insert(irc_func_dict
, CMD_PART
, cmd_part
);
2254 dict_insert(irc_func_dict
, TOK_PART
, cmd_part
);
2255 dict_insert(irc_func_dict
, CMD_ERROR
, cmd_error
);
2256 dict_insert(irc_func_dict
, TOK_ERROR
, cmd_error
);
2257 dict_insert(irc_func_dict
, CMD_TOPIC
, cmd_topic
);
2258 dict_insert(irc_func_dict
, TOK_TOPIC
, cmd_topic
);
2259 dict_insert(irc_func_dict
, CMD_AWAY
, cmd_away
);
2260 dict_insert(irc_func_dict
, TOK_AWAY
, cmd_away
);
2261 dict_insert(irc_func_dict
, CMD_SILENCE
, cmd_silence
);
2262 dict_insert(irc_func_dict
, TOK_SILENCE
, cmd_silence
);
2263 dict_insert(irc_func_dict
, CMD_KICK
, cmd_kick
);
2264 dict_insert(irc_func_dict
, TOK_KICK
, cmd_kick
);
2265 dict_insert(irc_func_dict
, CMD_SQUIT
, cmd_squit
);
2266 dict_insert(irc_func_dict
, TOK_SQUIT
, cmd_squit
);
2267 dict_insert(irc_func_dict
, CMD_KILL
, cmd_kill
);
2268 dict_insert(irc_func_dict
, TOK_KILL
, cmd_kill
);
2269 dict_insert(irc_func_dict
, CMD_NOTICE
, cmd_notice
);
2270 dict_insert(irc_func_dict
, TOK_NOTICE
, cmd_notice
);
2271 dict_insert(irc_func_dict
, CMD_STATS
, cmd_stats
);
2272 dict_insert(irc_func_dict
, TOK_STATS
, cmd_stats
);
2273 dict_insert(irc_func_dict
, CMD_SVSJOIN
, cmd_svsjoin
);
2274 dict_insert(irc_func_dict
, TOK_SVSJOIN
, cmd_svsjoin
);
2275 dict_insert(irc_func_dict
, CMD_SVSNICK
, cmd_svsnick
);
2276 dict_insert(irc_func_dict
, TOK_SVSNICK
, cmd_svsnick
);
2277 dict_insert(irc_func_dict
, CMD_SVSPART
, cmd_svspart
);
2278 dict_insert(irc_func_dict
, TOK_SVSPART
, cmd_svspart
);
2279 dict_insert(irc_func_dict
, CMD_SWHOIS
, cmd_dummy
);
2280 dict_insert(irc_func_dict
, TOK_SWHOIS
, cmd_dummy
);
2281 dict_insert(irc_func_dict
, CMD_WHOIS
, cmd_whois
);
2282 dict_insert(irc_func_dict
, TOK_WHOIS
, cmd_whois
);
2283 dict_insert(irc_func_dict
, CMD_GLINE
, cmd_gline
);
2284 dict_insert(irc_func_dict
, TOK_GLINE
, cmd_gline
);
2285 dict_insert(irc_func_dict
, CMD_SHUN
, cmd_shun
);
2286 dict_insert(irc_func_dict
, TOK_SHUN
, cmd_shun
);
2287 dict_insert(irc_func_dict
, CMD_OPMODE
, cmd_opmode
);
2288 dict_insert(irc_func_dict
, TOK_OPMODE
, cmd_opmode
);
2289 dict_insert(irc_func_dict
, CMD_CLEARMODE
, cmd_clearmode
);
2290 dict_insert(irc_func_dict
, TOK_CLEARMODE
, cmd_clearmode
);
2291 dict_insert(irc_func_dict
, CMD_VERSION
, cmd_version
);
2292 dict_insert(irc_func_dict
, TOK_VERSION
, cmd_version
);
2293 dict_insert(irc_func_dict
, CMD_ADMIN
, cmd_admin
);
2294 dict_insert(irc_func_dict
, TOK_ADMIN
, cmd_admin
);
2296 /* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
2297 * Apparently to obliterate channels from any servers that think they
2300 dict_insert(irc_func_dict
, CMD_DESTRUCT
, cmd_dummy
);
2301 dict_insert(irc_func_dict
, TOK_DESTRUCT
, cmd_dummy
);
2302 /* Ignore invites */
2303 dict_insert(irc_func_dict
, CMD_INVITE
, cmd_dummy
);
2304 dict_insert(irc_func_dict
, TOK_INVITE
, cmd_dummy
);
2305 /* DESYNCH is just informational, so ignore it */
2306 dict_insert(irc_func_dict
, CMD_DESYNCH
, cmd_dummy
);
2307 dict_insert(irc_func_dict
, TOK_DESYNCH
, cmd_dummy
);
2308 /* Ignore channel operator notices. */
2309 dict_insert(irc_func_dict
, CMD_WALLCHOPS
, cmd_dummy
);
2310 dict_insert(irc_func_dict
, TOK_WALLCHOPS
, cmd_dummy
);
2311 dict_insert(irc_func_dict
, CMD_WALLVOICES
, cmd_dummy
);
2312 dict_insert(irc_func_dict
, TOK_WALLVOICES
, cmd_dummy
);
2313 dict_insert(irc_func_dict
, CMD_WALLHOPS
, cmd_dummy
);
2314 dict_insert(irc_func_dict
, TOK_WALLHOPS
, cmd_dummy
);
2315 /* Ignore opers being silly. */
2316 dict_insert(irc_func_dict
, CMD_WALLOPS
, cmd_dummy
);
2317 dict_insert(irc_func_dict
, TOK_WALLOPS
, cmd_dummy
);
2318 dict_insert(irc_func_dict
, CMD_WALLHOPS
, cmd_dummy
);
2319 dict_insert(irc_func_dict
, TOK_WALLHOPS
, cmd_dummy
);
2320 dict_insert(irc_func_dict
, TOK_WALLUSERS
, cmd_dummy
);
2321 /* Ignore dnsbl exemptions */
2322 dict_insert(irc_func_dict
, TOK_EXEMPT
, cmd_dummy
);
2323 dict_insert(irc_func_dict
, TOK_MARK
, cmd_dummy
);
2324 dict_insert(irc_func_dict
, CMD_PRIVS
, cmd_privs
);
2325 dict_insert(irc_func_dict
, TOK_PRIVS
, cmd_privs
);
2326 /* Ignore remote luser */
2327 dict_insert(irc_func_dict
, TOK_LUSERS
, cmd_dummy
);
2328 /* We have reliable clock! Always! Wraaa! */
2329 dict_insert(irc_func_dict
, CMD_SETTIME
, cmd_dummy
);
2330 dict_insert(irc_func_dict
, TOK_SETTIME
, cmd_dummy
);
2332 /* ignore /trace and /motd commands targetted at us */
2333 dict_insert(irc_func_dict
, TOK_TRACE
, cmd_dummy
);
2334 dict_insert(irc_func_dict
, TOK_MOTD
, cmd_dummy
);
2337 dict_insert(irc_func_dict
, "331", cmd_num_topic
);
2338 dict_insert(irc_func_dict
, "332", cmd_num_topic
);
2339 dict_insert(irc_func_dict
, "333", cmd_num_topic
);
2340 dict_insert(irc_func_dict
, "345", cmd_dummy
); /* blah has been invited to blah */
2341 dict_insert(irc_func_dict
, "432", cmd_error_nick
); /* Erroneus [sic] nickname */
2342 /* ban list resetting */
2343 /* "stats g" responses */
2344 dict_insert(irc_func_dict
, "247", cmd_num_gline
);
2345 dict_insert(irc_func_dict
, "542", cmd_num_shun
);
2346 dict_insert(irc_func_dict
, "219", cmd_dummy
); /* "End of /STATS report" */
2347 /* other numeric responses we might get */
2348 dict_insert(irc_func_dict
, "401", cmd_dummy
); /* target left network */
2349 dict_insert(irc_func_dict
, "403", cmd_dummy
); /* no such channel */
2350 dict_insert(irc_func_dict
, "404", cmd_dummy
); /* cannot send to channel */
2351 dict_insert(irc_func_dict
, "439", cmd_dummy
); /* target change too fast */
2352 dict_insert(irc_func_dict
, "441", cmd_dummy
); /* target isn't on that channel */
2353 dict_insert(irc_func_dict
, "442", cmd_dummy
); /* you aren't on that channel */
2354 dict_insert(irc_func_dict
, "443", cmd_dummy
); /* is already on channel (after invite?) */
2355 dict_insert(irc_func_dict
, "461", cmd_dummy
); /* Not enough parameters (after TOPIC w/ 0 args) */
2356 dict_insert(irc_func_dict
, "467", cmd_dummy
); /* Channel key already set */
2358 num_privmsg_funcs
= 16;
2359 privmsg_funcs
= malloc(sizeof(privmsg_func_t
)*num_privmsg_funcs
);
2360 memset(privmsg_funcs
, 0, sizeof(privmsg_func_t
)*num_privmsg_funcs
);
2362 num_notice_funcs
= 16;
2363 notice_funcs
= malloc(sizeof(privmsg_func_t
)*num_notice_funcs
);
2364 memset(notice_funcs
, 0, sizeof(privmsg_func_t
)*num_notice_funcs
);
2366 userList_init(&dead_users
);
2367 reg_del_channel_func(remove_unbursted_channel
);
2368 reg_exit_func(parse_cleanup
);
2372 parse_line(char *line
, int recursive
)
2374 char *argv
[MAXNUMPARAMS
], *origin
;
2375 int argc
, cmd
, res
=0;
2378 argc
= split_line(line
, true, MAXNUMPARAMS
, argv
);
2379 cmd
= self
->uplink
|| !argv
[0][1] || !argv
[0][2];
2382 if (argv
[0][0] == ':') {
2384 } else if (!argv
[0][1] || !argv
[0][2]) {
2385 struct server
*sNode
= GetServerN(argv
[0]);
2386 origin
= sNode
? sNode
->name
: 0;
2388 struct userNode
*uNode
= GetUserN(argv
[0]);
2389 origin
= uNode
? uNode
->nick
: 0;
2393 if ((func
= dict_find(irc_func_dict
, argv
[cmd
], NULL
)))
2394 res
= func(origin
, argc
-cmd
, argv
+cmd
);
2397 log_module(MAIN_LOG
, LOG_ERROR
, "PARSE ERROR on line: %s", unsplit_string(argv
, argc
, NULL
));
2398 } else if (!recursive
) {
2400 for (i
=0; i
<dead_users
.used
; i
++)
2401 free_user(dead_users
.list
[i
]);
2402 dead_users
.used
= 0;
2408 parse_foreach(char *target_list
, foreach_chanfunc cf
, foreach_nonchan nc
, foreach_userfunc uf
, foreach_nonuser nu
, void *data
)
2414 while (*j
!= 0 && *j
!= ',')
2419 if (IsChannelName(target_list
)
2420 || (target_list
[0] == '0' && target_list
[1] == '\0')) {
2421 struct chanNode
*chan
= GetChannel(target_list
);
2428 nc(target_list
, data
);
2431 struct userNode
*user
;
2432 struct privmsg_desc
*pd
= data
;
2434 pd
->is_qualified
= 0;
2435 if (*target_list
== '@') {
2437 } else if (strchr(target_list
, '@')) {
2438 struct server
*server
;
2440 pd
->is_qualified
= 1;
2441 user
= GetUserH(strtok(target_list
, "@"));
2442 server
= GetServerH(strtok(NULL
, "@"));
2444 if (user
&& (user
->uplink
!= server
)) {
2445 /* Don't attempt to index into any arrays
2446 using a user's numeric on another server. */
2450 user
= GetUserN(target_list
);
2458 nu(target_list
, data
);
2462 } while (old
== ',');
2466 get_local_numeric(void)
2468 static unsigned int next_numeric
= 0;
2469 if (self
->clients
> self
->num_mask
)
2471 while (self
->users
[next_numeric
])
2472 if (++next_numeric
> self
->num_mask
)
2474 return next_numeric
;
2478 make_numeric(struct server
*svr
, int local_num
, char *outbuf
)
2482 if (force_n2k
|| svr
->numeric
[1]) {
2487 llen
= (local_num
< 64*64) ? 2 : 3;
2489 strncpy(outbuf
, svr
->numeric
, slen
);
2490 inttobase64(outbuf
+slen
, local_num
, llen
);
2491 outbuf
[slen
+llen
] = 0;
2495 AddServer(struct server
*uplink
, const char *name
, int hops
, time_t boot
, time_t link
, const char *numeric
, const char *description
)
2497 struct server
* sNode
;
2500 if ((sNode
= GetServerN(numeric
))) {
2501 /* This means we're trying to re-add an existant server.
2502 * To be safe, we should forget the previous incarnation.
2503 * (And all its linked servers.)
2505 * It usually only happens in replays when the original
2506 * had a ping timeout and the replay didn't (because
2507 * replaying a ping timeout invariably gets things wrong).
2509 DelServer(sNode
, 0, NULL
);
2512 switch (strlen(numeric
)) {
2513 case 5: slen
= 2; mlen
= 3; break;
2514 case 4: slen
= 1; mlen
= 3; break;
2515 case 3: slen
= 1; mlen
= 2; break;
2517 log_module(MAIN_LOG
, LOG_ERROR
, "AddServer(\"%s\", \"%s\", ...): Numeric %s has invalid length.", uplink
->name
, name
, numeric
);
2521 sNode
= calloc(1, sizeof(*sNode
));
2522 sNode
->uplink
= uplink
;
2523 safestrncpy(sNode
->name
, name
, sizeof(sNode
->name
));
2524 sNode
->num_mask
= base64toint(numeric
+slen
, mlen
);
2528 strncpy(sNode
->numeric
, numeric
, slen
);
2529 safestrncpy(sNode
->description
, description
, sizeof(sNode
->description
));
2530 sNode
->users
= calloc(sNode
->num_mask
+1, sizeof(*sNode
->users
));
2531 serverList_init(&sNode
->children
);
2532 if (sNode
->uplink
) {
2533 /* uplink may be NULL if we're just building ourself */
2534 serverList_append(&sNode
->uplink
->children
, sNode
);
2536 servers_num
[base64toint(numeric
, slen
)] = sNode
;
2537 dict_insert(servers
, sNode
->name
, sNode
);
2541 void DelServer(struct server
* serv
, int announce
, const char *message
)
2545 /* If we receive an ERROR command before the SERVER
2546 * command a NULL server can be passed */
2550 /* Hrm, what's the right way to SQUIT some other server?
2551 * (This code is only to handle killing juped servers.) */
2552 if (announce
&& (serv
->uplink
== self
) && (serv
!= self
->uplink
))
2553 irc_squit(serv
, message
, NULL
);
2555 /* must recursively remove servers linked to this one first */
2556 for (i
=serv
->children
.used
;i
>0;)
2557 if (serv
->children
.list
[--i
] != self
)
2558 DelServer(serv
->children
.list
[i
], false, NULL
);
2560 /* clean up server's user hash tables */
2561 for (i
=0;i
<=serv
->num_mask
;i
++)
2563 DelUser(serv
->users
[i
], NULL
, false, "server delinked");
2567 serverList_remove(&serv
->uplink
->children
, serv
);
2568 if (serv
== self
->uplink
)
2569 self
->uplink
= NULL
;
2570 servers_num
[base64toint(serv
->numeric
, strlen(serv
->numeric
))] = NULL
;
2571 dict_remove(servers
, serv
->name
);
2572 serverList_clean(&serv
->children
);
2578 AddService(const char *nick
, const char *modes
, const char *desc
, const char *hostname
)
2580 char numeric
[COMBO_NUMERIC_LEN
+1];
2581 int local_num
= get_local_numeric();
2582 time_t timestamp
= now
;
2583 struct userNode
*old_user
= GetUserH(nick
);
2586 if (IsLocal(old_user
))
2588 timestamp
= old_user
->timestamp
- 1;
2590 if (local_num
== -1) {
2591 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to allocate numnick for service %s", nick
);
2595 hostname
= self
->name
;
2596 make_numeric(self
, local_num
, numeric
);
2597 /* TODO: Make these modes part of the conf file */
2598 return AddUser(self
, nick
, nick
, hostname
, modes
? modes
: "+oik", numeric
, desc
, now
, "AAAAAA");
2602 AddClone(const char *nick
, const char *ident
, const char *hostname
, const char *desc
)
2604 char numeric
[COMBO_NUMERIC_LEN
+1];
2605 int local_num
= get_local_numeric();
2606 time_t timestamp
= now
;
2607 struct userNode
*old_user
= GetUserH(nick
);
2610 if (IsLocal(old_user
))
2612 timestamp
= old_user
->timestamp
- 1;
2614 if (local_num
== -1) {
2615 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to allocate numnick for clone %s", nick
);
2618 make_numeric(self
, local_num
, numeric
);
2619 return AddUser(self
, nick
, ident
, hostname
, "+i", numeric
, desc
, timestamp
, "AAAAAA");
2623 is_valid_nick(const char *nick
) {
2625 /* IRC has some of The Most Fucked-Up ideas about character sets
2627 if (!isalpha(*nick
) && !strchr("{|}~[\\]^_`", *nick
))
2629 for (ii
= 0; nick
[ii
]; ++ii
)
2630 if (!isalnum(nick
[ii
]) && !strchr("{|}~[\\]^-_`", nick
[ii
]))
2632 if (strlen(nick
) > nicklen
)
2637 static struct userNode
*
2638 AddUser(struct server
* uplink
, const char *nick
, const char *ident
, const char *hostname
, const char *modes
, const char *numeric
, const char *userinfo
, time_t timestamp
, const char *realip
)
2640 struct userNode
*oldUser
, *uNode
;
2641 unsigned int n
, ignore_user
;
2643 if ((strlen(numeric
) < 3) || (strlen(numeric
) > 5)) {
2644 log_module(MAIN_LOG
, LOG_WARNING
, "AddUser(%p, %s, ...): numeric %s wrong length!", uplink
, nick
, numeric
);
2649 log_module(MAIN_LOG
, LOG_WARNING
, "AddUser(%p, %s, ...): server for numeric %s doesn't exist!", uplink
, nick
, numeric
);
2653 if (uplink
!= GetServerN(numeric
)) {
2654 log_module(MAIN_LOG
, LOG_WARNING
, "AddUser(%p, %s, ...): server for numeric %s differs from nominal uplink %s.", uplink
, nick
, numeric
, uplink
->name
);
2658 if (!is_valid_nick(nick
)) {
2659 log_module(MAIN_LOG
, LOG_WARNING
, "AddUser(%p, %s, ...): invalid nickname detected.", uplink
, nick
);
2664 if ((oldUser
= GetUserH(nick
))) {
2665 if (IsLocal(oldUser
) && (IsService(oldUser
) || IsPersistent(oldUser
))) {
2666 /* The service should collide the new user off. */
2667 oldUser
->timestamp
= timestamp
- 1;
2670 if (oldUser
->timestamp
> timestamp
) {
2671 /* "Old" user is really newer; remove them */
2672 DelUser(oldUser
, 0, 1, "Overruled by older nick");
2674 /* User being added is too new; do not add them to
2675 * clients, but do add them to the server's list, since it
2676 * will send a KILL and QUIT soon. */
2681 /* create new usernode and set all values */
2682 uNode
= calloc(1, sizeof(*uNode
));
2683 uNode
->nick
= strdup(nick
);
2684 safestrncpy(uNode
->ident
, ident
, sizeof(uNode
->ident
));
2685 safestrncpy(uNode
->info
, userinfo
, sizeof(uNode
->info
));
2686 safestrncpy(uNode
->hostname
, hostname
, sizeof(uNode
->hostname
));
2687 safestrncpy(uNode
->numeric
, numeric
, sizeof(uNode
->numeric
));
2688 irc_p10_pton(&uNode
->ip
, realip
);
2690 if (irc_in_addr_is_ipv4(uNode
->ip
)) {
2691 make_virtip((char*)irc_ntoa(&uNode
->ip
), (char*)irc_ntoa(&uNode
->ip
), uNode
->cryptip
);
2692 make_virthost((char*)irc_ntoa(&uNode
->ip
), uNode
->hostname
, uNode
->crypthost
);
2693 } else if (irc_in_addr_is_ipv6(uNode
->ip
)) {
2694 make_ipv6virthost((char*)irc_ntoa(&uNode
->ip
), uNode
->hostname
, uNode
->crypthost
);
2697 if (!uNode
->crypthost
&& uNode
->cryptip
)
2698 snprintf(uNode
->crypthost
, sizeof(uNode
->crypthost
), "%s", strdup(uNode
->cryptip
));
2700 uNode
->timestamp
= timestamp
;
2701 modeList_init(&uNode
->channels
);
2702 uNode
->uplink
= uplink
;
2703 if (++uNode
->uplink
->clients
> uNode
->uplink
->max_clients
) {
2704 uNode
->uplink
->max_clients
= uNode
->uplink
->clients
;
2706 uNode
->num_local
= base64toint(numeric
+strlen(uNode
->uplink
->numeric
), 3) & uNode
->uplink
->num_mask
;
2707 uNode
->uplink
->users
[uNode
->num_local
] = uNode
;
2708 mod_usermode(uNode
, modes
);
2710 set_geoip_info(uNode
);
2715 dict_insert(clients
, uNode
->nick
, uNode
);
2716 if (dict_size(clients
) > max_clients
) {
2717 max_clients
= dict_size(clients
);
2718 max_clients_time
= now
;
2722 for (n
=0; n
<nuf_used
; n
++)
2723 if (nuf_list
[n
](uNode
))
2726 if ((uNode
->loc
== 1) && (uNode
->handle_info
))
2727 send_func_list(uNode
);
2732 /* removes user from it's server's hash table and nick hash table */
2734 DelUser(struct userNode
* user
, struct userNode
*killer
, int announce
, const char *why
)
2740 /* mark them as dead, in case anybody cares */
2743 /* remove pending adduser commands */
2744 wipe_adduser_pending(NULL
, user
);
2746 /* remove user from all channels */
2747 while (user
->channels
.used
> 0)
2748 DelChannelUser(user
, user
->channels
.list
[user
->channels
.used
-1]->channel
, false, 0);
2750 /* Call these in reverse order so ChanServ can update presence
2751 information before NickServ nukes the handle_info. */
2752 for (n
= duf_used
; n
> 0; )
2753 duf_list
[--n
](user
, killer
, why
);
2755 user
->uplink
->clients
--;
2756 user
->uplink
->users
[user
->num_local
] = NULL
;
2758 userList_remove(&curr_opers
, user
);
2759 /* remove from global dictionary, but not if after a collide */
2760 if (user
== dict_find(clients
, user
->nick
, NULL
))
2761 dict_remove(clients
, user
->nick
);
2763 if (IsInvisible(user
))
2768 irc_quit(user
, why
);
2770 irc_kill(killer
, user
, why
);
2773 modeList_clean(&user
->channels
);
2775 /* Clean up version data */
2776 if(user
->version_reply
) {
2777 free(user
->version_reply
);
2778 user
->version_reply
= NULL
;
2781 /* clean up geoip data if any */
2782 if(user
->country_code
) free(user
->country_code
);
2783 if(user
->city
) free(user
->city
);
2784 if(user
->region
) free(user
->region
);
2785 if(user
->postal_code
) free(user
->postal_code
);
2787 /* We don't free them, in case we try to privmsg them or something
2788 * (like when a stupid oper kills themself). We just put them onto
2789 * a list of clients that get freed after processing each line.
2791 if (dead_users
.size
)
2792 userList_append(&dead_users
, user
);
2797 static void call_oper_funcs(struct userNode
*user
);
2799 void mod_usermode(struct userNode
*user
, const char *mode_change
) {
2801 const char *word
= mode_change
;
2803 if (!user
|| !mode_change
)
2806 call_user_mode_funcs(user
, mode_change
);
2808 while (*word
!= ' ' && *word
) word
++;
2809 while (*word
== ' ') word
++;
2811 #define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
2812 switch (*mode_change
++) {
2813 case 0: case ' ': return;
2814 case '+': add
= 1; break;
2815 case '-': add
= 0; break;
2818 if(!IsOper(user
)) { /* Dont re-oper an oper */
2819 userList_append(&curr_opers
, user
);
2820 call_oper_funcs(user
);
2823 userList_remove(&curr_opers
, user
);
2825 do_user_mode(FLAGS_OPER
);
2827 case 'O': do_user_mode(FLAGS_LOCOP
); break;
2828 case 'i': do_user_mode(FLAGS_INVISIBLE
);
2834 case 'w': do_user_mode(FLAGS_WALLOP
); break;
2835 case 's': do_user_mode(FLAGS_SERVNOTICE
); break;
2836 case 'd': do_user_mode(FLAGS_DEAF
); break;
2837 case 'k': do_user_mode(FLAGS_SERVICE
); break;
2838 case 'g': do_user_mode(FLAGS_GLOBAL
); break;
2839 // sethost - reed/apples
2840 // case 'h': do_user_mode(FLAGS_HELPER); break;
2841 // I check if there's an 'h' in the first part, and if there,
2842 // then everything after the space becomes their new host.
2843 case 'h': do_user_mode(FLAGS_SETHOST
);
2845 char sethost
[MAXLEN
];
2847 for (ii
=0; (*word
!= ' ') && (*word
!= '\0'); )
2848 sethost
[ii
++] = *word
++;
2850 while (*word
== ' ')
2852 safestrncpy(user
->sethost
, sethost
, sizeof(user
->sethost
));
2855 case 'x': do_user_mode(FLAGS_HIDDEN_HOST
); break;
2860 for (ii
=0; (*word
!= ' ') && (*word
!= '\0'); )
2861 tag
[ii
++] = *word
++;
2863 while (*word
== ' ')
2865 call_account_func(user
, tag
);
2872 for (ii
=0; (*word
!= ' ') && (*word
!= '\0'); )
2873 host
[ii
++] = *word
++;
2875 while (*word
== ' ')
2877 assign_fakehost(user
, host
, 0);
2885 struct mod_chanmode
*
2886 mod_chanmode_parse(struct chanNode
*channel
, char **modes
, unsigned int argc
, unsigned int flags
, short base_oplevel
)
2888 struct mod_chanmode
*change
;
2889 unsigned int ii
, in_arg
, ch_arg
, add
;
2893 if (!(change
= mod_chanmode_alloc(argc
- 1)))
2896 for (ii
= ch_arg
= 0, in_arg
= add
= 1;
2897 (modes
[0][ii
] != '\0') && (modes
[0][ii
] != ' ');
2899 switch (modes
[0][ii
]) {
2906 #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)
2907 case 'C': do_chan_mode(MODE_NOCTCPS
); break;
2908 case 'D': do_chan_mode(MODE_DELAYJOINS
); break;
2909 case 'c': do_chan_mode(MODE_NOCOLORS
); break;
2910 case 'i': do_chan_mode(MODE_INVITEONLY
); break;
2911 case 'm': do_chan_mode(MODE_MODERATED
); break;
2912 case 'n': do_chan_mode(MODE_NOPRIVMSGS
); break;
2913 case 'p': do_chan_mode(MODE_PRIVATE
); break;
2914 case 'r': do_chan_mode(MODE_REGONLY
); break;
2915 case 's': do_chan_mode(MODE_SECRET
); break;
2916 case 't': do_chan_mode(MODE_TOPICLIMIT
); break;
2917 case 'S': do_chan_mode(MODE_STRIPCOLOR
); break;
2918 case 'M': do_chan_mode(MODE_MODUNREG
); break;
2919 case 'N': do_chan_mode(MODE_NONOTICE
); break;
2920 case 'Q': do_chan_mode(MODE_NOQUITMSGS
); break;
2921 case 'T': do_chan_mode(MODE_NOAMSG
); break;
2922 case 'O': do_chan_mode(MODE_OPERSONLY
); break;
2923 case 'Z': do_chan_mode(MODE_SSLONLY
); break;
2924 case 'L': do_chan_mode(MODE_HIDEMODE
); break;
2926 if (!(flags
& MCP_REGISTERED
)) {
2927 do_chan_mode(MODE_REGISTERED
);
2929 mod_chanmode_free(change
);
2938 change
->modes_set
|= MODE_LIMIT
;
2939 change
->new_limit
= atoi(modes
[in_arg
++]);
2941 change
->modes_set
&= ~MODE_LIMIT
;
2942 change
->modes_clear
|= MODE_LIMIT
;
2949 change
->modes_set
|= MODE_KEY
;
2950 safestrncpy(change
->new_key
, modes
[in_arg
++], sizeof(change
->new_key
));
2952 change
->modes_clear
|= MODE_KEY
;
2953 if (!(flags
& MCP_KEY_FREE
)) {
2965 change
->modes_set
|= MODE_UPASS
;
2966 safestrncpy(change
->new_upass
, modes
[in_arg
++], sizeof(change
->new_upass
));
2968 change
->modes_clear
|= MODE_UPASS
;
2969 if (!(flags
& MCP_UPASS_FREE
)) {
2980 change
->modes_set
|= MODE_APASS
;
2981 safestrncpy(change
->new_apass
, modes
[in_arg
++], sizeof(change
->new_apass
));
2983 change
->modes_clear
|= MODE_APASS
;
2984 if (!(flags
& MCP_APASS_FREE
)) {
2992 if (!(flags
& MCP_ALLOW_OVB
))
2996 change
->args
[ch_arg
].mode
= MODE_BAN
;
2998 change
->args
[ch_arg
].mode
|= MODE_REMOVE
;
2999 change
->args
[ch_arg
++].u
.hostmask
= modes
[in_arg
++];
3002 if (!(flags
& MCP_ALLOW_OVB
))
3006 change
->args
[ch_arg
].mode
= MODE_EXEMPT
;
3008 change
->args
[ch_arg
].mode
|= MODE_REMOVE
;
3009 change
->args
[ch_arg
++].u
.hostmask
= modes
[in_arg
++];
3011 case 'o': case 'h': case 'v':
3013 struct userNode
*victim
;
3019 oplevel_str
= strchr(modes
[in_arg
], ':');
3022 /* XXYYY M #channel +o XXYYY:<oplevel> */
3023 *oplevel_str
++ = '\0';
3024 oplevel
= parse_oplevel(oplevel_str
);
3025 if (oplevel
<= base_oplevel
&& !(flags
& MCP_FROM_SERVER
))
3026 oplevel
= base_oplevel
+ 1;
3028 else if (channel
->modes
& MODE_UPASS
)
3029 oplevel
= base_oplevel
+ 1;
3033 /* Check that oplevel is within bounds. */
3034 if (oplevel
> MAXOPLEVEL
)
3035 oplevel
= MAXOPLEVEL
;
3037 if (!(flags
& MCP_ALLOW_OVB
))
3042 if (modes
[0][ii
] == 'o')
3043 change
->args
[ch_arg
].mode
= MODE_CHANOP
;
3044 else if (modes
[0][ii
] == 'h')
3045 change
->args
[ch_arg
].mode
= MODE_HALFOP
;
3046 else if (modes
[0][ii
] == 'v')
3047 change
->args
[ch_arg
].mode
= MODE_VOICE
;
3050 change
->args
[ch_arg
].mode
|= MODE_REMOVE
;
3051 if (flags
& MCP_FROM_SERVER
)
3052 victim
= GetUserN(modes
[in_arg
++]);
3054 victim
= GetUserH(modes
[in_arg
++]);
3057 if ((change
->args
[ch_arg
].u
.member
= GetUserMode(channel
, victim
)))
3059 /* Apply the oplevel change */
3060 change
->args
[ch_arg
].u
.member
->oplevel
= oplevel
;
3066 if (!(flags
& MCP_FROM_SERVER
))
3071 change
->argc
= ch_arg
; /* in case any turned out to be ignored */
3072 if (change
->modes_set
& MODE_SECRET
) {
3073 change
->modes_set
&= ~(MODE_PRIVATE
);
3074 change
->modes_clear
|= MODE_PRIVATE
;
3075 } else if (change
->modes_set
& MODE_PRIVATE
) {
3076 change
->modes_set
&= ~(MODE_SECRET
);
3077 change
->modes_clear
|= MODE_SECRET
;
3081 mod_chanmode_free(change
);
3085 struct chanmode_buffer
{
3088 struct chanNode
*channel
;
3089 struct userNode
*actor
;
3090 unsigned int modes_used
;
3091 unsigned int args_used
;
3093 unsigned int is_add
: 1;
3094 unsigned int is_chanop
: 1;
3098 mod_chanmode_append(struct chanmode_buffer
*buf
, char ch
, const char *arg
)
3100 size_t arg_len
= strlen(arg
);
3101 if (buf
->modes_used
> (MAXMODEPARAMS
) ||
3102 buf
->modes_used
+ buf
->args_used
+ buf
->chname_len
+ arg_len
> 450) {
3103 memcpy(buf
->modes
+ buf
->modes_used
, buf
->args
, buf
->args_used
);
3104 buf
->modes
[buf
->modes_used
+ buf
->args_used
] = '\0';
3105 irc_mode((buf
->is_chanop
? buf
->actor
: NULL
), buf
->channel
, buf
->modes
);
3106 buf
->modes
[0] = buf
->is_add
? '+' : '-';
3107 buf
->modes_used
= 1;
3110 buf
->modes
[buf
->modes_used
++] = ch
;
3111 buf
->args
[buf
->args_used
++] = ' ';
3112 memcpy(buf
->args
+ buf
->args_used
, arg
, arg_len
);
3113 buf
->args_used
+= arg_len
;
3117 mod_chanmode_announce(struct userNode
*who
, struct chanNode
*channel
, struct mod_chanmode
*change
)
3119 struct chanmode_buffer chbuf
;
3121 struct modeNode
*mn
;
3122 char int_buff
[32], mode
= '\0';
3124 assert(change
->argc
<= change
->alloc_argc
);
3125 memset(&chbuf
, 0, sizeof(chbuf
));
3126 chbuf
.channel
= channel
;
3128 chbuf
.chname_len
= strlen(channel
->name
);
3130 mn
= GetUserMode(channel
, who
);
3131 if ((mn
&& (mn
->modes
& MODE_CHANOP
)) || off_channel
)
3132 chbuf
.is_chanop
= 1;
3134 /* First remove modes */
3136 if (change
->modes_clear
) {
3138 chbuf
.modes
[chbuf
.modes_used
++] = mode
= '-';
3139 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) chbuf.modes[chbuf.modes_used++] = CHAR
3140 DO_MODE_CHAR(PRIVATE
, 'p');
3141 DO_MODE_CHAR(SECRET
, 's');
3142 DO_MODE_CHAR(MODERATED
, 'm');
3143 DO_MODE_CHAR(TOPICLIMIT
, 't');
3144 DO_MODE_CHAR(INVITEONLY
, 'i');
3145 DO_MODE_CHAR(NOPRIVMSGS
, 'n');
3146 DO_MODE_CHAR(LIMIT
, 'l');
3147 DO_MODE_CHAR(DELAYJOINS
, 'D');
3148 DO_MODE_CHAR(REGONLY
, 'r');
3149 DO_MODE_CHAR(NOCOLORS
, 'c');
3150 DO_MODE_CHAR(NOCTCPS
, 'C');
3151 DO_MODE_CHAR(STRIPCOLOR
, 'S');
3152 DO_MODE_CHAR(MODUNREG
, 'M');
3153 DO_MODE_CHAR(NONOTICE
, 'N');
3154 DO_MODE_CHAR(NOQUITMSGS
, 'Q');
3155 DO_MODE_CHAR(NOAMSG
, 'T');
3156 DO_MODE_CHAR(OPERSONLY
, 'O');
3157 DO_MODE_CHAR(REGISTERED
, 'z');
3158 DO_MODE_CHAR(SSLONLY
, 'Z');
3159 DO_MODE_CHAR(HIDEMODE
, 'L');
3161 if (change
->modes_clear
& channel
->modes
& MODE_KEY
)
3162 mod_chanmode_append(&chbuf
, 'k', channel
->key
);
3163 if (change
->modes_clear
& channel
->modes
& MODE_UPASS
)
3164 mod_chanmode_append(&chbuf
, 'U', channel
->upass
);
3165 if (change
->modes_clear
* channel
->modes
& MODE_APASS
)
3166 mod_chanmode_append(&chbuf
, 'A', channel
->apass
);
3168 for (arg
= 0; arg
< change
->argc
; ++arg
) {
3169 if (!(change
->args
[arg
].mode
& MODE_REMOVE
))
3172 chbuf
.modes
[chbuf
.modes_used
++] = mode
= '-';
3173 switch (change
->args
[arg
].mode
& ~MODE_REMOVE
) {
3175 mod_chanmode_append(&chbuf
, 'b', change
->args
[arg
].u
.hostmask
);
3178 mod_chanmode_append(&chbuf
, 'e', change
->args
[arg
].u
.hostmask
);
3181 if (change
->args
[arg
].mode
& MODE_CHANOP
)
3182 mod_chanmode_append(&chbuf
, 'o', change
->args
[arg
].u
.member
->user
->numeric
);
3183 if (change
->args
[arg
].mode
& MODE_HALFOP
)
3184 mod_chanmode_append(&chbuf
, 'h', change
->args
[arg
].u
.member
->user
->numeric
);
3185 if (change
->args
[arg
].mode
& MODE_VOICE
)
3186 mod_chanmode_append(&chbuf
, 'v', change
->args
[arg
].u
.member
->user
->numeric
);
3193 if (change
->modes_set
) {
3195 chbuf
.modes
[chbuf
.modes_used
++] = mode
= '+';
3196 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_set & MODE_##BIT) chbuf.modes[chbuf.modes_used++] = CHAR
3197 DO_MODE_CHAR(PRIVATE
, 'p');
3198 DO_MODE_CHAR(SECRET
, 's');
3199 DO_MODE_CHAR(MODERATED
, 'm');
3200 DO_MODE_CHAR(TOPICLIMIT
, 't');
3201 DO_MODE_CHAR(INVITEONLY
, 'i');
3202 DO_MODE_CHAR(NOPRIVMSGS
, 'n');
3203 DO_MODE_CHAR(DELAYJOINS
, 'D');
3204 DO_MODE_CHAR(REGONLY
, 'r');
3205 DO_MODE_CHAR(NOCOLORS
, 'c');
3206 DO_MODE_CHAR(NOCTCPS
, 'C');
3207 DO_MODE_CHAR(STRIPCOLOR
, 'S');
3208 DO_MODE_CHAR(MODUNREG
, 'M');
3209 DO_MODE_CHAR(NONOTICE
, 'N');
3210 DO_MODE_CHAR(NOQUITMSGS
, 'Q');
3211 DO_MODE_CHAR(NOAMSG
, 'T');
3212 DO_MODE_CHAR(OPERSONLY
, 'O');
3213 DO_MODE_CHAR(REGISTERED
, 'z');
3214 DO_MODE_CHAR(SSLONLY
, 'Z');
3215 DO_MODE_CHAR(HIDEMODE
, 'L');
3217 if(change
->modes_set
& MODE_KEY
)
3218 mod_chanmode_append(&chbuf
, 'k', change
->new_key
);
3219 if (change
->modes_set
& MODE_UPASS
)
3220 mod_chanmode_append(&chbuf
, 'U', change
->new_upass
);
3221 if (change
->modes_set
& MODE_APASS
)
3222 mod_chanmode_append(&chbuf
, 'A', change
->new_apass
);
3223 if(change
->modes_set
& MODE_LIMIT
) {
3224 sprintf(int_buff
, "%d", change
->new_limit
);
3225 mod_chanmode_append(&chbuf
, 'l', int_buff
);
3228 for (arg
= 0; arg
< change
->argc
; ++arg
) {
3229 if (change
->args
[arg
].mode
& MODE_REMOVE
)
3232 chbuf
.modes
[chbuf
.modes_used
++] = mode
= '+';
3233 switch (change
->args
[arg
].mode
) {
3235 mod_chanmode_append(&chbuf
, 'b', change
->args
[arg
].u
.hostmask
);
3238 mod_chanmode_append(&chbuf
, 'e', change
->args
[arg
].u
.hostmask
);
3241 if (change
->args
[arg
].mode
& MODE_CHANOP
)
3242 mod_chanmode_append(&chbuf
, 'o', change
->args
[arg
].u
.member
->user
->numeric
);
3243 if (change
->args
[arg
].mode
& MODE_HALFOP
)
3244 mod_chanmode_append(&chbuf
, 'h', change
->args
[arg
].u
.member
->user
->numeric
);
3245 if (change
->args
[arg
].mode
& MODE_VOICE
)
3246 mod_chanmode_append(&chbuf
, 'v', change
->args
[arg
].u
.member
->user
->numeric
);
3251 /* Flush the buffer and apply changes locally */
3252 if (chbuf
.modes_used
> 0) {
3253 memcpy(chbuf
.modes
+ chbuf
.modes_used
, chbuf
.args
, chbuf
.args_used
);
3254 chbuf
.modes
[chbuf
.modes_used
+ chbuf
.args_used
] = '\0';
3255 irc_mode((chbuf
.is_chanop
? chbuf
.actor
: NULL
), chbuf
.channel
, chbuf
.modes
);
3257 mod_chanmode_apply(who
, channel
, change
);
3261 mod_chanmode_format(struct mod_chanmode
*change
, char *outbuff
)
3263 unsigned int used
= 0;
3264 assert(change
->argc
<= change
->alloc_argc
);
3265 if (change
->modes_clear
) {
3266 outbuff
[used
++] = '-';
3267 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) outbuff[used++] = CHAR
3268 DO_MODE_CHAR(PRIVATE
, 'p');
3269 DO_MODE_CHAR(SECRET
, 's');
3270 DO_MODE_CHAR(MODERATED
, 'm');
3271 DO_MODE_CHAR(TOPICLIMIT
, 't');
3272 DO_MODE_CHAR(INVITEONLY
, 'i');
3273 DO_MODE_CHAR(NOPRIVMSGS
, 'n');
3274 DO_MODE_CHAR(LIMIT
, 'l');
3275 DO_MODE_CHAR(KEY
, 'k');
3276 DO_MODE_CHAR(UPASS
, 'U');
3277 DO_MODE_CHAR(APASS
, 'A');
3278 DO_MODE_CHAR(DELAYJOINS
, 'D');
3279 DO_MODE_CHAR(REGONLY
, 'r');
3280 DO_MODE_CHAR(NOCOLORS
, 'c');
3281 DO_MODE_CHAR(NOCTCPS
, 'C');
3282 DO_MODE_CHAR(STRIPCOLOR
, 'S');
3283 DO_MODE_CHAR(MODUNREG
, 'M');
3284 DO_MODE_CHAR(NONOTICE
, 'N');
3285 DO_MODE_CHAR(NOQUITMSGS
, 'Q');
3286 DO_MODE_CHAR(NOAMSG
, 'T');
3287 DO_MODE_CHAR(OPERSONLY
, 'O');
3288 DO_MODE_CHAR(REGISTERED
, 'z');
3289 DO_MODE_CHAR(SSLONLY
, 'Z');
3290 DO_MODE_CHAR(HIDEMODE
, 'L');
3293 if (change
->modes_set
) {
3294 outbuff
[used
++] = '+';
3295 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_set & MODE_##BIT) outbuff[used++] = CHAR
3296 DO_MODE_CHAR(PRIVATE
, 'p');
3297 DO_MODE_CHAR(SECRET
, 's');
3298 DO_MODE_CHAR(MODERATED
, 'm');
3299 DO_MODE_CHAR(TOPICLIMIT
, 't');
3300 DO_MODE_CHAR(INVITEONLY
, 'i');
3301 DO_MODE_CHAR(NOPRIVMSGS
, 'n');
3302 DO_MODE_CHAR(DELAYJOINS
, 'D');
3303 DO_MODE_CHAR(REGONLY
, 'r');
3304 DO_MODE_CHAR(NOCOLORS
, 'c');
3305 DO_MODE_CHAR(NOCTCPS
, 'C');
3306 DO_MODE_CHAR(STRIPCOLOR
, 'S');
3307 DO_MODE_CHAR(MODUNREG
, 'M');
3308 DO_MODE_CHAR(NONOTICE
, 'N');
3309 DO_MODE_CHAR(NOQUITMSGS
, 'Q');
3310 DO_MODE_CHAR(NOAMSG
, 'T');
3311 DO_MODE_CHAR(OPERSONLY
, 'O');
3312 DO_MODE_CHAR(REGISTERED
, 'z');
3313 DO_MODE_CHAR(SSLONLY
, 'Z');
3314 DO_MODE_CHAR(HIDEMODE
, 'L');
3316 switch (change
->modes_set
& (MODE_KEY
|MODE_LIMIT
|MODE_APASS
|MODE_UPASS
)) {
3317 /* Doing this implementation has been a pain in the arse, I hope I didn't forget a possible combination */
3318 case MODE_KEY
|MODE_LIMIT
|MODE_APASS
|MODE_UPASS
:
3319 used
+= sprintf(outbuff
+used
, "lkAU %d %s %s %s", change
->new_limit
, change
->new_key
,change
->new_apass
, change
->new_upass
);
3322 case MODE_KEY
|MODE_LIMIT
|MODE_APASS
:
3323 used
+= sprintf(outbuff
+used
, "lkA %d %s %s", change
->new_limit
, change
->new_key
, change
->new_apass
);
3325 case MODE_KEY
|MODE_LIMIT
|MODE_UPASS
:
3326 used
+= sprintf(outbuff
+used
, "lkU %d %s %s", change
->new_limit
, change
->new_key
, change
->new_upass
);
3328 case MODE_KEY
|MODE_APASS
|MODE_UPASS
:
3329 used
+= sprintf(outbuff
+used
, "kAU %s %s %s", change
->new_key
, change
->new_apass
, change
->new_upass
);
3332 case MODE_KEY
|MODE_APASS
:
3333 used
+= sprintf(outbuff
+used
, "kA %s %s", change
->new_key
, change
->new_apass
);
3335 case MODE_KEY
|MODE_UPASS
:
3336 used
+= sprintf(outbuff
+used
, "kU %s %s", change
->new_key
, change
->new_upass
);
3338 case MODE_KEY
|MODE_LIMIT
:
3339 used
+= sprintf(outbuff
+used
, "lk %d %s", change
->new_limit
, change
->new_key
);
3342 case MODE_LIMIT
|MODE_UPASS
:
3343 used
+= sprintf(outbuff
+used
, "lU %d %s", change
->new_limit
, change
->new_upass
);
3345 case MODE_LIMIT
|MODE_APASS
:
3346 used
+= sprintf(outbuff
+used
, "lA %d %s", change
->new_limit
, change
->new_apass
);
3348 case MODE_APASS
|MODE_UPASS
:
3349 used
+= sprintf(outbuff
+used
, "AU %s %s", change
->new_apass
, change
->new_upass
);
3351 case MODE_LIMIT
|MODE_APASS
|MODE_UPASS
:
3352 used
+= sprintf(outbuff
+used
, "lAU %d %s %s", change
->new_limit
, change
->new_apass
, change
->new_upass
);
3356 used
+= sprintf(outbuff
+used
, "A %s", change
->new_apass
);
3359 used
+= sprintf(outbuff
+used
, "U %s", change
->new_upass
);
3362 used
+= sprintf(outbuff
+used
, "k %s", change
->new_key
);
3365 used
+= sprintf(outbuff
+used
, "l %d", change
->new_limit
);
3374 clear_chanmode(struct chanNode
*channel
, const char *modes
)
3376 unsigned int remove
;
3378 for (remove
= 0; *modes
; modes
++) {
3380 case 'o': remove
|= MODE_CHANOP
; break;
3381 case 'h': remove
|= MODE_HALFOP
; break;
3382 case 'v': remove
|= MODE_VOICE
; break;
3383 case 'p': remove
|= MODE_PRIVATE
; break;
3384 case 's': remove
|= MODE_SECRET
; break;
3385 case 'm': remove
|= MODE_MODERATED
; break;
3386 case 't': remove
|= MODE_TOPICLIMIT
; break;
3387 case 'i': remove
|= MODE_INVITEONLY
; break;
3388 case 'n': remove
|= MODE_NOPRIVMSGS
; break;
3391 channel
->key
[0] = '\0';
3394 remove
|= MODE_APASS
;
3395 channel
->apass
[0] = '\0';
3398 remove
|= MODE_UPASS
;
3399 channel
->upass
[0] = '\0';
3402 remove
|= MODE_LIMIT
;
3405 case 'b': remove
|= MODE_BAN
; break;
3406 case 'e': remove
|= MODE_EXEMPT
; break;
3407 case 'D': remove
|= MODE_DELAYJOINS
; break;
3408 case 'r': remove
|= MODE_REGONLY
; break;
3409 case 'c': remove
|= MODE_NOCOLORS
; break;
3410 case 'C': remove
|= MODE_NOCTCPS
; break;
3411 case 'S': remove
|= MODE_STRIPCOLOR
; break;
3412 case 'M': remove
|= MODE_MODUNREG
; break;
3413 case 'N': remove
|= MODE_NONOTICE
; break;
3414 case 'Q': remove
|= MODE_NOQUITMSGS
; break;
3415 case 'T': remove
|= MODE_NOAMSG
; break;
3416 case 'O': remove
|= MODE_OPERSONLY
; break;
3417 case 'z': remove
|= MODE_REGISTERED
; break;
3418 case 'Z': remove
|= MODE_SSLONLY
; break;
3419 case 'L': remove
|= MODE_HIDEMODE
; break;
3426 /* Remove simple modes. */
3427 channel
->modes
&= ~remove
;
3429 /* If removing bans, kill 'em all. */
3430 if ((remove
& MODE_BAN
) && channel
->banlist
.used
) {
3432 for (i
=0; i
<channel
->banlist
.used
; i
++)
3433 free(channel
->banlist
.list
[i
]);
3434 channel
->banlist
.used
= 0;
3437 /* If removing exempts, kill 'em all. */
3438 if ((remove
& MODE_EXEMPT
) && channel
->exemptlist
.used
) {
3440 for (i
=0; i
<channel
->exemptlist
.used
; i
++)
3441 free(channel
->exemptlist
.list
[i
]);
3442 channel
->exemptlist
.used
= 0;
3445 /* Remove member modes. */
3446 if ((remove
& (MODE_CHANOP
| MODE_HALFOP
| MODE_VOICE
)) && channel
->members
.used
) {
3447 int mask
= ~(remove
& (MODE_CHANOP
| MODE_HALFOP
| MODE_VOICE
));
3450 for (i
= 0; i
< channel
->members
.used
; i
++)
3451 channel
->members
.list
[i
]->modes
&= mask
;
3458 reg_privmsg_func(struct userNode
*user
, privmsg_func_t handler
)
3460 unsigned int numeric
= user
->num_local
;
3461 if (numeric
>= num_privmsg_funcs
) {
3462 int newnum
= numeric
+ 8;
3463 privmsg_funcs
= realloc(privmsg_funcs
, newnum
*sizeof(privmsg_func_t
));
3464 memset(privmsg_funcs
+num_privmsg_funcs
, 0, (newnum
-num_privmsg_funcs
)*sizeof(privmsg_func_t
));
3465 num_privmsg_funcs
= newnum
;
3467 if (privmsg_funcs
[numeric
])
3468 log_module(MAIN_LOG
, LOG_WARNING
, "re-registering new privmsg handler for numeric %d", numeric
);
3469 privmsg_funcs
[numeric
] = handler
;
3473 unreg_privmsg_func(struct userNode
*user
, privmsg_func_t handler
)
3477 if (!user
|| handler
)
3478 return; /* this really only works with users */
3480 memset(privmsg_funcs
+user
->num_local
, 0, sizeof(privmsg_func_t
));
3482 for (x
= user
->num_local
+1; x
< num_privmsg_funcs
; x
++)
3483 memmove(privmsg_funcs
+x
-1, privmsg_funcs
+x
, sizeof(privmsg_func_t
));
3485 privmsg_funcs
= realloc(privmsg_funcs
, num_privmsg_funcs
*sizeof(privmsg_func_t
));
3486 num_privmsg_funcs
--;
3491 reg_notice_func(struct userNode
*user
, privmsg_func_t handler
)
3493 unsigned int numeric
= user
->num_local
;
3494 if (numeric
>= num_notice_funcs
) {
3495 int newnum
= numeric
+ 8;
3496 notice_funcs
= realloc(notice_funcs
, newnum
*sizeof(privmsg_func_t
));
3497 memset(notice_funcs
+num_notice_funcs
, 0, (newnum
-num_notice_funcs
)*sizeof(privmsg_func_t
));
3498 num_notice_funcs
= newnum
;
3500 if (notice_funcs
[numeric
])
3501 log_module(MAIN_LOG
, LOG_WARNING
, "re-registering new notice handler for numeric %d", numeric
);
3502 notice_funcs
[numeric
] = handler
;
3506 unreg_notice_func(struct userNode
*user
, privmsg_func_t handler
)
3510 if (!user
|| handler
)
3511 return; /* this really only works with users */
3513 memset(notice_funcs
+user
->num_local
, 0, sizeof(privmsg_func_t
));
3515 for (x
= user
->num_local
+1; x
< num_notice_funcs
; x
++)
3516 memmove(notice_funcs
+x
-1, notice_funcs
+x
, sizeof(privmsg_func_t
));
3518 memset(notice_funcs
+user
->num_local
, 0, sizeof(privmsg_func_t
));
3519 notice_funcs
= realloc(notice_funcs
, num_notice_funcs
*sizeof(privmsg_func_t
));
3524 reg_oper_func(oper_func_t handler
)
3526 if (of_used
== of_size
) {
3529 of_list
= realloc(of_list
, of_size
*sizeof(oper_func_t
));
3532 of_list
= malloc(of_size
*sizeof(oper_func_t
));
3535 of_list
[of_used
++] = handler
;
3539 call_oper_funcs(struct userNode
*user
)
3544 for (n
=0; n
<of_used
; n
++)
3551 unsigned int i
, hop
, max_hop
=1;
3554 /* burst (juped) servers, closest first (except self, which is sent already) */
3555 for (i
=0; i
<ArrayLength(servers_num
); i
++)
3556 if (servers_num
[i
] && servers_num
[i
]->hops
> max_hop
)
3557 max_hop
= servers_num
[i
]->hops
;
3558 for (hop
=1; hop
<=max_hop
; hop
++) {
3559 for (i
=0;i
<ArrayLength(servers_num
);i
++) {
3561 && (servers_num
[i
]->hops
== hop
)
3562 && (servers_num
[i
] != self
->uplink
))
3563 irc_server(servers_num
[i
]);
3567 /* burst local nicks */
3568 for (i
=0; i
<=self
->num_mask
; i
++)
3570 irc_user(self
->users
[i
]);
3572 /* build dict of unbursted channel names (just copy existing channels) */
3573 unbursted_channels
= dict_new();
3574 for (it
= dict_first(channels
); it
; it
= iter_next(it
))
3575 dict_insert(unbursted_channels
, iter_key(it
), iter_data(it
));
3582 parse_oplevel(char *str
)
3585 while (isdigit(*str
))
3586 oplevel
= oplevel
* 10 + *str
++ - '0';