]>
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 3 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_ALIST "ALIST"
33 #define CMD_ASLL "ASLL"
34 #define CMD_AWAY "AWAY"
35 #define CMD_BURST "BURST"
36 #define CMD_CLEARMODE "CLEARMODE"
37 #define CMD_CLOSE "CLOSE"
38 #define CMD_CNOTICE "CNOTICE"
39 #define CMD_CONNECT "CONNECT"
40 #define CMD_CPRIVMSG "CPRIVMSG"
41 #define CMD_CREATE "CREATE"
42 #define CMD_DESTRUCT "DESTRUCT"
43 #define CMD_DESYNCH "DESYNCH"
46 #define CMD_EOB "END_OF_BURST"
47 #define CMD_EOB_ACK "EOB_ACK"
48 #define CMD_ERROR "ERROR"
49 #define CMD_FAKEHOST "FAKE"
51 #define CMD_GLINE "GLINE"
52 #define CMD_HASH "HASH"
53 #define CMD_HELP "HELP"
54 #define CMD_INFO "INFO"
55 #define CMD_INVITE "INVITE"
56 #define CMD_ISON "ISON"
57 #define CMD_JOIN "JOIN"
58 #define CMD_JUPE "JUPE"
59 #define CMD_KICK "KICK"
60 #define CMD_KILL "KILL"
61 #define CMD_LINKS "LINKS"
62 #define CMD_LIST "LIST"
63 #define CMD_LUSERS "LUSERS"
65 #define CMD_MARK "MARK"
66 #define CMD_MODE "MODE"
67 #define CMD_MOTD "MOTD"
68 #define CMD_NAMES "NAMES"
69 #define CMD_NICK "NICK"
70 #define CMD_NOTICE "NOTICE"
71 #define CMD_OPER "OPER"
72 #define CMD_OPMODE "OPMODE"
73 #define CMD_PART "PART"
74 #define CMD_PASS "PASS"
75 #define CMD_PING "PING"
76 #define CMD_PONG "PONG"
77 #define CMD_POST "POST"
78 #define CMD_PRIVMSG "PRIVMSG"
79 #define CMD_PRIVS "PRIVS"
80 #define CMD_PROTO "PROTO"
81 #define CMD_QUIT "QUIT"
82 #define CMD_REHASH "REHASH"
83 #define CMD_REMOVE "REMOVE"
84 #define CMD_RESET "RESET"
85 #define CMD_RESTART "RESTART"
86 #define CMD_RPING "RPING"
87 #define CMD_RPONG "RPONG"
88 #define CMD_SASL "SASL"
89 #define CMD_SERVER "SERVER"
90 #define CMD_SERVLIST "SERVLIST"
91 #define CMD_SERVSET "SERVSET"
93 #define CMD_SETTIME "SETTIME"
94 #define CMD_SGLINE "SGLINE"
95 #define CMD_SHUN "SHUN"
96 #define CMD_SILENCE "SILENCE"
99 #define CMD_SSHUN "SSHUN"
100 #define CMD_SPAMFILTER "SPAMFILTER"
101 #define CMD_SQUERY "SQUERY"
102 #define CMD_SQUIT "SQUIT"
103 #define CMD_STATS "STATS"
104 #define CMD_SVSJOIN "SVSJOIN"
105 #define CMD_SVSNICK "SVSNICK"
106 #define CMD_SVSPART "SVSPART"
107 #define CMD_SVSQUIT "SVSQUIT"
108 #define CMD_SWHOIS "SWHOIS"
109 #define CMD_TEMPSHUN "TEMPSHUN"
110 #define CMD_TIME "TIME"
111 #define CMD_TOPIC "TOPIC"
112 #define CMD_TRACE "TRACE"
113 #define CMD_UPING "UPING"
114 #define CMD_USER "USER"
115 #define CMD_USERHOST "USERHOST"
116 #define CMD_USERIP "USERIP"
117 #define CMD_VERSION "VERSION"
118 #define CMD_WALLCHOPS "WALLCHOPS"
119 #define CMD_WALLOPS "WALLOPS"
120 #define CMD_WALLHOPS "WALLHOPS"
121 #define CMD_WALLUSERS "WALLUSERS"
122 #define CMD_WALLVOICES "WALLVOICES"
123 #define CMD_WALLHOPS "WALLHOPS"
124 #define CMD_WHO "WHO"
125 #define CMD_WHOIS "WHOIS"
126 #define CMD_WHOWAS "WHOWAS"
127 #define CMD_ZLINE "ZLINE"
129 /* Tokenized commands. */
130 #define TOK_ACCOUNT "AC"
131 #define TOK_ADMIN "AD"
132 #define TOK_ALIST "AL"
133 #define TOK_ASLL "LL"
135 #define TOK_BURST "B"
136 #define TOK_CLEARMODE "CM"
137 #define TOK_CLOSE "CLOSE"
138 #define TOK_CNOTICE "CN"
139 #define TOK_CONNECT "CO"
140 #define TOK_CPRIVMSG "CP"
141 #define TOK_CREATE "C"
142 #define TOK_DESTRUCT "DE"
143 #define TOK_DESYNCH "DS"
144 #define TOK_DIE "DIE"
145 #define TOK_DNS "DNS"
147 #define TOK_EOB_ACK "EA"
148 #define TOK_ERROR "Y"
149 #define TOK_EXEMPT "EX"
150 #define TOK_FAKEHOST "FA"
151 #define TOK_GET "GET"
152 #define TOK_GLINE "GL"
153 #define TOK_HASH "HASH"
154 #define TOK_HELP "HELP"
156 #define TOK_INVITE "I"
157 #define TOK_ISON "ISON"
159 #define TOK_JUPE "JU"
162 #define TOK_LINKS "LI"
163 #define TOK_LIST "LIST"
164 #define TOK_LUSERS "LU"
165 #define TOK_MAP "MAP"
166 #define TOK_MARK "MK"
168 #define TOK_MOTD "MO"
169 #define TOK_NAMES "E"
171 #define TOK_NOTICE "O"
172 #define TOK_OPER "OPER"
173 #define TOK_OPMODE "OM"
175 #define TOK_PASS "PA"
178 #define TOK_POST "POST"
179 #define TOK_PRIVMSG "P"
180 #define TOK_PRIVS "PRIVS"
181 #define TOK_PROTO "PROTO"
183 #define TOK_REHASH "REHASH"
184 #define TOK_REMOVE "RM"
185 #define TOK_RESET "RESET"
186 #define TOK_RESTART "RESTART"
187 #define TOK_RPING "RI"
188 #define TOK_RPONG "RO"
189 #define TOK_SASL "SASL"
190 #define TOK_SERVER "S"
191 #define TOK_SERVLIST "SERVSET"
192 #define TOK_SERVSET "SERVSET"
193 #define TOK_SET "SET"
194 #define TOK_SETTIME "SE"
195 #define TOK_SGLINE "SGL"
196 #define TOK_SHUN "SU"
197 #define TOK_SILENCE "U"
198 #define TOK_SMO "SMO"
199 #define TOK_SNO "SNO"
200 #define TOK_SSHUN "SSU"
201 #define TOK_SPAMFILTER "SF"
202 #define TOK_SQUERY "SQUERY"
203 #define TOK_SQUIT "SQ"
204 #define TOK_STATS "R"
205 #define TOK_SVSJOIN "SJ"
206 #define TOK_SVSNICK "SN"
207 #define TOK_SVSPART "SP"
208 #define TOK_SVSQUIT "SX"
209 #define TOK_SWHOIS "SW"
210 #define TOK_TEMPSHUN "TS"
211 #define TOK_TIME "TI"
212 #define TOK_TOPIC "T"
213 #define TOK_TRACE "TR"
214 #define TOK_UPING "UP"
215 #define TOK_USER "USER"
216 #define TOK_USERHOST "USERHOST"
217 #define TOK_USERIP "USERIP"
218 #define TOK_VERSION "V"
219 #define TOK_WALLCHOPS "WC"
220 #define TOK_WALLOPS "WA"
221 #define TOK_WALLHOPS "WH"
222 #define TOK_WALLUSERS "WU"
223 #define TOK_WALLVOICES "WV"
224 #define TOK_WALLHOPS "WH"
226 #define TOK_WHOIS "W"
227 #define TOK_WHOWAS "X"
228 #define TOK_ZLINE "ZL"
230 /* Protocol messages; aliased to full commands or tokens depending
231 on compile-time configuration. ircu prefers tokens WITH THE
232 EXCEPTION OF THE SERVER AND PASS COMMANDS, which cannot be
233 tokenized, because clients' (ie. a linking server) commands are
234 only checked against the full command list.
236 #if defined(ENABLE_TOKENS)
237 #define TYPE(NAME) TOK_ ## NAME
238 #else /* !ENABLE_TOKENS */
239 #define TYPE(NAME) CMD_ ## NAME
240 #endif /* ENABLE_TOKENS */
242 #define P10_ACCOUNT TYPE(ACCOUNT)
243 #define P10_ADMIN TYPE(ADMIN)
244 #define P10_ASLL TYPE(ASLL)
245 #define P10_AWAY TYPE(AWAY)
246 #define P10_BURST TYPE(BURST)
247 #define P10_CLEARMODE TYPE(CLEARMODE)
248 #define P10_CLOSE TYPE(CLOSE)
249 #define P10_CNOTICE TYPE(CNOTICE)
250 #define P10_CONNECT TYPE(CONNECT)
251 #define P10_CPRIVMSG TYPE(CPRIVMSG)
252 #define P10_CREATE TYPE(CREATE)
253 #define P10_DESTRUCT TYPE(DESTRUCT)
254 #define P10_DESYNCH TYPE(DESYNCH)
255 #define P10_DIE TYPE(DIE)
256 #define P10_DNS TYPE(DNS)
257 #define P10_EOB TYPE(EOB)
258 #define P10_EOB_ACK TYPE(EOB_ACK)
259 #define P10_ERROR TYPE(ERROR)
260 #define P10_FAKEHOST TYPE(FAKEHOST)
261 #define P10_GET TYPE(GET)
262 #define P10_GLINE TYPE(GLINE)
263 #define P10_HASH TYPE(HASH)
264 #define P10_HELP TYPE(HELP)
265 #define P10_INFO TYPE(INFO)
266 #define P10_INVITE TYPE(INVITE)
267 #define P10_ISON TYPE(ISON)
268 #define P10_JOIN TYPE(JOIN)
269 #define P10_JUPE TYPE(JUPE)
270 #define P10_KICK TYPE(KICK)
271 #define P10_KILL TYPE(KILL)
272 #define P10_LINKS TYPE(LINKS)
273 #define P10_LIST TYPE(LIST)
274 #define P10_LUSERS TYPE(LUSERS)
275 #define P10_MAP TYPE(MAP)
276 #define P10_MARK TYPE(MARK)
277 #define P10_MODE TYPE(MODE)
278 #define P10_MOTD TYPE(MOTD)
279 #define P10_NAMES TYPE(NAMES)
280 #define P10_NICK TYPE(NICK)
281 #define P10_NOTICE TYPE(NOTICE)
282 #define P10_OPER TYPE(OPER)
283 #define P10_OPMODE TYPE(OPMODE)
284 #define P10_PART TYPE(PART)
285 #define P10_PASS CMD_PASS
286 #define P10_PING TYPE(PING)
287 #define P10_PONG TYPE(PONG)
288 #define P10_POST TYPE(POST)
289 #define P10_PRIVMSG TYPE(PRIVMSG)
290 #define P10_PRIVS TYPE(PRIVS)
291 #define P10_PROTO TYPE(PROTO)
292 #define P10_QUIT TYPE(QUIT)
293 #define P10_REHASH TYPE(REHASH)
294 #define P10_REMOVE TYPE(REMOVE)
295 #define P10_RESET TYPE(RESET)
296 #define P10_RESTART TYPE(RESTART)
297 #define P10_RPING TYPE(RPING)
298 #define P10_RPONG TYPE(RPONG)
299 #define P10_SASL TYPE(SASL)
300 #define P10_SERVER CMD_SERVER
301 #define P10_SERVLIST TYPE(SERVLIST)
302 #define P10_SERVSET TYPE(SERVSET)
303 #define P10_SET TYPE(SET)
304 #define P10_SETTIME TYPE(SETTIME)
305 #define P10_SGLINE TYPE(SGLINE)
306 #define P10_SHUN TYPE(SHUN)
307 #define P10_SILENCE TYPE(SILENCE)
308 #define P10_SMO TYPE(SMO)
309 #define P10_SNO TYPE(SNO)
310 #define P10_SSHUN TYPE(SSHUN)
311 #define P10_SPAMFILTER TYPE(SPAMFILTER)
312 #define P10_SQUERY TYPE(SQUERY)
313 #define P10_SQUIT TYPE(SQUIT)
314 #define P10_STATS TYPE(STATS)
315 #define P10_SVSJOIN TYPE(SVSJOIN)
316 #define P10_SVSNICK TYPE(SVSNICK)
317 #define P10_SVSPART TYPE(SVSPART)
318 #define P10_SVSQUIT TYPE(SVSQUIT)
319 #define P10_SWHOIS TYPE(SWHOIS)
320 #define P10_TEMPSHUN TYPE(TEMPSHUN)
321 #define P10_TIME TYPE(TIME)
322 #define P10_TOPIC TYPE(TOPIC)
323 #define P10_TRACE TYPE(TRACE)
324 #define P10_UPING TYPE(UPING)
325 #define P10_USER TYPE(USER)
326 #define P10_USERHOST TYPE(USERHOST)
327 #define P10_USERIP TYPE(USERIP)
328 #define P10_VERSION TYPE(VERSION)
329 #define P10_WALLCHOPS TYPE(WALLCHOPS)
330 #define P10_WALLOPS TYPE(WALLOPS)
331 #define P10_WALLHOPS TYPE(WALLHOPS)
332 #define P10_WALLUSERS TYPE(WALLUSERS)
333 #define P10_WALLVOICES TYPE(WALLVOICES)
334 #define P10_WHO TYPE(WHO)
335 #define P10_WHOIS TYPE(WHOIS)
336 #define P10_WHOWAS TYPE(WHOWAS)
337 #define P10_ZLINE TYPE(ZLINE)
338 #define P10_EXEMPT TYPE(EXEMPT)
340 /* Servers claiming to have a boot or link time before PREHISTORY
341 * trigger errors to the log. We hope no server has been running
342 * constantly since September 1994. :)
344 #define PREHISTORY 780000000
346 #define MODELEN 40 + KEYLEN
348 static struct server
* servers_num
[ 64 * 64 ];
349 static privmsg_func_t
* privmsg_funcs
;
350 static unsigned int num_privmsg_funcs
;
351 static privmsg_func_t
* notice_funcs
;
352 static unsigned int num_notice_funcs
;
353 static struct dict
* unbursted_channels
;
354 static const char * his_servername
;
355 static const char * his_servercomment
;
356 static int extended_accounts
;
358 /* These correspond to 1 << X: 01234567890123456789012345 */
359 const char irc_user_mode_chars
[] = "oOiw dkgh x BnIX azDRWHLq" ;
361 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
);
363 extern int off_channel
;
364 extern int DefConLevel
;
365 extern int DefConTimeOut
;
366 extern char * DefConChanModes
;
368 static int parse_oplevel ( char * str
);
370 char privbuf
[ 512 ] = "" ;
372 /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
373 * server and Y's indentifying the client on that server. */
375 GetServerN ( const char * numeric
)
377 switch ( strlen ( numeric
)) {
379 return servers_num
[ base64toint ( numeric
, 2 )];
383 return servers_num
[ base64toint ( numeric
, 1 )];
390 GetUserN ( const char * numeric
) /* using numeric */
396 switch ( strlen ( numeric
)) {
398 log_module ( MAIN_LOG
, LOG_WARNING
, "GetUserN( %s ): numeric too long!" , numeric
);
400 case 5 : slen
= 2 ; ulen
= 3 ; break ;
401 case 4 : slen
= 1 ; ulen
= 3 ; break ;
402 case 3 : slen
= 1 ; ulen
= 2 ; break ;
403 case 2 : case 1 : case 0 :
404 log_module ( MAIN_LOG
, LOG_WARNING
, "GetUserN( %s ): numeric too short!" , numeric
);
407 if (!( s
= servers_num
[ base64toint ( numeric
, slen
)])) {
408 log_module ( MAIN_LOG
, LOG_WARNING
, "GetUserN( %s ): couldn't find server (len= %d )!" , numeric
, slen
);
411 n
= base64toint ( numeric
+ slen
, ulen
) & s
-> num_mask
;
412 if (!( un
= s
-> users
[ n
])) {
413 log_module ( MAIN_LOG
, LOG_WARNING
, "GetUserN( %s ) couldn't find user!" , numeric
);
418 extern struct userNode
* opserv
;
420 check_ctcp ( struct userNode
* user
, struct userNode
* bot
, char * text
, UNUSED_ARG ( int server_qualified
))
423 /* if its a version reply, do an alert check (only alerts with version=something) */
425 if ( text
[ 0 ] == ' \001 ' ) {
427 cmd
= mysep (& text
, " " );
428 if (! irccasecmp ( cmd
, "VERSION" )) {
429 char * version
= mysep (& text
, " \n " );
432 /* opserv_debug("Opserv got CTCP VERSION Notice from %s: %s", user->nick, version); */
433 /* TODO: setup a ctcp_funcs thing to handle this and other CTCPS properly */
434 user
-> version_reply
= strdup ( version
);
435 /* TODO: put this in the db */
436 if ( match_ircglob ( version
, "WebTV;*" ))
437 user
-> no_notice
= true ; /* webbies cant see notices */
445 privmsg_user_helper ( struct userNode
* un
, void * data
)
447 struct privmsg_desc
* pd
= data
;
448 unsigned int num
= un
-> num_local
;
449 if (! pd
-> is_notice
) {
450 if (( num
< num_privmsg_funcs
) && privmsg_funcs
[ num
]) {
451 privmsg_funcs
[ num
]( pd
-> user
, un
, pd
-> text
, pd
-> is_qualified
);
454 if (( num
< num_notice_funcs
) && notice_funcs
[ num
]) {
455 check_ctcp ( pd
-> user
, un
, pd
-> text
, pd
-> is_qualified
);
456 notice_funcs
[ num
]( pd
-> user
, un
, pd
-> text
, pd
-> is_qualified
);
461 /* equiv to user doing /connect server port target */
462 void irc_connect ( struct userNode
* user
, char * server
, unsigned int port
, struct server
* target
)
464 putsock ( " %s " P10_CONNECT
" %s %d %s " , user
-> numeric
, server
, port
, target
-> numeric
);
468 irc_squit_route ( struct server
* srv
, const char * message
, ...)
472 va_start ( arg_list
, message
);
473 vsnprintf ( buffer
, MAXLEN
- 2 , message
, arg_list
);
474 buffer
[ MAXLEN
- 1 ] = 0 ;
476 /* When would we squit ourselves exactly?? -Rubin */
477 if ( srv
== self
&& cManager
. uplink
-> state
== CONNECTED
) {
480 /* Quit all clients linked to me. */
481 for ( i
= 0 ; i
<= self
-> num_mask
; i
++) {
484 irc_quit ( self
-> users
[ i
], buffer
);
488 putsock ( " %s " P10_SQUIT
" %s %d : %s " , self
-> numeric
, srv
-> name
, 0 , buffer
);
491 /* Force a reconnect to the currently selected server. */
492 cManager
. uplink
-> tries
= 0 ;
493 log_module ( MAIN_LOG
, LOG_INFO
, "Squitting from uplink: %s " , buffer
);
499 irc_server ( struct server
* srv
)
501 char extranum
[ COMBO_NUMERIC_LEN
+ 1 ];
503 inttobase64 ( extranum
, srv
-> num_mask
, ( srv
-> numeric
[ 1 ] || ( srv
-> num_mask
>= 64 * 64 )) ? 3 : 2 );
505 putsock ( P10_SERVER
" %s %d " FMT_TIME_T
" " FMT_TIME_T
" J10 %s%s +s6o : %s " ,
506 srv
-> name
, srv
-> hops
+ 1 , srv
-> boot
, srv
-> link_time
, srv
-> numeric
, extranum
, srv
-> description
);
508 putsock ( " %s " P10_SERVER
" %s %d " FMT_TIME_T
" " FMT_TIME_T
" %c 10 %s%s +s6o : %s " ,
509 self
-> numeric
, srv
-> name
, srv
-> hops
+ 1 , srv
-> boot
, srv
-> link_time
, ( srv
-> self_burst
? 'J' : 'P' ), srv
-> numeric
, extranum
, srv
-> description
);
514 irc_p10_pton ( irc_in_addr_t
* ip
, const char * input
)
516 if ( strlen ( input
) == 6 ) {
518 memset ( ip
, 0 , 6 * sizeof ( ip
-> in6
[ 0 ]));
519 value
= base64toint ( input
, 6 );
521 ip
-> in6
[ 5 ] = htons ( 65535 );
522 ip
-> in6
[ 6 ] = htons ( value
>> 16 );
523 ip
-> in6
[ 7 ] = htons ( value
& 65535 );
525 unsigned int pos
= 0 ;
529 for ( left
= ( 25 - strlen ( input
)) / 3 - pos
; left
; left
--)
533 ip
-> in6
[ pos
++] = ntohs ( base64toint ( input
, 3 ));
541 irc_p10_ntop ( char * output
, const irc_in_addr_t
* ip
)
543 if (! irc_in_addr_is_valid (* ip
)) {
544 strcpy ( output
, "AAAAAA" );
545 } else if ( irc_in_addr_is_ipv4 (* ip
)) {
547 in4
= ( ntohs ( ip
-> in6
[ 6 ]) << 16 ) | ntohs ( ip
-> in6
[ 7 ]);
548 inttobase64 ( output
, in4
, 6 );
550 } else if ( irc_in_addr_is_ipv6 (* ip
)) {
551 unsigned int max_start
, max_zeros
, curr_zeros
, zero
, ii
;
552 /* Can start by printing out the leading non-zero parts. */
553 for ( ii
= 0 ; ( ip
-> in6
[ ii
]) && ( ii
< 8 ); ++ ii
) {
554 inttobase64 ( output
, ntohs ( ip
-> in6
[ ii
]), 3 );
557 /* Find the longest run of zeros. */
558 for ( max_start
= zero
= ii
, max_zeros
= curr_zeros
= 0 ; ii
< 8 ; ++ ii
) {
561 else if ( curr_zeros
> max_zeros
) {
562 max_start
= ii
- curr_zeros
;
563 max_zeros
= curr_zeros
;
567 if ( curr_zeros
> max_zeros
) {
568 max_start
= ii
- curr_zeros
;
569 max_zeros
= curr_zeros
;
572 /* Print the rest of the address */
573 for ( ii
= zero
; ii
< 8 ; ) {
574 if (( ii
== max_start
) && max_zeros
) {
578 inttobase64 ( output
, ntohs ( ip
-> in6
[ ii
]), 3 );
584 strcpy ( output
, "???" );
589 irc_user ( struct userNode
* user
)
592 if (! user
|| IsDummy ( user
))
594 irc_p10_ntop ( b64ip
, & user
-> ip
);
598 irc_user_modes ( user
, modes
, sizeof ( modes
));
599 /* we don't need to put the + in modes because it's in the format string. */
600 putsock ( " %s " P10_NICK
" %s %d " FMT_TIME_T
" %s %s + %s %s %s : %s " ,
601 user
-> uplink
-> numeric
, user
-> nick
, user
-> uplink
-> hops
+ 1 , user
-> timestamp
, user
-> ident
, user
-> hostname
, modes
, b64ip
, user
-> numeric
, user
-> info
);
603 putsock ( " %s " P10_NICK
" %s %d " FMT_TIME_T
" %s %s %s %s : %s " ,
604 user
-> uplink
-> numeric
, user
-> nick
, user
-> uplink
-> hops
+ 1 , user
-> timestamp
, user
-> ident
, user
-> hostname
, b64ip
, user
-> numeric
, user
-> info
);
609 irc_rename ( struct userNode
* user
, const char * new_handle
)
611 if ( extended_accounts
)
612 putsock ( " %s " P10_ACCOUNT
" %s M %s " , self
-> numeric
, user
-> numeric
, new_handle
);
616 irc_delete ( struct userNode
* user
)
618 if ( extended_accounts
)
619 putsock ( " %s " P10_ACCOUNT
" %s U" , self
-> numeric
, user
-> numeric
);
623 irc_account ( struct userNode
* user
, const char * stamp
, time_t timestamp
)
625 if ( extended_accounts
)
626 putsock ( " %s " P10_ACCOUNT
" %s R %s " FMT_TIME_T
, self
-> numeric
, user
-> numeric
, stamp
, timestamp
);
628 putsock ( " %s " P10_ACCOUNT
" %s %s " FMT_TIME_T
, self
-> numeric
, user
-> numeric
, stamp
, timestamp
);
632 irc_fakehost ( struct userNode
* user
, const char * host
)
634 putsock ( " %s " P10_FAKEHOST
" %s %s " , self
-> numeric
, user
-> numeric
, host
);
638 irc_regnick ( UNUSED_ARG ( struct userNode
* user
))
640 /* no operation here */
644 irc_nick ( struct userNode
* user
, UNUSED_ARG ( const char * old_nick
))
646 putsock ( " %s " P10_NICK
" %s " FMT_TIME_T
, user
-> numeric
, user
-> nick
, now
);
650 irc_fetchtopic ( struct userNode
* from
, const char * to
)
654 putsock ( " %s " P10_TOPIC
" %s " , from
-> numeric
, to
);
658 irc_squit ( struct server
* srv
, const char * message
, const char * service_message
)
660 if (! service_message
)
661 service_message
= message
;
663 /* Are we leaving the network? */
664 if ( srv
== self
&& cManager
. uplink
-> state
== CONNECTED
) {
667 /* Quit all clients linked to me. */
668 for ( i
= 0 ; i
<= self
-> num_mask
; i
++) {
671 irc_quit ( self
-> users
[ i
], service_message
);
675 putsock ( " %s " P10_SQUIT
" %s %d : %s " , self
-> numeric
, srv
-> name
, 0 , message
);
678 /* Force a reconnect to the currently selected server. */
679 cManager
. uplink
-> tries
= 0 ;
680 log_module ( MAIN_LOG
, LOG_INFO
, "Squitting from uplink: %s " , message
);
686 irc_wallchops ( struct userNode
* from
, const char * to
, const char * message
)
688 putsock ( " %s " P10_WALLCHOPS
" %s : %s " , from
-> numeric
, to
, message
);
692 irc_wallops ( const char * format
, ...)
696 va_start ( arg_list
, format
);
697 vsnprintf ( buffer
, MAXLEN
- 2 , format
, arg_list
);
698 buffer
[ MAXLEN
- 1 ] = 0 ;
699 putsock ( " %s " P10_WALLOPS
" : %s " , self
-> numeric
, buffer
);
703 deliver_to_dummy ( struct userNode
* source
, struct userNode
* dest
, const char * message
, int type
)
707 if (! dest
|| ! IsDummy ( dest
) || ! IsLocal ( dest
))
709 num
= dest
-> num_local
;
712 if (( num
< num_notice_funcs
) && notice_funcs
[ num
])
713 notice_funcs
[ num
]( source
, dest
, message
, 0 );
716 if (( num
< num_privmsg_funcs
) && privmsg_funcs
[ num
])
717 privmsg_funcs
[ num
]( source
, dest
, message
, 0 );
724 irc_notice ( struct userNode
* from
, const char * to
, const char * message
)
726 if ( to
[ 0 ] == '#' || to
[ 0 ] == '$'
727 || ! deliver_to_dummy ( from
, GetUserN ( to
), message
, 0 ))
728 putsock ( " %s " P10_NOTICE
" %s : %s " , from
-> numeric
, to
, message
);
732 irc_notice_user ( struct userNode
* from
, struct userNode
* to
, const char * message
)
734 if (! deliver_to_dummy ( from
, to
, message
, 0 ))
735 putsock ( " %s " P10_NOTICE
" %s : %s " , from
-> numeric
, to
-> numeric
, message
);
739 irc_privmsg ( struct userNode
* from
, const char * to
, const char * message
)
741 if ( to
[ 0 ] == '#' || to
[ 0 ] == '$'
742 || ! deliver_to_dummy ( from
, GetUserN ( to
), message
, 1 ))
743 putsock ( " %s " P10_PRIVMSG
" %s : %s " , from
-> numeric
, to
, message
);
747 irc_privmsg_user ( struct userNode
* from
, struct userNode
* to
, const char * message
)
749 putsock ( " %s " P10_PRIVMSG
" %s : %s " , from
-> numeric
, to
-> numeric
, message
);
753 irc_version_user ( struct userNode
* from
, struct userNode
* to
)
755 irc_privmsg_user ( from
, to
, " \001 VERSION \001 " );
761 putsock ( " %s " P10_EOB
, self
-> numeric
);
767 putsock ( " %s " P10_EOB_ACK
, self
-> numeric
);
771 str
= conf_get_data ( "services/opserv/nick" , RECDB_QSTRING
);
774 if ( nick
&& ( DefConLevel
< 5 )) {
775 DefConProcess ( GetUserH ( nick
));
777 if ( DefConTimeOut
> 0 )
778 timeq_add ( now
+ DefConTimeOut
, defcon_timeout
, NULL
);
783 irc_rpong ( const char * from1
, const char * from2
, const char * pingtime
, const char * clientinfo
)
785 putsock ( " %s " P10_RPONG
" %s %s %s : %s " , self
-> numeric
, from1
, from2
, pingtime
, clientinfo
);
789 irc_ping ( const char * payload
)
791 putsock ( " %s " P10_PING
" : %s " , self
-> numeric
, payload
);
795 irc_pong ( const char * who
, const char * data
)
797 putsock ( " %s " P10_PONG
" %s : %s " , self
-> numeric
, who
, data
);
801 irc_pong_asll ( const char * who
, const char * orig_ts
)
805 struct timeval sys_now
;
808 orig
. tv_sec
= strtoul ( orig_ts
, & delim
, 10 );
809 orig
. tv_usec
= (* delim
== '.' ) ? strtoul ( delim
+ 1 , NULL
, 10 ) : 0 ;
810 gettimeofday (& sys_now
, NULL
);
811 diff
= ( sys_now
. tv_sec
- orig
. tv_sec
) * 1000 + ( sys_now
. tv_usec
- orig
. tv_usec
) / 1000 ;
812 putsock ( " %s " P10_PONG
" %s %s %d %l u. %0 6lu" , self
-> numeric
, who
, orig_ts
, diff
, ( unsigned long ) sys_now
. tv_sec
, ( unsigned long ) sys_now
. tv_usec
);
816 irc_pass ( const char * passwd
)
818 putsock ( P10_PASS
" : %s " , passwd
);
822 irc_introduce ( const char * passwd
)
824 void timed_send_ping ( void * data
);
826 self
-> self_burst
= self
-> burst
= 1 ;
830 timeq_add ( now
+ ping_freq
, timed_send_ping
, 0 );
834 irc_gline ( struct server
* srv
, struct gline
* gline
, int silent
)
836 putsock ( " %s " P10_GLINE
" %s + %s " FMT_TIME_T
" " FMT_TIME_T
" : %s < %s > %s " ,
837 self
-> numeric
, ( srv
? srv
-> numeric
: "*" ), gline
-> target
, gline
-> expires
- now
, now
, silent
? "AUTO " : "" , gline
-> issuer
, gline
-> reason
);
841 irc_shun ( struct server
* srv
, struct shun
* shun
)
843 putsock ( " %s " P10_SHUN
" %s + %s " FMT_TIME_T
" " FMT_TIME_T
" :< %s > %s " ,
844 self
-> numeric
, ( srv
? srv
-> numeric
: "*" ), shun
-> target
, shun
-> expires
- now
, now
, shun
-> issuer
, shun
-> reason
);
848 irc_settime ( const char * srv_name_mask
, time_t new_time
)
850 ioset_set_time ( new_time
);
851 if (! strcmp ( srv_name_mask
, "*" ))
853 putsock ( " %s " P10_SETTIME
" " FMT_TIME_T
" %s " , self
-> numeric
, new_time
, srv_name_mask
);
857 irc_ungline ( const char * mask
)
859 putsock ( " %s " P10_GLINE
" * - %s " FMT_TIME_T
, self
-> numeric
, mask
, now
);
863 irc_unshun ( const char * mask
)
865 putsock ( " %s " P10_SHUN
" * - %s " FMT_TIME_T
, self
-> numeric
, mask
, now
);
869 irc_burst ( struct chanNode
* chan
)
871 char burst_line
[ 512 ];
872 int pos
, base_len
, len
;
875 struct exemptNode
* en
;
877 unsigned int first_ban
;
878 unsigned int first_exempt
;
881 base_len
= sprintf ( burst_line
, " %s " P10_BURST
" %s " FMT_TIME_T
" " ,
882 self
-> numeric
, chan
-> name
, chan
-> timestamp
);
883 len
= irc_make_chanmode ( chan
, burst_line
+ base_len
);
884 pos
= base_len
+ len
;
885 if ( len
> 0 && chan
-> members
. used
> 0 )
886 burst_line
[ pos
++] = ' ' ;
888 if ( chan
-> members
. used
< 1 )
889 return ; /* dont burst empty channels (created by discrims) */
891 for ( n
= 0 ; n
< chan
-> members
. used
; n
++) {
892 mn
= chan
-> members
. list
[ n
];
894 burst_line
[ pos
- 1 ] = 0 ; /* -1 to back up over the space or comma */
895 putsock ( " %s " , burst_line
);
900 memcpy ( burst_line
+ pos
, mn
-> user
-> numeric
, strlen ( mn
-> user
-> numeric
));
901 pos
+= strlen ( mn
-> user
-> numeric
);
902 if ( mn
-> modes
&& ( mn
-> modes
!= last_mode
)) {
903 last_mode
= mn
-> modes
;
904 burst_line
[ pos
++] = ':' ;
905 if ( last_mode
& MODE_CHANOP
)
906 burst_line
[ pos
++] = 'o' ;
907 if ( last_mode
& MODE_HALFOP
)
908 burst_line
[ pos
++] = 'h' ;
909 if ( last_mode
& MODE_VOICE
)
910 burst_line
[ pos
++] = 'v' ;
912 if (( n
+ 1 )< chan
-> members
. used
)
913 burst_line
[ pos
++] = ',' ;
916 if ( len
> 0 && ( chan
-> banlist
. used
> 0 || chan
-> exemptlist
. used
> 0 ))
917 burst_line
[ pos
++] = ' ' ;
919 if ( chan
-> banlist
. used
) {
923 for ( n
= 0 ; n
< chan
-> banlist
. used
; ) {
924 if ( first_ban
&& ( pos
< 500 )) {
925 burst_line
[ pos
++] = ':' ;
926 burst_line
[ pos
++] = '%' ;
928 bn
= chan
-> banlist
. list
[ n
];
929 len
= strlen ( bn
-> ban
);
930 if ( pos
+ 2 + len
< 505 ) {
931 memcpy ( burst_line
+ pos
, bn
-> ban
, len
);
933 burst_line
[ pos
++] = ' ' ;
937 burst_line
[ pos
- 1 ] = 0 ;
938 putsock ( " %s " , burst_line
);
945 if ( chan
-> exemptlist
. used
) {
946 /* dump the exempts */
949 for ( n
= 0 ; n
< chan
-> exemptlist
. used
; ) {
950 if ( first_exempt
&& ( pos
< 500 )) {
951 if ( chan
-> banlist
. used
< 1 ) {
952 burst_line
[ pos
++] = ':' ;
953 burst_line
[ pos
++] = '%' ;
954 burst_line
[ pos
++] = ' ' ;
956 burst_line
[ pos
++] = '~' ;
957 burst_line
[ pos
++] = ' ' ;
959 en
= chan
-> exemptlist
. list
[ n
];
960 len
= strlen ( en
-> exempt
);
961 if ( pos
+ 2 + len
< 505 ) {
962 memcpy ( burst_line
+ pos
, en
-> exempt
, len
);
964 burst_line
[ pos
++] = ' ' ;
968 burst_line
[ pos
- 1 ] = 0 ;
969 putsock ( " %s " , burst_line
);
975 /* print the last line */
977 putsock ( " %s " , burst_line
);
981 irc_quit ( struct userNode
* user
, const char * message
)
983 putsock ( " %s " P10_QUIT
" : %s " , user
-> numeric
, message
);
987 irc_error ( const char * to
, const char * message
)
990 putsock ( " %s " P10_ERROR
" : %s " , to
, message
);
992 putsock ( ": %s " P10_ERROR
" : %s " , self
-> name
, message
);
997 irc_kill ( struct userNode
* from
, struct userNode
* target
, const char * message
)
1000 putsock ( " %s " P10_KILL
" %s : %s ! %s ( %s )" ,
1001 from
-> numeric
, target
-> numeric
, self
-> name
, from
-> nick
, message
);
1003 putsock ( " %s " P10_KILL
" %s : %s ( %s )" ,
1004 self
-> numeric
, target
-> numeric
, self
-> name
, message
);
1009 irc_mode ( struct userNode
* from
, struct chanNode
* target
, const char * modes
)
1011 call_channel_mode_funcs ( from
, target
, ( char **)& modes
, 0 );
1012 putsock ( " %s " P10_MODE
" %s %s " FMT_TIME_T
,
1013 ( from
? from
-> numeric
: self
-> numeric
),
1014 target
-> name
, modes
, target
-> timestamp
);
1017 /* Added to allow services to mode users
1018 2005 - 8 - 10 by Life4Christ
1021 irc_umode ( struct userNode
* target
, const char * modes
)
1023 putsock ( " %s " P10_MODE
" %s %s " , self
-> numeric
, target
-> nick
, modes
);
1028 irc_invite ( struct userNode
* from
, struct userNode
* who
, struct chanNode
* to
)
1030 putsock ( " %s " P10_INVITE
" %s %s " , from
-> numeric
, who
-> nick
, to
-> name
);
1034 irc_silence ( struct userNode
* who
, const char * mask
, int add
)
1036 putsock ( " %s " P10_SILENCE
" %s %s%s " , self
-> numeric
, who
-> numeric
, add
? "+" : "-" , mask
);
1040 irc_join ( struct userNode
* who
, struct chanNode
* what
)
1042 if ( what
-> members
. used
== 1 ) {
1043 putsock ( " %s " P10_CREATE
" %s " FMT_TIME_T
,
1044 who
-> numeric
, what
-> name
, what
-> timestamp
);
1046 putsock ( " %s " P10_JOIN
" %s " FMT_TIME_T
, who
-> numeric
, what
-> name
, what
-> timestamp
);
1051 irc_svsjoin ( struct userNode
* from
, struct userNode
* who
, struct chanNode
* to
)
1053 putsock ( " %s " P10_SVSJOIN
" %s %s " FMT_TIME_T
, from
-> uplink
-> numeric
, who
-> numeric
, to
-> name
, now
);
1057 irc_svspart ( struct userNode
* from
, struct userNode
* who
, struct chanNode
* to
)
1059 putsock ( " %s " P10_SVSPART
" %s %s " , from
-> uplink
-> numeric
, who
-> numeric
, to
-> name
);
1063 irc_svsquit ( struct userNode
* from
, struct userNode
* who
, char const * reason
)
1065 putsock ( " %s " P10_SVSQUIT
" %s : %s " , from
-> uplink
-> numeric
, who
-> numeric
, reason
);
1069 irc_kick ( struct userNode
* who
, struct userNode
* target
, struct chanNode
* channel
, const char * msg
)
1071 const char * numeric
;
1072 struct modeNode
* mn
= GetUserMode ( channel
, who
);
1073 numeric
= (( mn
&& ( mn
-> modes
& MODE_CHANOP
)) || off_channel
) ? who
-> numeric
: self
-> numeric
;
1074 putsock ( " %s " P10_KICK
" %s %s : %s " ,
1075 numeric
, channel
-> name
, target
-> numeric
, msg
);
1079 irc_stats ( struct userNode
* from
, struct server
* target
, char type
)
1081 putsock ( " %s " P10_STATS
" %c : %s " , from
-> numeric
, type
, target
-> numeric
);
1085 irc_svsnick ( struct userNode
* from
, struct userNode
* target
, const char * newnick
)
1087 putsock ( " %s " P10_SVSNICK
" %s %s " FMT_TIME_T
, from
-> uplink
-> numeric
, target
-> numeric
, newnick
, now
);
1091 irc_swhois ( struct userNode
* from
, struct userNode
* target
, const char * message
)
1093 putsock ( " %s " P10_SWHOIS
" %s %s%s " , from
-> uplink
-> numeric
, target
-> numeric
, message
? ":" : "" ,
1094 message
? message
: "" );
1099 irc_tempshun ( struct userNode
* from
, struct userNode
* target
, int remove
, const char * reason
)
1101 putsock ( " %s " P10_TEMPSHUN
" %s %s : %s " , from
-> numeric
, ( remove
? "-" : "+" ), target
-> numeric
, reason
);
1105 irc_part ( struct userNode
* who
, struct chanNode
* what
, const char * reason
)
1108 putsock ( " %s " P10_PART
" %s : %s " , who
-> numeric
, what
-> name
, reason
);
1110 putsock ( " %s " P10_PART
" %s " , who
-> numeric
, what
-> name
);
1115 irc_topic ( struct userNode
* service
, struct userNode
* who
, struct chanNode
* what
, const char * topic
)
1118 int type
= 4 , host_in_topic
= 0 , hasident
= 0 , hhtype
= 0 ;
1119 const char * hstr
, * tstr
, * hhstr
, * htstr
;
1120 char * host
, * hostmask
;
1122 char sident
[ MAXLEN
];
1124 tstr
= conf_get_data ( "server/type" , RECDB_QSTRING
);
1125 hstr
= conf_get_data ( "server/host_in_topic" , RECDB_QSTRING
);
1126 hhstr
= conf_get_data ( "server/hidden_host" , RECDB_QSTRING
);
1127 htstr
= conf_get_data ( "server/hidden_host_type" , RECDB_QSTRING
);
1131 type
= 4 ; /* default to 040 style topics */
1133 hhtype
= atoi ( htstr
);
1136 if ( IsHiddenHost ( who
) && IsFakeHost ( who
))
1137 safestrncpy ( shost
, who
-> fakehost
, sizeof ( shost
));
1138 else if ( IsHiddenHost ( who
) && IsSetHost ( who
)) {
1139 hostmask
= strdup ( who
-> sethost
);
1140 if (( host
= ( strrchr ( hostmask
, '@' )))) {
1147 safestrncpy ( sident
, hostmask
, sizeof ( shost
));
1149 safestrncpy ( sident
, who
-> ident
, sizeof ( shost
));
1151 safestrncpy ( shost
, host
, sizeof ( shost
));
1152 } else if ( IsHiddenHost ( who
) && (( hhtype
== 1 ) || ( hhtype
== 3 )) && who
-> handle_info
&& hhstr
) {
1153 snprintf ( shost
, sizeof ( shost
), " %s . %s " , who
-> handle_info
-> handle
, hhstr
);
1154 } else if ( IsHiddenHost ( who
) && (( hhtype
== 2 ) || ( hhtype
== 3 )) && who
-> crypthost
[ 0 ]) {
1155 safestrncpy ( shost
, who
-> crypthost
, sizeof ( shost
));
1157 safestrncpy ( shost
, who
-> hostname
, sizeof ( shost
));
1159 host_in_topic
= atoi ( hstr
);
1163 putsock ( " %s " P10_TOPIC
" %s %s%s%s%s%s " FMT_TIME_T
" " FMT_TIME_T
" : %s " , service
-> numeric
, what
-> name
,
1164 who
-> nick
, host_in_topic
? "!" : "" , host_in_topic
? ( IsSetHost ( who
) ? sident
: who
-> ident
) : "" ,
1165 host_in_topic
? "@" : "" , host_in_topic
? shost
: "" , what
-> timestamp
, now
, topic
);
1168 putsock ( " %s " P10_TOPIC
" %s : %s " , who
-> numeric
, what
-> name
, topic
);
1173 irc_raw ( const char * what
)
1175 putsock ( " %s " , what
);
1179 irc_numeric ( struct userNode
* user
, unsigned int num
, const char * format
, ...)
1182 char buffer
[ MAXLEN
];
1183 va_start ( arg_list
, format
);
1184 vsnprintf ( buffer
, MAXLEN
- 2 , format
, arg_list
);
1185 buffer
[ MAXLEN
- 1 ] = 0 ;
1186 putsock ( ": %s %0 3d %s %s " , self
-> name
, num
, user
-> nick
, buffer
);
1190 irc_mark ( struct userNode
* user
, char * mark
)
1192 char * host
= user
-> hostname
;
1194 const char * tstr
= NULL
;
1195 unsigned int ii
= 0 ;
1198 tstr
= conf_get_data ( "server/type" , RECDB_QSTRING
);
1205 for ( ii
= 0 ; ii
< user
-> marks
-> used
; ii
++)
1206 if (! irccasecmp ( user
-> marks
-> list
[ ii
], mark
))
1212 user
-> marks
= alloc_string_list ( 1 );
1213 string_list_append ( user
-> marks
, strdup ( mark
));
1218 putsock ( " %s " CMD_MARK
" %s MARK %s " , self
-> numeric
, user
-> nick
, mark
);
1222 /* TODO: Allow mark overwrite. If they are marked, and their fakehost is oldmark.hostname, update it to newmark.hostname so mark can be called multiple times. Probably requires ircd modification also */
1226 /* if the mark will put us over the host length, clip some off the left hand side
1229 if ( strlen ( host
) + 1 + strlen ( mark
) > HOSTLEN
)
1230 host
+= 1 + ( ( strlen ( host
) + 1 + strlen ( mark
)) - HOSTLEN
);
1231 putsock ( " %s " CMD_MARK
" %s DNSBL +m %s . %s " , self
-> numeric
, user
-> nick
, mark
, host
);
1232 putsock ( " %s " CMD_MARK
" %s DNSBL_DATA %s " , self
-> numeric
, user
-> nick
, mark
);
1234 /* Save it in the user */
1235 user
-> mark
= strdup ( mark
);
1237 /* If they are not otherwise marked, mark their host with fakehost */
1238 if (! IsFakeHost ( user
) && ! IsSetHost ( user
) && !( IsHiddenHost ( user
) && user
-> handle_info
) )
1240 struct modeNode
* mn
= NULL
;
1241 char fakehost
[ HOSTLEN
];
1242 unsigned int count
= 0 ;
1245 putsock ( " %s " CMD_FAKEHOST
" %s %s . %s " , self
-> numeric
, user
-> numeric
, mark
, host
);
1246 putsock ( " %s " CMD_MODE
" %s +x" , self
-> numeric
, user
-> nick
);
1248 snprintf ( fakehost
, sizeof ( fakehost
), " %s . %s " , mark
, host
);
1249 safestrncpy ( user
-> fakehost
, fakehost
, sizeof ( user
-> fakehost
));
1251 for ( n
= count
= 0 ; n
< user
-> channels
. used
; n
++) {
1252 mn
= user
-> channels
. list
[ n
];
1253 if ( strlen ( mn
-> channel
-> name
) >= 1 ) /* Sanity */
1254 check_bans ( user
, mn
-> channel
-> name
);
1259 void irc_sno ( unsigned int mask
, char const * format
, ...) {
1261 char buffer
[ MAXLEN
];
1262 va_start ( arg_list
, format
);
1263 vsnprintf ( buffer
, MAXLEN
- 2 , format
, arg_list
);
1264 buffer
[ MAXLEN
- 1 ] = 0 ;
1265 putsock ( " %s " CMD_SNO
" %d : %s " , self
-> numeric
, mask
, buffer
);
1269 irc_sasl ( struct server
* dest
, const char * identifier
, const char * subcmd
, const char * data
)
1271 putsock ( " %s " P10_SASL
" %s %s %s %s " , self
-> numeric
, dest
-> numeric
, identifier
, subcmd
, data
);
1274 static void send_burst ( void );
1277 change_nicklen ( int new_nicklen
)
1280 char new_nick
[ NICKLEN
+ 1 ];
1281 struct userNode
* user
;
1283 nicklen
= new_nicklen
;
1284 /* fix up any users we have here */
1285 for ( nn
= 0 ; nn
<= self
-> num_mask
; nn
++) {
1286 if (!( user
= self
-> users
[ nn
]))
1288 safestrncpy ( new_nick
, user
-> nick
, sizeof ( new_nick
));
1289 new_nick
[ nicklen
] = 0 ;
1290 NickChange ( user
, new_nick
, 1 );
1294 static CMD_FUNC ( cmd_whois
)
1296 struct userNode
* from
;
1297 struct userNode
* who
;
1299 unsigned int i
, mlen
, len
;
1303 if (!( from
= GetUserH ( origin
))) {
1304 log_module ( MAIN_LOG
, LOG_ERROR
, "Could not find WHOIS origin user %s " , origin
);
1307 if (!( who
= GetUserH ( argv
[ 2 ]))) {
1308 irc_numeric ( from
, ERR_NOSUCHNICK
, " %s @ %s :No such nick" , argv
[ 2 ], self
-> name
);
1312 if ( IsFakeHost ( who
) && IsHiddenHost ( who
))
1313 irc_numeric ( from
, RPL_WHOISUSER
, " %s %s %s * : %s " , who
-> nick
, who
-> ident
, who
-> fakehost
, who
-> info
);
1314 else if ( IsHiddenHost ( who
) && who
-> handle_info
&& hidden_host_suffix
)
1315 irc_numeric ( from
, RPL_WHOISUSER
, " %s %s %s . %s * : %s " , who
-> nick
, who
-> ident
, who
-> handle_info
-> handle
, hidden_host_suffix
, who
-> info
);
1317 irc_numeric ( from
, RPL_WHOISUSER
, " %s %s %s * : %s " , who
-> nick
, who
-> ident
, who
-> hostname
, who
-> info
);
1319 if (! IsService ( who
) || ( from
== who
)) {
1320 struct modeNode
* mn
;
1321 mlen
= strlen ( self
-> name
) + strlen ( from
-> nick
) + 12 + strlen ( who
-> nick
);
1324 for ( i
= who
-> channels
. used
; i
> 0 ; )
1326 mn
= who
-> channels
. list
[-- i
];
1328 if (! IsOper ( from
) && ( mn
-> channel
-> modes
& ( MODE_PRIVATE
| MODE_SECRET
)) && ! GetUserMode ( mn
-> channel
, from
))
1331 if ( len
+ strlen ( mn
-> channel
-> name
) + mlen
> MAXLEN
- 5 )
1333 irc_numeric ( from
, RPL_WHOISCHANNELS
, " %s : %s " , who
-> nick
, buf
);
1339 *( buf
+ len
++) = '-' ;
1340 if (( mn
-> channel
-> modes
& ( MODE_PRIVATE
| MODE_SECRET
)) && ! GetUserMode ( mn
-> channel
, from
))
1341 *( buf
+ len
++) = '*' ;
1342 if ( mn
-> modes
& MODE_CHANOP
)
1343 *( buf
+ len
++) = '@' ;
1344 else if ( mn
-> modes
& MODE_HALFOP
)
1345 *( buf
+ len
++) = '%' ;
1346 else if ( mn
-> modes
& MODE_VOICE
)
1347 *( buf
+ len
++) = '+' ;
1350 *( buf
+ len
) = '\0' ;
1351 strcpy ( buf
+ len
, mn
-> channel
-> name
);
1352 len
+= strlen ( mn
-> channel
-> name
);
1353 strcat ( buf
+ len
, " " );
1357 irc_numeric ( from
, RPL_WHOISCHANNELS
, " %s : %s " , who
-> nick
, buf
);
1360 if ( his_servername
&& his_servercomment
&& ! IsOper ( from
) && from
!= who
)
1361 irc_numeric ( from
, RPL_WHOISSERVER
, " %s %s : %s " , who
-> nick
, his_servername
, his_servercomment
);
1363 irc_numeric ( from
, RPL_WHOISSERVER
, " %s %s : %s " , who
-> nick
, who
-> uplink
-> name
, who
-> uplink
-> description
);
1366 irc_numeric ( from
, RPL_AWAY
, " %s :Away" , who
-> nick
);
1368 irc_numeric ( from
, RPL_WHOISOPERATOR
, " %s : %s " , who
-> nick
, IsLocal ( who
) ? "is a megalomaniacal power hungry tyrant" : "is an IRC Operator" );
1369 if ( who
-> handle_info
)
1370 irc_numeric ( from
, RPL_WHOISACCOUNT
, " %s %s :is logged in as" , who
-> nick
, who
-> handle_info
-> handle
);
1371 if ( IsHiddenHost ( who
) && who
-> handle_info
&& ( IsOper ( from
) || from
== who
))
1372 irc_numeric ( from
, RPL_WHOISACTUALLY
, " %s %s @ %s %s :Actual user@host, Actual IP" , who
-> nick
, who
-> ident
, who
-> hostname
, irc_ntoa (& who
-> ip
));
1373 if ( IsLocal ( who
) && ! IsService ( who
) && ( IsOper ( from
) || from
== who
))
1374 irc_numeric ( from
, RPL_WHOISIDLE
, " %s %l d %l d :seconds idle, signon time" , who
-> nick
, now
- who
-> idle_since
, who
-> timestamp
);
1376 irc_numeric ( from
, RPL_ENDOFWHOIS
, " %s :End of /WHOIS list" , who
-> nick
);
1380 static CMD_FUNC ( cmd_server
)
1388 /* another server introduced us */
1389 srv
= AddServer ( GetServerH ( origin
), argv
[ 1 ], atoi ( argv
[ 2 ]), atoi ( argv
[ 3 ]), atoi ( argv
[ 4 ]), argv
[ 6 ], argv
[ argc
- 1 ]);
1392 srv
-> self_burst
= argv
[ 5 ][ 0 ] == 'J' ;
1395 /* this must be our uplink */
1396 srv
= self
-> uplink
= AddServer ( self
, argv
[ 1 ], atoi ( argv
[ 2 ]), atoi ( argv
[ 3 ]), atoi ( argv
[ 4 ]), argv
[ 6 ], argv
[ argc
- 1 ]);
1399 srv
-> self_burst
= argv
[ 5 ][ 0 ] == 'J' ;
1401 if (( argv
[ 7 ][ 0 ] == '+' ) && ! force_n2k
) {
1402 log_module ( MAIN_LOG
, LOG_WARNING
, "Got Undernet-style SERVER message but \" force_n2k \" not on." );
1407 /* Fix up our timestamps if necessary. */
1408 if ( srv
-> boot
<= PREHISTORY
) {
1409 /* Server from the mists of time.. */
1410 if ( srv
-> hops
== 1 ) {
1411 log_module ( MAIN_LOG
, LOG_ERROR
, "Server %s claims to have booted at time " FMT_TIME_T
". This is absurd." , srv
-> name
, srv
-> boot
);
1413 } else if (( str
= conf_get_data ( "server/reliable_clock" , RECDB_QSTRING
))
1414 && enabled_string ( str
)) {
1415 /* If we have a reliable clock, we just keep our current time. */
1417 if ( srv
-> boot
<= self
-> boot
) {
1418 /* The other server is older than us. Accept their timestamp.
1419 * Alternately, we are same age, but we accept their time
1420 * since we are linking to them. */
1421 self
-> boot
= srv
-> boot
;
1422 ioset_set_time ( srv
-> link_time
1426 if ( srv
== self
-> uplink
) {
1427 extern time_t burst_begin
;
1434 static CMD_FUNC ( cmd_eob
)
1436 struct server
* sender
;
1439 if (!( sender
= GetServerH ( origin
)))
1441 if ( sender
== self
-> uplink
) {
1442 cManager
. uplink
-> state
= CONNECTED
;
1443 for ( it
= dict_first ( unbursted_channels
); it
; it
= iter_next ( it
))
1444 irc_burst ( iter_data ( it
));
1445 dict_delete ( unbursted_channels
);
1446 unbursted_channels
= NULL
;
1450 /* now that we know who our uplink is,
1451 * we can center the routing map and activate auto-routing.
1453 //activate_routing(NULL, NULL, NULL);
1456 sender
-> self_burst
= 0 ;
1457 recalc_bursts ( sender
);
1458 call_server_link_funcs ( sender
);
1459 /* let auto-routing figure out if we were
1460 * wating on this server to link a child to it */
1461 /* DONT call this if uplink is _US_ */
1462 if ( sender
-> uplink
!= self
)
1463 routing_handle_connect ( sender
-> name
, sender
-> uplink
-> name
);
1467 static CMD_FUNC ( cmd_eob_ack
)
1469 extern time_t burst_begin
;
1471 if ( GetServerH ( origin
) == self
-> uplink
) {
1472 burst_length
= now
- burst_begin
;
1473 self
-> self_burst
= self
-> burst
= 0 ;
1475 cManager
. uplink
-> state
= CONNECTED
;
1479 static CMD_FUNC ( cmd_rping
)
1481 struct server
* dest
;
1483 if (!( dest
= GetServerN ( argv
[ 1 ])))
1484 return 1 ; /* if its a jupe or something, return 1 so its silently ignored */
1487 irc_rpong ( argv
[ 2 ], argv
[ 3 ], argv
[ 4 ], argv
[ 5 ]);
1492 static CMD_FUNC ( cmd_sasl
)
1494 struct server
* serv
;
1499 serv
= GetServerH ( origin
);
1503 call_sasl_input_func ( serv
, argv
[ 2 ], argv
[ 3 ], argv
[ 4 ], ( argc
> 5 ? argv
[ argc
- 1 ] : NULL
));
1508 static CMD_FUNC ( cmd_ping
)
1511 struct userNode
* un
;
1514 irc_pong_asll ( argv
[ 2 ], argv
[ 3 ]);
1515 else if (( srv
= GetServerH ( origin
)))
1516 irc_pong ( self
-> name
, srv
-> numeric
);
1517 else if (( un
= GetUserH ( origin
)))
1518 irc_pong ( self
-> name
, un
-> numeric
);
1520 irc_pong ( self
-> name
, origin
);
1522 timeq_del ( 0 , timed_send_ping
, 0 , TIMEQ_IGNORE_WHEN
| TIMEQ_IGNORE_DATA
);
1523 timeq_del ( 0 , timed_ping_timeout
, 0 , TIMEQ_IGNORE_WHEN
| TIMEQ_IGNORE_DATA
);
1524 timeq_add ( now
+ ping_freq
, timed_send_ping
, 0 );
1529 static CMD_FUNC ( cmd_error_nick
)
1531 /* Go back to original IRC length .. and try to reconnect :/ */
1533 irc_squit ( self
, "Got erroneous nickname, truncating nicks." , NULL
);
1537 struct create_desc
{
1538 struct userNode
* user
;
1543 join_helper ( struct chanNode
* chan
, void * data
)
1545 struct create_desc
* cd
= data
;
1546 AddChannelUser ( cd
-> user
, chan
);
1550 create_helper ( char * name
, void * data
)
1552 struct create_desc
* cd
= data
;
1554 if (! strcmp ( name
, "0" )) {
1555 while ( cd
-> user
-> channels
. used
> 0 )
1556 DelChannelUser ( cd
-> user
, cd
-> user
-> channels
. list
[ 0 ]-> channel
, 0 , 0 );
1560 AddChannelUser ( cd
-> user
, AddChannel ( name
, cd
-> when
, NULL
, NULL
, NULL
));
1563 static CMD_FUNC ( cmd_create
)
1565 struct create_desc cd
;
1566 struct userNode
* user
;
1568 if (( argc
< 3 ) || !( user
= GetUserH ( origin
)))
1571 cd
. when
= atoi ( argv
[ 2 ]);
1572 parse_foreach ( argv
[ 1 ], join_helper
, create_helper
, NULL
, NULL
, & cd
);
1576 static CMD_FUNC ( cmd_join
)
1578 struct create_desc cd
;
1580 if (!( cd
. user
= GetUserH ( origin
)))
1587 cd
. when
= atoi ( argv
[ 2 ]);
1588 parse_foreach ( argv
[ 1 ], join_helper
, create_helper
, NULL
, NULL
, & cd
);
1592 static CMD_FUNC ( cmd_svsjoin
)
1594 struct create_desc cd
;
1596 if (!( cd
. user
= GetUserH ( argv
[ 1 ])))
1603 cd
. when
= atoi ( argv
[ 3 ]);
1604 parse_foreach ( argv
[ 2 ], join_helper
, create_helper
, NULL
, NULL
, & cd
);
1608 static CMD_FUNC ( cmd_pong
)
1612 if (! strcmp ( argv
[ 2 ], self
-> name
)) {
1613 timeq_del ( 0 , timed_send_ping
, 0 , TIMEQ_IGNORE_WHEN
| TIMEQ_IGNORE_DATA
);
1614 timeq_del ( 0 , timed_ping_timeout
, 0 , TIMEQ_IGNORE_WHEN
| TIMEQ_IGNORE_DATA
);
1615 timeq_add ( now
+ ping_freq
, timed_send_ping
, 0 );
1621 static CMD_FUNC ( cmd_nick
)
1623 struct userNode
* user
;
1624 if (( user
= GetUserH ( origin
))) {
1625 /* nick change (since the source is a user numeric) */
1628 NickChange ( user
, argv
[ 1 ], 1 );
1630 struct server
* serv
;
1631 struct userNode
* nuser
;
1636 serv
= GetServerH ( origin
);
1638 unsplit_string ( argv
+ 6 , argc
- 9 , modes
);
1641 nuser
= AddUser ( serv
, argv
[ 1 ], argv
[ 4 ], argv
[ 5 ], modes
, argv
[ argc
- 2 ], argv
[ argc
- 1 ], atoi ( argv
[ 3 ]), argv
[ argc
- 3 ]);
1646 static CMD_FUNC ( cmd_account
)
1648 struct userNode
* user
;
1649 struct server
* server
;
1650 struct handle_info
* hi
;
1652 if (( argc
< 3 ) || ! origin
|| !( server
= GetServerH ( origin
)))
1653 return 0 ; /* Origin must be server. */
1655 /* This next line appears to tremple origin.. why? */
1656 user
= GetUserN ( argv
[ 1 ]);
1658 return 1 ; /* A QUIT probably passed the ACCOUNT. */
1660 if (! extended_accounts
) /* any need for this function without? */
1663 if (! strcmp ( argv
[ 2 ], "C" ))
1665 if (( hi
= loc_auth ( NULL
, argv
[ 4 ], argv
[ 5 ], NULL
)))
1668 putsock ( " %s " P10_ACCOUNT
" %s A %s " FMT_TIME_T
, self
-> numeric
, server
-> numeric
, argv
[ 3 ], hi
-> registered
);
1670 log_module ( MAIN_LOG
, LOG_DEBUG
, "loc_auth: %s \n " , user
-> nick
);
1675 putsock ( " %s " P10_ACCOUNT
" %s D %s " , self
-> numeric
, server
-> numeric
, argv
[ 3 ]);
1679 else if (! strcmp ( argv
[ 2 ], "H" )) /* New enhanced (host) version of C */
1681 if (( hi
= loc_auth ( NULL
, argv
[ 5 ], argv
[ 6 ], argv
[ 4 ] )))
1684 putsock ( " %s " P10_ACCOUNT
" %s A %s " FMT_TIME_T
, self
-> numeric
, server
-> numeric
, argv
[ 3 ], hi
-> registered
);
1689 putsock ( " %s " P10_ACCOUNT
" %s D %s " , self
-> numeric
, server
-> numeric
, argv
[ 3 ]);
1693 else if (! strcmp ( argv
[ 2 ], "S" ))
1695 if (( hi
= loc_auth ( argv
[ 5 ], argv
[ 6 ], argv
[ 7 ], argv
[ 4 ])))
1698 putsock ( " %s " P10_ACCOUNT
" %s A %s " FMT_TIME_T
, self
-> numeric
, server
-> numeric
, argv
[ 3 ], hi
-> registered
);
1703 putsock ( " %s " P10_ACCOUNT
" %s D %s " , self
-> numeric
, server
-> numeric
, argv
[ 3 ]);
1707 else if (! strcmp ( argv
[ 2 ], "R" ))
1708 call_account_func ( user
, argv
[ 3 ]);
1710 call_account_func ( user
, argv
[ 2 ]); /* For backward compatability */
1714 static CMD_FUNC ( cmd_fakehost
)
1716 struct userNode
* user
;
1718 if (( argc
< 3 ) || ! origin
|| ! GetServerH ( origin
))
1720 if (!( user
= GetUserN ( argv
[ 1 ])))
1722 assign_fakehost ( user
, argv
[ 2 ], 0 );
1730 #define P(priv) { #priv, PRIV_ ## priv }
1731 P ( CHAN_LIMIT
), P ( MODE_LCHAN
), P ( WALK_LCHAN
), P ( DEOP_LCHAN
),
1732 P ( SHOW_INVIS
), P ( SHOW_ALL_INVIS
), P ( UNLIMIT_QUERY
), P ( KILL
),
1733 P ( LOCAL_KILL
), P ( REHASH
), P ( RESTART
), P ( DIE
),
1734 P ( GLINE
), P ( LOCAL_GLINE
), P ( JUPE
), P ( LOCAL_JUPE
),
1735 P ( OPMODE
), P ( LOCAL_OPMODE
), P ( SET
), P ( WHOX
),
1736 P ( BADCHAN
), P ( LOCAL_BADCHAN
), P ( SEE_CHAN
), P ( PROPAGATE
),
1737 P ( DISPLAY
), P ( SEE_OPERS
), P ( WIDE_GLINE
), P ( FORCE_OPMODE
),
1738 P ( FORCE_LOCAL_OPMODE
), P ( REMOTEREHASH
), P ( CHECK
), P ( SEE_SECRET_CHAN
),
1739 P ( SHUN
), P ( LOCAL_SHUN
), P ( WIDE_SHUN
), P ( ZLINE
),
1740 P ( LOCAL_ZLINE
), P ( WIDE_ZLINE
), P ( LIST_CHAN
), P ( WHOIS_NOTICE
),
1741 P ( HIDE_IDLE
), P ( XTRAOP
), P ( HIDE_CHANNELS
), P ( DISPLAY_MODE
),
1742 P ( FREEFORM
), P ( REMOVE
), P ( SPAMFILTER
), P ( ADMIN
),
1743 P ( APASS_OPMODE
), P ( HIDE_OPER
), P ( REMOTE
), P ( SERVICE
),
1748 char * client_report_privs ( struct userNode
* client
)
1753 for ( i
= 0 ; privtab
[ i
]. name
; i
++) {
1754 if ( HasPriv ( client
, privtab
[ i
]. priv
)) {
1755 strcat ( privbuf
, privtab
[ i
]. name
);
1756 strcat ( privbuf
, " " );
1760 privbuf
[ strlen ( privbuf
)] = 0 ;
1765 int clear_privs ( struct userNode
* who
) {
1769 for ( i
= 0 ; privtab
[ i
]. name
; i
++)
1770 RevokePriv ( who
, privtab
[ i
]. priv
);
1775 int client_modify_priv_by_name ( struct userNode
* who
, char * priv
, int what
) {
1780 for ( i
= 0 ; privtab
[ i
]. name
; i
++) {
1781 if ( 0 == strcmp ( privtab
[ i
]. name
, priv
)) {
1782 if ( what
== PRIV_ADD
)
1783 GrantPriv ( who
, privtab
[ i
]. priv
);
1784 else if ( what
== PRIV_DEL
) {
1785 RevokePriv ( who
, privtab
[ i
]. priv
);
1792 int check_priv ( char * priv
)
1796 for ( i
= 0 ; privtab
[ i
]. name
; i
++) {
1797 if ( 0 == strcmp ( privtab
[ i
]. name
, priv
)) {
1805 irc_privs ( struct userNode
* target
, char * flag
, int add
)
1807 client_modify_priv_by_name ( target
, flag
, add
);
1808 putsock ( " %s " P10_PRIVS
" %s %s%s " , self
-> numeric
, target
-> numeric
, ( add
== PRIV_ADD
) ? "+" : "-" , flag
);
1812 irc_raw_privs ( struct userNode
* target
, const char * privs
)
1814 putsock ( " %s " P10_PRIVS
" %s %s " , self
-> numeric
, target
-> numeric
, privs
);
1817 static CMD_FUNC ( cmd_privs
)
1824 int what
= PRIV_ADD
;
1829 struct server
* sender
;
1830 struct userNode
* user
;
1833 tstr
= conf_get_data ( "server/type" , RECDB_QSTRING
);
1838 if (!( sender
= GetServerH ( origin
))) { /* from oper */
1839 return 1 ; /* ignore as no services have privs set */
1840 } else { /* from server */
1842 return 1 ; /* silently ignore */
1844 user
= argc
> 1 ? GetUserN ( argv
[ 1 ]) : NULL
;
1849 for ( i
= 1 ; i
< argc
; i
++) {
1850 strcat ( buf
, argv
[ i
]);
1854 for ( i
= 2 ; i
< argc
; i
++) {
1855 if (* argv
[ i
] == '+' ) { what
= PRIV_ADD
; argv
[ i
]++; }
1856 if (* argv
[ i
] == '-' ) { what
= PRIV_DEL
; argv
[ i
]++; }
1857 for ( tmp
= x3_strtok (& p
, argv
[ i
], "," ); tmp
;
1858 tmp
= x3_strtok (& p
, NULL
, "," )) {
1859 if (! strcmp ( tmp
, "PRIV_NONE" )) {
1860 if ( now
> user
-> timestamp
+ 5 )
1864 client_modify_priv_by_name ( user
, tmp
, what
);
1871 static CMD_FUNC ( cmd_burst
)
1874 char modes
[ MAXLEN
], * members
= "" ;
1875 static char exemptlist
[ MAXLEN
], banlist
[ MAXLEN
];
1876 unsigned int next
= 3 , res
= 1 ;
1877 int ctype
= 0 , echeck
= 0 , bcheck
= 0 ;
1878 struct chanData
* cData
;
1879 struct chanNode
* cNode
;
1880 struct userNode
* un
;
1881 struct modeNode
* mNode
;
1885 char * user
, * end
, sep
;
1887 time_t in_timestamp
;
1894 tstr
= conf_get_data ( "server/type" , RECDB_QSTRING
);
1902 while ( next
< argc
) {
1903 switch ( argv
[ next
][ 0 ]) {
1907 for ( pos
= argv
[ next
], n_modes
= 1 ; * pos
; pos
++)
1908 if ((* pos
== 'k' ) || (* pos
== 'l' ) || (* pos
== 'A' )
1909 || (* pos
== 'U' ) || (( type
> 7 ) && (* pos
== 'L' )))
1911 if ( next
+ n_modes
> argc
)
1912 n_modes
= argc
- next
;
1913 unsplit_string ( argv
+ next
, n_modes
, modes
);
1919 for ( parm
= mysep (& argv
[ next
], " " ); /* parm = first param */
1920 parm
; /* While param is not null */
1921 parm
= mysep (& argv
[ next
], " " ) /* parm = next param */
1924 if ( 0 == strcmp ( "~" , parm
))
1928 /* strip % char off start of very first ban */
1929 if ( strlen ( parm
) > 1 ) {
1930 strncat ( banlist
, strtok ( parm
, "%" ), sizeof ( banlist
) - 1 - strlen ( banlist
));
1931 strncat ( banlist
, " " , sizeof ( banlist
) - 1 - strlen ( banlist
));
1935 strncat ( banlist
, parm
, sizeof ( banlist
) - 1 - strlen ( banlist
));
1936 strncat ( banlist
, " " , sizeof ( banlist
) - 1 - strlen ( banlist
));
1938 } else if ( ctype
== 2 ) {
1942 strncat ( exemptlist
, parm
, sizeof ( exemptlist
) - 1 - strlen ( exemptlist
));
1943 strncat ( exemptlist
, " " , sizeof ( exemptlist
) - 1 - strlen ( exemptlist
));
1950 default : members
= argv
[ next
++]; break ;
1954 in_timestamp
= atoi ( argv
[ 2 ]);
1955 if (( cNode
= dict_find ( unbursted_channels
, argv
[ 1 ], NULL
))) {
1956 cNode
-> timestamp
= in_timestamp
;
1957 dict_remove ( unbursted_channels
, cNode
-> name
);
1960 cNode
= AddChannel ( argv
[ 1 ], in_timestamp
, modes
, banlist
, exemptlist
);
1961 cData
= cNode
-> channel_info
;
1964 if ( cNode
-> modes
& MODE_REGISTERED
) {
1965 irc_join ( opserv
, cNode
);
1966 irc_mode ( opserv
, cNode
, "-z" );
1967 irc_part ( opserv
, cNode
, "" );
1971 /* Burst channel members in now. */
1972 for ( user
= members
, sep
= * members
, mode
= 0 ; sep
; user
= end
) {
1973 for ( end
= user
+ 3 ; isalnum (* end
) || * end
== '[' || * end
== ']' ; end
++) ;
1974 sep
= * end
++; end
[- 1 ] = 0 ;
1977 while (( sep
= * end
++)) {
1979 mode
|= MODE_CHANOP
;
1981 } else if ( sep
== 'h' ) {
1982 mode
|= MODE_HALFOP
;
1984 } else if ( sep
== 'v' ) {
1987 } else if ( isdigit ( sep
)) {
1988 mode
|= MODE_CHANOP
;
1990 oplevel
+= parse_oplevel ( end
);
1992 oplevel
= parse_oplevel ( end
);
1993 while ( isdigit (* end
)) end
++;
2000 if (!( un
= GetUserN ( user
))) {
2004 if (( mNode
= AddChannelUser ( un
, cNode
))) {
2005 mNode
-> modes
= mode
;
2006 mNode
-> oplevel
= oplevel
;
2014 * This is a stub that doesn't actually do anything. It should be completed
2015 * so that bans on *!*@markname.* match users as it does in nefarious
2017 static CMD_FUNC ( cmd_mark
)
2021 struct userNode
* target
;
2023 * log_module(MAIN_LOG, LOG_ERROR, "DEBUG: mark, user %s, type %s, arg %s", argv[1], argv[2], argv[3]);
2026 tstr
= conf_get_data ( "server/type" , RECDB_QSTRING
);
2030 type
= 4 ; /* default to 040 style topics */
2034 if (! strcasecmp ( argv
[ 2 ], "DNSBL" )) {
2038 else if (! strcasecmp ( argv
[ 2 ], "DNSBL_DATA" ) || ! strcasecmp ( argv
[ 2 ], "MARK" )) {
2040 unsigned int ii
= 0 ;
2041 /* DNSBL_DATA name */
2042 target
= GetUserH ( argv
[ 1 ]);
2044 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find user %s whose dnsbl mark is changing." , argv
[ 1 ]);
2049 for ( ii
= 0 ; ii
< target
-> marks
-> used
; ii
++)
2050 if (! irccasecmp ( target
-> marks
-> list
[ ii
], argv
[ 3 ]))
2055 target
-> marks
= alloc_string_list ( 1 );
2056 string_list_append ( target
-> marks
, strdup ( argv
[ 3 ]));
2059 target
-> mark
= strdup ( argv
[ 3 ]);
2063 else if (! strcasecmp ( argv
[ 2 ], "CVERSION" )) {
2064 /* CTCP VERSION mark */
2065 target
= GetUserH ( argv
[ 1 ]);
2067 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find user %s whose version mark is changing." , argv
[ 1 ]);
2071 char * version
= unsplit_string ( argv
+ 3 , argc
- 3 , NULL
);
2075 target
-> version_reply
= strdup ( version
);
2077 if ( match_ircglob ( version
, "WebTV;*" ))
2078 target
-> no_notice
= true ; /* webbies cant see notices */
2082 else if (! strcasecmp ( argv
[ 2 ], "SSLCLIFP" )) {
2083 /* SSL fingerprint mark */
2084 target
= GetUserH ( argv
[ 1 ]);
2086 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find user %s whose SSL fingerprint mark is changing." , argv
[ 1 ]);
2090 char * sslfp
= unsplit_string ( argv
+ 3 , argc
- 3 , NULL
);
2094 target
-> sslfp
= strdup ( sslfp
);
2098 /* unknown type of mark */
2102 static CMD_FUNC ( cmd_mode
)
2104 struct chanNode
* cn
;
2105 struct userNode
* un
;
2106 char * sethost
; // sethost - reed/apples
2107 int i
; // sethost - reed/apples
2111 if (! IsChannelName ( argv
[ 1 ])) {
2112 un
= GetUserH ( argv
[ 1 ]);
2114 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find user %s whose mode is changing." , argv
[ 1 ]);
2117 // sethost - reed/apples
2119 mod_usermode ( un
, argv
[ 2 ]);
2121 sethost
= malloc ( strlen ( argv
[ 2 ]) + 1 + strlen ( argv
[ 3 ]) + 1 );
2123 while (( sethost
[ i
++] = * argv
[ 2 ]++));
2126 while (( sethost
[ i
++] = * argv
[ 3 ]++));
2127 mod_usermode ( un
, sethost
); // sethost - reed/apples
2133 if (!( cn
= GetChannel ( argv
[ 1 ]))) {
2134 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing." , argv
[ 1 ]);
2137 if (( un
= GetUserH ( origin
))) {
2138 struct modeNode
* mn
;
2139 /* Update idle time for person setting the mode */
2140 if (( mn
= GetUserMode ( cn
, un
)))
2141 mn
-> idle_since
= now
;
2143 /* If it came from a server, reset timestamp to re-sync. */
2144 cn
-> timestamp
= atoi ( argv
[ argc
- 1 ]);
2147 if ( checkDefCon ( DEFCON_NO_MODE_CHANGE
) && ! IsOper ( un
)) {
2149 str
= conf_get_data ( "services/opserv/nick" , RECDB_QSTRING
);
2151 char modes
[ MODELEN
];
2152 struct userNode
* opserv
= GetUserH ( str
);
2154 send_message_type ( 4 , un
, opserv
, "Channel modes cannot be changed due to DefCon level %d in effect, please try again soon" , DefConLevel
);
2155 irc_make_chanmode ( cn
, modes
);
2156 irc_mode ( opserv
, cn
, modes
);
2157 irc_mode ( opserv
, cn
, DefConChanModes
);
2163 return mod_chanmode ( un
, cn
, argv
+ 2 , argc
- 2 , MCP_ALLOW_OVB
| MCP_FROM_SERVER
|( un
? MC_NOTIFY
: 0 ));
2166 static CMD_FUNC ( cmd_opmode
)
2168 struct chanNode
* cn
;
2169 struct userNode
* un
;
2174 if (!( cn
= GetChannel ( argv
[ 1 ]))) {
2175 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing." , argv
[ 1 ]);
2178 if (!( un
= GetUserH ( origin
))) {
2179 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find user %s requesting OPMODE." , origin
);
2183 log_module ( MAIN_LOG
, LOG_ERROR
, "Non-privileged user %s using OPMODE." , un
-> nick
);
2187 return mod_chanmode ( un
, cn
, argv
+ 2 , argc
- 2 , MCP_ALLOW_OVB
| MCP_FROM_SERVER
); /* do NOT announce opmode locally */
2190 static int clear_chanmode ( struct chanNode
* channel
, const char * modes
);
2192 static CMD_FUNC ( cmd_clearmode
)
2194 struct chanNode
* cn
;
2195 struct userNode
* un
;
2200 if (!( cn
= GetChannel ( argv
[ 1 ]))) {
2201 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing." , argv
[ 1 ]);
2204 if (!( un
= GetUserH ( origin
))) {
2205 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find user %s requesting CLEARMODE." , origin
);
2209 log_module ( MAIN_LOG
, LOG_ERROR
, "Non-privileged user %s using CLEARMODE." , un
-> nick
);
2213 return clear_chanmode ( cn
, argv
[ 2 ]);
2216 static CMD_FUNC ( cmd_topic
)
2218 struct chanNode
* cn
;
2219 time_t chan_ts
, topic_ts
;
2220 struct userNode
* user
;
2224 if (!( cn
= GetChannel ( argv
[ 1 ]))) {
2225 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose topic is being set" , argv
[ 1 ]);
2230 if ( argc
== 5 ) { /* Asuka / Topic Bursting IRCu's */
2231 user
= GetUserH ( origin
);
2232 chan_ts
= atoi ( argv
[ 2 ]);
2233 topic_ts
= atoi ( argv
[ 3 ]);
2234 } else if ( argc
>= 6 ) { /* Nefarious 0.5.0 */
2235 user
= GetUserH ( strtok ( argv
[ 2 ], "!" ));
2236 chan_ts
= atoi ( argv
[ 3 ]);
2237 topic_ts
= atoi ( argv
[ 4 ]);
2238 } else { /* Regular IRCu (No Topic Bursting)*/
2239 user
= GetUserH ( origin
);
2240 chan_ts
= cn
-> timestamp
;
2244 SetChannelTopic ( cn
, user
, user
, argv
[ argc
- 1 ], 0 );
2245 cn
-> topic_time
= topic_ts
;
2249 static CMD_FUNC ( cmd_num_topic
)
2251 struct chanNode
* cn
;
2254 return 0 ; /* huh? */
2256 cn
= GetChannel ( argv
[ 2 ]);
2258 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s in topic reply" , argv
[ 2 ]);
2264 switch ( atoi ( argv
[ 0 ])) {
2267 break ; /* no topic */
2271 safestrncpy ( cn
-> topic
, unsplit_string ( argv
+ 3 , argc
- 3 , NULL
), sizeof ( cn
-> topic
));
2276 safestrncpy ( cn
-> topic_nick
, argv
[ 3 ], sizeof ( cn
-> topic_nick
));
2277 cn
-> topic_time
= atoi ( argv
[ 4 ]);
2280 return 0 ; /* should never happen */
2285 static CMD_FUNC ( cmd_num_gline
)
2291 gline_add ( origin
, argv
[ 3 ], atoi ( argv
[ 4 ])- now
, argv
[ 5 ], now
, 0 , 0 );
2293 if (! strcmp ( argv
[ 5 ], "+" ))
2294 gline_add ( origin
, argv
[ 3 ], atoi ( argv
[ 4 ])- now
, argv
[ 6 ], now
, 0 , 0 );
2299 static CMD_FUNC ( cmd_num_shun
)
2305 shun_add ( origin
, argv
[ 3 ], atoi ( argv
[ 4 ])- now
, argv
[ 5 ], now
, 0 );
2307 if (! strcmp ( argv
[ 5 ], "+" ))
2308 shun_add ( origin
, argv
[ 3 ], atoi ( argv
[ 4 ])- now
, argv
[ 6 ], now
, 0 );
2313 static CMD_FUNC ( cmd_quit
)
2315 struct userNode
* user
;
2318 /* Sometimes we get a KILL then a QUIT or the like, so we don't want to
2319 * call DelUser unless we have the user in our grasp. */
2320 if (( user
= GetUserH ( origin
)))
2321 DelUser ( user
, NULL
, false , argv
[ 1 ]);
2325 static CMD_FUNC ( cmd_kill
)
2327 struct userNode
* user
;
2330 user
= GetUserN ( argv
[ 1 ]);
2332 /* If we get a KILL for a non-existent user, it could be a
2333 * Ghost response to a KILL we sent out earlier. So we only
2334 * whine if the target is local.
2336 if (! strncmp ( argv
[ 1 ], self
-> numeric
, strlen ( self
-> numeric
))) {
2337 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to find kill victim %s " , argv
[ 1 ]);
2343 if ( IsLocal ( user
) && IsService ( user
)) {
2344 /* TODO: rate limit this so silly things don't happen. */
2345 ReintroduceUser ( user
);
2349 DelUser ( user
, NULL
, false , argv
[ 2 ]);
2353 static CMD_FUNC ( cmd_svspart
)
2355 struct userNode
* user
;
2359 user
= GetUserN ( argv
[ 1 ]);
2362 parse_foreach ( argv
[ 2 ], part_helper
, NULL
, NULL
, NULL
, user
);
2366 static CMD_FUNC ( cmd_silence
)
2368 struct userNode
* user
;
2376 if ( strncmp ( argv
[ 1 ], "*" , 2 ) == 0 )
2378 if (!( user
= GetUserH ( origin
))) {
2379 log_module ( MAIN_LOG
, LOG_ERROR
, "Could not find SILENCE origin user %s " , origin
);
2384 user
= GetUserN ( argv
[ 1 ]);
2386 /* Sanity, go nuts if this happens */
2390 /* We can safely ignore this if a user adding a silence is not
2391 * ignored. However this brings up a TODO. If a user logs in and
2392 * they have silences on the IRCd then we need to set them here
2395 if (! user
-> handle_info
)
2401 for ( i
= 0 ; i
< user
-> handle_info
-> ignores
-> used
; i
++) {
2402 if (! irccasecmp ( mask
+ 1 , user
-> handle_info
-> ignores
-> list
[ i
]))
2403 user
-> handle_info
-> ignores
-> list
[ i
] = user
-> handle_info
-> ignores
-> list
[-- user
-> handle_info
-> ignores
-> used
];
2406 for ( i
= 0 ; i
< user
-> handle_info
-> ignores
-> used
; i
++) {
2407 if (! strcmp ( mask
+ 1 , user
-> handle_info
-> ignores
-> list
[ i
]))
2408 return 1 ; /* Already on the users NickServ ignore list, safely ignore */
2411 new_mask
= strdup ( mask
+ 1 );
2412 string_list_append ( user
-> handle_info
-> ignores
, new_mask
);
2417 static CMD_FUNC ( cmd_kick
)
2421 ChannelUserKicked ( GetUserH ( origin
), GetUserN ( argv
[ 2 ]), GetChannel ( argv
[ 1 ]));
2425 static CMD_FUNC ( cmd_squit
)
2427 struct server
* server
;
2432 if (!( server
= GetServerH ( argv
[ 1 ])))
2435 if ( server
== self
-> uplink
) {
2436 /* Force a reconnect to the currently selected server. */
2437 cManager
. uplink
-> tries
= 0 ;
2438 log_module ( MAIN_LOG
, LOG_INFO
, "Squitting from uplink: %s " , argv
[ 3 ]);
2443 uplink
= strdup ( server
-> uplink
-> name
);
2444 DelServer ( server
, 0 , argv
[ 3 ]);
2445 /* if its a pingout and pingout connecting is enabled
2446 or its a read error and readerror connecting is enabled
2447 or were doing a "N" and i need to connect that server somewhere */
2448 routing_handle_squit ( argv
[ 1 ], uplink
, argv
[ 3 ]);
2453 static CMD_FUNC ( cmd_privmsg
)
2455 struct privmsg_desc pd
;
2458 pd
. user
= GetUserH ( origin
);
2459 if (! pd
. user
|| ( IsGagged ( pd
. user
) && ! IsOper ( pd
. user
)))
2462 if ( checkDefCon ( DEFCON_OPER_ONLY
) && ! IsOper ( pd
. user
)) {
2464 str
= conf_get_data ( "services/opserv/nick" , RECDB_QSTRING
);
2466 send_message_type ( 4 , pd
. user
, GetUserH ( str
), "Services are currently not available, please try again soon" );
2470 if ( checkDefCon ( DEFCON_SILENT_OPER_ONLY
) && ! IsOper ( pd
. user
))
2471 return 1 ; /* Silently Ignore */
2474 pd
. text
= argv
[ argc
- 1 ];
2475 parse_foreach ( argv
[ 1 ], privmsg_chan_helper
, NULL
, privmsg_user_helper
, privmsg_invalid
, & pd
);
2480 static CMD_FUNC ( cmd_notice
)
2482 struct privmsg_desc pd
;
2489 pd
. user
= GetUserH ( origin
);
2492 if (! pd
. user
|| ( IsGagged ( pd
. user
) && ! IsOper ( pd
. user
))) {
2497 parse_foreach ( argv
[ 1 ], privmsg_chan_helper
, NULL
, privmsg_user_helper
, privmsg_invalid
, & pd
);
2500 srv
= GetServerH ( origin
);
2502 char * sargv
[ MAXNUMPARAMS
];
2505 sargc
= split_line ( argv
[ 2 ], true , MAXNUMPARAMS
, sargv
);
2507 if (! strcasecmp ( sargv
[ 0 ], "Connect:" )) {
2508 /* :Connect: Host shoe.loxxin.net not listed in ircd.conf */
2509 if (! strcasecmp ( sargv
[ 3 ], "not" ) && ! strcasecmp ( sargv
[ 4 ], "listed" )) {
2510 routing_handle_connect_failure ( srv
, sargv
[ 2 ], unsplit_string ( sargv
+ 3 , sargc
- 3 , NULL
));
2513 else if (! strcasecmp ( sargv
[ 0 ], "Link" )) {
2514 /* :Link with mephisto.etheria.cx cancelled: Server mephisto.etheria.cx[216.46.33.71]
2516 * :Link with laptop.afternet.org cancelled: Connection refused
2518 if (! strcasecmp ( sargv
[ 3 ], "cancelled:" )) {
2519 routing_handle_connect_failure ( srv
, sargv
[ 2 ], unsplit_string ( sargv
+ 4 , sargc
- 4 , NULL
));
2526 static CMD_FUNC ( cmd_away
)
2528 struct userNode
* uNode
;
2530 uNode
= GetUserH ( origin
);
2534 uNode
-> modes
&= ~ FLAGS_AWAY
;
2536 uNode
-> modes
|= FLAGS_AWAY
;
2540 static CMD_FUNC ( cmd_gline
)
2544 if ( argv
[ 2 ][ 0 ] == '+' ) {
2547 gline_add ( origin
, argv
[ 2 ]+ 1 , strtoul ( argv
[ 3 ], NULL
, 0 ), argv
[ argc
- 1 ], now
, 0 , 0 );
2549 } else if ( argv
[ 2 ][ 0 ] == '-' ) {
2550 gline_remove ( argv
[ 2 ]+ 1 , 0 );
2556 static CMD_FUNC ( cmd_sgline
)
2558 struct server
* sender
;
2563 if (!( sender
= GetServerH ( origin
)))
2566 gline_add ( origin
, argv
[ 1 ], strtoul ( argv
[ 2 ], NULL
, 0 ), argv
[ argc
- 1 ], now
, 1 , 0 );
2570 static CMD_FUNC ( cmd_sshun
)
2572 struct server
* sender
;
2577 if (!( sender
= GetServerH ( origin
)))
2580 shun_add ( origin
, argv
[ 1 ], strtoul ( argv
[ 2 ], NULL
, 0 ), argv
[ argc
- 1 ], now
, 1 );
2584 static CMD_FUNC ( cmd_shun
)
2588 if ( argv
[ 2 ][ 0 ] == '+' ) {
2591 shun_add ( origin
, argv
[ 2 ]+ 1 , strtoul ( argv
[ 3 ], NULL
, 0 ), argv
[ argc
- 1 ], now
, 0 );
2593 } else if ( argv
[ 2 ][ 0 ] == '-' ) {
2594 shun_remove ( argv
[ 2 ]+ 1 , 0 );
2600 static CMD_FUNC ( cmd_svsnick
)
2602 struct userNode
* target
, * dest
;
2604 || !( target
= GetUserN ( argv
[ 1 ]))
2606 || ( dest
= GetUserH ( argv
[ 2 ])))
2608 NickChange ( target
, argv
[ 2 ], 0 );
2613 free_user ( struct userNode
* user
)
2620 parse_cleanup ( UNUSED_ARG ( void * extra
))
2624 free ( of_list_extra
);
2625 free ( privmsg_funcs
);
2626 num_privmsg_funcs
= 0 ;
2628 num_notice_funcs
= 0 ;
2630 dict_delete ( irc_func_dict
);
2631 for ( nn
= 0 ; nn
< dead_users
. used
; nn
++)
2632 free_user ( dead_users
. list
[ nn
]);
2633 userList_clean (& dead_users
);
2637 p10_conf_reload ( void ) {
2638 hidden_host_suffix
= conf_get_data ( "server/hidden_host" , RECDB_QSTRING
);
2639 his_servername
= conf_get_data ( "server/his_servername" , RECDB_QSTRING
);
2640 his_servercomment
= conf_get_data ( "server/his_servercomment" , RECDB_QSTRING
);
2644 remove_unbursted_channel ( struct chanNode
* cNode
, UNUSED_ARG ( void * extra
)) {
2645 if ( unbursted_channels
)
2646 dict_remove ( unbursted_channels
, cNode
-> name
);
2652 const char * str
, * desc
;
2653 int numnick
, usermask
, max_users
;
2654 char numer
[ COMBO_NUMERIC_LEN
+ 1 ];
2656 /* read config items */
2657 str
= conf_get_data ( "server/extended_accounts" , RECDB_QSTRING
);
2658 extended_accounts
= str
? enabled_string ( str
) : 1 ;
2659 str
= conf_get_data ( "server/ping_freq" , RECDB_QSTRING
);
2660 ping_freq
= str
? ParseInterval ( str
) : 120 ;
2661 str
= conf_get_data ( "server/ping_timeout" , RECDB_QSTRING
);
2662 ping_timeout
= str
? ParseInterval ( str
) : 30 ;
2663 str
= conf_get_data ( "server/force_n2k" , RECDB_QSTRING
);
2664 force_n2k
= str
? enabled_string ( str
) : 1 ;
2665 str
= conf_get_data ( "server/numeric" , RECDB_QSTRING
);
2667 log_module ( MAIN_LOG
, LOG_ERROR
, "No server/numeric entry in config file." );
2670 numnick
= atoi ( str
);
2671 str
= conf_get_data ( "server/max_users" , RECDB_QSTRING
);
2672 max_users
= str
? atoi ( str
) : 4096 ;
2673 for ( usermask
= 4 ; usermask
< max_users
; usermask
<<= 1 ) ;
2675 if (( numnick
< 64 ) && ( usermask
< 4096 ) && ! force_n2k
)
2676 inttobase64 ( numer
, ( numnick
<< 12 ) + ( usermask
& 0x00fff ), 3 );
2678 inttobase64 ( numer
, ( numnick
<< 18 ) + ( usermask
& 0x3ffff ), 5 );
2680 str
= conf_get_data ( "server/hostname" , RECDB_QSTRING
);
2681 desc
= conf_get_data ( "server/description" , RECDB_QSTRING
);
2682 if (! str
|| ! desc
) {
2683 log_module ( MAIN_LOG
, LOG_ERROR
, "No server/hostname entry in config file." );
2686 self
= AddServer ( NULL
, str
, 0 , boot_time
, now
, numer
, desc
);
2687 conf_register_reload ( p10_conf_reload
);
2689 irc_func_dict
= dict_new ();
2690 dict_insert ( irc_func_dict
, CMD_BURST
, cmd_burst
);
2691 dict_insert ( irc_func_dict
, TOK_BURST
, cmd_burst
);
2692 dict_insert ( irc_func_dict
, CMD_CREATE
, cmd_create
);
2693 dict_insert ( irc_func_dict
, TOK_CREATE
, cmd_create
);
2694 dict_insert ( irc_func_dict
, CMD_EOB
, cmd_eob
);
2695 dict_insert ( irc_func_dict
, TOK_EOB
, cmd_eob
);
2696 dict_insert ( irc_func_dict
, CMD_EOB_ACK
, cmd_eob_ack
);
2697 dict_insert ( irc_func_dict
, TOK_EOB_ACK
, cmd_eob_ack
);
2698 dict_insert ( irc_func_dict
, CMD_MODE
, cmd_mode
);
2699 dict_insert ( irc_func_dict
, TOK_MODE
, cmd_mode
);
2700 dict_insert ( irc_func_dict
, CMD_MARK
, cmd_mark
);
2701 dict_insert ( irc_func_dict
, TOK_MARK
, cmd_mark
);
2702 dict_insert ( irc_func_dict
, CMD_NICK
, cmd_nick
);
2703 dict_insert ( irc_func_dict
, TOK_NICK
, cmd_nick
);
2704 dict_insert ( irc_func_dict
, CMD_ACCOUNT
, cmd_account
);
2705 dict_insert ( irc_func_dict
, TOK_ACCOUNT
, cmd_account
);
2706 dict_insert ( irc_func_dict
, CMD_FAKEHOST
, cmd_fakehost
);
2707 dict_insert ( irc_func_dict
, TOK_FAKEHOST
, cmd_fakehost
);
2708 dict_insert ( irc_func_dict
, CMD_PASS
, cmd_pass
);
2709 dict_insert ( irc_func_dict
, TOK_PASS
, cmd_pass
);
2710 dict_insert ( irc_func_dict
, CMD_PING
, cmd_ping
);
2711 dict_insert ( irc_func_dict
, TOK_PING
, cmd_ping
);
2712 dict_insert ( irc_func_dict
, CMD_PRIVMSG
, cmd_privmsg
);
2713 dict_insert ( irc_func_dict
, TOK_PRIVMSG
, cmd_privmsg
);
2714 dict_insert ( irc_func_dict
, CMD_PONG
, cmd_pong
);
2715 dict_insert ( irc_func_dict
, TOK_PONG
, cmd_pong
);
2716 dict_insert ( irc_func_dict
, CMD_QUIT
, cmd_quit
);
2717 dict_insert ( irc_func_dict
, TOK_QUIT
, cmd_quit
);
2718 dict_insert ( irc_func_dict
, CMD_SERVER
, cmd_server
);
2719 dict_insert ( irc_func_dict
, TOK_SERVER
, cmd_server
);
2720 dict_insert ( irc_func_dict
, CMD_JOIN
, cmd_join
);
2721 dict_insert ( irc_func_dict
, TOK_JOIN
, cmd_join
);
2722 dict_insert ( irc_func_dict
, CMD_PART
, cmd_part
);
2723 dict_insert ( irc_func_dict
, TOK_PART
, cmd_part
);
2724 dict_insert ( irc_func_dict
, CMD_ERROR
, cmd_error
);
2725 dict_insert ( irc_func_dict
, TOK_ERROR
, cmd_error
);
2726 dict_insert ( irc_func_dict
, CMD_TOPIC
, cmd_topic
);
2727 dict_insert ( irc_func_dict
, TOK_TOPIC
, cmd_topic
);
2728 dict_insert ( irc_func_dict
, CMD_AWAY
, cmd_away
);
2729 dict_insert ( irc_func_dict
, TOK_AWAY
, cmd_away
);
2730 dict_insert ( irc_func_dict
, CMD_SILENCE
, cmd_silence
);
2731 dict_insert ( irc_func_dict
, TOK_SILENCE
, cmd_silence
);
2732 dict_insert ( irc_func_dict
, CMD_KICK
, cmd_kick
);
2733 dict_insert ( irc_func_dict
, TOK_KICK
, cmd_kick
);
2734 dict_insert ( irc_func_dict
, CMD_SQUIT
, cmd_squit
);
2735 dict_insert ( irc_func_dict
, TOK_SQUIT
, cmd_squit
);
2736 dict_insert ( irc_func_dict
, CMD_KILL
, cmd_kill
);
2737 dict_insert ( irc_func_dict
, TOK_KILL
, cmd_kill
);
2738 dict_insert ( irc_func_dict
, CMD_NOTICE
, cmd_notice
);
2739 dict_insert ( irc_func_dict
, TOK_NOTICE
, cmd_notice
);
2740 dict_insert ( irc_func_dict
, CMD_STATS
, cmd_stats
);
2741 dict_insert ( irc_func_dict
, TOK_STATS
, cmd_stats
);
2742 dict_insert ( irc_func_dict
, CMD_SVSJOIN
, cmd_svsjoin
);
2743 dict_insert ( irc_func_dict
, TOK_SVSJOIN
, cmd_svsjoin
);
2744 dict_insert ( irc_func_dict
, CMD_SVSNICK
, cmd_svsnick
);
2745 dict_insert ( irc_func_dict
, TOK_SVSNICK
, cmd_svsnick
);
2746 dict_insert ( irc_func_dict
, CMD_SVSPART
, cmd_svspart
);
2747 dict_insert ( irc_func_dict
, TOK_SVSPART
, cmd_svspart
);
2748 dict_insert ( irc_func_dict
, CMD_SWHOIS
, cmd_dummy
);
2749 dict_insert ( irc_func_dict
, TOK_SWHOIS
, cmd_dummy
);
2750 dict_insert ( irc_func_dict
, CMD_TEMPSHUN
, cmd_dummy
);
2751 dict_insert ( irc_func_dict
, TOK_TEMPSHUN
, cmd_dummy
);
2752 dict_insert ( irc_func_dict
, CMD_WHOIS
, cmd_whois
);
2753 dict_insert ( irc_func_dict
, TOK_WHOIS
, cmd_whois
);
2754 dict_insert ( irc_func_dict
, CMD_GLINE
, cmd_gline
);
2755 dict_insert ( irc_func_dict
, TOK_GLINE
, cmd_gline
);
2756 dict_insert ( irc_func_dict
, CMD_SGLINE
, cmd_sgline
);
2757 dict_insert ( irc_func_dict
, TOK_SGLINE
, cmd_sgline
);
2758 dict_insert ( irc_func_dict
, CMD_SHUN
, cmd_shun
);
2759 dict_insert ( irc_func_dict
, TOK_SHUN
, cmd_shun
);
2760 dict_insert ( irc_func_dict
, CMD_SSHUN
, cmd_sshun
);
2761 dict_insert ( irc_func_dict
, TOK_SSHUN
, cmd_sshun
);
2762 dict_insert ( irc_func_dict
, CMD_OPMODE
, cmd_opmode
);
2763 dict_insert ( irc_func_dict
, TOK_OPMODE
, cmd_opmode
);
2764 dict_insert ( irc_func_dict
, CMD_CLEARMODE
, cmd_clearmode
);
2765 dict_insert ( irc_func_dict
, TOK_CLEARMODE
, cmd_clearmode
);
2766 dict_insert ( irc_func_dict
, CMD_VERSION
, cmd_version
);
2767 dict_insert ( irc_func_dict
, TOK_VERSION
, cmd_version
);
2768 dict_insert ( irc_func_dict
, CMD_ADMIN
, cmd_admin
);
2769 dict_insert ( irc_func_dict
, TOK_ADMIN
, cmd_admin
);
2770 dict_insert ( irc_func_dict
, CMD_SMO
, cmd_dummy
);
2771 dict_insert ( irc_func_dict
, TOK_SMO
, cmd_dummy
);
2772 dict_insert ( irc_func_dict
, CMD_SNO
, cmd_dummy
);
2773 dict_insert ( irc_func_dict
, TOK_SNO
, cmd_dummy
);
2775 dict_insert ( irc_func_dict
, CMD_RPING
, cmd_rping
);
2776 dict_insert ( irc_func_dict
, TOK_RPING
, cmd_rping
);
2777 dict_insert ( irc_func_dict
, CMD_RPONG
, cmd_dummy
);
2778 dict_insert ( irc_func_dict
, TOK_RPONG
, cmd_dummy
);
2780 dict_insert ( irc_func_dict
, CMD_SASL
, cmd_sasl
);
2781 dict_insert ( irc_func_dict
, TOK_SASL
, cmd_sasl
);
2783 /* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
2784 * Apparently to obliterate channels from any servers that think they
2787 dict_insert ( irc_func_dict
, CMD_DESTRUCT
, cmd_dummy
);
2788 dict_insert ( irc_func_dict
, TOK_DESTRUCT
, cmd_dummy
);
2789 /* Ignore invites */
2790 dict_insert ( irc_func_dict
, CMD_INVITE
, cmd_dummy
);
2791 dict_insert ( irc_func_dict
, TOK_INVITE
, cmd_dummy
);
2792 /* DESYNCH is just informational, so ignore it */
2793 dict_insert ( irc_func_dict
, CMD_DESYNCH
, cmd_dummy
);
2794 dict_insert ( irc_func_dict
, TOK_DESYNCH
, cmd_dummy
);
2795 /* Ignore channel operator notices. */
2796 dict_insert ( irc_func_dict
, CMD_WALLCHOPS
, cmd_dummy
);
2797 dict_insert ( irc_func_dict
, TOK_WALLCHOPS
, cmd_dummy
);
2798 dict_insert ( irc_func_dict
, CMD_WALLVOICES
, cmd_dummy
);
2799 dict_insert ( irc_func_dict
, TOK_WALLVOICES
, cmd_dummy
);
2800 dict_insert ( irc_func_dict
, CMD_WALLHOPS
, cmd_dummy
);
2801 dict_insert ( irc_func_dict
, TOK_WALLHOPS
, cmd_dummy
);
2802 /* Ignore opers being silly. */
2803 dict_insert ( irc_func_dict
, CMD_WALLOPS
, cmd_dummy
);
2804 dict_insert ( irc_func_dict
, TOK_WALLOPS
, cmd_dummy
);
2805 dict_insert ( irc_func_dict
, CMD_WALLHOPS
, cmd_dummy
);
2806 dict_insert ( irc_func_dict
, TOK_WALLHOPS
, cmd_dummy
);
2807 dict_insert ( irc_func_dict
, TOK_WALLUSERS
, cmd_dummy
);
2808 /* Ignore dnsbl exemptions */
2809 dict_insert ( irc_func_dict
, TOK_EXEMPT
, cmd_dummy
);
2810 dict_insert ( irc_func_dict
, CMD_PRIVS
, cmd_privs
);
2811 dict_insert ( irc_func_dict
, TOK_PRIVS
, cmd_privs
);
2812 /* ignore ALIST for now */
2813 dict_insert ( irc_func_dict
, TOK_ALIST
, cmd_dummy
);
2814 dict_insert ( irc_func_dict
, CMD_ALIST
, cmd_dummy
);
2815 /* ignore SPAMFILTER */
2816 dict_insert ( irc_func_dict
, TOK_SPAMFILTER
, cmd_dummy
);
2817 dict_insert ( irc_func_dict
, CMD_SPAMFILTER
, cmd_dummy
);
2818 /* Ignore remote luser */
2819 dict_insert ( irc_func_dict
, TOK_LUSERS
, cmd_dummy
);
2820 /* We have reliable clock! Always! Wraaa! */
2821 dict_insert ( irc_func_dict
, CMD_SETTIME
, cmd_dummy
);
2822 dict_insert ( irc_func_dict
, TOK_SETTIME
, cmd_dummy
);
2823 /* Ignore ZLINE/ZL/REMOVE/RM */
2824 dict_insert ( irc_func_dict
, CMD_ZLINE
, cmd_dummy
);
2825 dict_insert ( irc_func_dict
, TOK_ZLINE
, cmd_dummy
);
2826 dict_insert ( irc_func_dict
, CMD_REMOVE
, cmd_dummy
);
2827 dict_insert ( irc_func_dict
, TOK_REMOVE
, cmd_dummy
);
2829 /* ignore /trace and /motd commands targetted at us */
2830 dict_insert ( irc_func_dict
, TOK_TRACE
, cmd_dummy
);
2831 dict_insert ( irc_func_dict
, TOK_MOTD
, cmd_dummy
);
2832 dict_insert ( irc_func_dict
, TOK_UPING
, cmd_dummy
);
2835 dict_insert ( irc_func_dict
, "331" , cmd_num_topic
);
2836 dict_insert ( irc_func_dict
, "332" , cmd_num_topic
);
2837 dict_insert ( irc_func_dict
, "333" , cmd_num_topic
);
2838 dict_insert ( irc_func_dict
, "345" , cmd_dummy
); /* blah has been invited to blah */
2839 dict_insert ( irc_func_dict
, "432" , cmd_error_nick
); /* Erroneus [sic] nickname */
2840 /* ban list resetting */
2841 /* "stats g" responses */
2842 dict_insert ( irc_func_dict
, "230" , cmd_dummy
); /* ignore stats headers */
2843 dict_insert ( irc_func_dict
, "247" , cmd_num_gline
);
2844 dict_insert ( irc_func_dict
, "542" , cmd_num_shun
);
2845 dict_insert ( irc_func_dict
, "219" , cmd_dummy
); /* "End of /STATS report" */
2846 /* other numeric responses we might get */
2847 dict_insert ( irc_func_dict
, "401" , cmd_dummy
); /* target left network */
2848 dict_insert ( irc_func_dict
, "403" , cmd_dummy
); /* no such channel */
2849 dict_insert ( irc_func_dict
, "404" , cmd_dummy
); /* cannot send to channel */
2850 dict_insert ( irc_func_dict
, "439" , cmd_dummy
); /* target change too fast */
2851 dict_insert ( irc_func_dict
, "441" , cmd_dummy
); /* target isn't on that channel */
2852 dict_insert ( irc_func_dict
, "442" , cmd_dummy
); /* you aren't on that channel */
2853 dict_insert ( irc_func_dict
, "443" , cmd_dummy
); /* is already on channel (after invite?) */
2854 dict_insert ( irc_func_dict
, "461" , cmd_dummy
); /* Not enough parameters (after TOPIC w/ 0 args) */
2855 dict_insert ( irc_func_dict
, "467" , cmd_dummy
); /* Channel key already set */
2857 num_privmsg_funcs
= 16 ;
2858 privmsg_funcs
= malloc ( sizeof ( privmsg_func_t
)* num_privmsg_funcs
);
2859 memset ( privmsg_funcs
, 0 , sizeof ( privmsg_func_t
)* num_privmsg_funcs
);
2861 num_notice_funcs
= 16 ;
2862 notice_funcs
= malloc ( sizeof ( privmsg_func_t
)* num_notice_funcs
);
2863 memset ( notice_funcs
, 0 , sizeof ( privmsg_func_t
)* num_notice_funcs
);
2865 userList_init (& dead_users
);
2866 reg_del_channel_func ( remove_unbursted_channel
, NULL
);
2867 reg_exit_func ( parse_cleanup
, NULL
);
2868 // reg_notice_func(opserv, check_ctcp);
2872 parse_line ( char * line
, int recursive
)
2874 char * argv
[ MAXNUMPARAMS
], * origin
;
2875 int argc
, cmd
, res
= 0 ;
2878 argc
= split_line ( line
, true , MAXNUMPARAMS
, argv
);
2879 cmd
= self
-> uplink
|| ! argv
[ 0 ][ 1 ] || ! argv
[ 0 ][ 2 ];
2882 if ( argv
[ 0 ][ 0 ] == ':' ) {
2884 } else if (! argv
[ 0 ][ 1 ] || ! argv
[ 0 ][ 2 ]) {
2885 struct server
* sNode
= GetServerN ( argv
[ 0 ]);
2886 origin
= sNode
? sNode
-> name
: 0 ;
2888 struct userNode
* uNode
= GetUserN ( argv
[ 0 ]);
2889 origin
= uNode
? uNode
-> nick
: 0 ;
2893 if (( func
= dict_find ( irc_func_dict
, argv
[ cmd
], NULL
)))
2894 res
= func ( origin
, argc
- cmd
, argv
+ cmd
);
2897 log_module ( MAIN_LOG
, LOG_ERROR
, "PARSE ERROR on line: %s " , unsplit_string ( argv
, argc
, NULL
));
2898 } else if (! recursive
) {
2900 for ( i
= 0 ; i
< dead_users
. used
; i
++)
2901 free_user ( dead_users
. list
[ i
]);
2902 dead_users
. used
= 0 ;
2908 parse_foreach ( char * target_list
, foreach_chanfunc cf
, foreach_nonchan nc
, foreach_userfunc uf
, foreach_nonuser nu
, void * data
)
2914 while (* j
!= 0 && * j
!= ',' )
2919 if ( IsChannelName ( target_list
)
2920 || ( target_list
[ 0 ] == '0' && target_list
[ 1 ] == '\0' )) {
2921 struct chanNode
* chan
= GetChannel ( target_list
);
2928 nc ( target_list
, data
);
2931 struct userNode
* user
;
2932 struct privmsg_desc
* pd
= data
;
2934 pd
-> is_qualified
= 0 ;
2935 if (* target_list
== '@' ) {
2937 } else if ( strchr ( target_list
, '@' )) {
2938 struct server
* server
;
2940 pd
-> is_qualified
= 1 ;
2941 user
= GetUserH ( strtok ( target_list
, "@" ));
2942 server
= GetServerH ( strtok ( NULL
, "@" ));
2944 if ( user
&& ( user
-> uplink
!= server
)) {
2945 /* Don't attempt to index into any arrays
2946 using a user's numeric on another server. */
2950 user
= GetUserN ( target_list
);
2958 nu ( target_list
, data
);
2962 } while ( old
== ',' );
2966 get_local_numeric ( void )
2968 static unsigned int next_numeric
= 0 ;
2969 if ( self
-> clients
> self
-> num_mask
)
2971 while ( self
-> users
[ next_numeric
])
2972 if (++ next_numeric
> self
-> num_mask
)
2974 return next_numeric
;
2978 make_numeric ( struct server
* svr
, int local_num
, char * outbuf
)
2982 if ( force_n2k
|| svr
-> numeric
[ 1 ]) {
2987 llen
= ( local_num
< 64 * 64 ) ? 2 : 3 ;
2989 strncpy ( outbuf
, svr
-> numeric
, slen
);
2990 inttobase64 ( outbuf
+ slen
, local_num
, llen
);
2991 outbuf
[ slen
+ llen
] = 0 ;
2995 AddServer ( struct server
* uplink
, const char * name
, int hops
, time_t boot
, time_t link_time
, const char * numeric
, const char * description
)
2997 struct server
* sNode
;
3000 if (( sNode
= GetServerN ( numeric
))) {
3001 /* This means we're trying to re-add an existant server.
3002 * To be safe, we should forget the previous incarnation.
3003 * (And all its linked servers.)
3005 * It usually only happens in replays when the original
3006 * had a ping timeout and the replay didn't (because
3007 * replaying a ping timeout invariably gets things wrong).
3009 DelServer ( sNode
, 0 , NULL
);
3012 switch ( strlen ( numeric
)) {
3013 case 5 : slen
= 2 ; mlen
= 3 ; break ;
3014 case 4 : slen
= 1 ; mlen
= 3 ; break ;
3015 case 3 : slen
= 1 ; mlen
= 2 ; break ;
3017 log_module ( MAIN_LOG
, LOG_ERROR
, "AddServer( \" %s \" , \" %s \" , ...): Numeric %s has invalid length." , uplink
-> name
, name
, numeric
);
3021 sNode
= calloc ( 1 , sizeof (* sNode
));
3022 sNode
-> uplink
= uplink
;
3023 safestrncpy ( sNode
-> name
, name
, sizeof ( sNode
-> name
));
3024 sNode
-> num_mask
= base64toint ( numeric
+ slen
, mlen
);
3027 sNode
-> link_time
= link_time
;
3028 strncpy ( sNode
-> numeric
, numeric
, slen
);
3029 safestrncpy ( sNode
-> description
, description
, sizeof ( sNode
-> description
));
3030 sNode
-> users
= calloc ( sNode
-> num_mask
+ 1 , sizeof (* sNode
-> users
));
3031 serverList_init (& sNode
-> children
);
3032 if ( sNode
-> uplink
) {
3033 /* uplink may be NULL if we're just building ourself */
3034 serverList_append (& sNode
-> uplink
-> children
, sNode
);
3036 servers_num
[ base64toint ( numeric
, slen
)] = sNode
;
3037 dict_insert ( servers
, sNode
-> name
, sNode
);
3041 void DelServer ( struct server
* serv
, int announce
, const char * message
)
3045 /* If we receive an ERROR command before the SERVER
3046 * command a NULL server can be passed */
3050 /* Hrm, what's the right way to SQUIT some other server?
3051 * (This code is only to handle killing juped servers.) */
3052 if ( announce
&& ( serv
-> uplink
== self
) && ( serv
!= self
-> uplink
))
3053 irc_squit ( serv
, message
, NULL
);
3055 /* must recursively remove servers linked to this one first */
3056 for ( i
= serv
-> children
. used
; i
> 0 ;)
3057 if ( serv
-> children
. list
[-- i
] != self
)
3058 DelServer ( serv
-> children
. list
[ i
], false , NULL
);
3060 /* clean up server's user hash tables */
3061 for ( i
= 0 ; i
<= serv
-> num_mask
; i
++)
3063 DelUser ( serv
-> users
[ i
], NULL
, false , "server delinked" );
3067 serverList_remove (& serv
-> uplink
-> children
, serv
);
3068 if ( serv
== self
-> uplink
)
3069 self
-> uplink
= NULL
;
3070 servers_num
[ base64toint ( serv
-> numeric
, strlen ( serv
-> numeric
))] = NULL
;
3071 dict_remove ( servers
, serv
-> name
);
3072 serverList_clean (& serv
-> children
);
3078 AddLocalUser ( const char * nick
, const char * ident
, const char * hostname
, const char * desc
, const char * modes
)
3080 char numeric
[ COMBO_NUMERIC_LEN
+ 1 ];
3081 int local_num
= get_local_numeric ();
3082 time_t timestamp
= now
;
3083 struct userNode
* old_user
= GetUserH ( nick
);
3089 if ( IsLocal ( old_user
))
3091 timestamp
= old_user
-> timestamp
- 1 ;
3093 if ( local_num
== - 1 ) {
3094 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to allocate numnick for service %s " , nick
);
3098 hostname
= self
-> name
;
3099 make_numeric ( self
, local_num
, numeric
);
3100 return AddUser ( self
, nick
, ident
, hostname
, modes
, numeric
, desc
, timestamp
, "AAAAAA" );
3104 AddClone ( const char * nick
, const char * ident
, const char * hostname
, const char * desc
)
3106 char numeric
[ COMBO_NUMERIC_LEN
+ 1 ];
3107 int local_num
= get_local_numeric ();
3108 time_t timestamp
= now
;
3109 struct userNode
* old_user
= GetUserH ( nick
);
3112 if ( IsLocal ( old_user
))
3114 timestamp
= old_user
-> timestamp
- 1 ;
3116 if ( local_num
== - 1 ) {
3117 log_module ( MAIN_LOG
, LOG_ERROR
, "Unable to allocate numnick for clone %s " , nick
);
3120 make_numeric ( self
, local_num
, numeric
);
3121 return AddUser ( self
, nick
, ident
, hostname
, "+i" , numeric
, desc
, timestamp
, "AAAAAA" );
3125 is_valid_nick ( const char * nick
) {
3127 /* IRC has some of The Most Fucked-Up ideas about character sets
3129 if (! isalpha (* nick
) && ! strchr ( "{|}~[ \\ ]^_`" , * nick
))
3131 for ( ii
= 0 ; nick
[ ii
]; ++ ii
)
3132 if (! isalnum ( nick
[ ii
]) && ! strchr ( "{|}~[ \\ ]^-_`" , nick
[ ii
]))
3134 if ( strlen ( nick
) > nicklen
)
3139 static struct userNode
*
3140 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
)
3142 struct userNode
* oldUser
, * uNode
;
3143 unsigned int ignore_user
, dummy
;
3147 if (( strlen ( numeric
) < 3 ) || ( strlen ( numeric
) > 5 )) {
3148 log_module ( MAIN_LOG
, LOG_WARNING
, "AddUser( %p , %s , ...): numeric %s wrong length!" , ( void *) uplink
, nick
, numeric
);
3153 log_module ( MAIN_LOG
, LOG_WARNING
, "AddUser( %p , %s , ...): server for numeric %s doesn't exist!" , ( void *) uplink
, nick
, numeric
);
3157 if ( uplink
!= GetServerN ( numeric
)) {
3158 log_module ( MAIN_LOG
, LOG_WARNING
, "AddUser( %p , %s , ...): server for numeric %s differs from nominal uplink %s ." , ( void *) uplink
, nick
, numeric
, uplink
-> name
);
3162 dummy
= modes
&& modes
[ 0 ] == '*' ;
3165 } else if (! is_valid_nick ( nick
)) {
3166 log_module ( MAIN_LOG
, LOG_WARNING
, "AddUser( %p , %s , ...): invalid nickname detected." , ( void *) uplink
, nick
);
3171 if (( oldUser
= GetUserH ( nick
))) {
3172 if ( IsLocal ( oldUser
)
3173 && ( IsService ( oldUser
) || IsPersistent ( oldUser
))) {
3174 /* The service should collide the new user off - but not
3175 * if the new user is coming in during a burst. (During a
3176 * burst, the bursting server will kill either our user --
3177 * triggering a ReintroduceUser() -- or its own.)
3179 oldUser
-> timestamp
= timestamp
- 1 ;
3183 } else if ( oldUser
-> timestamp
> timestamp
) {
3184 /* "Old" user is really newer; remove them */
3185 DelUser ( oldUser
, 0 , 1 , "Overruled by older nick" );
3187 /* User being added is too new; do not add them to
3188 * clients, but do add them to the server's list, since it
3189 * will send a KILL and QUIT soon. */
3194 /* create new usernode and set all values */
3195 uNode
= calloc ( 1 , sizeof (* uNode
));
3196 uNode
-> nick
= strdup ( nick
);
3197 safestrncpy ( uNode
-> ident
, ident
, sizeof ( uNode
-> ident
));
3198 safestrncpy ( uNode
-> info
, userinfo
, sizeof ( uNode
-> info
));
3199 safestrncpy ( uNode
-> hostname
, hostname
, sizeof ( uNode
-> hostname
));
3200 safestrncpy ( uNode
-> numeric
, numeric
, sizeof ( uNode
-> numeric
));
3201 irc_p10_pton (& uNode
-> ip
, realip
);
3203 tstr
= conf_get_data ( "server/type" , RECDB_QSTRING
);
3206 if ( irc_in_addr_is_ipv4 ( uNode
-> ip
)) {
3207 make_virtip (( char *) irc_ntoa (& uNode
-> ip
), ( char *) irc_ntoa (& uNode
-> ip
), uNode
-> cryptip
);
3208 make_virthost (( char *) irc_ntoa (& uNode
-> ip
), uNode
-> hostname
, uNode
-> crypthost
);
3209 } else if ( irc_in_addr_is_ipv6 ( uNode
-> ip
)) {
3210 make_ipv6virthost (( char *) irc_ntoa (& uNode
-> ip
), uNode
-> hostname
, uNode
-> crypthost
);
3214 if (! uNode
-> crypthost
&& uNode
-> cryptip
)
3215 snprintf ( uNode
-> crypthost
, sizeof ( uNode
-> crypthost
), " %s " , strdup ( uNode
-> cryptip
));
3216 uNode
-> idle_since
= timestamp
;
3217 uNode
-> timestamp
= timestamp
;
3218 modeList_init (& uNode
-> channels
);
3219 uNode
-> uplink
= uplink
;
3220 if (++ uNode
-> uplink
-> clients
> uNode
-> uplink
-> max_clients
) {
3221 uNode
-> uplink
-> max_clients
= uNode
-> uplink
-> clients
;
3223 uNode
-> num_local
= base64toint ( numeric
+ strlen ( uNode
-> uplink
-> numeric
), 3 ) & uNode
-> uplink
-> num_mask
;
3224 uNode
-> uplink
-> users
[ uNode
-> num_local
] = uNode
;
3225 mod_usermode ( uNode
, modes
);
3227 uNode
-> modes
|= FLAGS_DUMMY
;
3229 set_geoip_info ( uNode
);
3234 dict_insert ( clients
, uNode
-> nick
, uNode
);
3235 if ( dict_size ( clients
) > max_clients
) {
3236 max_clients
= dict_size ( clients
);
3237 max_clients_time
= now
;
3241 call_new_user_funcs ( uNode
);
3243 if (( uNode
-> loc
== 1 ) && ( uNode
-> handle_info
))
3244 send_func_list ( uNode
);
3249 /* removes user from it's server's hash table and nick hash table */
3251 DelUser ( struct userNode
* user
, struct userNode
* killer
, int announce
, const char * why
)
3256 /* mark them as dead, in case anybody cares */
3259 /* remove pending adduser commands */
3260 wipe_adduser_pending ( NULL
, user
);
3262 /* remove user from all channels */
3263 while ( user
-> channels
. used
> 0 )
3264 DelChannelUser ( user
, user
-> channels
. list
[ user
-> channels
. used
- 1 ]-> channel
, NULL
, 0 );
3266 /* Call these in reverse order so ChanServ can update presence
3267 information before NickServ nukes the handle_info. */
3268 call_del_user_funcs ( user
, killer
, why
);
3270 user
-> uplink
-> clients
--;
3271 user
-> uplink
-> users
[ user
-> num_local
] = NULL
;
3273 userList_remove (& curr_opers
, user
);
3274 if ( count_opers
> 0 && ! IsBotM ( user
) && ! IsService ( user
) && ! IsHideOper ( user
))
3277 /* remove from global dictionary, but not if after a collide */
3278 if ( user
== dict_find ( clients
, user
-> nick
, NULL
))
3279 dict_remove ( clients
, user
-> nick
);
3281 if ( IsInvisible ( user
))
3286 irc_quit ( user
, why
);
3288 irc_kill ( killer
, user
, why
);
3291 if ( IsLocal ( user
)) {
3292 unsigned int num
= user
-> num_local
;
3293 if ( num
< num_privmsg_funcs
)
3294 privmsg_funcs
[ num
] = NULL
;
3295 if ( num
< num_notice_funcs
)
3296 notice_funcs
[ num
] = NULL
;
3299 modeList_clean (& user
-> channels
);
3301 /* Clean up version data */
3302 if ( user
-> version_reply
) {
3303 free ( user
-> version_reply
);
3304 user
-> version_reply
= NULL
;
3307 /* Clean up SSL fingerprint data */
3318 free_string_list ( user
-> marks
);
3321 /* clean up geoip data if any */
3322 if ( user
-> country_code
) free ( user
-> country_code
);
3323 if ( user
-> city
) free ( user
-> city
);
3324 if ( user
-> region
) free ( user
-> region
);
3325 if ( user
-> postal_code
) free ( user
-> postal_code
);
3327 /* We don't free them, in case we try to privmsg them or something
3328 * (like when a stupid oper kills themself). We just put them onto
3329 * a list of clients that get freed after processing each line.
3331 if ( dead_users
. size
)
3332 userList_append (& dead_users
, user
);
3337 static void call_oper_funcs ( struct userNode
* user
);
3339 void mod_usermode ( struct userNode
* user
, const char * mode_change
) {
3343 const char * word
= mode_change
;
3345 if (! user
|| ! mode_change
)
3348 call_user_mode_funcs ( user
, mode_change
);
3350 setmodes
= user
-> modes
;
3352 while (* word
!= ' ' && * word
) word
++;
3353 while (* word
== ' ' ) word
++;
3354 while (! donemodes
) {
3355 #define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
3356 switch (* mode_change
++) {
3360 case '+' : add
= 1 ; break ;
3361 case '-' : add
= 0 ; break ;
3363 do_user_mode ( FLAGS_OPER
);
3365 userList_remove (& curr_opers
, user
);
3366 } else if (! userList_contains (& curr_opers
, user
)) {
3367 userList_append (& curr_opers
, user
);
3368 call_oper_funcs ( user
);
3371 case 'O' : do_user_mode ( FLAGS_LOCOP
); break ;
3372 case 'i' : do_user_mode ( FLAGS_INVISIBLE
);
3378 case 'w' : do_user_mode ( FLAGS_WALLOP
); break ;
3379 case 'd' : do_user_mode ( FLAGS_DEAF
); break ;
3380 case 'k' : do_user_mode ( FLAGS_SERVICE
); break ;
3381 case 'g' : do_user_mode ( FLAGS_GLOBAL
); break ;
3382 case 'B' : do_user_mode ( FLAGS_BOT
); break ;
3383 case 'n' : do_user_mode ( FLAGS_HIDECHANS
); break ;
3384 case 'p' : do_user_mode ( FLAGS_HIDECHANS
); break ;
3385 case 'I' : do_user_mode ( FLAGS_HIDEIDLE
); break ;
3386 case 'X' : do_user_mode ( FLAGS_XTRAOP
); break ;
3387 case 'C' : do_user_mode ( FLAGS_CLOAKHOST
);
3389 char cloakhost
[ MAXLEN
];
3391 for ( ii
= 0 ; (* word
!= ' ' ) && (* word
!= '\0' ); )
3392 cloakhost
[ ii
++] = * word
++;
3394 while (* word
== ' ' )
3396 safestrncpy ( user
-> crypthost
, cloakhost
, sizeof ( user
-> crypthost
));
3399 case 'c' : do_user_mode ( FLAGS_CLOAKIP
);
3401 char cloakip
[ MAXLEN
];
3403 for ( ii
= 0 ; (* word
!= ' ' ) && (* word
!= '\0' ); )
3404 cloakip
[ ii
++] = * word
++;
3406 while (* word
== ' ' )
3408 safestrncpy ( user
-> cryptip
, cloakip
, sizeof ( user
-> cryptip
));
3411 // sethost - reed/apples
3412 // case 'h': do_user_mode(FLAGS_HELPER); break;
3413 // I check if there's an 'h' in the first part, and if there,
3414 // then everything after the space becomes their new host.
3415 case 'h' : do_user_mode ( FLAGS_SETHOST
);
3417 char sethost
[ MAXLEN
];
3419 for ( ii
= 0 ; (* word
!= ' ' ) && (* word
!= '\0' ); )
3420 sethost
[ ii
++] = * word
++;
3422 while (* word
== ' ' )
3424 safestrncpy ( user
-> sethost
, sethost
, sizeof ( user
-> sethost
));
3427 case 'x' : do_user_mode ( FLAGS_HIDDEN_HOST
); break ;
3432 for ( ii
= 0 ; (* word
!= ' ' ) && (* word
!= '\0' ); )
3433 tag
[ ii
++] = * word
++;
3435 while (* word
== ' ' )
3437 call_account_func ( user
, tag
);
3444 for ( ii
= 0 ; (* word
!= ' ' ) && (* word
!= '\0' ); )
3445 host
[ ii
++] = * word
++;
3447 while (* word
== ' ' )
3449 assign_fakehost ( user
, host
, 0 );
3452 case 'a' : do_user_mode ( FLAGS_ADMIN
); break ;
3453 case 'z' : do_user_mode ( FLAGS_SSL
); break ;
3454 case 'D' : do_user_mode ( FLAGS_PRIVDEAF
); break ;
3455 case 'R' : do_user_mode ( FLAGS_ACCOUNTONLY
); break ;
3456 case 'W' : do_user_mode ( FLAGS_WHOIS
); break ;
3457 case 'H' : do_user_mode ( FLAGS_HIDEOPER
); break ;
3458 case 'L' : do_user_mode ( FLAGS_NOLINK
); break ;
3459 case 'q' : do_user_mode ( FLAGS_COMMONCHANSONLY
); break ;
3465 if (!( setmodes
& FLAGS_OPER
) && IsOper ( user
)) {
3466 if (! IsBotM ( user
) && ! IsService ( user
) && ! IsHideOper ( user
))
3471 if (( setmodes
& FLAGS_OPER
) && ! IsOper ( user
)) {
3472 if ( count_opers
> 1 && !( setmodes
& FLAGS_BOT
) &&
3473 !( setmodes
& FLAGS_SERVICE
) && !( setmodes
& FLAGS_HIDEOPER
))
3478 if (!( setmodes
& FLAGS_HIDEOPER
) &&
3479 !( setmodes
& FLAGS_SERVICE
) &&
3480 !( setmodes
& FLAGS_BOT
) &&
3481 ( IsHideOper ( user
) || IsService ( user
) || IsBotM ( user
))) {
3482 if (( setmodes
& FLAGS_OPER
) && IsOper ( user
) && count_opers
> 0 )
3487 if ((( setmodes
& FLAGS_HIDEOPER
) ||
3488 ( setmodes
& FLAGS_SERVICE
) ||
3489 ( setmodes
& FLAGS_BOT
)) &&
3490 ! IsHideOper ( user
) && ! IsService ( user
) && ! IsBotM ( user
)) {
3491 if (( setmodes
& FLAGS_OPER
) && IsOper ( user
))
3497 keyncpy ( char output
[], char input
[], size_t output_size
)
3501 if ( input
[ 0 ] == ':' )
3507 for ( ii
= 0 ; ( ii
+ 1 < output_size
) && ( input
[ ii
] != '\0' ); ++ ii
)
3509 output
[ ii
] = input
[ ii
];
3516 struct mod_chanmode
*
3517 mod_chanmode_parse ( struct chanNode
* channel
, char ** modes
, unsigned int argc
, unsigned int flags
, short base_oplevel
)
3519 struct mod_chanmode
* change
;
3520 unsigned int ii
, in_arg
, ch_arg
, add
;
3524 if (!( change
= mod_chanmode_alloc ( argc
- 1 )))
3527 for ( ii
= ch_arg
= 0 , in_arg
= add
= 1 ;
3528 ( modes
[ 0 ][ ii
] != '\0' ) && ( modes
[ 0 ][ ii
] != ' ' );
3530 switch ( modes
[ 0 ][ ii
]) {
3537 #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)
3538 case 'C' : do_chan_mode ( MODE_NOCTCPS
); break ;
3539 case 'D' : do_chan_mode ( MODE_DELAYJOINS
); break ;
3540 case 'c' : do_chan_mode ( MODE_NOCOLORS
); break ;
3541 case 'i' : do_chan_mode ( MODE_INVITEONLY
); break ;
3542 case 'm' : do_chan_mode ( MODE_MODERATED
); break ;
3543 case 'n' : do_chan_mode ( MODE_NOPRIVMSGS
); break ;
3544 case 'p' : do_chan_mode ( MODE_PRIVATE
); break ;
3545 case 'r' : do_chan_mode ( MODE_REGONLY
); break ;
3546 case 's' : do_chan_mode ( MODE_SECRET
); break ;
3547 case 't' : do_chan_mode ( MODE_TOPICLIMIT
); break ;
3548 case 'S' : do_chan_mode ( MODE_STRIPCOLOR
); break ;
3549 case 'M' : do_chan_mode ( MODE_MODUNREG
); break ;
3550 case 'N' : do_chan_mode ( MODE_NONOTICE
); break ;
3551 case 'Q' : do_chan_mode ( MODE_NOQUITMSGS
); break ;
3552 case 'T' : do_chan_mode ( MODE_NOAMSG
); break ;
3553 case 'O' : do_chan_mode ( MODE_OPERSONLY
); break ;
3554 case 'a' : do_chan_mode ( MODE_ADMINSONLY
); break ;
3555 case 'Z' : do_chan_mode ( MODE_SSLONLY
); break ;
3556 case 'L' : do_chan_mode ( MODE_HIDEMODE
); break ;
3558 if (!( flags
& MCP_REGISTERED
)) {
3559 do_chan_mode ( MODE_REGISTERED
);
3561 mod_chanmode_free ( change
);
3570 change
-> modes_set
|= MODE_LIMIT
;
3571 change
-> new_limit
= atoi ( modes
[ in_arg
++]);
3573 change
-> modes_set
&= ~ MODE_LIMIT
;
3574 change
-> modes_clear
|= MODE_LIMIT
;
3579 if (( in_arg
>= argc
)
3580 || keyncpy ( change
-> new_key
, modes
[ in_arg
++], sizeof ( change
-> new_key
)))
3582 change
-> modes_set
|= MODE_KEY
;
3584 change
-> modes_clear
|= MODE_KEY
;
3585 if (!( flags
& MCP_KEY_FREE
)) {
3595 if (( in_arg
>= argc
)
3596 || keyncpy ( change
-> new_upass
, modes
[ in_arg
++], sizeof ( change
-> new_upass
)))
3598 change
-> modes_set
|= MODE_UPASS
;
3600 change
-> modes_clear
|= MODE_UPASS
;
3601 if (!( flags
& MCP_UPASS_FREE
)) {
3610 if (( in_arg
>= argc
)
3611 || keyncpy ( change
-> new_apass
, modes
[ in_arg
++], sizeof ( change
-> new_apass
)))
3613 change
-> modes_set
|= MODE_APASS
;
3615 change
-> modes_clear
|= MODE_APASS
;
3616 if (!( flags
& MCP_APASS_FREE
)) {
3624 if (!( flags
& MCP_ALLOW_OVB
))
3628 change
-> args
[ ch_arg
]. mode
= MODE_BAN
;
3630 change
-> args
[ ch_arg
]. mode
|= MODE_REMOVE
;
3631 change
-> args
[ ch_arg
++]. u
. hostmask
= modes
[ in_arg
++];
3634 if (!( flags
& MCP_ALLOW_OVB
))
3638 change
-> args
[ ch_arg
]. mode
= MODE_EXEMPT
;
3640 change
-> args
[ ch_arg
]. mode
|= MODE_REMOVE
;
3641 change
-> args
[ ch_arg
++]. u
. hostmask
= modes
[ in_arg
++];
3643 case 'o' : case 'h' : case 'v' :
3645 struct userNode
* victim
;
3651 oplevel_str
= strchr ( modes
[ in_arg
], ':' );
3654 /* XXYYY M #channel +o XXYYY:<oplevel> */
3655 * oplevel_str
++ = '\0' ;
3656 oplevel
= parse_oplevel ( oplevel_str
);
3657 if ( oplevel
<= base_oplevel
&& !( flags
& MCP_FROM_SERVER
))
3658 oplevel
= base_oplevel
+ 1 ;
3660 else if ( channel
-> modes
& MODE_UPASS
)
3661 oplevel
= base_oplevel
+ 1 ;
3665 /* Check that oplevel is within bounds. */
3666 if ( oplevel
> MAXOPLEVEL
)
3667 oplevel
= MAXOPLEVEL
;
3669 if (!( flags
& MCP_ALLOW_OVB
))
3674 if ( modes
[ 0 ][ ii
] == 'o' )
3675 change
-> args
[ ch_arg
]. mode
= MODE_CHANOP
;
3676 else if ( modes
[ 0 ][ ii
] == 'h' )
3677 change
-> args
[ ch_arg
]. mode
= MODE_HALFOP
;
3678 else if ( modes
[ 0 ][ ii
] == 'v' )
3679 change
-> args
[ ch_arg
]. mode
= MODE_VOICE
;
3682 change
-> args
[ ch_arg
]. mode
|= MODE_REMOVE
;
3683 if ( flags
& MCP_FROM_SERVER
)
3684 victim
= GetUserN ( modes
[ in_arg
++]);
3686 victim
= GetUserH ( modes
[ in_arg
++]);
3689 if (( change
-> args
[ ch_arg
]. u
. member
= GetUserMode ( channel
, victim
)))
3691 /* Apply the oplevel change */
3692 change
-> args
[ ch_arg
]. u
. member
-> oplevel
= oplevel
;
3698 if (!( flags
& MCP_FROM_SERVER
))
3703 change
-> argc
= ch_arg
; /* in case any turned out to be ignored */
3704 if ( change
-> modes_set
& MODE_SECRET
) {
3705 change
-> modes_set
&= ~( MODE_PRIVATE
);
3706 change
-> modes_clear
|= MODE_PRIVATE
;
3707 } else if ( change
-> modes_set
& MODE_PRIVATE
) {
3708 change
-> modes_set
&= ~( MODE_SECRET
);
3709 change
-> modes_clear
|= MODE_SECRET
;
3713 mod_chanmode_free ( change
);
3717 struct chanmode_buffer
{
3720 struct chanNode
* channel
;
3721 struct userNode
* actor
;
3722 unsigned int modes_used
;
3723 unsigned int args_used
;
3725 unsigned int is_add
: 1 ;
3726 unsigned int is_chanop
: 1 ;
3730 mod_chanmode_append ( struct chanmode_buffer
* buf
, char ch
, const char * arg
)
3732 size_t arg_len
= strlen ( arg
);
3733 if ( buf
-> modes_used
> ( MAXMODEPARAMS
) ||
3734 buf
-> modes_used
+ buf
-> args_used
+ buf
-> chname_len
+ arg_len
> 450 ) {
3735 memcpy ( buf
-> modes
+ buf
-> modes_used
, buf
-> args
, buf
-> args_used
);
3736 buf
-> modes
[ buf
-> modes_used
+ buf
-> args_used
] = '\0' ;
3737 irc_mode (( buf
-> is_chanop
? buf
-> actor
: NULL
), buf
-> channel
, buf
-> modes
);
3738 buf
-> modes
[ 0 ] = buf
-> is_add
? '+' : '-' ;
3739 buf
-> modes_used
= 1 ;
3742 buf
-> modes
[ buf
-> modes_used
++] = ch
;
3743 buf
-> args
[ buf
-> args_used
++] = ' ' ;
3744 memcpy ( buf
-> args
+ buf
-> args_used
, arg
, arg_len
);
3745 buf
-> args_used
+= arg_len
;
3749 mod_chanmode_announce ( struct userNode
* who
, struct chanNode
* channel
, struct mod_chanmode
* change
)
3751 struct chanmode_buffer chbuf
;
3753 struct modeNode
* mn
;
3754 char int_buff
[ 32 ], mode
= '\0' ;
3756 assert ( change
-> argc
<= change
-> alloc_argc
);
3757 memset (& chbuf
, 0 , sizeof ( chbuf
));
3758 chbuf
. channel
= channel
;
3760 chbuf
. chname_len
= strlen ( channel
-> name
);
3762 mn
= GetUserMode ( channel
, who
);
3763 if (( mn
&& ( mn
-> modes
& MODE_CHANOP
)) || off_channel
)
3764 chbuf
. is_chanop
= 1 ;
3766 /* First remove modes */
3768 if ( change
-> modes_clear
) {
3770 chbuf
. modes
[ chbuf
. modes_used
++] = mode
= '-' ;
3771 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) chbuf.modes[chbuf.modes_used++] = CHAR
3772 DO_MODE_CHAR ( PRIVATE
, 'p' );
3773 DO_MODE_CHAR ( SECRET
, 's' );
3774 DO_MODE_CHAR ( MODERATED
, 'm' );
3775 DO_MODE_CHAR ( TOPICLIMIT
, 't' );
3776 DO_MODE_CHAR ( INVITEONLY
, 'i' );
3777 DO_MODE_CHAR ( NOPRIVMSGS
, 'n' );
3778 DO_MODE_CHAR ( LIMIT
, 'l' );
3779 DO_MODE_CHAR ( DELAYJOINS
, 'D' );
3780 DO_MODE_CHAR ( REGONLY
, 'r' );
3781 DO_MODE_CHAR ( NOCOLORS
, 'c' );
3782 DO_MODE_CHAR ( NOCTCPS
, 'C' );
3783 DO_MODE_CHAR ( STRIPCOLOR
, 'S' );
3784 DO_MODE_CHAR ( MODUNREG
, 'M' );
3785 DO_MODE_CHAR ( NONOTICE
, 'N' );
3786 DO_MODE_CHAR ( NOQUITMSGS
, 'Q' );
3787 DO_MODE_CHAR ( NOAMSG
, 'T' );
3788 DO_MODE_CHAR ( OPERSONLY
, 'O' );
3789 DO_MODE_CHAR ( ADMINSONLY
, 'a' );
3790 DO_MODE_CHAR ( REGISTERED
, 'z' );
3791 DO_MODE_CHAR ( SSLONLY
, 'Z' );
3792 DO_MODE_CHAR ( HIDEMODE
, 'L' );
3794 if ( change
-> modes_clear
& channel
-> modes
& MODE_KEY
)
3795 mod_chanmode_append (& chbuf
, 'k' , channel
-> key
);
3796 if ( change
-> modes_clear
& channel
-> modes
& MODE_UPASS
)
3797 mod_chanmode_append (& chbuf
, 'U' , channel
-> upass
);
3798 if ( change
-> modes_clear
& channel
-> modes
& MODE_APASS
)
3799 mod_chanmode_append (& chbuf
, 'A' , channel
-> apass
);
3801 for ( arg
= 0 ; arg
< change
-> argc
; ++ arg
) {
3802 if (!( change
-> args
[ arg
]. mode
& MODE_REMOVE
))
3805 chbuf
. modes
[ chbuf
. modes_used
++] = mode
= '-' ;
3806 switch ( change
-> args
[ arg
]. mode
& ~ MODE_REMOVE
) {
3808 mod_chanmode_append (& chbuf
, 'b' , change
-> args
[ arg
]. u
. hostmask
);
3811 mod_chanmode_append (& chbuf
, 'e' , change
-> args
[ arg
]. u
. hostmask
);
3814 if ( change
-> args
[ arg
]. mode
& MODE_CHANOP
)
3815 mod_chanmode_append (& chbuf
, 'o' , change
-> args
[ arg
]. u
. member
-> user
-> numeric
);
3816 if ( change
-> args
[ arg
]. mode
& MODE_HALFOP
)
3817 mod_chanmode_append (& chbuf
, 'h' , change
-> args
[ arg
]. u
. member
-> user
-> numeric
);
3818 if ( change
-> args
[ arg
]. mode
& MODE_VOICE
)
3819 mod_chanmode_append (& chbuf
, 'v' , change
-> args
[ arg
]. u
. member
-> user
-> numeric
);
3826 if ( change
-> modes_set
) {
3828 chbuf
. modes
[ chbuf
. modes_used
++] = mode
= '+' ;
3829 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_set & MODE_##BIT) chbuf.modes[chbuf.modes_used++] = CHAR
3830 DO_MODE_CHAR ( PRIVATE
, 'p' );
3831 DO_MODE_CHAR ( SECRET
, 's' );
3832 DO_MODE_CHAR ( MODERATED
, 'm' );
3833 DO_MODE_CHAR ( TOPICLIMIT
, 't' );
3834 DO_MODE_CHAR ( INVITEONLY
, 'i' );
3835 DO_MODE_CHAR ( NOPRIVMSGS
, 'n' );
3836 DO_MODE_CHAR ( DELAYJOINS
, 'D' );
3837 DO_MODE_CHAR ( REGONLY
, 'r' );
3838 DO_MODE_CHAR ( NOCOLORS
, 'c' );
3839 DO_MODE_CHAR ( NOCTCPS
, 'C' );
3840 DO_MODE_CHAR ( STRIPCOLOR
, 'S' );
3841 DO_MODE_CHAR ( MODUNREG
, 'M' );
3842 DO_MODE_CHAR ( NONOTICE
, 'N' );
3843 DO_MODE_CHAR ( NOQUITMSGS
, 'Q' );
3844 DO_MODE_CHAR ( NOAMSG
, 'T' );
3845 DO_MODE_CHAR ( OPERSONLY
, 'O' );
3846 DO_MODE_CHAR ( ADMINSONLY
, 'a' );
3847 DO_MODE_CHAR ( REGISTERED
, 'z' );
3848 DO_MODE_CHAR ( SSLONLY
, 'Z' );
3849 DO_MODE_CHAR ( HIDEMODE
, 'L' );
3851 if ( change
-> modes_set
& MODE_KEY
)
3852 mod_chanmode_append (& chbuf
, 'k' , change
-> new_key
);
3853 if ( change
-> modes_set
& MODE_UPASS
)
3854 mod_chanmode_append (& chbuf
, 'U' , change
-> new_upass
);
3855 if ( change
-> modes_set
& MODE_APASS
)
3856 mod_chanmode_append (& chbuf
, 'A' , change
-> new_apass
);
3857 if ( change
-> modes_set
& MODE_LIMIT
) {
3858 sprintf ( int_buff
, " %d " , change
-> new_limit
);
3859 mod_chanmode_append (& chbuf
, 'l' , int_buff
);
3862 for ( arg
= 0 ; arg
< change
-> argc
; ++ arg
) {
3863 if ( change
-> args
[ arg
]. mode
& MODE_REMOVE
)
3866 chbuf
. modes
[ chbuf
. modes_used
++] = mode
= '+' ;
3867 switch ( change
-> args
[ arg
]. mode
) {
3869 mod_chanmode_append (& chbuf
, 'b' , change
-> args
[ arg
]. u
. hostmask
);
3872 mod_chanmode_append (& chbuf
, 'e' , change
-> args
[ arg
]. u
. hostmask
);
3875 if ( change
-> args
[ arg
]. mode
& MODE_CHANOP
)
3876 mod_chanmode_append (& chbuf
, 'o' , change
-> args
[ arg
]. u
. member
-> user
-> numeric
);
3877 if ( change
-> args
[ arg
]. mode
& MODE_HALFOP
)
3878 mod_chanmode_append (& chbuf
, 'h' , change
-> args
[ arg
]. u
. member
-> user
-> numeric
);
3879 if ( change
-> args
[ arg
]. mode
& MODE_VOICE
)
3880 mod_chanmode_append (& chbuf
, 'v' , change
-> args
[ arg
]. u
. member
-> user
-> numeric
);
3885 /* Flush the buffer and apply changes locally */
3886 if ( chbuf
. modes_used
> 0 ) {
3887 memcpy ( chbuf
. modes
+ chbuf
. modes_used
, chbuf
. args
, chbuf
. args_used
);
3888 chbuf
. modes
[ chbuf
. modes_used
+ chbuf
. args_used
] = '\0' ;
3889 irc_mode (( chbuf
. is_chanop
? chbuf
. actor
: NULL
), chbuf
. channel
, chbuf
. modes
);
3891 mod_chanmode_apply ( who
, channel
, change
);
3895 mod_chanmode_format ( struct mod_chanmode
* change
, char * outbuff
)
3897 unsigned int used
= 0 ;
3898 assert ( change
-> argc
<= change
-> alloc_argc
);
3899 if ( change
-> modes_clear
) {
3900 outbuff
[ used
++] = '-' ;
3901 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) outbuff[used++] = CHAR
3902 DO_MODE_CHAR ( PRIVATE
, 'p' );
3903 DO_MODE_CHAR ( SECRET
, 's' );
3904 DO_MODE_CHAR ( MODERATED
, 'm' );
3905 DO_MODE_CHAR ( TOPICLIMIT
, 't' );
3906 DO_MODE_CHAR ( INVITEONLY
, 'i' );
3907 DO_MODE_CHAR ( NOPRIVMSGS
, 'n' );
3908 DO_MODE_CHAR ( LIMIT
, 'l' );
3909 DO_MODE_CHAR ( KEY
, 'k' );
3910 DO_MODE_CHAR ( UPASS
, 'U' );
3911 DO_MODE_CHAR ( APASS
, 'A' );
3912 DO_MODE_CHAR ( DELAYJOINS
, 'D' );
3913 DO_MODE_CHAR ( REGONLY
, 'r' );
3914 DO_MODE_CHAR ( NOCOLORS
, 'c' );
3915 DO_MODE_CHAR ( NOCTCPS
, 'C' );
3916 DO_MODE_CHAR ( STRIPCOLOR
, 'S' );
3917 DO_MODE_CHAR ( MODUNREG
, 'M' );
3918 DO_MODE_CHAR ( NONOTICE
, 'N' );
3919 DO_MODE_CHAR ( NOQUITMSGS
, 'Q' );
3920 DO_MODE_CHAR ( NOAMSG
, 'T' );
3921 DO_MODE_CHAR ( OPERSONLY
, 'O' );
3922 DO_MODE_CHAR ( ADMINSONLY
, 'a' );
3923 DO_MODE_CHAR ( REGISTERED
, 'z' );
3924 DO_MODE_CHAR ( SSLONLY
, 'Z' );
3925 DO_MODE_CHAR ( HIDEMODE
, 'L' );
3928 if ( change
-> modes_set
) {
3929 outbuff
[ used
++] = '+' ;
3930 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_set & MODE_##BIT) outbuff[used++] = CHAR
3931 DO_MODE_CHAR ( PRIVATE
, 'p' );
3932 DO_MODE_CHAR ( SECRET
, 's' );
3933 DO_MODE_CHAR ( MODERATED
, 'm' );
3934 DO_MODE_CHAR ( TOPICLIMIT
, 't' );
3935 DO_MODE_CHAR ( INVITEONLY
, 'i' );
3936 DO_MODE_CHAR ( NOPRIVMSGS
, 'n' );
3937 DO_MODE_CHAR ( DELAYJOINS
, 'D' );
3938 DO_MODE_CHAR ( REGONLY
, 'r' );
3939 DO_MODE_CHAR ( NOCOLORS
, 'c' );
3940 DO_MODE_CHAR ( NOCTCPS
, 'C' );
3941 DO_MODE_CHAR ( STRIPCOLOR
, 'S' );
3942 DO_MODE_CHAR ( MODUNREG
, 'M' );
3943 DO_MODE_CHAR ( NONOTICE
, 'N' );
3944 DO_MODE_CHAR ( NOQUITMSGS
, 'Q' );
3945 DO_MODE_CHAR ( NOAMSG
, 'T' );
3946 DO_MODE_CHAR ( OPERSONLY
, 'O' );
3947 DO_MODE_CHAR ( ADMINSONLY
, 'a' );
3948 DO_MODE_CHAR ( REGISTERED
, 'z' );
3949 DO_MODE_CHAR ( SSLONLY
, 'Z' );
3950 DO_MODE_CHAR ( HIDEMODE
, 'L' );
3952 DO_MODE_CHAR ( KEY
, 'k' );
3953 DO_MODE_CHAR ( LIMIT
, 'l' );
3954 DO_MODE_CHAR ( APASS
, 'A' );
3955 DO_MODE_CHAR ( UPASS
, 'U' );
3958 #define DO_MODE_PARM(BIT, PARM) if (change->modes_set & MODE_##BIT) used += sprintf(outbuff+used, " %s " , PARM);
3959 DO_MODE_PARM ( KEY
, change
-> new_key
);
3960 if ( change
-> modes_set
& MODE_LIMIT
) used
+= sprintf ( outbuff
+ used
, " %d " , change
-> new_limit
);
3961 DO_MODE_PARM ( APASS
, change
-> new_apass
);
3962 DO_MODE_PARM ( UPASS
, change
-> new_upass
);
3970 clear_chanmode ( struct chanNode
* channel
, const char * modes
)
3972 unsigned int cleared
;
3974 for ( cleared
= 0 ; * modes
; modes
++) {
3976 case 'o' : cleared
|= MODE_CHANOP
; break ;
3977 case 'h' : cleared
|= MODE_HALFOP
; break ;
3978 case 'v' : cleared
|= MODE_VOICE
; break ;
3979 case 'p' : cleared
|= MODE_PRIVATE
; break ;
3980 case 's' : cleared
|= MODE_SECRET
; break ;
3981 case 'm' : cleared
|= MODE_MODERATED
; break ;
3982 case 't' : cleared
|= MODE_TOPICLIMIT
; break ;
3983 case 'i' : cleared
|= MODE_INVITEONLY
; break ;
3984 case 'n' : cleared
|= MODE_NOPRIVMSGS
; break ;
3986 cleared
|= MODE_KEY
;
3987 channel
-> key
[ 0 ] = '\0' ;
3990 cleared
|= MODE_APASS
;
3991 channel
-> apass
[ 0 ] = '\0' ;
3994 cleared
|= MODE_UPASS
;
3995 channel
-> upass
[ 0 ] = '\0' ;
3998 cleared
|= MODE_LIMIT
;
4001 case 'b' : cleared
|= MODE_BAN
; break ;
4002 case 'e' : cleared
|= MODE_EXEMPT
; break ;
4003 case 'D' : cleared
|= MODE_DELAYJOINS
; break ;
4004 case 'r' : cleared
|= MODE_REGONLY
; break ;
4005 case 'c' : cleared
|= MODE_NOCOLORS
; break ;
4006 case 'C' : cleared
|= MODE_NOCTCPS
; break ;
4007 case 'S' : cleared
|= MODE_STRIPCOLOR
; break ;
4008 case 'M' : cleared
|= MODE_MODUNREG
; break ;
4009 case 'N' : cleared
|= MODE_NONOTICE
; break ;
4010 case 'Q' : cleared
|= MODE_NOQUITMSGS
; break ;
4011 case 'T' : cleared
|= MODE_NOAMSG
; break ;
4012 case 'O' : cleared
|= MODE_OPERSONLY
; break ;
4013 case 'a' : cleared
|= MODE_ADMINSONLY
; break ;
4014 case 'z' : cleared
|= MODE_REGISTERED
; break ;
4015 case 'Z' : cleared
|= MODE_SSLONLY
; break ;
4016 case 'L' : cleared
|= MODE_HIDEMODE
; break ;
4023 /* Remove simple modes. */
4024 channel
-> modes
&= ~ cleared
;
4026 /* If removing bans, kill 'em all. */
4027 if (( cleared
& MODE_BAN
) && channel
-> banlist
. used
) {
4029 for ( i
= 0 ; i
< channel
-> banlist
. used
; i
++)
4030 free ( channel
-> banlist
. list
[ i
]);
4031 channel
-> banlist
. used
= 0 ;
4034 /* If removing exempts, kill 'em all. */
4035 if (( cleared
& MODE_EXEMPT
) && channel
-> exemptlist
. used
) {
4037 for ( i
= 0 ; i
< channel
-> exemptlist
. used
; i
++)
4038 free ( channel
-> exemptlist
. list
[ i
]);
4039 channel
-> exemptlist
. used
= 0 ;
4042 /* Removed member modes. */
4043 if (( cleared
& ( MODE_CHANOP
| MODE_HALFOP
| MODE_VOICE
)) && channel
-> members
. used
) {
4044 int mask
= ~( cleared
& ( MODE_CHANOP
| MODE_HALFOP
| MODE_VOICE
));
4047 for ( i
= 0 ; i
< channel
-> members
. used
; i
++)
4048 channel
-> members
. list
[ i
]-> modes
&= mask
;
4055 reg_privmsg_func ( struct userNode
* user
, privmsg_func_t handler
)
4057 unsigned int numeric
= user
-> num_local
;
4058 if ( numeric
>= num_privmsg_funcs
) {
4059 int newnum
= numeric
+ 8 , ii
;
4060 privmsg_funcs
= realloc ( privmsg_funcs
, newnum
* sizeof ( privmsg_func_t
));
4061 for ( ii
= num_privmsg_funcs
; ii
< newnum
; ++ ii
)
4062 privmsg_funcs
[ ii
] = NULL
;
4063 num_privmsg_funcs
= newnum
;
4065 if ( privmsg_funcs
[ numeric
])
4066 log_module ( MAIN_LOG
, LOG_WARNING
, "re-registering new privmsg handler for numeric %d " , numeric
);
4067 privmsg_funcs
[ numeric
] = handler
;
4071 unreg_privmsg_func ( struct userNode
* user
)
4073 if (! IsLocal ( user
) || user
-> num_local
>= num_privmsg_funcs
)
4074 return ; /* this really only works with users */
4076 privmsg_funcs
[ user
-> num_local
] = NULL
;
4081 reg_notice_func ( struct userNode
* user
, privmsg_func_t handler
)
4083 unsigned int numeric
= user
-> num_local
;
4084 if ( numeric
>= num_notice_funcs
) {
4085 int newnum
= numeric
+ 8 , ii
;
4086 notice_funcs
= realloc ( notice_funcs
, newnum
* sizeof ( privmsg_func_t
));
4087 for ( ii
= num_privmsg_funcs
; ii
< newnum
; ++ ii
)
4088 privmsg_funcs
[ ii
] = NULL
;
4089 num_notice_funcs
= newnum
;
4091 if ( notice_funcs
[ numeric
])
4092 log_module ( MAIN_LOG
, LOG_WARNING
, "re-registering new notice handler for numeric %d " , numeric
);
4093 notice_funcs
[ numeric
] = handler
;
4097 unreg_notice_func ( struct userNode
* user
)
4099 if (! IsLocal ( user
) || user
-> num_local
>= num_privmsg_funcs
)
4100 return ; /* this really only works with users */
4102 notice_funcs
[ user
-> num_local
] = NULL
;
4108 unsigned int i
, hop
, max_hop
= 1 ;
4111 /* burst (juped) servers, closest first (except self, which is sent already) */
4112 for ( i
= 0 ; i
< ArrayLength ( servers_num
); i
++)
4113 if ( servers_num
[ i
] && servers_num
[ i
]-> hops
> max_hop
)
4114 max_hop
= servers_num
[ i
]-> hops
;
4115 for ( hop
= 1 ; hop
<= max_hop
; hop
++) {
4116 for ( i
= 0 ; i
< ArrayLength ( servers_num
); i
++) {
4118 && ( servers_num
[ i
]-> hops
== hop
)
4119 && ( servers_num
[ i
] != self
-> uplink
))
4120 irc_server ( servers_num
[ i
]);
4124 /* burst local nicks */
4125 for ( i
= 0 ; i
<= self
-> num_mask
; i
++)
4127 irc_user ( self
-> users
[ i
]);
4129 /* build dict of unbursted channel names (just copy existing channels) */
4130 unbursted_channels
= dict_new ();
4131 for ( it
= dict_first ( channels
); it
; it
= iter_next ( it
))
4132 dict_insert ( unbursted_channels
, iter_key ( it
), iter_data ( it
));
4139 parse_oplevel ( char * str
)
4142 while ( isdigit (* str
))
4143 oplevel
= oplevel
* 10 + * str
++ - '0' ;