]>
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 srvx.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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.
21 #include "proto-common.c"
24 #define CMD_ACCOUNT "ACCOUNT"
25 #define CMD_ADMIN "ADMIN"
26 #define CMD_ASLL "ASLL"
27 #define CMD_AWAY "AWAY"
28 #define CMD_BURST "BURST"
29 #define CMD_CLEARMODE "CLEARMODE"
30 #define CMD_CLOSE "CLOSE"
31 #define CMD_CNOTICE "CNOTICE"
32 #define CMD_CONNECT "CONNECT"
33 #define CMD_CPRIVMSG "CPRIVMSG"
34 #define CMD_CREATE "CREATE"
35 #define CMD_DESTRUCT "DESTRUCT"
36 #define CMD_DESYNCH "DESYNCH"
39 #define CMD_EOB "END_OF_BURST"
40 #define CMD_EOB_ACK "EOB_ACK"
41 #define CMD_ERROR "ERROR"
42 #define CMD_FAKEHOST "FAKE"
44 #define CMD_GLINE "GLINE"
45 #define CMD_HASH "HASH"
46 #define CMD_HELP "HELP"
47 #define CMD_INFO "INFO"
48 #define CMD_INVITE "INVITE"
49 #define CMD_ISON "ISON"
50 #define CMD_JOIN "JOIN"
51 #define CMD_JUPE "JUPE"
52 #define CMD_KICK "KICK"
53 #define CMD_KILL "KILL"
54 #define CMD_LINKS "LINKS"
55 #define CMD_LIST "LIST"
56 #define CMD_LUSERS "LUSERS"
58 #define CMD_MODE "MODE"
59 #define CMD_MOTD "MOTD"
60 #define CMD_NAMES "NAMES"
61 #define CMD_NICK "NICK"
62 #define CMD_NOTICE "NOTICE"
63 #define CMD_OPER "OPER"
64 #define CMD_OPMODE "OPMODE"
65 #define CMD_PART "PART"
66 #define CMD_PASS "PASS"
67 #define CMD_PING "PING"
68 #define CMD_PONG "PONG"
69 #define CMD_POST "POST"
70 #define CMD_PRIVMSG "PRIVMSG"
71 #define CMD_PRIVS "PRIVS"
72 #define CMD_PROTO "PROTO"
73 #define CMD_QUIT "QUIT"
74 #define CMD_REHASH "REHASH"
75 #define CMD_RESET "RESET"
76 #define CMD_RESTART "RESTART"
77 #define CMD_RPING "RPING"
78 #define CMD_RPONG "RPONG"
79 #define CMD_SERVER "SERVER"
80 #define CMD_SERVLIST "SERVLIST"
81 #define CMD_SERVSET "SERVSET"
83 #define CMD_SETTIME "SETTIME"
84 #define CMD_SILENCE "SILENCE"
85 #define CMD_SQUERY "SQUERY"
86 #define CMD_SQUIT "SQUIT"
87 #define CMD_STATS "STATS"
88 #define CMD_SVSNICK "SVSNICK"
89 #define CMD_TIME "TIME"
90 #define CMD_TOPIC "TOPIC"
91 #define CMD_TRACE "TRACE"
92 #define CMD_UPING "UPING"
93 #define CMD_USER "USER"
94 #define CMD_USERHOST "USERHOST"
95 #define CMD_USERIP "USERIP"
96 #define CMD_VERSION "VERSION"
97 #define CMD_WALLCHOPS "WALLCHOPS"
98 #define CMD_WALLOPS "WALLOPS"
99 #define CMD_WALLUSERS "WALLUSERS"
100 #define CMD_WALLVOICES "WALLVOICES"
101 #define CMD_WHO "WHO"
102 #define CMD_WHOIS "WHOIS"
103 #define CMD_WHOWAS "WHOWAS"
105 /* Tokenized commands. */
106 #define TOK_ACCOUNT "AC"
107 #define TOK_ADMIN "AD"
108 #define TOK_ASLL "LL"
110 #define TOK_BURST "B"
111 #define TOK_CLEARMODE "CM"
112 #define TOK_CLOSE "CLOSE"
113 #define TOK_CNOTICE "CN"
114 #define TOK_CONNECT "CO"
115 #define TOK_CPRIVMSG "CP"
116 #define TOK_CREATE "C"
117 #define TOK_DESTRUCT "DE"
118 #define TOK_DESYNCH "DS"
119 #define TOK_DIE "DIE"
120 #define TOK_DNS "DNS"
122 #define TOK_EOB_ACK "EA"
123 #define TOK_ERROR "Y"
124 #define TOK_FAKEHOST "FA"
125 #define TOK_GET "GET"
126 #define TOK_GLINE "GL"
127 #define TOK_HASH "HASH"
128 #define TOK_HELP "HELP"
130 #define TOK_INVITE "I"
131 #define TOK_ISON "ISON"
133 #define TOK_JUPE "JU"
136 #define TOK_LINKS "LI"
137 #define TOK_LIST "LIST"
138 #define TOK_LUSERS "LU"
139 #define TOK_MAP "MAP"
141 #define TOK_MOTD "MO"
142 #define TOK_NAMES "E"
144 #define TOK_NOTICE "O"
145 #define TOK_OPER "OPER"
146 #define TOK_OPMODE "OM"
148 #define TOK_PASS "PA"
151 #define TOK_POST "POST"
152 #define TOK_PRIVMSG "P"
153 #define TOK_PRIVS "PRIVS"
154 #define TOK_PROTO "PROTO"
156 #define TOK_REHASH "REHASH"
157 #define TOK_RESET "RESET"
158 #define TOK_RESTART "RESTART"
159 #define TOK_RPING "RI"
160 #define TOK_RPONG "RO"
161 #define TOK_SERVER "S"
162 #define TOK_SERVLIST "SERVSET"
163 #define TOK_SERVSET "SERVSET"
164 #define TOK_SET "SET"
165 #define TOK_SETTIME "SE"
166 #define TOK_SILENCE "U"
167 #define TOK_SQUERY "SQUERY"
168 #define TOK_SQUIT "SQ"
169 #define TOK_STATS "R"
170 #define TOK_SVSNICK "SN"
171 #define TOK_TIME "TI"
172 #define TOK_TOPIC "T"
173 #define TOK_TRACE "TR"
174 #define TOK_UPING "UP"
175 #define TOK_USER "USER"
176 #define TOK_USERHOST "USERHOST"
177 #define TOK_USERIP "USERIP"
178 #define TOK_VERSION "V"
179 #define TOK_WALLCHOPS "WC"
180 #define TOK_WALLOPS "WA"
181 #define TOK_WALLUSERS "WU"
182 #define TOK_WALLVOICES "WV"
184 #define TOK_WHOIS "W"
185 #define TOK_WHOWAS "X"
187 /* Protocol messages; aliased to full commands or tokens depending
188 on compile-time configuration. ircu prefers tokens WITH THE
189 EXCEPTION OF THE SERVER AND PASS COMMANDS, which cannot be
190 tokenized, because clients' (ie. a linking server) commands are
191 only checked against the full command list.
193 #if defined(ENABLE_TOKENS)
194 #define TYPE(NAME) TOK_ ## NAME
195 #else /* !ENABLE_TOKENS */
196 #define TYPE(NAME) CMD_ ## NAME
197 #endif /* ENABLE_TOKENS */
199 #define P10_ACCOUNT TYPE(ACCOUNT)
200 #define P10_ADMIN TYPE(ADMIN)
201 #define P10_ASLL TYPE(ASLL)
202 #define P10_AWAY TYPE(AWAY)
203 #define P10_BURST TYPE(BURST)
204 #define P10_CLEARMODE TYPE(CLEARMODE)
205 #define P10_CLOSE TYPE(CLOSE)
206 #define P10_CNOTICE TYPE(CNOTICE)
207 #define P10_CONNECT TYPE(CONNECT)
208 #define P10_CPRIVMSG TYPE(CPRIVMSG)
209 #define P10_CREATE TYPE(CREATE)
210 #define P10_DESTRUCT TYPE(DESTRUCT)
211 #define P10_DESYNCH TYPE(DESYNCH)
212 #define P10_DIE TYPE(DIE)
213 #define P10_DNS TYPE(DNS)
214 #define P10_EOB TYPE(EOB)
215 #define P10_EOB_ACK TYPE(EOB_ACK)
216 #define P10_ERROR TYPE(ERROR)
217 #define P10_FAKEHOST TYPE(FAKEHOST)
218 #define P10_GET TYPE(GET)
219 #define P10_GLINE TYPE(GLINE)
220 #define P10_HASH TYPE(HASH)
221 #define P10_HELP TYPE(HELP)
222 #define P10_INFO TYPE(INFO)
223 #define P10_INVITE TYPE(INVITE)
224 #define P10_ISON TYPE(ISON)
225 #define P10_JOIN TYPE(JOIN)
226 #define P10_JUPE TYPE(JUPE)
227 #define P10_KICK TYPE(KICK)
228 #define P10_KILL TYPE(KILL)
229 #define P10_LINKS TYPE(LINKS)
230 #define P10_LIST TYPE(LIST)
231 #define P10_LUSERS TYPE(LUSERS)
232 #define P10_MAP TYPE(MAP)
233 #define P10_MODE TYPE(MODE)
234 #define P10_MOTD TYPE(MOTD)
235 #define P10_NAMES TYPE(NAMES)
236 #define P10_NICK TYPE(NICK)
237 #define P10_NOTICE TYPE(NOTICE)
238 #define P10_OPER TYPE(OPER)
239 #define P10_OPMODE TYPE(OPMODE)
240 #define P10_PART TYPE(PART)
241 #define P10_PASS CMD_PASS
242 #define P10_PING TYPE(PING)
243 #define P10_PONG TYPE(PONG)
244 #define P10_POST TYPE(POST)
245 #define P10_PRIVMSG TYPE(PRIVMSG)
246 #define P10_PRIVS TYPE(PRIVS)
247 #define P10_PROTO TYPE(PROTO)
248 #define P10_QUIT TYPE(QUIT)
249 #define P10_REHASH TYPE(REHASH)
250 #define P10_RESET TYPE(RESET)
251 #define P10_RESTART TYPE(RESTART)
252 #define P10_RPING TYPE(RPING)
253 #define P10_RPONG TYPE(RPONG)
254 #define P10_SERVER CMD_SERVER
255 #define P10_SERVLIST TYPE(SERVLIST)
256 #define P10_SERVSET TYPE(SERVSET)
257 #define P10_SET TYPE(SET)
258 #define P10_SETTIME TYPE(SETTIME)
259 #define P10_SILENCE TYPE(SILENCE)
260 #define P10_SQUERY TYPE(SQUERY)
261 #define P10_SQUIT TYPE(SQUIT)
262 #define P10_STATS TYPE(STATS)
263 #define P10_SVSNICK TYPE(SVSNICK)
264 #define P10_TIME TYPE(TIME)
265 #define P10_TOPIC TYPE(TOPIC)
266 #define P10_TRACE TYPE(TRACE)
267 #define P10_UPING TYPE(UPING)
268 #define P10_USER TYPE(USER)
269 #define P10_USERHOST TYPE(USERHOST)
270 #define P10_USERIP TYPE(USERIP)
271 #define P10_VERSION TYPE(VERSION)
272 #define P10_WALLCHOPS TYPE(WALLCHOPS)
273 #define P10_WALLOPS TYPE(WALLOPS)
274 #define P10_WALLUSERS TYPE(WALLUSERS)
275 #define P10_WALLVOICES TYPE(WALLVOICES)
276 #define P10_WHO TYPE(WHO)
277 #define P10_WHOIS TYPE(WHOIS)
278 #define P10_WHOWAS TYPE(WHOWAS)
280 /* Servers claiming to have a boot or link time before PREHISTORY
281 * trigger errors to the log. We hope no server has been running
282 * constantly since September 1994. :)
284 #define PREHISTORY 780000000
286 static struct server
*servers_num
[64*64];
287 static privmsg_func_t
*privmsg_funcs
;
288 static unsigned int num_privmsg_funcs
;
289 static privmsg_func_t
*notice_funcs
;
290 static unsigned int num_notice_funcs
;
291 static struct dict
*unbursted_channels
;
292 static char *his_servername
;
293 static char *his_servercomment
;
295 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
);
297 extern int off_channel
;
299 /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
300 * server and Y's indentifying the client on that server. */
302 GetServerN(const char *numeric
)
304 switch (strlen(numeric
)) {
306 return servers_num
[base64toint(numeric
, 2)];
310 return servers_num
[base64toint(numeric
, 1)];
317 GetUserN(const char *numeric
) /* using numeric */
323 switch (strlen(numeric
)) {
325 log_module(MAIN_LOG
, LOG_WARNING
, "GetUserN(%s): numeric too long!", numeric
);
327 case 5: slen
= 2; ulen
= 3; break;
328 case 4: slen
= 1; ulen
= 3; break;
329 case 3: slen
= 1; ulen
= 2; break;
330 case 2: case 1: case 0:
331 log_module(MAIN_LOG
, LOG_WARNING
, "GetUserN(%s): numeric too short!", numeric
);
334 if (!(s
= servers_num
[base64toint(numeric
, slen
)])) {
335 log_module(MAIN_LOG
, LOG_WARNING
, "GetUserN(%s): couldn't find server (len=%d)!", numeric
, slen
);
338 n
= base64toint(numeric
+slen
, ulen
) & s
->num_mask
;
339 if (!(un
= s
->users
[n
])) {
340 log_module(MAIN_LOG
, LOG_WARNING
, "GetUserN(%s) couldn't find user!", numeric
);
346 privmsg_user_helper(struct userNode
*un
, void *data
)
348 struct privmsg_desc
*pd
= data
;
349 unsigned int num
= un
->num_local
;
350 if (!pd
->is_notice
) {
351 if ((num
< num_privmsg_funcs
) && privmsg_funcs
[num
]) {
352 privmsg_funcs
[num
](pd
->user
, un
, pd
->text
, pd
->is_qualified
);
355 if ((num
< num_notice_funcs
) && notice_funcs
[num
]) {
356 notice_funcs
[num
](pd
->user
, un
, pd
->text
, pd
->is_qualified
);
362 irc_server(struct server
*srv
)
364 char extranum
[COMBO_NUMERIC_LEN
+1];
366 inttobase64(extranum
, srv
->num_mask
, (srv
->numeric
[1] || (srv
->num_mask
>= 64*64)) ? 3 : 2);
368 /* The +s, ignored by Run's ircu, means "service" to Undernet's ircu */
369 putsock(P10_SERVER
" %s %d %li %li J10 %s%s +s :%s",
370 srv
->name
, srv
->hops
+1, srv
->boot
, srv
->link
, srv
->numeric
, extranum
, srv
->description
);
372 putsock("%s " P10_SERVER
" %s %d %li %li %c10 %s%s +s :%s",
373 self
->numeric
, srv
->name
, srv
->hops
+1, srv
->boot
, srv
->link
, (srv
->self_burst
? 'J' : 'P'), srv
->numeric
, extranum
, srv
->description
);
378 irc_user(struct userNode
*user
)
383 inttobase64(b64ip
, ntohl(user
->ip
.s_addr
), 6);
390 modes
[modelen
++] = 'o';
391 if (IsInvisible(user
))
392 modes
[modelen
++] = 'i';
394 modes
[modelen
++] = 'w';
396 modes
[modelen
++] = 'k';
397 if (IsServNotice(user
))
398 modes
[modelen
++] = 's';
400 modes
[modelen
++] = 'd';
402 modes
[modelen
++] = 'g';
403 // sethost - reed/apples
404 // if (IsHelperIrcu(user))
406 modes
[modelen
++] = 'h';
407 if (IsFakeHost(user
))
408 modes
[modelen
++] = 'f';
409 if (IsHiddenHost(user
))
410 modes
[modelen
++] = 'x';
413 /* we don't need to put the + in modes because it's in the format string. */
414 putsock("%s " P10_NICK
" %s %d %li %s %s +%s %s %s :%s",
415 user
->uplink
->numeric
, user
->nick
, user
->uplink
->hops
+1, user
->timestamp
, user
->ident
, user
->hostname
, modes
, b64ip
, user
->numeric
, user
->info
);
417 putsock("%s " P10_NICK
" %s %d %li %s %s %s %s :%s",
418 user
->uplink
->numeric
, user
->nick
, user
->uplink
->hops
+1, user
->timestamp
, user
->ident
, user
->hostname
, b64ip
, user
->numeric
, user
->info
);
423 irc_account(struct userNode
*user
, const char *stamp
)
425 putsock("%s " P10_ACCOUNT
" %s %s", self
->numeric
, user
->numeric
, stamp
);
429 irc_fakehost(struct userNode
*user
, const char *host
)
431 putsock("%s " P10_FAKEHOST
" %s %s", self
->numeric
, user
->numeric
, host
);
435 irc_regnick(UNUSED_ARG(struct userNode
*user
))
437 /* no operation here */
441 irc_nick(struct userNode
*user
, UNUSED_ARG(const char *old_nick
))
443 putsock("%s " P10_NICK
" %s "FMT_TIME_T
, user
->numeric
, user
->nick
, now
);
447 irc_fetchtopic(struct userNode
*from
, const char *to
)
451 putsock("%s " P10_TOPIC
" %s", from
->numeric
, to
);
455 irc_squit(struct server
*srv
, const char *message
, const char *service_message
)
457 if (!service_message
)
458 service_message
= message
;
460 /* Are we leaving the network? */
461 if (srv
== self
&& cManager
.uplink
->state
== CONNECTED
) {
464 /* Quit all clients linked to me. */
465 for (i
= 0; i
<= self
->num_mask
; i
++) {
468 irc_quit(self
->users
[i
], service_message
);
472 putsock("%s " P10_SQUIT
" %s %d :%s", self
->numeric
, srv
->name
, 0, message
);
475 /* Force a reconnect to the currently selected server. */
476 cManager
.uplink
->tries
= 0;
477 log_module(MAIN_LOG
, LOG_INFO
, "Squitting from uplink: %s", message
);
483 irc_wallchops(struct userNode
*from
, const char *to
, const char *message
)
485 putsock("%s " P10_WALLCHOPS
" %s :%s", from
->numeric
, to
, message
);
489 irc_notice(struct userNode
*from
, const char *to
, const char *message
)
491 putsock("%s " P10_NOTICE
" %s :%s", from
->numeric
, to
, message
);
495 irc_notice_user(struct userNode
*from
, struct userNode
*to
, const char *message
)
497 putsock("%s " P10_NOTICE
" %s :%s", from
->numeric
, to
->numeric
, message
);
501 irc_privmsg(struct userNode
*from
, const char *to
, const char *message
)
503 putsock("%s " P10_PRIVMSG
" %s :%s", from
->numeric
, to
, message
);
509 putsock("%s " P10_EOB
, self
->numeric
);
515 putsock("%s " P10_EOB_ACK
, self
->numeric
);
519 irc_ping(const char *payload
)
521 putsock("%s " P10_PING
" :%s", self
->numeric
, payload
);
525 irc_pong(const char *who
, const char *data
)
527 putsock("%s " P10_PONG
" %s :%s", self
->numeric
, who
, data
);
531 irc_pass(const char *passwd
)
533 putsock(P10_PASS
" :%s", passwd
);
537 irc_introduce(const char *passwd
)
539 void timed_send_ping(void *data
);
541 self
->self_burst
= self
->burst
= 1;
545 timeq_add(now
+ ping_freq
, timed_send_ping
, 0);
549 irc_gline(struct server
*srv
, struct gline
*gline
)
551 putsock("%s " P10_GLINE
" %s +%s %ld :<%s> %s",
552 self
->numeric
, (srv
? srv
->numeric
: "*"), gline
->target
, gline
->expires
-now
, gline
->issuer
, gline
->reason
);
556 irc_settime(const char *srv_name_mask
, time_t new_time
)
558 ioset_set_time(new_time
);
559 if (!strcmp(srv_name_mask
, "*"))
561 putsock("%s " P10_SETTIME
" " FMT_TIME_T
" %s", self
->numeric
, new_time
, srv_name_mask
);
565 irc_ungline(const char *mask
)
567 putsock("%s " P10_GLINE
" * -%s", self
->numeric
, mask
);
571 irc_burst(struct chanNode
*chan
)
573 char burst_line
[512];
574 int pos
, base_len
, len
;
580 base_len
= sprintf(burst_line
, "%s " P10_BURST
" %s " FMT_TIME_T
" ",
581 self
->numeric
, chan
->name
, chan
->timestamp
);
582 len
= irc_make_chanmode(chan
, burst_line
+base_len
);
583 pos
= base_len
+ len
;
585 burst_line
[pos
++] = ' ';
588 for (n
=0; n
<chan
->members
.used
; n
++) {
589 mn
= chan
->members
.list
[n
];
591 burst_line
[pos
-1] = 0; /* -1 to back up over the space or comma */
592 putsock("%s", burst_line
);
596 memcpy(burst_line
+pos
, mn
->user
->numeric
, strlen(mn
->user
->numeric
));
597 pos
+= strlen(mn
->user
->numeric
);
598 if (mn
->modes
&& (mn
->modes
!= last_mode
)) {
599 last_mode
= mn
->modes
;
600 burst_line
[pos
++] = ':';
601 if (last_mode
& MODE_CHANOP
)
602 burst_line
[pos
++] = 'o';
603 if (last_mode
& MODE_VOICE
)
604 burst_line
[pos
++] = 'v';
606 if ((n
+1)<chan
->members
.used
)
607 burst_line
[pos
++] = ',';
609 if (chan
->banlist
.used
) {
611 if (pos
+2+strlen(chan
->banlist
.list
[0]->ban
) > 505) {
612 burst_line
[pos
-1] = 0;
613 putsock("%s", burst_line
);
616 burst_line
[pos
++] = ' ';
619 burst_line
[pos
++] = ':';
620 burst_line
[pos
++] = '%';
622 for (n
=0; n
<chan
->banlist
.used
; n
++) {
623 bn
= chan
->banlist
.list
[n
];
624 len
= strlen(bn
->ban
);
625 if (pos
+len
+1 > 510) {
626 burst_line
[pos
-1] = 0; /* -1 to back up over the space or comma */
627 putsock("%s", burst_line
);
630 memcpy(burst_line
+pos
, bn
->ban
, len
);
632 burst_line
[pos
++] = ' ';
635 /* print the last line */
637 putsock("%s", burst_line
);
641 irc_quit(struct userNode
*user
, const char *message
)
643 putsock("%s " P10_QUIT
" :%s", user
->numeric
, message
);
647 irc_error(const char *to
, const char *message
)
650 putsock("%s " P10_ERROR
" :%s", to
, message
);
652 putsock(":%s " P10_ERROR
" :%s", self
->name
, message
);
657 irc_kill(struct userNode
*from
, struct userNode
*target
, const char *message
)
660 putsock("%s " P10_KILL
" %s :%s!%s (%s)",
661 from
->numeric
, target
->numeric
, self
->name
, from
->nick
, message
);
663 putsock("%s " P10_KILL
" %s :%s (%s)",
664 self
->numeric
, target
->numeric
, self
->name
, message
);
669 irc_mode(struct userNode
*from
, struct chanNode
*target
, const char *modes
)
671 putsock("%s " P10_MODE
" %s %s "FMT_TIME_T
,
672 (from
? from
->numeric
: self
->numeric
),
673 target
->name
, modes
, target
->timestamp
);
677 irc_invite(struct userNode
*from
, struct userNode
*who
, struct chanNode
*to
)
679 putsock("%s " P10_INVITE
" %s %s", from
->numeric
, who
->nick
, to
->name
);
683 irc_join(struct userNode
*who
, struct chanNode
*what
)
685 if (what
->members
.used
== 1) {
686 putsock("%s " P10_CREATE
" %s %lu",
687 who
->numeric
, what
->name
, what
->timestamp
);
689 putsock("%s " P10_JOIN
" %s %lu", who
->numeric
, what
->name
, what
->timestamp
);
694 irc_kick(struct userNode
*who
, struct userNode
*target
, struct chanNode
*channel
, const char *msg
)
697 struct modeNode
*mn
= GetUserMode(channel
, who
);
698 numeric
= ((mn
&& (mn
->modes
& MODE_CHANOP
)) || off_channel
) ? who
->numeric
: self
->numeric
;
699 putsock("%s " P10_KICK
" %s %s :%s",
700 numeric
, channel
->name
, target
->numeric
, msg
);
704 irc_stats(struct userNode
*from
, struct server
*target
, char type
)
706 putsock("%s " P10_STATS
" %c :%s", from
->numeric
, type
, target
->numeric
);
710 irc_svsnick(struct userNode
*from
, struct userNode
*target
, const char *newnick
)
712 putsock("%s " P10_SVSNICK
" %s %s "FMT_TIME_T
, from
->uplink
->numeric
, target
->numeric
, newnick
, now
);
716 irc_part(struct userNode
*who
, struct chanNode
*what
, const char *reason
)
719 putsock("%s " P10_PART
" %s :%s", who
->numeric
, what
->name
, reason
);
721 putsock("%s " P10_PART
" %s", who
->numeric
, what
->name
);
726 irc_topic(struct userNode
*who
, struct chanNode
*what
, const char *topic
)
728 putsock("%s " P10_TOPIC
" %s :%s", who
->numeric
, what
->name
, topic
);
732 irc_raw(const char *what
)
738 irc_numeric(struct userNode
*user
, unsigned int num
, const char *format
, ...)
742 va_start(arg_list
, format
);
743 vsnprintf(buffer
, MAXLEN
-2, format
, arg_list
);
744 buffer
[MAXLEN
-1] = 0;
745 putsock(":%s %03d %s %s", self
->name
, num
, user
->nick
, buffer
);
748 static void send_burst(void);
751 change_nicklen(int new_nicklen
)
754 char new_nick
[NICKLEN
+1];
755 struct userNode
*user
;
757 nicklen
= new_nicklen
;
758 /* fix up any users we have here */
759 for (nn
=0; nn
<=self
->num_mask
; nn
++) {
760 if (!(user
= self
->users
[nn
]))
762 safestrncpy(new_nick
, user
->nick
, sizeof(new_nick
));
763 new_nick
[nicklen
] = 0;
764 NickChange(user
, new_nick
, 1);
768 static CMD_FUNC(cmd_whois
)
770 struct userNode
*from
;
771 struct userNode
*who
;
775 if (!(from
= GetUserH(origin
))) {
776 log_module(MAIN_LOG
, LOG_ERROR
, "Could not find WHOIS origin user %s", origin
);
779 if(!(who
= GetUserH(argv
[2]))) {
780 irc_numeric(from
, ERR_NOSUCHNICK
, "%s@%s :No such nick", argv
[2], self
->name
);
783 if (IsHiddenHost(who
) && !IsOper(from
)) {
784 /* Just stay quiet. */
787 irc_numeric(from
, RPL_WHOISUSER
, "%s %s %s * :%s", who
->nick
, who
->ident
, who
->hostname
, who
->info
);
788 if (his_servername
&& his_servercomment
)
789 irc_numeric(from
, RPL_WHOISSERVER
, "%s %s :%s", who
->nick
, his_servername
, his_servercomment
);
791 irc_numeric(from
, RPL_WHOISSERVER
, "%s %s :%s", who
->nick
, who
->uplink
->name
, who
->uplink
->description
);
794 irc_numeric(from
, RPL_WHOISOPERATOR
, "%s :is a megalomaniacal power hungry tyrant", who
->nick
);
796 irc_numeric(from
, RPL_ENDOFWHOIS
, "%s :End of /WHOIS list", who
->nick
);
800 static CMD_FUNC(cmd_server
)
808 /* another server introduced us */
809 srv
= AddServer(GetServerH(origin
), argv
[1], atoi(argv
[2]), atoi(argv
[3]), atoi(argv
[4]), argv
[6], argv
[argc
-1]);
812 srv
->self_burst
= argv
[5][0] == 'J';
815 /* this must be our uplink */
816 srv
= self
->uplink
= AddServer(self
, argv
[1], atoi(argv
[2]), atoi(argv
[3]), atoi(argv
[4]), argv
[6], argv
[argc
-1]);
819 srv
->self_burst
= argv
[5][0] == 'J';
821 if ((argv
[7][0] == '+') && !force_n2k
) {
822 log_module(MAIN_LOG
, LOG_WARNING
, "Got Undernet-style SERVER message but \"force_n2k\" not on.");
827 /* Fix up our timestamps if necessary. */
828 if (srv
->boot
<= PREHISTORY
) {
829 /* Server from the mists of time.. */
830 if (srv
->hops
== 1) {
831 log_module(MAIN_LOG
, LOG_ERROR
, "Server %s claims to have booted at time "FMT_TIME_T
". This is absurd.", srv
->name
, srv
->boot
);
833 } else if ((str
= conf_get_data("server/reliable_clock", RECDB_QSTRING
))
834 && enabled_string(str
)) {
835 /* If we have a reliable clock, we just keep our current time. */
837 if (srv
->boot
<= self
->boot
) {
838 /* The other server is older than us. Accept their timestamp.
839 * Alternately, we are same age, but we accept their time
840 * since we are linking to them. */
841 self
->boot
= srv
->boot
;
842 ioset_set_time(srv
->link
);
845 if (srv
== self
->uplink
) {
846 extern time_t burst_begin
;
852 static CMD_FUNC(cmd_eob
)
854 struct server
*sender
;
858 if (!(sender
= GetServerH(origin
)))
860 if (sender
== self
->uplink
) {
861 cManager
.uplink
->state
= CONNECTED
;
862 for (it
= dict_first(unbursted_channels
); it
; it
= iter_next(it
))
863 irc_burst(iter_data(it
));
864 dict_delete(unbursted_channels
);
865 unbursted_channels
= NULL
;
869 sender
->self_burst
= 0;
870 recalc_bursts(sender
);
871 for (ii
=0; ii
<slf_used
; ii
++)
872 slf_list
[ii
](sender
);
876 static CMD_FUNC(cmd_eob_ack
)
878 extern time_t burst_begin
;
880 if (GetServerH(origin
) == self
->uplink
) {
881 burst_length
= now
- burst_begin
;
882 self
->self_burst
= self
->burst
= 0;
884 cManager
.uplink
->state
= CONNECTED
;
888 static CMD_FUNC(cmd_ping
)
894 irc_pong(argv
[2], argv
[1]);
895 else if ((srv
= GetServerH(origin
)))
896 irc_pong(self
->name
, srv
->numeric
);
897 else if ((un
= GetUserH(origin
)))
898 irc_pong(self
->name
, un
->numeric
);
900 irc_pong(self
->name
, origin
);
902 timeq_del(0, timed_send_ping
, 0, TIMEQ_IGNORE_WHEN
|TIMEQ_IGNORE_DATA
);
903 timeq_del(0, timed_ping_timeout
, 0, TIMEQ_IGNORE_WHEN
|TIMEQ_IGNORE_DATA
);
904 timeq_add(now
+ ping_freq
, timed_send_ping
, 0);
909 static CMD_FUNC(cmd_error_nick
)
911 /* Go back to original IRC length .. and try to reconnect :/ */
913 irc_squit(self
, "Got erroneous nickname, truncating nicks.", NULL
);
918 struct userNode
*user
;
923 join_helper(struct chanNode
*chan
, void *data
)
925 struct create_desc
*cd
= data
;
926 AddChannelUser(cd
->user
, chan
);
930 create_helper(char *name
, void *data
)
932 struct create_desc
*cd
= data
;
934 if (!strcmp(name
, "0")) {
935 while (cd
->user
->channels
.used
> 0)
936 DelChannelUser(cd
->user
, cd
->user
->channels
.list
[0]->channel
, 0, 0);
940 AddChannelUser(cd
->user
, AddChannel(name
, cd
->when
, NULL
, NULL
));
943 static CMD_FUNC(cmd_create
)
945 struct create_desc cd
;
946 struct userNode
*user
;
948 if ((argc
< 3) || !(user
= GetUserH(origin
)))
951 cd
.when
= atoi(argv
[2]);
952 parse_foreach(argv
[1], join_helper
, create_helper
, NULL
, NULL
, &cd
);
956 static CMD_FUNC(cmd_join
)
958 struct create_desc cd
;
960 if (!(cd
.user
= GetUserH(origin
)))
967 cd
.when
= atoi(argv
[2]);
968 parse_foreach(argv
[1], join_helper
, create_helper
, NULL
, NULL
, &cd
);
972 static CMD_FUNC(cmd_pong
)
976 if (!strcmp(argv
[2], self
->name
)) {
977 timeq_del(0, timed_send_ping
, 0, TIMEQ_IGNORE_WHEN
|TIMEQ_IGNORE_DATA
);
978 timeq_del(0, timed_ping_timeout
, 0, TIMEQ_IGNORE_WHEN
|TIMEQ_IGNORE_DATA
);
979 timeq_add(now
+ ping_freq
, timed_send_ping
, 0);
985 static CMD_FUNC(cmd_nick
)
987 struct userNode
*user
;
988 if ((user
= GetUserH(origin
))) {
989 /* nick change (since the source is a user numeric) */
992 NickChange(user
, argv
[1], 1);
999 serv
= GetServerH(origin
);
1001 unsplit_string(argv
+6, argc
-9, modes
);
1004 AddUser(serv
, argv
[1], argv
[4], argv
[5], modes
, argv
[argc
-2], argv
[argc
-1], atoi(argv
[3]), argv
[argc
-3]);
1009 static CMD_FUNC(cmd_account
)
1011 struct userNode
*user
;
1013 if ((argc
< 3) || !origin
|| !GetServerH(origin
))
1014 return 0; /* Origin must be server. */
1015 user
= GetUserN(argv
[1]);
1017 return 1; /* A QUIT probably passed the ACCOUNT. */
1018 call_account_func(user
, argv
[2]);
1022 static CMD_FUNC(cmd_fakehost
)
1024 struct userNode
*user
;
1026 if ((argc
< 3) || !origin
|| !GetServerH(origin
))
1028 if (!(user
= GetUserN(argv
[1])))
1030 assign_fakehost(user
, argv
[2], 0);
1034 static CMD_FUNC(cmd_burst
)
1037 char modes
[MAXLEN
], *members
= "", *banlist
= NULL
;
1038 unsigned int next
= 3, res
= 1;
1039 struct chanNode
*cNode
;
1040 struct userNode
*un
;
1041 struct modeNode
*mNode
;
1043 char *user
, *end
, sep
;
1044 time_t in_timestamp
;
1049 while (next
< argc
) {
1050 switch (argv
[next
][0]) {
1054 for (pos
=argv
[next
], n_modes
= 1; *pos
; pos
++)
1055 if ((*pos
== 'k') || (*pos
== 'l'))
1057 unsplit_string(argv
+next
, n_modes
, modes
);
1061 case '%': banlist
= argv
[next
++]+1; break;
1062 default: members
= argv
[next
++]; break;
1066 in_timestamp
= atoi(argv
[2]);
1067 if ((cNode
= dict_find(unbursted_channels
, argv
[1], NULL
))) {
1068 cNode
->timestamp
= in_timestamp
;
1069 dict_remove(unbursted_channels
, cNode
->name
);
1072 cNode
= AddChannel(argv
[1], in_timestamp
, modes
, banlist
);
1074 /* Burst channel members in now. */
1075 for (user
= members
, sep
= *members
, mode
= 0; sep
; user
= end
) {
1076 for (end
= user
+ 3; isalnum(*end
) || *end
== '[' || *end
== ']'; end
++) ;
1077 sep
= *end
++; end
[-1] = 0;
1080 while ((sep
= *end
++)) {
1082 mode
|= MODE_CHANOP
;
1083 else if (sep
== 'v')
1091 if (!(un
= GetUserN(user
))) {
1095 if ((mNode
= AddChannelUser(un
, cNode
)))
1096 mNode
->modes
= mode
;
1102 static CMD_FUNC(cmd_mode
)
1104 struct chanNode
*cn
;
1105 struct userNode
*un
;
1106 char *sethost
; // sethost - reed/apples
1107 int i
; // sethost - reed/apples
1111 if (!IsChannelName(argv
[1])) {
1112 un
= GetUserH(argv
[1]);
1114 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find user %s whose mode is changing.", argv
[1]);
1117 // sethost - reed/apples
1119 mod_usermode(un
, argv
[2]);
1121 sethost
= malloc(strlen(argv
[2]) + 1 + strlen(argv
[3]) + 1);
1123 while((sethost
[i
++] = *argv
[2]++));
1126 while((sethost
[i
++] = *argv
[3]++));
1127 mod_usermode(un
, sethost
); // sethost - reed/apples
1133 if (!(cn
= GetChannel(argv
[1]))) {
1134 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing.", argv
[1]);
1137 if ((un
= GetUserH(origin
))) {
1138 struct modeNode
*mn
;
1139 /* Update idle time for person setting the mode */
1140 if ((mn
= GetUserMode(cn
, un
)))
1141 mn
->idle_since
= now
;
1143 /* If it came from a server, reset timestamp to re-sync. */
1144 cn
->timestamp
= atoi(argv
[argc
-1]);
1147 return mod_chanmode(un
, cn
, argv
+2, argc
-2, MCP_ALLOW_OVB
|MCP_FROM_SERVER
|(un
? MC_NOTIFY
: 0));
1150 static CMD_FUNC(cmd_opmode
)
1152 struct chanNode
*cn
;
1153 struct userNode
*un
;
1158 if (!(cn
= GetChannel(argv
[1]))) {
1159 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing.", argv
[1]);
1162 if (!(un
= GetUserH(origin
))) {
1163 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find user %s requesting OPMODE.", origin
);
1167 log_module(MAIN_LOG
, LOG_ERROR
, "Non-privileged user %s using OPMODE.", un
->nick
);
1171 return mod_chanmode(un
, cn
, argv
+2, argc
-2, MCP_ALLOW_OVB
|MCP_FROM_SERVER
); /* do NOT announce opmode locally */
1174 static int clear_chanmode(struct chanNode
*channel
, const char *modes
);
1176 static CMD_FUNC(cmd_clearmode
)
1178 struct chanNode
*cn
;
1179 struct userNode
*un
;
1184 if (!(cn
= GetChannel(argv
[1]))) {
1185 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose mode is changing.", argv
[1]);
1188 if (!(un
= GetUserH(origin
))) {
1189 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find user %s requesting CLEARMODE.", origin
);
1193 log_module(MAIN_LOG
, LOG_ERROR
, "Non-privileged user %s using CLEARMODE.", un
->nick
);
1197 return clear_chanmode(cn
, argv
[2]);
1200 static CMD_FUNC(cmd_topic
)
1202 struct chanNode
*cn
;
1203 time_t chan_ts
, topic_ts
;
1207 if (!(cn
= GetChannel(argv
[1]))) {
1208 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s whose topic is being set", argv
[1]);
1212 /* Looks like an Asuka style topic burst. */
1213 chan_ts
= atoi(argv
[2]);
1214 topic_ts
= atoi(argv
[3]);
1216 chan_ts
= cn
->timestamp
;
1219 SetChannelTopic(cn
, GetUserH(origin
), argv
[argc
-1], 0);
1220 cn
->topic_time
= topic_ts
;
1224 static CMD_FUNC(cmd_num_topic
)
1226 struct chanNode
*cn
;
1229 return 0; /* huh? */
1231 cn
= GetChannel(argv
[2]);
1233 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find channel %s in topic reply", argv
[2]);
1239 switch (atoi(argv
[0])) {
1242 break; /* no topic */
1246 safestrncpy(cn
->topic
, unsplit_string(argv
+3, argc
-3, NULL
), sizeof(cn
->topic
));
1251 safestrncpy(cn
->topic_nick
, argv
[3], sizeof(cn
->topic_nick
));
1252 cn
->topic_time
= atoi(argv
[4]);
1255 return 0; /* should never happen */
1260 static CMD_FUNC(cmd_num_gline
)
1264 gline_add(origin
, argv
[3], atoi(argv
[4])-now
, argv
[5], now
, 0);
1268 static CMD_FUNC(cmd_quit
)
1270 struct userNode
*user
;
1273 /* Sometimes we get a KILL then a QUIT or the like, so we don't want to
1274 * call DelUser unless we have the user in our grasp. */
1275 if ((user
= GetUserH(origin
)))
1276 DelUser(user
, NULL
, false, argv
[1]);
1280 static CMD_FUNC(cmd_kill
)
1282 struct userNode
*user
;
1285 user
= GetUserN(argv
[1]);
1287 /* If we get a KILL for a non-existent user, it could be a
1288 * Ghost response to a KILL we sent out earlier. So we only
1289 * whine if the target is local.
1291 if (!strncmp(argv
[1], self
->numeric
, strlen(self
->numeric
)))
1292 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to find kill victim %s", argv
[1]);
1296 if (IsLocal(user
) && IsService(user
)) {
1297 /* TODO: rate limit this so silly things don't happen. */
1298 ReintroduceUser(user
);
1302 DelUser(user
, NULL
, false, argv
[2]);
1306 static CMD_FUNC(cmd_part
)
1308 struct userNode
*user
;
1312 user
= GetUserH(origin
);
1315 parse_foreach(argv
[1], part_helper
, NULL
, NULL
, NULL
, user
);
1319 static CMD_FUNC(cmd_kick
)
1323 ChannelUserKicked(GetUserH(origin
), GetUserN(argv
[2]), GetChannel(argv
[1]));
1327 static CMD_FUNC(cmd_squit
)
1329 struct server
*server
;
1333 if (!(server
= GetServerH(argv
[1])))
1336 if (server
== self
->uplink
) {
1337 /* Force a reconnect to the currently selected server. */
1338 cManager
.uplink
->tries
= 0;
1339 log_module(MAIN_LOG
, LOG_INFO
, "Squitting from uplink: %s", argv
[3]);
1344 DelServer(server
, 0, argv
[3]);
1348 static CMD_FUNC(cmd_privmsg
)
1350 struct privmsg_desc pd
;
1353 pd
.user
= GetUserH(origin
);
1354 if (!pd
.user
|| (IsGagged(pd
.user
) && !IsOper(pd
.user
)))
1358 parse_foreach(argv
[1], privmsg_chan_helper
, NULL
, privmsg_user_helper
, privmsg_invalid
, &pd
);
1362 static CMD_FUNC(cmd_notice
)
1364 struct privmsg_desc pd
;
1367 pd
.user
= GetUserH(origin
);
1368 if (!pd
.user
|| (IsGagged(pd
.user
) && !IsOper(pd
.user
)))
1372 parse_foreach(argv
[1], privmsg_chan_helper
, NULL
, privmsg_user_helper
, privmsg_invalid
, &pd
);
1376 static CMD_FUNC(cmd_away
)
1378 struct userNode
*uNode
;
1380 uNode
= GetUserH(origin
);
1384 uNode
->modes
&= ~FLAGS_AWAY
;
1386 uNode
->modes
|= FLAGS_AWAY
;
1390 static CMD_FUNC(cmd_gline
)
1394 if (argv
[2][0] == '+') {
1397 gline_add(origin
, argv
[2]+1, strtoul(argv
[3], NULL
, 0), argv
[argc
-1], now
, 0);
1399 } else if (argv
[2][0] == '-') {
1400 gline_remove(argv
[2]+1, 0);
1406 static CMD_FUNC(cmd_svsnick
)
1408 struct userNode
*target
, *dest
;
1410 || !(target
= GetUserN(argv
[1]))
1412 || (dest
= GetUserH(argv
[2])))
1414 NickChange(target
, argv
[2], 0);
1418 static oper_func_t
*of_list
;
1419 static unsigned int of_size
= 0, of_used
= 0;
1422 free_user(struct userNode
*user
)
1433 free(privmsg_funcs
);
1436 dict_delete(irc_func_dict
);
1437 for (nn
=0; nn
<dead_users
.used
; nn
++)
1438 free_user(dead_users
.list
[nn
]);
1439 userList_clean(&dead_users
);
1443 p10_conf_reload(void) {
1444 hidden_host_suffix
= conf_get_data("server/hidden_host", RECDB_QSTRING
);
1448 remove_unbursted_channel(struct chanNode
*cNode
) {
1449 if (unbursted_channels
)
1450 dict_remove(unbursted_channels
, cNode
->name
);
1456 const char *str
, *desc
;
1457 int numnick
, usermask
, max_users
;
1458 char numer
[COMBO_NUMERIC_LEN
+1];
1460 /* read config items */
1461 str
= conf_get_data("server/ping_freq", RECDB_QSTRING
);
1462 ping_freq
= str
? ParseInterval(str
) : 120;
1463 str
= conf_get_data("server/ping_timeout", RECDB_QSTRING
);
1464 ping_timeout
= str
? ParseInterval(str
) : 30;
1465 str
= conf_get_data("server/force_n2k", RECDB_QSTRING
);
1466 force_n2k
= str
? enabled_string(str
) : 1;
1467 str
= conf_get_data("server/numeric", RECDB_QSTRING
);
1469 log_module(MAIN_LOG
, LOG_ERROR
, "No server/numeric entry in config file.");
1472 numnick
= atoi(str
);
1473 str
= conf_get_data("server/max_users", RECDB_QSTRING
);
1474 max_users
= str
? atoi(str
) : 4096;
1475 for (usermask
= 4; usermask
< max_users
; usermask
<<= 1) ;
1477 if ((numnick
< 64) && (usermask
< 4096) && !force_n2k
)
1478 inttobase64(numer
, (numnick
<< 12) + (usermask
& 0x00fff), 3);
1480 inttobase64(numer
, (numnick
<< 18) + (usermask
& 0x3ffff), 5);
1482 str
= conf_get_data("server/his_servername", RECDB_QSTRING
);
1483 his_servername
= str
? strdup(str
) : NULL
;
1484 str
= conf_get_data("server/his_servercomment", RECDB_QSTRING
);
1485 his_servercomment
= str
? strdup(str
) : NULL
;
1487 str
= conf_get_data("server/hostname", RECDB_QSTRING
);
1488 desc
= conf_get_data("server/description", RECDB_QSTRING
);
1489 if (!str
|| !desc
) {
1490 log_module(MAIN_LOG
, LOG_ERROR
, "No server/hostname entry in config file.");
1493 self
= AddServer(NULL
, str
, 0, boot_time
, now
, numer
, desc
);
1494 conf_register_reload(p10_conf_reload
);
1496 irc_func_dict
= dict_new();
1497 dict_insert(irc_func_dict
, CMD_BURST
, cmd_burst
);
1498 dict_insert(irc_func_dict
, TOK_BURST
, cmd_burst
);
1499 dict_insert(irc_func_dict
, CMD_CREATE
, cmd_create
);
1500 dict_insert(irc_func_dict
, TOK_CREATE
, cmd_create
);
1501 dict_insert(irc_func_dict
, CMD_EOB
, cmd_eob
);
1502 dict_insert(irc_func_dict
, TOK_EOB
, cmd_eob
);
1503 dict_insert(irc_func_dict
, CMD_EOB_ACK
, cmd_eob_ack
);
1504 dict_insert(irc_func_dict
, TOK_EOB_ACK
, cmd_eob_ack
);
1505 dict_insert(irc_func_dict
, CMD_MODE
, cmd_mode
);
1506 dict_insert(irc_func_dict
, TOK_MODE
, cmd_mode
);
1507 dict_insert(irc_func_dict
, CMD_NICK
, cmd_nick
);
1508 dict_insert(irc_func_dict
, TOK_NICK
, cmd_nick
);
1509 dict_insert(irc_func_dict
, CMD_ACCOUNT
, cmd_account
);
1510 dict_insert(irc_func_dict
, TOK_ACCOUNT
, cmd_account
);
1511 dict_insert(irc_func_dict
, CMD_FAKEHOST
, cmd_fakehost
);
1512 dict_insert(irc_func_dict
, TOK_FAKEHOST
, cmd_fakehost
);
1513 dict_insert(irc_func_dict
, CMD_PASS
, cmd_pass
);
1514 dict_insert(irc_func_dict
, TOK_PASS
, cmd_pass
);
1515 dict_insert(irc_func_dict
, CMD_PING
, cmd_ping
);
1516 dict_insert(irc_func_dict
, TOK_PING
, cmd_ping
);
1517 dict_insert(irc_func_dict
, CMD_PRIVMSG
, cmd_privmsg
);
1518 dict_insert(irc_func_dict
, TOK_PRIVMSG
, cmd_privmsg
);
1519 dict_insert(irc_func_dict
, CMD_PONG
, cmd_pong
);
1520 dict_insert(irc_func_dict
, TOK_PONG
, cmd_pong
);
1521 dict_insert(irc_func_dict
, CMD_QUIT
, cmd_quit
);
1522 dict_insert(irc_func_dict
, TOK_QUIT
, cmd_quit
);
1523 dict_insert(irc_func_dict
, CMD_SERVER
, cmd_server
);
1524 dict_insert(irc_func_dict
, TOK_SERVER
, cmd_server
);
1525 dict_insert(irc_func_dict
, CMD_JOIN
, cmd_join
);
1526 dict_insert(irc_func_dict
, TOK_JOIN
, cmd_join
);
1527 dict_insert(irc_func_dict
, CMD_PART
, cmd_part
);
1528 dict_insert(irc_func_dict
, TOK_PART
, cmd_part
);
1529 dict_insert(irc_func_dict
, CMD_ERROR
, cmd_error
);
1530 dict_insert(irc_func_dict
, TOK_ERROR
, cmd_error
);
1531 dict_insert(irc_func_dict
, CMD_TOPIC
, cmd_topic
);
1532 dict_insert(irc_func_dict
, TOK_TOPIC
, cmd_topic
);
1533 dict_insert(irc_func_dict
, CMD_AWAY
, cmd_away
);
1534 dict_insert(irc_func_dict
, TOK_AWAY
, cmd_away
);
1535 dict_insert(irc_func_dict
, CMD_SILENCE
, cmd_dummy
);
1536 dict_insert(irc_func_dict
, TOK_SILENCE
, cmd_dummy
);
1537 dict_insert(irc_func_dict
, CMD_KICK
, cmd_kick
);
1538 dict_insert(irc_func_dict
, TOK_KICK
, cmd_kick
);
1539 dict_insert(irc_func_dict
, CMD_SQUIT
, cmd_squit
);
1540 dict_insert(irc_func_dict
, TOK_SQUIT
, cmd_squit
);
1541 dict_insert(irc_func_dict
, CMD_KILL
, cmd_kill
);
1542 dict_insert(irc_func_dict
, TOK_KILL
, cmd_kill
);
1543 dict_insert(irc_func_dict
, CMD_NOTICE
, cmd_notice
);
1544 dict_insert(irc_func_dict
, TOK_NOTICE
, cmd_notice
);
1545 dict_insert(irc_func_dict
, CMD_STATS
, cmd_stats
);
1546 dict_insert(irc_func_dict
, TOK_STATS
, cmd_stats
);
1547 dict_insert(irc_func_dict
, CMD_SVSNICK
, cmd_svsnick
);
1548 dict_insert(irc_func_dict
, TOK_SVSNICK
, cmd_svsnick
);
1549 dict_insert(irc_func_dict
, CMD_WHOIS
, cmd_whois
);
1550 dict_insert(irc_func_dict
, TOK_WHOIS
, cmd_whois
);
1551 dict_insert(irc_func_dict
, CMD_GLINE
, cmd_gline
);
1552 dict_insert(irc_func_dict
, TOK_GLINE
, cmd_gline
);
1553 dict_insert(irc_func_dict
, CMD_OPMODE
, cmd_opmode
);
1554 dict_insert(irc_func_dict
, TOK_OPMODE
, cmd_opmode
);
1555 dict_insert(irc_func_dict
, CMD_CLEARMODE
, cmd_clearmode
);
1556 dict_insert(irc_func_dict
, TOK_CLEARMODE
, cmd_clearmode
);
1557 dict_insert(irc_func_dict
, CMD_VERSION
, cmd_version
);
1558 dict_insert(irc_func_dict
, TOK_VERSION
, cmd_version
);
1559 dict_insert(irc_func_dict
, CMD_ADMIN
, cmd_admin
);
1560 dict_insert(irc_func_dict
, TOK_ADMIN
, cmd_admin
);
1562 /* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
1563 * Apparently to obliterate channels from any servers that think they
1566 dict_insert(irc_func_dict
, CMD_DESTRUCT
, cmd_dummy
);
1567 dict_insert(irc_func_dict
, TOK_DESTRUCT
, cmd_dummy
);
1568 /* Ignore invites */
1569 dict_insert(irc_func_dict
, CMD_INVITE
, cmd_dummy
);
1570 dict_insert(irc_func_dict
, TOK_INVITE
, cmd_dummy
);
1571 /* DESYNCH is just informational, so ignore it */
1572 dict_insert(irc_func_dict
, CMD_DESYNCH
, cmd_dummy
);
1573 dict_insert(irc_func_dict
, TOK_DESYNCH
, cmd_dummy
);
1574 /* Ignore channel operator notices. */
1575 dict_insert(irc_func_dict
, CMD_WALLCHOPS
, cmd_dummy
);
1576 dict_insert(irc_func_dict
, TOK_WALLCHOPS
, cmd_dummy
);
1577 dict_insert(irc_func_dict
, CMD_WALLVOICES
, cmd_dummy
);
1578 dict_insert(irc_func_dict
, TOK_WALLVOICES
, cmd_dummy
);
1579 /* Ignore opers being silly. */
1580 dict_insert(irc_func_dict
, CMD_WALLOPS
, cmd_dummy
);
1581 dict_insert(irc_func_dict
, TOK_WALLOPS
, cmd_dummy
);
1582 /* We have reliable clock! Always! Wraaa! */
1583 dict_insert(irc_func_dict
, CMD_SETTIME
, cmd_dummy
);
1584 dict_insert(irc_func_dict
, TOK_SETTIME
, cmd_dummy
);
1586 dict_insert(irc_func_dict
, "331", cmd_num_topic
);
1587 dict_insert(irc_func_dict
, "332", cmd_num_topic
);
1588 dict_insert(irc_func_dict
, "333", cmd_num_topic
);
1589 dict_insert(irc_func_dict
, "345", cmd_dummy
); /* blah has been invited to blah */
1590 dict_insert(irc_func_dict
, "432", cmd_error_nick
); /* Erroneus [sic] nickname */
1591 /* ban list resetting */
1592 /* "stats g" responses */
1593 dict_insert(irc_func_dict
, "247", cmd_num_gline
);
1594 dict_insert(irc_func_dict
, "219", cmd_dummy
); /* "End of /STATS report" */
1595 /* other numeric responses we might get */
1596 dict_insert(irc_func_dict
, "401", cmd_dummy
); /* target left network */
1597 dict_insert(irc_func_dict
, "403", cmd_dummy
); /* no such channel */
1598 dict_insert(irc_func_dict
, "404", cmd_dummy
); /* cannot send to channel */
1599 dict_insert(irc_func_dict
, "441", cmd_dummy
); /* target isn't on that channel */
1600 dict_insert(irc_func_dict
, "442", cmd_dummy
); /* you aren't on that channel */
1601 dict_insert(irc_func_dict
, "443", cmd_dummy
); /* is already on channel (after invite?) */
1602 dict_insert(irc_func_dict
, "461", cmd_dummy
); /* Not enough parameters (after TOPIC w/ 0 args) */
1603 dict_insert(irc_func_dict
, "467", cmd_dummy
); /* Channel key already set */
1605 num_privmsg_funcs
= 16;
1606 privmsg_funcs
= malloc(sizeof(privmsg_func_t
)*num_privmsg_funcs
);
1607 memset(privmsg_funcs
, 0, sizeof(privmsg_func_t
)*num_privmsg_funcs
);
1609 num_notice_funcs
= 16;
1610 notice_funcs
= malloc(sizeof(privmsg_func_t
)*num_notice_funcs
);
1611 memset(notice_funcs
, 0, sizeof(privmsg_func_t
)*num_notice_funcs
);
1613 userList_init(&dead_users
);
1614 reg_del_channel_func(remove_unbursted_channel
);
1615 reg_exit_func(parse_cleanup
);
1619 parse_line(char *line
, int recursive
)
1621 char *argv
[MAXNUMPARAMS
], *origin
;
1622 int argc
, cmd
, res
=0;
1625 argc
= split_line(line
, true, MAXNUMPARAMS
, argv
);
1626 cmd
= self
->uplink
|| !argv
[0][1] || !argv
[0][2];
1629 if (argv
[0][0] == ':') {
1631 } else if (!argv
[0][1] || !argv
[0][2]) {
1632 struct server
*sNode
= GetServerN(argv
[0]);
1633 origin
= sNode
? sNode
->name
: 0;
1635 struct userNode
*uNode
= GetUserN(argv
[0]);
1636 origin
= uNode
? uNode
->nick
: 0;
1640 if ((func
= dict_find(irc_func_dict
, argv
[cmd
], NULL
)))
1641 res
= func(origin
, argc
-cmd
, argv
+cmd
);
1644 log_module(MAIN_LOG
, LOG_ERROR
, "PARSE ERROR on line: %s", unsplit_string(argv
, argc
, NULL
));
1645 } else if (!recursive
) {
1647 for (i
=0; i
<dead_users
.used
; i
++)
1648 free_user(dead_users
.list
[i
]);
1649 dead_users
.used
= 0;
1655 parse_foreach(char *target_list
, foreach_chanfunc cf
, foreach_nonchan nc
, foreach_userfunc uf
, foreach_nonuser nu
, void *data
)
1660 while (*j
!= 0 && *j
!= ',')
1664 if (IsChannelName(target_list
)
1665 || (target_list
[0] == '0' && target_list
[1] == '\0')) {
1666 struct chanNode
*chan
= GetChannel(target_list
);
1672 nc(target_list
, data
);
1675 struct userNode
*user
;
1676 struct privmsg_desc
*pd
= data
;
1678 pd
->is_qualified
= 0;
1679 if (*target_list
== '@') {
1681 } else if (strchr(target_list
, '@')) {
1682 struct server
*server
;
1684 pd
->is_qualified
= 1;
1685 user
= GetUserH(strtok(target_list
, "@"));
1686 server
= GetServerH(strtok(NULL
, "@"));
1688 if (user
&& (user
->uplink
!= server
)) {
1689 /* Don't attempt to index into any arrays
1690 using a user's numeric on another server. */
1694 user
= GetUserN(target_list
);
1702 nu(target_list
, data
);
1706 } while (old
== ',');
1710 get_local_numeric(void)
1712 static unsigned int next_numeric
= 0;
1713 if (self
->clients
> self
->num_mask
)
1715 while (self
->users
[next_numeric
])
1716 if (++next_numeric
> self
->num_mask
)
1718 return next_numeric
;
1722 make_numeric(struct server
*svr
, int local_num
, char *outbuf
)
1726 if (force_n2k
|| svr
->numeric
[1]) {
1731 llen
= (local_num
< 64*64) ? 2 : 3;
1733 strncpy(outbuf
, svr
->numeric
, slen
);
1734 inttobase64(outbuf
+slen
, local_num
, llen
);
1735 outbuf
[slen
+llen
] = 0;
1739 AddServer(struct server
*uplink
, const char *name
, int hops
, time_t boot
, time_t link
, const char *numeric
, const char *description
)
1741 struct server
* sNode
;
1744 if ((sNode
= GetServerN(numeric
))) {
1745 /* This means we're trying to re-add an existant server.
1746 * To be safe, we should forget the previous incarnation.
1747 * (And all its linked servers.)
1749 * It usually only happens in replays when the original
1750 * had a ping timeout and the replay didn't (because
1751 * replaying a ping timeout invariably gets things wrong).
1753 DelServer(sNode
, 0, NULL
);
1756 switch (strlen(numeric
)) {
1757 case 5: slen
= 2; mlen
= 3; break;
1758 case 4: slen
= 1; mlen
= 3; break;
1759 case 3: slen
= 1; mlen
= 2; break;
1761 log_module(MAIN_LOG
, LOG_ERROR
, "AddServer(\"%s\", \"%s\", ...): Numeric %s has invalid length.", uplink
->name
, name
, numeric
);
1765 sNode
= calloc(1, sizeof(*sNode
));
1766 sNode
->uplink
= uplink
;
1767 safestrncpy(sNode
->name
, name
, sizeof(sNode
->name
));
1768 sNode
->num_mask
= base64toint(numeric
+slen
, mlen
);
1772 strncpy(sNode
->numeric
, numeric
, slen
);
1773 safestrncpy(sNode
->description
, description
, sizeof(sNode
->description
));
1774 sNode
->users
= calloc(sNode
->num_mask
+1, sizeof(*sNode
->users
));
1775 serverList_init(&sNode
->children
);
1776 if (sNode
->uplink
) {
1777 /* uplink may be NULL if we're just building ourself */
1778 serverList_append(&sNode
->uplink
->children
, sNode
);
1780 servers_num
[base64toint(numeric
, slen
)] = sNode
;
1781 dict_insert(servers
, sNode
->name
, sNode
);
1785 void DelServer(struct server
* serv
, int announce
, const char *message
)
1789 /* If we receive an ERROR command before the SERVER
1790 * command a NULL server can be passed */
1794 /* Hrm, what's the right way to SQUIT some other server?
1795 * (This code is only to handle killing juped servers.) */
1796 if (announce
&& (serv
->uplink
== self
) && (serv
!= self
->uplink
))
1797 irc_squit(serv
, message
, NULL
);
1799 /* must recursively remove servers linked to this one first */
1800 for (i
=serv
->children
.used
;i
>0;)
1801 if (serv
->children
.list
[--i
] != self
)
1802 DelServer(serv
->children
.list
[i
], false, NULL
);
1804 /* clean up server's user hash tables */
1805 for (i
=0;i
<=serv
->num_mask
;i
++)
1807 DelUser(serv
->users
[i
], NULL
, false, "server delinked");
1811 serverList_remove(&serv
->uplink
->children
, serv
);
1812 if (serv
== self
->uplink
)
1813 self
->uplink
= NULL
;
1814 servers_num
[base64toint(serv
->numeric
, strlen(serv
->numeric
))] = NULL
;
1815 dict_remove(servers
, serv
->name
);
1816 serverList_clean(&serv
->children
);
1822 AddService(const char *nick
, const char *desc
, const char *hostname
)
1824 char numeric
[COMBO_NUMERIC_LEN
+1];
1825 int local_num
= get_local_numeric();
1826 time_t timestamp
= now
;
1827 struct userNode
*old_user
= GetUserH(nick
);
1830 if (IsLocal(old_user
))
1832 timestamp
= old_user
->timestamp
- 1;
1834 if (local_num
== -1) {
1835 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to allocate numnick for service %s", nick
);
1839 hostname
= self
->name
;
1840 make_numeric(self
, local_num
, numeric
);
1841 return AddUser(self
, nick
, nick
, hostname
, "+oik", numeric
, desc
, now
, "AAAAAA");
1845 AddClone(const char *nick
, const char *ident
, const char *hostname
, const char *desc
)
1847 char numeric
[COMBO_NUMERIC_LEN
+1];
1848 int local_num
= get_local_numeric();
1849 time_t timestamp
= now
;
1850 struct userNode
*old_user
= GetUserH(nick
);
1853 if (IsLocal(old_user
))
1855 timestamp
= old_user
->timestamp
- 1;
1857 if (local_num
== -1) {
1858 log_module(MAIN_LOG
, LOG_ERROR
, "Unable to allocate numnick for clone %s", nick
);
1861 make_numeric(self
, local_num
, numeric
);
1862 return AddUser(self
, nick
, ident
, hostname
, "+i", numeric
, desc
, timestamp
, "AAAAAA");
1866 is_valid_nick(const char *nick
) {
1867 /* IRC has some of The Most Fucked-Up ideas about character sets
1869 if (!isalpha(*nick
) && !strchr("{|}~[\\]^_`", *nick
))
1871 for (++nick
; *nick
; ++nick
)
1872 if (!isalnum(*nick
) && !strchr("{|}~[\\]^-_`", *nick
))
1874 if (strlen(nick
) > nicklen
)
1879 static struct userNode
*
1880 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
)
1882 struct userNode
*oldUser
, *uNode
;
1883 unsigned int n
, ignore_user
;
1885 if ((strlen(numeric
) < 3) || (strlen(numeric
) > 5)) {
1886 log_module(MAIN_LOG
, LOG_WARNING
, "AddUser(%p, %s, ...): numeric %s wrong length!", uplink
, nick
, numeric
);
1891 log_module(MAIN_LOG
, LOG_WARNING
, "AddUser(%p, %s, ...): server for numeric %s doesn't exist!", uplink
, nick
, numeric
);
1895 if (uplink
!= GetServerN(numeric
)) {
1896 log_module(MAIN_LOG
, LOG_WARNING
, "AddUser(%p, %s, ...): server for numeric %s differs from nominal uplink %s.", uplink
, nick
, numeric
, uplink
->name
);
1900 if (!is_valid_nick(nick
)) {
1901 log_module(MAIN_LOG
, LOG_WARNING
, "AddUser(%p, %s, ...): invalid nickname detected.", uplink
, nick
);
1906 if ((oldUser
= GetUserH(nick
))) {
1907 if (IsLocal(oldUser
) && (IsService(oldUser
) || IsPersistent(oldUser
))) {
1908 /* The service should collide the new user off. */
1909 oldUser
->timestamp
= timestamp
- 1;
1912 if (oldUser
->timestamp
> timestamp
) {
1913 /* "Old" user is really newer; remove them */
1914 DelUser(oldUser
, 0, 1, "Overruled by older nick");
1916 /* User being added is too new; do not add them to
1917 * clients, but do add them to the server's list, since it
1918 * will send a KILL and QUIT soon. */
1923 /* create new usernode and set all values */
1924 uNode
= calloc(1, sizeof(*uNode
));
1925 uNode
->nick
= strdup(nick
);
1926 safestrncpy(uNode
->ident
, ident
, sizeof(uNode
->ident
));
1927 safestrncpy(uNode
->info
, userinfo
, sizeof(uNode
->info
));
1928 safestrncpy(uNode
->hostname
, hostname
, sizeof(uNode
->hostname
));
1929 safestrncpy(uNode
->numeric
, numeric
, sizeof(uNode
->numeric
));
1930 uNode
->ip
.s_addr
= htonl(base64toint(realip
, 6));
1931 uNode
->timestamp
= timestamp
;
1932 modeList_init(&uNode
->channels
);
1933 uNode
->uplink
= uplink
;
1934 if (++uNode
->uplink
->clients
> uNode
->uplink
->max_clients
) {
1935 uNode
->uplink
->max_clients
= uNode
->uplink
->clients
;
1937 uNode
->num_local
= base64toint(numeric
+strlen(uNode
->uplink
->numeric
), 3) & uNode
->uplink
->num_mask
;
1938 uNode
->uplink
->users
[uNode
->num_local
] = uNode
;
1939 mod_usermode(uNode
, modes
);
1943 dict_insert(clients
, uNode
->nick
, uNode
);
1944 if (dict_size(clients
) > max_clients
) {
1945 max_clients
= dict_size(clients
);
1946 max_clients_time
= now
;
1950 for (n
=0; n
<nuf_used
; n
++)
1951 if (nuf_list
[n
](uNode
))
1956 /* removes user from it's server's hash table and nick hash table */
1958 DelUser(struct userNode
* user
, struct userNode
*killer
, int announce
, const char *why
)
1962 /* mark them as dead, in case anybody cares */
1965 /* remove user from all channels */
1966 while (user
->channels
.used
> 0)
1967 DelChannelUser(user
, user
->channels
.list
[user
->channels
.used
-1]->channel
, false, 0);
1969 /* Call these in reverse order so ChanServ can update presence
1970 information before NickServ nukes the handle_info. */
1971 for (n
= duf_used
; n
> 0; )
1972 duf_list
[--n
](user
, killer
, why
);
1974 user
->uplink
->clients
--;
1975 user
->uplink
->users
[user
->num_local
] = NULL
;
1977 userList_remove(&curr_opers
, user
);
1978 /* remove from global dictionary, but not if after a collide */
1979 if (user
== dict_find(clients
, user
->nick
, NULL
))
1980 dict_remove(clients
, user
->nick
);
1982 if (IsInvisible(user
))
1987 irc_quit(user
, why
);
1989 irc_kill(killer
, user
, why
);
1992 modeList_clean(&user
->channels
);
1993 /* We don't free them, in case we try to privmsg them or something
1994 * (like when a stupid oper kills themself). We just put them onto
1995 * a list of clients that get freed after processing each line.
1997 if (dead_users
.size
)
1998 userList_append(&dead_users
, user
);
2003 void mod_usermode(struct userNode
*user
, const char *mode_change
) {
2004 static void call_oper_funcs(struct userNode
*user
);
2006 const char *word
= mode_change
;
2008 if (!user
|| !mode_change
)
2010 while (*word
!= ' ' && *word
) word
++;\
2011 while (*word
== ' ') word
++; \
2013 #define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
2014 switch (*mode_change
++) {
2015 case 0: case ' ': return;
2016 case '+': add
= 1; break;
2017 case '-': add
= 0; break;
2019 do_user_mode(FLAGS_OPER
);
2021 userList_append(&curr_opers
, user
);
2022 call_oper_funcs(user
);
2024 userList_remove(&curr_opers
, user
);
2027 case 'O': do_user_mode(FLAGS_LOCOP
); break;
2028 case 'i': do_user_mode(FLAGS_INVISIBLE
);
2034 case 'w': do_user_mode(FLAGS_WALLOP
); break;
2035 case 's': do_user_mode(FLAGS_SERVNOTICE
); break;
2036 case 'd': do_user_mode(FLAGS_DEAF
); break;
2037 case 'k': do_user_mode(FLAGS_SERVICE
); break;
2038 case 'g': do_user_mode(FLAGS_GLOBAL
); break;
2039 // sethost - reed/apples
2040 // case 'h': do_user_mode(FLAGS_HELPER); break;
2041 // I check if there's an 'h' in the first part, and if there,
2042 // then everything after the space becomes their new host.
2043 case 'h': do_user_mode(FLAGS_SETHOST
);
2045 char sethost
[MAXLEN
];
2047 for (ii
=0; (*word
!= ' ') && (*word
!= '\0'); )
2048 sethost
[ii
++] = *word
++;
2050 while (*word
== ' ')
2052 safestrncpy(user
->sethost
, sethost
, sizeof(user
->sethost
));
2055 case 'x': do_user_mode(FLAGS_HIDDEN_HOST
); break;
2060 for (ii
=0; (*word
!= ' ') && (*word
!= '\0'); )
2061 tag
[ii
++] = *word
++;
2063 while (*word
== ' ')
2065 call_account_func(user
, tag
);
2072 for (ii
=0; (*word
!= ' ') && (*word
!= '\0'); )
2073 host
[ii
++] = *word
++;
2075 while (*word
== ' ')
2077 assign_fakehost(user
, host
, 0);
2085 struct mod_chanmode
*
2086 mod_chanmode_parse(struct chanNode
*channel
, char **modes
, unsigned int argc
, unsigned int flags
)
2088 struct mod_chanmode
*change
;
2089 unsigned int ii
, in_arg
, ch_arg
, add
;
2093 if (!(change
= mod_chanmode_alloc(argc
- 1)))
2096 for (ii
= ch_arg
= 0, in_arg
= add
= 1;
2097 (modes
[0][ii
] != '\0') && (modes
[0][ii
] != ' ');
2099 switch (modes
[0][ii
]) {
2106 #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)
2107 case 'C': do_chan_mode(MODE_NOCTCPS
); break;
2108 case 'D': do_chan_mode(MODE_DELAYJOINS
); break;
2109 case 'c': do_chan_mode(MODE_NOCOLORS
); break;
2110 case 'i': do_chan_mode(MODE_INVITEONLY
); break;
2111 case 'm': do_chan_mode(MODE_MODERATED
); break;
2112 case 'n': do_chan_mode(MODE_NOPRIVMSGS
); break;
2113 case 'p': do_chan_mode(MODE_PRIVATE
); break;
2114 case 'r': do_chan_mode(MODE_REGONLY
); break;
2115 case 's': do_chan_mode(MODE_SECRET
); break;
2116 case 't': do_chan_mode(MODE_TOPICLIMIT
); break;
2117 case 'S': do_chan_mode(MODE_STRIPCOLOR
); break;
2118 case 'M': do_chan_mode(MODE_MODUNREG
); break;
2119 case 'N': do_chan_mode(MODE_NONOTICE
); break;
2120 case 'Q': do_chan_mode(MODE_NOQUITMSGS
); break;
2121 case 'T': do_chan_mode(MODE_NOAMSG
); break;
2122 case 'O': do_chan_mode(MODE_OPERSONLY
); break;
2123 // uncomment this when ssl is enabled on the network.
2124 // case 'z': do_chan_mode(MODE_SSLONLY); break;
2130 change
->modes_set
|= MODE_LIMIT
;
2131 change
->new_limit
= atoi(modes
[in_arg
++]);
2133 change
->modes_set
&= ~MODE_LIMIT
;
2134 change
->modes_clear
|= MODE_LIMIT
;
2141 change
->modes_set
|= MODE_KEY
;
2142 safestrncpy(change
->new_key
, modes
[in_arg
++], sizeof(change
->new_key
));
2144 change
->modes_clear
|= MODE_KEY
;
2145 if (!(flags
& MCP_KEY_FREE
)) {
2153 if (!(flags
& MCP_ALLOW_OVB
))
2157 change
->args
[ch_arg
].mode
= MODE_BAN
;
2159 change
->args
[ch_arg
].mode
|= MODE_REMOVE
;
2160 change
->args
[ch_arg
++].hostmask
= modes
[in_arg
++];
2164 struct userNode
*victim
;
2165 if (!(flags
& MCP_ALLOW_OVB
))
2169 change
->args
[ch_arg
].mode
= (modes
[0][ii
] == 'o') ? MODE_CHANOP
: MODE_VOICE
;
2171 change
->args
[ch_arg
].mode
|= MODE_REMOVE
;
2172 if (flags
& MCP_FROM_SERVER
)
2173 victim
= GetUserN(modes
[in_arg
++]);
2175 victim
= GetUserH(modes
[in_arg
++]);
2178 if ((change
->args
[ch_arg
].member
= GetUserMode(channel
, victim
)))
2183 if (!(flags
& MCP_FROM_SERVER
))
2188 change
->argc
= ch_arg
; /* in case any turned out to be ignored */
2189 if (change
->modes_set
& MODE_SECRET
) {
2190 change
->modes_set
&= ~(MODE_PRIVATE
);
2191 change
->modes_clear
|= MODE_PRIVATE
;
2192 } else if (change
->modes_set
& MODE_PRIVATE
) {
2193 change
->modes_set
&= ~(MODE_SECRET
);
2194 change
->modes_clear
|= MODE_SECRET
;
2198 mod_chanmode_free(change
);
2202 struct chanmode_buffer
{
2205 struct chanNode
*channel
;
2206 struct userNode
*actor
;
2207 unsigned int modes_used
;
2208 unsigned int args_used
;
2210 unsigned int is_add
: 1;
2211 unsigned int is_chanop
: 1;
2215 mod_chanmode_append(struct chanmode_buffer
*buf
, char ch
, const char *arg
)
2217 size_t arg_len
= strlen(arg
);
2218 if (buf
->modes_used
> (MAXMODEPARAMS
) ||
2219 buf
->modes_used
+ buf
->args_used
+ buf
->chname_len
+ arg_len
> 450) {
2220 memcpy(buf
->modes
+ buf
->modes_used
, buf
->args
, buf
->args_used
);
2221 buf
->modes
[buf
->modes_used
+ buf
->args_used
] = '\0';
2222 irc_mode((buf
->is_chanop
? buf
->actor
: NULL
), buf
->channel
, buf
->modes
);
2223 buf
->modes
[0] = buf
->is_add
? '+' : '-';
2224 buf
->modes_used
= 1;
2227 buf
->modes
[buf
->modes_used
++] = ch
;
2228 buf
->args
[buf
->args_used
++] = ' ';
2229 memcpy(buf
->args
+ buf
->args_used
, arg
, arg_len
);
2230 buf
->args_used
+= arg_len
;
2234 mod_chanmode_announce(struct userNode
*who
, struct chanNode
*channel
, struct mod_chanmode
*change
)
2236 struct chanmode_buffer chbuf
;
2238 struct modeNode
*mn
;
2239 char int_buff
[32], mode
= '\0';
2241 assert(change
->argc
<= change
->alloc_argc
);
2242 memset(&chbuf
, 0, sizeof(chbuf
));
2243 chbuf
.channel
= channel
;
2245 chbuf
.chname_len
= strlen(channel
->name
);
2247 mn
= GetUserMode(channel
, who
);
2248 if ((mn
&& (mn
->modes
& MODE_CHANOP
)) || off_channel
)
2249 chbuf
.is_chanop
= 1;
2251 /* First remove modes */
2253 if (change
->modes_clear
) {
2255 chbuf
.modes
[chbuf
.modes_used
++] = mode
= '-';
2256 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) chbuf.modes[chbuf.modes_used++] = CHAR
2257 DO_MODE_CHAR(PRIVATE
, 'p');
2258 DO_MODE_CHAR(SECRET
, 's');
2259 DO_MODE_CHAR(MODERATED
, 'm');
2260 DO_MODE_CHAR(TOPICLIMIT
, 't');
2261 DO_MODE_CHAR(INVITEONLY
, 'i');
2262 DO_MODE_CHAR(NOPRIVMSGS
, 'n');
2263 DO_MODE_CHAR(LIMIT
, 'l');
2264 DO_MODE_CHAR(DELAYJOINS
, 'D');
2265 DO_MODE_CHAR(REGONLY
, 'r');
2266 DO_MODE_CHAR(NOCOLORS
, 'c');
2267 DO_MODE_CHAR(NOCTCPS
, 'C');
2268 DO_MODE_CHAR(STRIPCOLOR
, 'S');
2269 DO_MODE_CHAR(MODUNREG
, 'M');
2270 DO_MODE_CHAR(NONOTICE
, 'N');
2271 DO_MODE_CHAR(NOQUITMSGS
, 'Q');
2272 DO_MODE_CHAR(NOAMSG
, 'T');
2273 DO_MODE_CHAR(OPERSONLY
, 'O');
2274 // uncomment this for ssl support
2275 //DO_MODE_CHAR(SSLONLY, 'z');
2277 if (change
->modes_clear
& channel
->modes
& MODE_KEY
)
2278 mod_chanmode_append(&chbuf
, 'k', channel
->key
);
2280 for (arg
= 0; arg
< change
->argc
; ++arg
) {
2281 if (!(change
->args
[arg
].mode
& MODE_REMOVE
))
2284 chbuf
.modes
[chbuf
.modes_used
++] = mode
= '-';
2285 switch (change
->args
[arg
].mode
& ~MODE_REMOVE
) {
2287 mod_chanmode_append(&chbuf
, 'b', change
->args
[arg
].hostmask
);
2290 if (change
->args
[arg
].mode
& MODE_CHANOP
)
2291 mod_chanmode_append(&chbuf
, 'o', change
->args
[arg
].member
->user
->numeric
);
2292 if (change
->args
[arg
].mode
& MODE_VOICE
)
2293 mod_chanmode_append(&chbuf
, 'v', change
->args
[arg
].member
->user
->numeric
);
2300 if (change
->modes_set
) {
2302 chbuf
.modes
[chbuf
.modes_used
++] = mode
= '+';
2303 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_set & MODE_##BIT) chbuf.modes[chbuf.modes_used++] = CHAR
2304 DO_MODE_CHAR(PRIVATE
, 'p');
2305 DO_MODE_CHAR(SECRET
, 's');
2306 DO_MODE_CHAR(MODERATED
, 'm');
2307 DO_MODE_CHAR(TOPICLIMIT
, 't');
2308 DO_MODE_CHAR(INVITEONLY
, 'i');
2309 DO_MODE_CHAR(NOPRIVMSGS
, 'n');
2310 DO_MODE_CHAR(DELAYJOINS
, 'D');
2311 DO_MODE_CHAR(REGONLY
, 'r');
2312 DO_MODE_CHAR(NOCOLORS
, 'c');
2313 DO_MODE_CHAR(NOCTCPS
, 'C');
2314 DO_MODE_CHAR(STRIPCOLOR
, 'S');
2315 DO_MODE_CHAR(MODUNREG
, 'M');
2316 DO_MODE_CHAR(NONOTICE
, 'N');
2317 DO_MODE_CHAR(NOQUITMSGS
, 'Q');
2318 DO_MODE_CHAR(NOAMSG
, 'T');
2319 DO_MODE_CHAR(OPERSONLY
, 'O');
2320 // uncomment this for ssl support
2321 //DO_MODE_CHAR(SSLONLY, 'z');
2323 if(change
->modes_set
& MODE_KEY
)
2324 mod_chanmode_append(&chbuf
, 'k', change
->new_key
);
2325 if(change
->modes_set
& MODE_LIMIT
) {
2326 sprintf(int_buff
, "%d", change
->new_limit
);
2327 mod_chanmode_append(&chbuf
, 'l', int_buff
);
2330 for (arg
= 0; arg
< change
->argc
; ++arg
) {
2331 if (change
->args
[arg
].mode
& MODE_REMOVE
)
2334 chbuf
.modes
[chbuf
.modes_used
++] = mode
= '+';
2335 switch (change
->args
[arg
].mode
) {
2337 mod_chanmode_append(&chbuf
, 'b', change
->args
[arg
].hostmask
);
2340 if (change
->args
[arg
].mode
& MODE_CHANOP
)
2341 mod_chanmode_append(&chbuf
, 'o', change
->args
[arg
].member
->user
->numeric
);
2342 if (change
->args
[arg
].mode
& MODE_VOICE
)
2343 mod_chanmode_append(&chbuf
, 'v', change
->args
[arg
].member
->user
->numeric
);
2348 /* Flush the buffer and apply changes locally */
2349 if (chbuf
.modes_used
> 0) {
2350 memcpy(chbuf
.modes
+ chbuf
.modes_used
, chbuf
.args
, chbuf
.args_used
);
2351 chbuf
.modes
[chbuf
.modes_used
+ chbuf
.args_used
] = '\0';
2352 irc_mode((chbuf
.is_chanop
? chbuf
.actor
: NULL
), chbuf
.channel
, chbuf
.modes
);
2354 mod_chanmode_apply(who
, channel
, change
);
2358 mod_chanmode_format(struct mod_chanmode
*change
, char *outbuff
)
2360 unsigned int used
= 0;
2361 assert(change
->argc
<= change
->alloc_argc
);
2362 if (change
->modes_clear
) {
2363 outbuff
[used
++] = '-';
2364 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) outbuff[used++] = CHAR
2365 DO_MODE_CHAR(PRIVATE
, 'p');
2366 DO_MODE_CHAR(SECRET
, 's');
2367 DO_MODE_CHAR(MODERATED
, 'm');
2368 DO_MODE_CHAR(TOPICLIMIT
, 't');
2369 DO_MODE_CHAR(INVITEONLY
, 'i');
2370 DO_MODE_CHAR(NOPRIVMSGS
, 'n');
2371 DO_MODE_CHAR(LIMIT
, 'l');
2372 DO_MODE_CHAR(KEY
, 'k');
2373 DO_MODE_CHAR(DELAYJOINS
, 'D');
2374 DO_MODE_CHAR(REGONLY
, 'r');
2375 DO_MODE_CHAR(NOCOLORS
, 'c');
2376 DO_MODE_CHAR(NOCTCPS
, 'C');
2377 DO_MODE_CHAR(STRIPCOLOR
, 'S');
2378 DO_MODE_CHAR(MODUNREG
, 'M');
2379 DO_MODE_CHAR(NONOTICE
, 'N');
2380 DO_MODE_CHAR(NOQUITMSGS
, 'Q');
2381 DO_MODE_CHAR(NOAMSG
, 'T');
2382 DO_MODE_CHAR(OPERSONLY
, 'O');
2383 // uncomment this for ssl support
2384 //DO_MODE_CHAR(SSLONLY, 'z');
2387 if (change
->modes_set
) {
2388 outbuff
[used
++] = '+';
2389 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_set & MODE_##BIT) outbuff[used++] = CHAR
2390 DO_MODE_CHAR(PRIVATE
, 'p');
2391 DO_MODE_CHAR(SECRET
, 's');
2392 DO_MODE_CHAR(MODERATED
, 'm');
2393 DO_MODE_CHAR(TOPICLIMIT
, 't');
2394 DO_MODE_CHAR(INVITEONLY
, 'i');
2395 DO_MODE_CHAR(NOPRIVMSGS
, 'n');
2396 DO_MODE_CHAR(DELAYJOINS
, 'D');
2397 DO_MODE_CHAR(REGONLY
, 'r');
2398 DO_MODE_CHAR(NOCOLORS
, 'c');
2399 DO_MODE_CHAR(NOCTCPS
, 'C');
2400 DO_MODE_CHAR(STRIPCOLOR
, 'S');
2401 DO_MODE_CHAR(MODUNREG
, 'M');
2402 DO_MODE_CHAR(NONOTICE
, 'N');
2403 DO_MODE_CHAR(NOQUITMSGS
, 'Q');
2404 DO_MODE_CHAR(NOAMSG
, 'T');
2405 DO_MODE_CHAR(OPERSONLY
, 'O');
2406 // uncomment this for ssl support
2407 //DO_MODE_CHAR(SSLONLY, 'z');
2409 switch (change
->modes_set
& (MODE_KEY
|MODE_LIMIT
)) {
2410 case MODE_KEY
|MODE_LIMIT
:
2411 used
+= sprintf(outbuff
+used
, "lk %d %s", change
->new_limit
, change
->new_key
);
2414 used
+= sprintf(outbuff
+used
, "k %s", change
->new_key
);
2417 used
+= sprintf(outbuff
+used
, "l %d", change
->new_limit
);
2426 clear_chanmode(struct chanNode
*channel
, const char *modes
)
2428 unsigned int remove
;
2430 for (remove
= 0; *modes
; modes
++) {
2432 case 'o': remove
|= MODE_CHANOP
; break;
2433 case 'v': remove
|= MODE_VOICE
; break;
2434 case 'p': remove
|= MODE_PRIVATE
; break;
2435 case 's': remove
|= MODE_SECRET
; break;
2436 case 'm': remove
|= MODE_MODERATED
; break;
2437 case 't': remove
|= MODE_TOPICLIMIT
; break;
2438 case 'i': remove
|= MODE_INVITEONLY
; break;
2439 case 'n': remove
|= MODE_NOPRIVMSGS
; break;
2442 channel
->key
[0] = '\0';
2445 remove
|= MODE_LIMIT
;
2448 case 'b': remove
|= MODE_BAN
; break;
2449 case 'D': remove
|= MODE_DELAYJOINS
; break;
2450 case 'r': remove
|= MODE_REGONLY
; break;
2451 case 'c': remove
|= MODE_NOCOLORS
;
2452 case 'C': remove
|= MODE_NOCTCPS
; break;
2453 case 'S': remove
|= MODE_STRIPCOLOR
; break;
2454 case 'M': remove
|= MODE_MODUNREG
; break;
2455 case 'N': remove
|= MODE_NONOTICE
; break;
2456 case 'Q': remove
|= MODE_NOQUITMSGS
; break;
2457 case 'T': remove
|= MODE_NOAMSG
; break;
2458 case 'O': remove
|= MODE_OPERSONLY
; break;
2465 /* Remove simple modes. */
2466 channel
->modes
&= ~remove
;
2468 /* If removing bans, kill 'em all. */
2469 if ((remove
& MODE_BAN
) && channel
->banlist
.used
) {
2471 for (i
=0; i
<channel
->banlist
.used
; i
++)
2472 free(channel
->banlist
.list
[i
]);
2473 channel
->banlist
.used
= 0;
2476 /* Remove member modes. */
2477 if ((remove
& (MODE_CHANOP
| MODE_VOICE
)) && channel
->members
.used
) {
2478 int mask
= ~(remove
& (MODE_CHANOP
| MODE_VOICE
));
2481 for (i
= 0; i
< channel
->members
.used
; i
++)
2482 channel
->members
.list
[i
]->modes
&= mask
;
2489 reg_privmsg_func(struct userNode
*user
, privmsg_func_t handler
)
2491 unsigned int numeric
= user
->num_local
;
2492 if (numeric
>= num_privmsg_funcs
) {
2493 int newnum
= numeric
+ 8;
2494 privmsg_funcs
= realloc(privmsg_funcs
, newnum
*sizeof(privmsg_func_t
));
2495 memset(privmsg_funcs
+num_privmsg_funcs
, 0, (newnum
-num_privmsg_funcs
)*sizeof(privmsg_func_t
));
2496 num_privmsg_funcs
= newnum
;
2498 if (privmsg_funcs
[numeric
])
2499 log_module(MAIN_LOG
, LOG_WARNING
, "re-registering new privmsg handler for numeric %d", numeric
);
2500 privmsg_funcs
[numeric
] = handler
;
2504 unreg_privmsg_func(struct userNode
*user
, privmsg_func_t handler
)
2508 if (!user
|| handler
)
2509 return; /* this really only works with users */
2511 memset(privmsg_funcs
+user
->num_local
, 0, sizeof(privmsg_func_t
));
2513 for (x
= user
->num_local
+1; x
< num_privmsg_funcs
; x
++)
2514 memmove(privmsg_funcs
+x
-1, privmsg_funcs
+x
, sizeof(privmsg_func_t
));
2516 privmsg_funcs
= realloc(privmsg_funcs
, num_privmsg_funcs
*sizeof(privmsg_func_t
));
2517 num_privmsg_funcs
--;
2522 reg_notice_func(struct userNode
*user
, privmsg_func_t handler
)
2524 unsigned int numeric
= user
->num_local
;
2525 if (numeric
>= num_notice_funcs
) {
2526 int newnum
= numeric
+ 8;
2527 notice_funcs
= realloc(notice_funcs
, newnum
*sizeof(privmsg_func_t
));
2528 memset(notice_funcs
+num_notice_funcs
, 0, (newnum
-num_notice_funcs
)*sizeof(privmsg_func_t
));
2529 num_notice_funcs
= newnum
;
2531 if (notice_funcs
[numeric
])
2532 log_module(MAIN_LOG
, LOG_WARNING
, "re-registering new notice handler for numeric %d", numeric
);
2533 notice_funcs
[numeric
] = handler
;
2537 unreg_notice_func(struct userNode
*user
, privmsg_func_t handler
)
2541 if (!user
|| handler
)
2542 return; /* this really only works with users */
2544 memset(notice_funcs
+user
->num_local
, 0, sizeof(privmsg_func_t
));
2546 for (x
= user
->num_local
+1; x
< num_notice_funcs
; x
++)
2547 memmove(notice_funcs
+x
-1, notice_funcs
+x
, sizeof(privmsg_func_t
));
2549 memset(notice_funcs
+user
->num_local
, 0, sizeof(privmsg_func_t
));
2550 notice_funcs
= realloc(notice_funcs
, num_notice_funcs
*sizeof(privmsg_func_t
));
2555 reg_oper_func(oper_func_t handler
)
2557 if (of_used
== of_size
) {
2560 of_list
= realloc(of_list
, of_size
*sizeof(oper_func_t
));
2563 of_list
= malloc(of_size
*sizeof(oper_func_t
));
2566 of_list
[of_used
++] = handler
;
2570 call_oper_funcs(struct userNode
*user
)
2575 for (n
=0; n
<of_used
; n
++)
2582 unsigned int i
, hop
, max_hop
=1;
2585 /* burst (juped) servers, closest first (except self, which is sent already) */
2586 for (i
=0; i
<ArrayLength(servers_num
); i
++)
2587 if (servers_num
[i
] && servers_num
[i
]->hops
> max_hop
)
2588 max_hop
= servers_num
[i
]->hops
;
2589 for (hop
=1; hop
<=max_hop
; hop
++) {
2590 for (i
=0;i
<ArrayLength(servers_num
);i
++) {
2592 && (servers_num
[i
]->hops
== hop
)
2593 && (servers_num
[i
] != self
->uplink
))
2594 irc_server(servers_num
[i
]);
2598 /* burst local nicks */
2599 for (i
=0; i
<=self
->num_mask
; i
++)
2601 irc_user(self
->users
[i
]);
2603 /* build dict of unbursted channel names (just copy existing channels) */
2604 unbursted_channels
= dict_new();
2605 for (it
= dict_first(channels
); it
; it
= iter_next(it
))
2606 dict_insert(unbursted_channels
, iter_key(it
), iter_data(it
));