]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | Index: include/channel.h |
2 | =================================================================== | |
3 | RCS file: /home/coder-com/cvs/ircu2.10/include/channel.h,v | |
4 | retrieving revision 1.32 | |
5 | diff -u -r1.32 channel.h | |
6 | --- include/channel.h 2002/04/03 21:16:01 1.32 | |
7 | +++ include/channel.h 2002/04/12 13:47:52 | |
8 | @@ -95,6 +95,8 @@ | |
9 | #define MODE_BURSTADDED 0x80000 /* channel was created by a BURST */ | |
10 | #define MODE_UPASS 0x100000 | |
11 | #define MODE_APASS 0x200000 | |
12 | +#define MODE_EMPTY 0x400000 /* LazyLeaf: no more locals, remove channel asap */ | |
13 | + | |
14 | /* | |
15 | * mode flags which take another parameter (With PARAmeterS) | |
16 | */ | |
17 | @@ -222,15 +224,20 @@ | |
18 | time_t creationtime; | |
19 | time_t topic_time; | |
20 | unsigned int users; | |
21 | + unsigned int locals; | |
22 | struct Membership* members; | |
23 | struct SLink* invites; | |
24 | struct SLink* banlist; | |
25 | struct Mode mode; | |
26 | char topic[TOPICLEN + 1]; | |
27 | char topic_nick[NICKLEN + 1]; | |
28 | - char chname[1]; | |
29 | + unsigned long ll_bits; /* LazyLeaf */ | |
30 | + char chname[1]; /* This *must* be last */ | |
31 | }; | |
32 | ||
33 | +#define LeafKnowsChannel(c,x) (cli_serv(c)->ll_mask & (x)->ll_bits) | |
34 | +#define LL_ALL (~0UL) | |
35 | + | |
36 | struct ListingArgs { | |
37 | time_t max_time; | |
38 | time_t min_time; | |
39 | @@ -350,6 +357,7 @@ | |
40 | extern int is_zombie(struct Client *cptr, struct Channel *chptr); | |
41 | extern int has_voice(struct Client *cptr, struct Channel *chptr); | |
42 | extern void send_channel_modes(struct Client *cptr, struct Channel *chptr); | |
43 | +extern void ll_send_channel(struct Client *cptr, struct Channel *chptr); | |
44 | extern char *pretty_mask(char *mask); | |
45 | extern void del_invite(struct Client *cptr, struct Channel *chptr); | |
46 | extern void list_next_channels(struct Client *cptr, int nr); | |
47 | Index: include/client.h | |
48 | =================================================================== | |
49 | RCS file: /home/coder-com/cvs/ircu2.10/include/client.h,v | |
50 | retrieving revision 1.26 | |
51 | diff -u -r1.26 client.h | |
52 | --- include/client.h 2002/04/05 11:36:58 1.26 | |
53 | +++ include/client.h 2002/04/12 13:47:52 | |
54 | @@ -369,6 +369,7 @@ | |
55 | #define FLAGS_DOID 0x00040000 /* I-lines say must use ident return */ | |
56 | #define FLAGS_NONL 0x00080000 /* No \n in buffer */ | |
57 | #define FLAGS_TS8 0x00100000 /* Why do you want to know? */ | |
58 | +#define FLAGS_LAZY 0x00200000 /* LazyLeaf */ | |
59 | #define FLAGS_MAP 0x00800000 /* Show server on the map */ | |
60 | #define FLAGS_JUNCTION 0x01000000 /* Junction causing the net.burst */ | |
61 | #define FLAGS_DEAF 0x02000000 /* Makes user deaf */ | |
62 | @@ -413,6 +414,7 @@ | |
63 | #define IsAccount(x) (cli_flags(x) & FLAGS_ACCOUNT) | |
64 | #define IsHiddenHost(x) (cli_flags(x) & FLAGS_HIDDENHOST) | |
65 | #define HasHiddenHost(x) (IsAccount(x) && IsHiddenHost(x)) | |
66 | +#define IsLazy(x) (cli_flags(x) & FLAGS_LAZY) | |
67 | ||
68 | #define IsPrivileged(x) (IsAnOper(x) || IsServer(x)) | |
69 | ||
70 | @@ -435,6 +437,7 @@ | |
71 | #define SetService(x) (cli_flags(x) |= FLAGS_SERVICE) | |
72 | #define SetAccount(x) (cli_flags(x) |= FLAGS_ACCOUNT) | |
73 | #define SetHiddenHost(x) (cli_flags(x) |= FLAGS_HIDDENHOST) | |
74 | +#define SetLazy(x) (cli_flags(x) |= FLAGS_LAZY) | |
75 | ||
76 | #define ClearAccess(x) (cli_flags(x) &= ~FLAGS_CHKACCESS) | |
77 | #define ClearBurst(x) (cli_flags(x) &= ~FLAGS_BURST) | |
78 | @@ -450,6 +453,7 @@ | |
79 | #define ClearWallops(x) (cli_flags(x) &= ~FLAGS_WALLOP) | |
80 | #define ClearServNotice(x) (cli_flags(x) &= ~FLAGS_SERVNOTICE) | |
81 | #define ClearHiddenHost(x) (cli_flags(x) &= ~FLAGS_HIDDENHOST) | |
82 | +#define ClearLazy(x) (cli_flags(x) &= ~FLAGS_LAZY) | |
83 | ||
84 | /* free flags */ | |
85 | #define FREEFLAG_SOCKET 0x0001 /* socket needs to be freed */ | |
86 | Index: include/handlers.h | |
87 | =================================================================== | |
88 | RCS file: /home/coder-com/cvs/ircu2.10/include/handlers.h,v | |
89 | retrieving revision 1.16 | |
90 | diff -u -r1.16 handlers.h | |
91 | --- include/handlers.h 2002/03/19 22:03:36 1.16 | |
92 | +++ include/handlers.h 2002/04/12 13:47:52 | |
93 | @@ -183,6 +183,7 @@ | |
94 | extern int ms_gline(struct Client*, struct Client*, int, char*[]); | |
95 | extern int ms_info(struct Client*, struct Client*, int, char*[]); | |
96 | extern int ms_invite(struct Client*, struct Client*, int, char*[]); | |
97 | +extern int ms_forget(struct Client*, struct Client*, int, char*[]); | |
98 | extern int ms_join(struct Client*, struct Client*, int, char*[]); | |
99 | extern int ms_jupe(struct Client*, struct Client*, int, char*[]); | |
100 | extern int ms_kick(struct Client*, struct Client*, int, char*[]); | |
101 | Index: include/ircd_features.h | |
102 | =================================================================== | |
103 | RCS file: /home/coder-com/cvs/ircu2.10/include/ircd_features.h,v | |
104 | retrieving revision 1.15 | |
105 | diff -u -r1.15 ircd_features.h | |
106 | --- include/ircd_features.h 2002/04/03 15:23:47 1.15 | |
107 | +++ include/ircd_features.h 2002/04/12 13:47:52 | |
108 | @@ -37,6 +37,7 @@ | |
109 | FEAT_KILL_IPMISMATCH, | |
110 | FEAT_IDLE_FROM_MSG, | |
111 | FEAT_HUB, | |
112 | + FEAT_LAZY_LEAF, | |
113 | FEAT_WALLOPS_OPER_ONLY, | |
114 | FEAT_NODNS, | |
115 | FEAT_RANDOM_SEED, | |
116 | Index: include/msg.h | |
117 | =================================================================== | |
118 | RCS file: /home/coder-com/cvs/ircu2.10/include/msg.h,v | |
119 | retrieving revision 1.12 | |
120 | diff -u -r1.12 msg.h | |
121 | --- include/msg.h 2002/02/14 00:20:40 1.12 | |
122 | +++ include/msg.h 2002/04/12 13:47:52 | |
123 | @@ -330,6 +330,10 @@ | |
124 | #define TOK_ACCOUNT "AC" | |
125 | #define CMD_ACCOUNT MSG_ACCOUNT, TOK_ACCOUNT | |
126 | ||
127 | +#define MSG_FORGET "FORGET" /* FORGET */ | |
128 | +#define TOK_FORGET "FO" | |
129 | +#define CMD_FORGET MSG_FORGET, TOK_FORGET | |
130 | + | |
131 | #define MSG_POST "POST" /* POST */ | |
132 | #define TOK_POST "POST" | |
133 | ||
134 | Index: include/s_serv.h | |
135 | =================================================================== | |
136 | RCS file: /home/coder-com/cvs/ircu2.10/include/s_serv.h,v | |
137 | retrieving revision 1.6 | |
138 | diff -u -r1.6 s_serv.h | |
139 | --- include/s_serv.h 2001/06/08 23:12:16 1.6 | |
140 | +++ include/s_serv.h 2002/04/12 13:47:52 | |
141 | @@ -12,9 +12,11 @@ | |
142 | ||
143 | struct ConfItem; | |
144 | struct Client; | |
145 | +struct Channel; | |
146 | ||
147 | extern unsigned int max_connection_count; | |
148 | extern unsigned int max_client_count; | |
149 | +extern unsigned long GlobalLeafBits; | |
150 | ||
151 | /* | |
152 | * Prototypes | |
153 | @@ -24,5 +26,8 @@ | |
154 | extern int a_kills_b_too(struct Client *a, struct Client *b); | |
155 | extern int server_estab(struct Client *cptr, struct ConfItem *aconf); | |
156 | ||
157 | +extern int ll_add(struct Client *cptr); | |
158 | +extern void ll_remove(struct Client *cptr); | |
159 | +extern void ll_check_channel(struct Client *cptr, struct Channel *chptr); | |
160 | ||
161 | #endif /* INCLUDED_s_serv_h */ | |
162 | Index: include/send.h | |
163 | =================================================================== | |
164 | RCS file: /home/coder-com/cvs/ircu2.10/include/send.h,v | |
165 | retrieving revision 1.17 | |
166 | diff -u -r1.17 send.h | |
167 | --- include/send.h 2002/02/14 00:20:41 1.17 | |
168 | +++ include/send.h 2002/04/12 13:47:52 | |
169 | @@ -47,6 +47,12 @@ | |
170 | const char *tok, struct Client *one, | |
171 | const char *pattern, ...); | |
172 | ||
173 | +/* Same as above, but only when the server's ll_mask matches */ | |
174 | +extern void sendcmdto_mask_butone(struct Client *from, const char *cmd, | |
175 | + const char *tok, unsigned long ll_mask, | |
176 | + struct Client *one, | |
177 | + const char *pattern, ...); | |
178 | + | |
179 | /* Send command to all channels user is on */ | |
180 | extern void sendcmdto_common_channels_butone(struct Client *from, | |
181 | const char *cmd, | |
182 | Index: include/struct.h | |
183 | =================================================================== | |
184 | RCS file: /home/coder-com/cvs/ircu2.10/include/struct.h,v | |
185 | retrieving revision 1.3 | |
186 | diff -u -r1.3 struct.h | |
187 | --- include/struct.h 2002/02/14 00:20:41 1.3 | |
188 | +++ include/struct.h 2002/04/12 13:47:52 | |
189 | @@ -52,6 +52,7 @@ | |
190 | unsigned short nn_last; /* Last numeric nick for p9 servers only */ | |
191 | unsigned int nn_mask; /* [Remote] FD_SETSIZE - 1 */ | |
192 | char nn_capacity[4]; /* numeric representation of server capacity */ | |
193 | + unsigned long ll_mask; /* LazyLeaf mask */ | |
194 | ||
195 | char *last_error_msg; /* Allocated memory with last message receive with an ERROR */ | |
196 | char by[NICKLEN + 1]; | |
197 | Index: ircd/Makefile.in | |
198 | =================================================================== | |
199 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/Makefile.in,v | |
200 | retrieving revision 1.43 | |
201 | diff -u -r1.43 Makefile.in | |
202 | --- ircd/Makefile.in 2002/04/03 21:16:01 1.43 | |
203 | +++ ircd/Makefile.in 2002/04/12 13:47:52 | |
204 | @@ -120,6 +120,7 @@ | |
205 | m_die.c \ | |
206 | m_endburst.c \ | |
207 | m_error.c \ | |
208 | + m_forget.c \ | |
209 | m_get.c \ | |
210 | m_gline.c \ | |
211 | m_help.c \ | |
212 | Index: ircd/channel.c | |
213 | =================================================================== | |
214 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/channel.c,v | |
215 | retrieving revision 1.81 | |
216 | diff -u -r1.81 channel.c | |
217 | --- ircd/channel.c 2002/04/03 21:16:01 1.81 | |
218 | +++ ircd/channel.c 2002/04/12 13:47:52 | |
219 | @@ -46,6 +46,7 @@ | |
220 | #include "s_conf.h" | |
221 | #include "s_debug.h" | |
222 | #include "s_misc.h" | |
223 | +#include "s_serv.h" | |
224 | #include "s_user.h" | |
225 | #include "send.h" | |
226 | #include "struct.h" | |
227 | @@ -533,6 +534,8 @@ | |
228 | remove_destruct_event(chptr); | |
229 | ++chptr->users; | |
230 | ++((cli_user(who))->joined); | |
231 | + if (MyUser(who)) | |
232 | + ++chptr->locals; | |
233 | } | |
234 | } | |
235 | ||
236 | @@ -562,6 +565,8 @@ | |
237 | (cli_user(member->user))->channel = member->next_channel; | |
238 | ||
239 | --(cli_user(member->user))->joined; | |
240 | + if (MyUser(member->user)) | |
241 | + --chptr->locals; | |
242 | ||
243 | member->next_member = membershipFreeList; | |
244 | membershipFreeList = member; | |
245 | @@ -587,6 +592,17 @@ | |
246 | struct Membership* member; | |
247 | assert(0 != chptr); | |
248 | ||
249 | + if (chptr->mode.mode & MODE_EMPTY) { | |
250 | + assert(feature_bool(FEAT_LAZY_LEAF)); | |
251 | + | |
252 | + /* Channel has no more locals, free it */ | |
253 | + do { | |
254 | + assert(!MyUser(chptr->members->user)); | |
255 | + } while (remove_member_from_channel(chptr->members)); | |
256 | + | |
257 | + return; | |
258 | + } | |
259 | + | |
260 | if ((member = find_member_link(chptr, cptr))) { | |
261 | if (remove_member_from_channel(member)) { | |
262 | if (channel_all_zombies(chptr)) { | |
263 | @@ -1417,6 +1433,7 @@ | |
264 | for (; acptr != &me; acptr = (cli_serv(acptr))->up) | |
265 | if (acptr == (cli_user(who))->server) /* Case d) (server 5) */ | |
266 | { | |
267 | + ll_check_channel(who, chptr); | |
268 | remove_user_from_channel(who, chptr); | |
269 | return; | |
270 | } | |
271 | @@ -1769,8 +1786,8 @@ | |
272 | ||
273 | if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) { | |
274 | /* If OPMODE was set, we're propagating the mode as an OPMODE message */ | |
275 | - sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect, | |
276 | - "%H %s%s%s%s%s%s", mbuf->mb_channel, | |
277 | + sendcmdto_mask_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_channel->ll_bits, | |
278 | + mbuf->mb_connect, "%H %s%s%s%s%s%s", mbuf->mb_channel, | |
279 | rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", | |
280 | addbuf, remstr, addstr); | |
281 | } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) { | |
282 | @@ -1789,14 +1806,16 @@ | |
283 | * we send the actual channel TS unless this is a HACK3 or a HACK4 | |
284 | */ | |
285 | if (IsServer(mbuf->mb_source)) | |
286 | - sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect, | |
287 | + sendcmdto_mask_butone(mbuf->mb_source, CMD_MODE, | |
288 | + mbuf->mb_channel->ll_bits, mbuf->mb_connect, | |
289 | "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel, | |
290 | rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", | |
291 | addbuf, remstr, addstr, | |
292 | (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 : | |
293 | mbuf->mb_channel->creationtime); | |
294 | else | |
295 | - sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect, | |
296 | + sendcmdto_mask_butone(mbuf->mb_source, CMD_MODE, | |
297 | + mbuf->mb_channel->ll_bits, mbuf->mb_connect, | |
298 | "%H %s%s%s%s%s%s", mbuf->mb_channel, | |
299 | rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", | |
300 | addbuf, remstr, addstr); | |
301 | @@ -3143,7 +3162,7 @@ | |
302 | ||
303 | /* send notification to all servers */ | |
304 | if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !IsLocalChannel(chan->chname)) | |
305 | - sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, | |
306 | + sendcmdto_mask_butone(jbuf->jb_source, CMD_JOIN, chan->ll_bits, jbuf->jb_connect, | |
307 | "%H %Tu", chan, chan->creationtime); | |
308 | ||
309 | /* Send the notification to the channel */ | |
310 | @@ -3192,9 +3211,37 @@ | |
311 | build_string(chanlist, &chanlist_i, | |
312 | jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0, | |
313 | i == 0 ? '\0' : ','); | |
314 | - if (JOINBUF_TYPE_PART == jbuf->jb_type) | |
315 | + | |
316 | + /* | |
317 | + * For lazy leafs, joins/parts have to be sent separately for | |
318 | + * each channel. | |
319 | + */ | |
320 | + switch (jbuf->jb_type) { | |
321 | + case JOINBUF_TYPE_CREATE: | |
322 | + sendcmdto_mask_butone(jbuf->jb_source, CMD_CREATE, | |
323 | + jbuf->jb_channels[i] ? jbuf->jb_channels[i]->ll_bits : LL_ALL, | |
324 | + jbuf->jb_connect, "%s %Tu", | |
325 | + jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", | |
326 | + jbuf->jb_create); | |
327 | + break; | |
328 | + | |
329 | + case JOINBUF_TYPE_PART: | |
330 | + sendcmdto_mask_butone(jbuf->jb_source, CMD_PART, | |
331 | + jbuf->jb_channels[i]->ll_bits, | |
332 | + jbuf->jb_connect, | |
333 | + jbuf->jb_comment ? "%s :%s" : "%s", | |
334 | + jbuf->jb_channels[i]->chname, | |
335 | + jbuf->jb_comment); | |
336 | + break; | |
337 | + } | |
338 | + | |
339 | + if (JOINBUF_TYPE_PART == jbuf->jb_type) { | |
340 | + /* Check now, as remove_user* may free the channel */ | |
341 | + ll_check_channel(jbuf->jb_source, jbuf->jb_channels[i]); | |
342 | + | |
343 | /* Remove user from channel */ | |
344 | remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]); | |
345 | + } | |
346 | ||
347 | jbuf->jb_channels[i] = 0; /* mark slot empty */ | |
348 | } | |
349 | @@ -3204,6 +3251,7 @@ | |
350 | STARTJOINLEN : STARTCREATELEN) + | |
351 | (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0)); | |
352 | ||
353 | +#if 0 | |
354 | /* and send the appropriate command */ | |
355 | switch (jbuf->jb_type) { | |
356 | case JOINBUF_TYPE_CREATE: | |
357 | @@ -3217,6 +3265,7 @@ | |
358 | jbuf->jb_comment); | |
359 | break; | |
360 | } | |
361 | +#endif | |
362 | ||
363 | return 0; | |
364 | } | |
365 | Index: ircd/ircd_features.c | |
366 | =================================================================== | |
367 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/ircd_features.c,v | |
368 | retrieving revision 1.19 | |
369 | diff -u -r1.19 ircd_features.c | |
370 | --- ircd/ircd_features.c 2002/04/03 15:23:48 1.19 | |
371 | +++ ircd/ircd_features.c 2002/04/12 13:47:52 | |
372 | @@ -244,6 +244,7 @@ | |
373 | F_B(KILL_IPMISMATCH, FEAT_OPER, 0, 0), | |
374 | F_B(IDLE_FROM_MSG, 0, 1, 0), | |
375 | F_B(HUB, 0, 0, 0), | |
376 | + F_B(LAZY_LEAF, 0, 0, 0), | |
377 | F_B(WALLOPS_OPER_ONLY, 0, 0, 0), | |
378 | F_B(NODNS, 0, 0, 0), | |
379 | F_N(RANDOM_SEED, FEAT_NODISP, random_seed_set, 0, 0, 0, 0, 0, 0), | |
380 | Index: ircd/m_burst.c | |
381 | =================================================================== | |
382 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_burst.c,v | |
383 | retrieving revision 1.16 | |
384 | diff -u -r1.16 m_burst.c | |
385 | --- ircd/m_burst.c 2002/03/27 22:30:24 1.16 | |
386 | +++ ircd/m_burst.c 2002/04/12 13:47:52 | |
387 | @@ -89,6 +89,7 @@ | |
388 | #include "ircd_policy.h" | |
389 | #include "ircd_reply.h" | |
390 | #include "ircd_string.h" | |
391 | +#include "ircd_features.h" | |
392 | #include "list.h" | |
393 | #include "match.h" | |
394 | #include "msg.h" | |
395 | @@ -463,6 +464,11 @@ | |
396 | lp->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* reset the flag */ | |
397 | lp_p = &(*lp_p)->next; | |
398 | } | |
399 | + } | |
400 | + | |
401 | + if (IsLazy(cptr) && !LeafKnowsChannel(cptr, chptr)) { | |
402 | + chptr->ll_bits |= cli_serv(cptr)->ll_mask; | |
403 | + send_channel_modes(cptr, chptr); | |
404 | } | |
405 | ||
406 | return mbuf ? modebuf_flush(mbuf) : 0; | |
407 | Index: ircd/m_clearmode.c | |
408 | =================================================================== | |
409 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_clearmode.c,v | |
410 | retrieving revision 1.20 | |
411 | diff -u -r1.20 m_clearmode.c | |
412 | --- ircd/m_clearmode.c 2002/02/14 00:20:42 1.20 | |
413 | +++ ircd/m_clearmode.c 2002/04/12 13:47:52 | |
414 | @@ -234,8 +234,8 @@ | |
415 | ||
416 | /* Then send it */ | |
417 | if (!IsLocalChannel(chptr->chname)) | |
418 | - sendcmdto_serv_butone(sptr, CMD_CLEARMODE, cptr, "%H %s", chptr, | |
419 | - control_buf); | |
420 | + sendcmdto_mask_butone(sptr, CMD_CLEARMODE, chptr->ll_bits, cptr, | |
421 | + "%H %s", chptr, control_buf); | |
422 | ||
423 | return 0; | |
424 | } | |
425 | Index: ircd/m_create.c | |
426 | =================================================================== | |
427 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_create.c,v | |
428 | retrieving revision 1.12 | |
429 | diff -u -r1.12 m_create.c | |
430 | --- ircd/m_create.c 2002/02/14 00:20:42 1.12 | |
431 | +++ ircd/m_create.c 2002/04/12 13:47:52 | |
432 | @@ -154,6 +154,7 @@ | |
433 | continue; | |
434 | ||
435 | if ((chptr = FindChannel(name))) { | |
436 | + int hack2 = IsLazy(cptr) ? 0 : MODEBUF_DEST_HACK2; | |
437 | name = chptr->chname; | |
438 | ||
439 | /* Check if we need to bounce a mode */ | |
440 | @@ -162,7 +163,7 @@ | |
441 | chptr->creationtime != MAGIC_REMOTE_JOIN_TS)) { | |
442 | modebuf_init(&mbuf, sptr, cptr, chptr, | |
443 | (MODEBUF_DEST_SERVER | /* Send mode to server */ | |
444 | - MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */ | |
445 | + hack2 | /* Send a HACK(2) message */ | |
446 | MODEBUF_DEST_BOUNCE)); /* And bounce the mode */ | |
447 | ||
448 | modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr); | |
449 | @@ -180,6 +181,11 @@ | |
450 | joinbuf_join(badop ? &join : &create, chptr, | |
451 | (badop || IsModelessChannel(name)) ? | |
452 | CHFL_DEOPPED : CHFL_CHANOP); | |
453 | + | |
454 | + if (IsLazy(cptr) && !LeafKnowsChannel(cptr, chptr)) { | |
455 | + chptr->ll_bits |= cli_serv(cptr)->ll_mask; | |
456 | + send_channel_modes(cptr, chptr); | |
457 | + } | |
458 | } | |
459 | ||
460 | joinbuf_flush(&join); /* flush out the joins and creates */ | |
461 | Index: ircd/m_join.c | |
462 | =================================================================== | |
463 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_join.c,v | |
464 | retrieving revision 1.19 | |
465 | diff -u -r1.19 m_join.c | |
466 | --- ircd/m_join.c 2002/03/13 09:19:21 1.19 | |
467 | +++ ircd/m_join.c 2002/04/12 13:47:52 | |
468 | @@ -373,6 +373,11 @@ | |
469 | chptr->creationtime = creation; | |
470 | } | |
471 | ||
472 | + if (IsLazy(cptr) && !LeafKnowsChannel(cptr, chptr)) { | |
473 | + chptr->ll_bits |= cli_serv(cptr)->ll_mask; | |
474 | + send_channel_modes(cptr, chptr); | |
475 | + } | |
476 | + | |
477 | joinbuf_join(&join, chptr, flags); | |
478 | } | |
479 | ||
480 | Index: ircd/m_kick.c | |
481 | =================================================================== | |
482 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_kick.c,v | |
483 | retrieving revision 1.8 | |
484 | diff -u -r1.8 m_kick.c | |
485 | --- ircd/m_kick.c 2002/03/13 09:19:21 1.8 | |
486 | +++ ircd/m_kick.c 2002/04/12 13:47:52 | |
487 | @@ -150,7 +150,7 @@ | |
488 | comment = EmptyString(parv[parc - 1]) ? parv[0] : parv[parc - 1]; | |
489 | ||
490 | if (!IsLocalChannel(name)) | |
491 | - sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, | |
492 | + sendcmdto_mask_butone(sptr, CMD_KICK, chptr->ll_bits, cptr, "%H %C :%s", chptr, who, | |
493 | comment); | |
494 | ||
495 | sendcmdto_channel_butserv_butone(sptr, CMD_KICK, chptr, NULL, "%H %C :%s", chptr, who, | |
496 | @@ -228,7 +228,7 @@ | |
497 | } | |
498 | } else { | |
499 | /* Propagate kick... */ | |
500 | - sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, | |
501 | + sendcmdto_mask_butone(sptr, CMD_KICK, chptr->ll_bits, cptr, "%H %C :%s", chptr, who, | |
502 | comment); | |
503 | ||
504 | if (member) { /* and tell the channel about it */ | |
505 | Index: ircd/m_server.c | |
506 | =================================================================== | |
507 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_server.c,v | |
508 | retrieving revision 1.26 | |
509 | diff -u -r1.26 m_server.c | |
510 | --- ircd/m_server.c 2002/03/19 22:03:36 1.26 | |
511 | +++ ircd/m_server.c 2002/04/12 13:47:52 | |
512 | @@ -181,6 +181,9 @@ | |
513 | case 's': | |
514 | SetService(cptr); | |
515 | break; | |
516 | + case 'l': | |
517 | + SetLazy(cptr); | |
518 | + break; | |
519 | } | |
520 | } | |
521 | ||
522 | Index: ircd/m_topic.c | |
523 | =================================================================== | |
524 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_topic.c,v | |
525 | retrieving revision 1.10 | |
526 | diff -u -r1.10 m_topic.c | |
527 | --- ircd/m_topic.c 2002/02/14 00:20:43 1.10 | |
528 | +++ ircd/m_topic.c 2002/04/12 13:47:52 | |
529 | @@ -115,8 +115,8 @@ | |
530 | chptr->topic_time = CurrentTime; | |
531 | /* Fixed in 2.10.11: Don't propergate local topics */ | |
532 | if (!IsLocalChannel(chptr->chname)) | |
533 | - sendcmdto_serv_butone(sptr, CMD_TOPIC, cptr, "%H :%s", chptr, | |
534 | - chptr->topic); | |
535 | + sendcmdto_mask_butone(sptr, CMD_TOPIC, chptr->ll_bits, cptr, "%H %Tu :%s", chptr, | |
536 | + chptr->topic_time, chptr->topic); | |
537 | if (newtopic) | |
538 | sendcmdto_channel_butserv_butone(sptr, CMD_TOPIC, chptr, NULL, | |
539 | "%H :%s", chptr, chptr->topic); | |
540 | Index: ircd/parse.c | |
541 | =================================================================== | |
542 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/parse.c,v | |
543 | retrieving revision 1.34 | |
544 | diff -u -r1.34 parse.c | |
545 | --- ircd/parse.c 2002/03/19 22:03:36 1.34 | |
546 | +++ ircd/parse.c 2002/04/12 13:47:53 | |
547 | @@ -577,6 +577,13 @@ | |
548 | /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
549 | { m_ignore, m_ignore, ms_account, m_ignore, m_ignore } | |
550 | }, | |
551 | + { | |
552 | + MSG_FORGET, | |
553 | + TOK_FORGET, | |
554 | + 0, MAXPARA, MFLG_SLOW, 0, | |
555 | + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ | |
556 | + { m_ignore, m_ignore, ms_forget, m_ignore, m_ignore } | |
557 | + }, | |
558 | /* This command is an alias for QUIT during the unregistered part of | |
559 | * of the server. This is because someone jumping via a broken web | |
560 | * proxy will send a 'POST' as their first command - which we will | |
561 | Index: ircd/s_bsd.c | |
562 | =================================================================== | |
563 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_bsd.c,v | |
564 | retrieving revision 1.48 | |
565 | diff -u -r1.48 s_bsd.c | |
566 | --- ircd/s_bsd.c 2002/04/03 06:45:49 1.48 | |
567 | +++ ircd/s_bsd.c 2002/04/12 13:47:53 | |
568 | @@ -465,7 +465,8 @@ | |
569 | sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s :%s", | |
570 | cli_name(&me), cli_serv(&me)->timestamp, newts, | |
571 | MAJOR_PROTOCOL, NumServCap(&me), | |
572 | - feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me)); | |
573 | + feature_bool(FEAT_HUB) ? "h" : | |
574 | + feature_bool(FEAT_LAZY_LEAF) ? "l" : "", cli_info(&me)); | |
575 | ||
576 | return (IsDead(cptr)) ? 0 : 1; | |
577 | } | |
578 | Index: ircd/s_misc.c | |
579 | =================================================================== | |
580 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_misc.c,v | |
581 | retrieving revision 1.31 | |
582 | diff -u -r1.31 s_misc.c | |
583 | --- ircd/s_misc.c 2002/04/02 00:26:47 1.31 | |
584 | +++ ircd/s_misc.c 2002/04/12 13:47:53 | |
585 | @@ -48,6 +48,7 @@ | |
586 | #include "s_conf.h" | |
587 | #include "s_debug.h" | |
588 | #include "s_user.h" | |
589 | +#include "s_serv.h" | |
590 | #include "send.h" | |
591 | #include "struct.h" | |
592 | #include "support.h" | |
593 | @@ -477,6 +478,8 @@ | |
594 | sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)", | |
595 | cli_serv(victim)->up, victim, comment); | |
596 | ||
597 | + if (IsLazy(victim)) | |
598 | + ll_remove(victim); | |
599 | #if defined(HEAD_IN_SAND_MAP) || defined(HEAD_IN_SAND_LINKS) | |
600 | map_update(victim); | |
601 | #endif | |
602 | Index: ircd/s_serv.c | |
603 | =================================================================== | |
604 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_serv.c,v | |
605 | retrieving revision 1.28 | |
606 | diff -u -r1.28 s_serv.c | |
607 | --- ircd/s_serv.c 2002/02/14 00:20:44 1.28 | |
608 | +++ ircd/s_serv.c 2002/04/12 13:47:53 | |
609 | @@ -36,6 +36,7 @@ | |
610 | #include "ircd_string.h" | |
611 | #include "ircd_snprintf.h" | |
612 | #include "ircd_xopen.h" | |
613 | +#include "ircd_log.h" | |
614 | #include "jupe.h" | |
615 | #include "list.h" | |
616 | #include "match.h" | |
617 | @@ -61,6 +62,7 @@ | |
618 | ||
619 | unsigned int max_connection_count = 0; | |
620 | unsigned int max_client_count = 0; | |
621 | +unsigned long GlobalLeafBits = 0; | |
622 | ||
623 | int exit_new_server(struct Client *cptr, struct Client *sptr, const char *host, | |
624 | time_t timestamp, const char *pattern, ...) | |
625 | @@ -113,7 +115,8 @@ | |
626 | sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s :%s", | |
627 | cli_name(&me), cli_serv(&me)->timestamp, | |
628 | cli_serv(cptr)->timestamp, MAJOR_PROTOCOL, NumServCap(&me), | |
629 | - feature_bool(FEAT_HUB) ? "h" : "", | |
630 | + feature_bool(FEAT_HUB) ? "h" : | |
631 | + feature_bool(FEAT_LAZY_LEAF) ? "l" : "", | |
632 | *(cli_info(&me)) ? cli_info(&me) : "IRCers United"); | |
633 | /* | |
634 | * Don't charge this IP# for connecting | |
635 | @@ -135,6 +138,9 @@ | |
636 | ||
637 | SetBurst(cptr); | |
638 | ||
639 | + if (IsLazy(cptr) && !ll_add(cptr)) | |
640 | + ClearLazy(cptr); | |
641 | + | |
642 | /* nextping = CurrentTime; */ | |
643 | ||
644 | /* | |
645 | @@ -241,6 +247,7 @@ | |
646 | * Last, send the BURST. | |
647 | * (Or for 2.9 servers: pass all channels plus statuses) | |
648 | */ | |
649 | + if (!IsLazy(cptr)) | |
650 | { | |
651 | struct Channel *chptr; | |
652 | for (chptr = GlobalChannelList; chptr; chptr = chptr->next) | |
653 | @@ -252,3 +259,42 @@ | |
654 | return 0; | |
655 | } | |
656 | ||
657 | +int ll_add(struct Client *cptr) | |
658 | +{ | |
659 | + int i = 1; | |
660 | + | |
661 | + assert(IsLazy(cptr)); | |
662 | + | |
663 | + while ((GlobalLeafBits & i) && i < 0x80000000) | |
664 | + i <<= 1; | |
665 | + if (GlobalLeafBits & i) { | |
666 | + sendto_opmask_butone(NULL, SNO_OLDSNO, "No more bits for LazyLeaf %s.", cli_name(cptr)); | |
667 | + return 0; | |
668 | + } | |
669 | + GlobalLeafBits |= i; | |
670 | + cli_serv(cptr)->ll_mask = i; | |
671 | + log_write(LS_DEBUG, L_DEBUG, 0, "Added LazyLeaf %s with mask 0x%lx. GlobalLeafBits=0x%lx", cli_name(cptr), i, GlobalLeafBits); | |
672 | + return 1; | |
673 | +} | |
674 | + | |
675 | +void ll_remove(struct Client *cptr) | |
676 | +{ | |
677 | + struct Channel *chptr; | |
678 | + | |
679 | + assert(IsLazy(cptr)); | |
680 | + | |
681 | + for (chptr = GlobalChannelList; chptr; chptr = chptr->next) | |
682 | + chptr->ll_bits &= ~cli_serv(cptr)->ll_mask; | |
683 | + | |
684 | + GlobalLeafBits &= ~cli_serv(cptr)->ll_mask; | |
685 | + log_write(LS_DEBUG, L_DEBUG, 0, "Removed LazyLeaf %s with mask 0x%lx. GlobalLeafBits=0x%lx", cli_name(cptr), cli_serv(cptr)->ll_mask, GlobalLeafBits); | |
686 | +} | |
687 | + | |
688 | +void ll_check_channel(struct Client *cptr, struct Channel *chptr) | |
689 | +{ | |
690 | + if (feature_bool(FEAT_LAZY_LEAF) && MyUser(cptr) && chptr->locals <= 1) { | |
691 | + log_write(LS_DEBUG, L_DEBUG, 0, "LazyLeaf: Channel %s has no more locals", chptr->chname); | |
692 | + sendcmdto_serv_butone(&me, CMD_FORGET, NULL, "%s", chptr->chname); | |
693 | + chptr->mode.mode |= MODE_EMPTY; | |
694 | + } | |
695 | +} | |
696 | Index: ircd/send.c | |
697 | =================================================================== | |
698 | RCS file: /home/coder-com/cvs/ircu2.10/ircd/send.c,v | |
699 | retrieving revision 1.46 | |
700 | diff -u -r1.46 send.c | |
701 | --- ircd/send.c 2002/02/14 00:20:45 1.46 | |
702 | +++ ircd/send.c 2002/04/12 13:47:53 | |
703 | @@ -328,6 +328,35 @@ | |
704 | msgq_clean(mb); | |
705 | } | |
706 | ||
707 | +void sendcmdto_mask_butone(struct Client *from, const char *cmd, | |
708 | + const char *tok, unsigned long ll_mask, | |
709 | + struct Client *one, | |
710 | + const char *pattern, ...) | |
711 | +{ | |
712 | + struct VarData vd; | |
713 | + struct MsgBuf *mb; | |
714 | + struct DLink *lp; | |
715 | + | |
716 | + vd.vd_format = pattern; /* set up the struct VarData for %v */ | |
717 | + va_start(vd.vd_args, pattern); | |
718 | + | |
719 | + /* use token */ | |
720 | + mb = msgq_make(&me, "%C %s %v", from, tok, &vd); | |
721 | + va_end(vd.vd_args); | |
722 | + | |
723 | + /* send it to our downlinks */ | |
724 | + for (lp = cli_serv(&me)->down; lp; lp = lp->next) { | |
725 | + if (one && lp->value.cptr == cli_from(one)) | |
726 | + continue; | |
727 | + if (IsLazy(lp->value.cptr) && !(cli_serv(lp->value.cptr)->ll_mask & ll_mask)) | |
728 | + continue; | |
729 | + send_buffer(lp->value.cptr, mb, 0); | |
730 | + } | |
731 | + | |
732 | + msgq_clean(mb); | |
733 | +} | |
734 | + | |
735 | + | |
736 | /* | |
737 | * Send a (prefix) command originating from <from> to all channels | |
738 | * <from> is locally on. <from> must be a user. <tok> is ignored in | |
739 | --- /dev/null Thu Aug 24 12:00:32 2000 | |
740 | +++ doc/readme.lazylinks Fri Apr 12 16:47:36 2002 | |
741 | @@ -0,0 +1,46 @@ | |
742 | +Concept | |
743 | +~~~~~~~ | |
744 | +The idea behind lazy links is that leafs often don't need much of the | |
745 | +state information they are sent. Currently, only lazy channels are | |
746 | +implemented; this means lazy leafs will only be burst channels that | |
747 | +they have local users on. | |
748 | + | |
749 | +Protocol | |
750 | +~~~~~~~~ | |
751 | +If a leaf has FEAT_LAZY_LEAF set, it sends a +l flag in the SERVER message | |
752 | +it sends to its hub (note that if FEAT_HUB is also set, it takes precedence | |
753 | +over FEAT_LAZY_LEAF). The hub will then mark this leaf as 'lazy', and will | |
754 | +not burst any channels to it. The hub will also keep a bitmask of which leaves | |
755 | +know which channels. Subsequently, when the leaf tries to announce a channel | |
756 | +to its hub (via a BURST, JOIN or CREATE) and the leaf doesn't "know" about | |
757 | +that channel from the hub's point of view, the hub will send a full BURST of | |
758 | +the channel back to the leaf, and mark the channel as "known" to the leaf. | |
759 | +Note that a server with FEAT_LAZY_LEAF set *will* accept BURST messages outside | |
760 | +of net.burst. When a channel has no more local clients, the leaf will send a | |
761 | +FORGET message to the hub and destroy the channel locally. Upon receipt of this | |
762 | +meessage, the hub will remove the "known" bit for that channel/leaf pair, and | |
763 | +it will burst the channel again if the leaf tries to create it later on. The | |
764 | +FORGET message has the following syntax: | |
765 | + <server numeric> FO <#channel> | |
766 | + | |
767 | +Code | |
768 | +~~~~ | |
769 | +struct Server has a ll_mask field which is assigned to each lazy leaf on its | |
770 | +uplink hub. Every leaf gets a bit, so the maximum number of leafs is 32 on | |
771 | +32-bit machines. struct Channel now has a ll_bits bitmask field which stores | |
772 | +which leaves "know" the channel. A new sendcmd_to_mask_butone function was | |
773 | +used instead of sendcmdto_serv_butone which doesn't send to lazy leaves that | |
774 | +don't match the specified mask (currently, chptr->ll_bits). | |
775 | + | |
776 | +Bugs | |
777 | +~~~~ | |
778 | +This documentation is less than complete. | |
779 | + | |
780 | +Commands like LIST, TOPIC, MODE issued on a lazy leaf for channels that hasn't | |
781 | +been burst to it will incorrectly report the channels doesn't exist. This should | |
782 | +be handled by forwarding those messages to its uplink. | |
783 | + | |
784 | +joinbuf_flush now sends each join/part as a separate message, because they each | |
785 | +have to be matched against the leaves' "known channel" bits. | |
786 | + | |
787 | +Probably more. | |
788 | --- /dev/null Thu Aug 24 12:00:32 2000 | |
789 | +++ ircd/m_forget.c Wed Apr 3 23:07:14 2002 | |
790 | @@ -0,0 +1,123 @@ | |
791 | +/* | |
792 | + * IRC - Internet Relay Chat, ircd/m_forget.c | |
793 | + * Copyright (C) 2002 Alex Badea <vampire@p16.pub.ro> | |
794 | + * | |
795 | + * See file AUTHORS in IRC package for additional names of | |
796 | + * the programmers. | |
797 | + * | |
798 | + * This program is free software; you can redistribute it and/or modify | |
799 | + * it under the terms of the GNU General Public License as published by | |
800 | + * the Free Software Foundation; either version 1, or (at your option) | |
801 | + * any later version. | |
802 | + * | |
803 | + * This program is distributed in the hope that it will be useful, | |
804 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
805 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
806 | + * GNU General Public License for more details. | |
807 | + * | |
808 | + * You should have received a copy of the GNU General Public License | |
809 | + * along with this program; if not, write to the Free Software | |
810 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
811 | + * | |
812 | + * $Id: lazy.diff,v 1.2 2002/04/12 13:50:27 vampire Exp $ | |
813 | + */ | |
814 | + | |
815 | +/* | |
816 | + * m_functions execute protocol messages on this server: | |
817 | + * | |
818 | + * cptr is always NON-NULL, pointing to a *LOCAL* client | |
819 | + * structure (with an open socket connected!). This | |
820 | + * identifies the physical socket where the message | |
821 | + * originated (or which caused the m_function to be | |
822 | + * executed--some m_functions may call others...). | |
823 | + * | |
824 | + * sptr is the source of the message, defined by the | |
825 | + * prefix part of the message if present. If not | |
826 | + * or prefix not found, then sptr==cptr. | |
827 | + * | |
828 | + * (!IsServer(cptr)) => (cptr == sptr), because | |
829 | + * prefixes are taken *only* from servers... | |
830 | + * | |
831 | + * (IsServer(cptr)) | |
832 | + * (sptr == cptr) => the message didn't | |
833 | + * have the prefix. | |
834 | + * | |
835 | + * (sptr != cptr && IsServer(sptr) means | |
836 | + * the prefix specified servername. (?) | |
837 | + * | |
838 | + * (sptr != cptr && !IsServer(sptr) means | |
839 | + * that message originated from a remote | |
840 | + * user (not local). | |
841 | + * | |
842 | + * combining | |
843 | + * | |
844 | + * (!IsServer(sptr)) means that, sptr can safely | |
845 | + * taken as defining the target structure of the | |
846 | + * message in this server. | |
847 | + * | |
848 | + * *Always* true (if 'parse' and others are working correct): | |
849 | + * | |
850 | + * 1) sptr->from == cptr (note: cptr->from == cptr) | |
851 | + * | |
852 | + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr | |
853 | + * *cannot* be a local connection, unless it's | |
854 | + * actually cptr!). [MyConnect(x) should probably | |
855 | + * be defined as (x == x->from) --msa ] | |
856 | + * | |
857 | + * parc number of variable parameter strings (if zero, | |
858 | + * parv is allowed to be NULL) | |
859 | + * | |
860 | + * parv a NULL terminated list of parameter pointers, | |
861 | + * | |
862 | + * parv[0], sender (prefix string), if not present | |
863 | + * this points to an empty string. | |
864 | + * parv[1]...parv[parc-1] | |
865 | + * pointers to additional parameters | |
866 | + * parv[parc] == NULL, *always* | |
867 | + * | |
868 | + * note: it is guaranteed that parv[0]..parv[parc-1] are all | |
869 | + * non-NULL pointers. | |
870 | + */ | |
871 | +#include "config.h" | |
872 | + | |
873 | +#include "client.h" | |
874 | +#include "hash.h" | |
875 | +#include "ircd.h" | |
876 | +#include "ircd_reply.h" | |
877 | +#include "ircd_string.h" | |
878 | +#include "msg.h" | |
879 | +#include "numeric.h" | |
880 | +#include "numnicks.h" | |
881 | +#include "send.h" | |
882 | +#include "channel.h" | |
883 | +#include "ircd_log.h" | |
884 | + | |
885 | +#include <assert.h> | |
886 | +#include <stdlib.h> | |
887 | + | |
888 | +/* | |
889 | + * ms_forget - server message handler | |
890 | + */ | |
891 | +int ms_forget(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
892 | +{ | |
893 | + struct Channel *chptr; | |
894 | + | |
895 | + assert(0 != cptr); | |
896 | + assert(0 != sptr); | |
897 | + assert(IsServer(cptr)); | |
898 | + | |
899 | + if (parc < 2) | |
900 | + return need_more_params(sptr, "FORGET"); | |
901 | + | |
902 | + /* | |
903 | + * Only lazy leafs may forget about channels. | |
904 | + * Ignore forget messages for channels that don't exist. | |
905 | + */ | |
906 | + if (!IsLazy(cptr) || !(chptr = FindChannel(parv[1]))) | |
907 | + return 0; | |
908 | + | |
909 | + chptr->ll_bits &= ~cli_serv(cptr)->ll_mask; | |
910 | + log_write(LS_DEBUG, L_DEBUG, 0, "LazyLeaf %s forgot about %s", cli_name(cptr), chptr->chname); | |
911 | + | |
912 | + return 0; | |
913 | +} |