ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/s_user.c
Revision: 158
Committed: Wed Oct 19 09:35:52 2005 UTC (18 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 42598 byte(s)
Log Message:
- Fixed bug where we would increase Count.invisi even
  if invisible_on_connect is off

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * s_user.c: User related functions.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "channel.h"
27 #include "channel_mode.h"
28 #include "client.h"
29 #include "common.h"
30 #include "hash.h"
31 #include "ircd.h"
32 #include "listener.h"
33 #include "motd.h"
34 #include "numeric.h"
35 #include "s_conf.h"
36 #include "s_user.h"
37 #include "s_serv.h"
38 #include "s_stats.h"
39 #include "send.h"
40 #include "supported.h"
41 #include "whowas.h"
42 #include "packet.h"
43 #include "userhost.h"
44 #include "msg.h"
45
46 int MaxClientCount = 1;
47 int MaxConnectionCount = 1;
48 struct Callback *entering_umode_cb = NULL;
49 struct Callback *umode_cb = NULL;
50 struct Callback *uid_get_cb = NULL;
51
52 static char umode_buffer[IRCD_BUFSIZE];
53
54 static void user_welcome(struct Client *);
55 static void report_and_set_user_flags(struct Client *, const struct AccessItem *);
56 static int check_xline(struct Client *);
57 static int check_regexp_xline(struct Client *);
58 static void introduce_client(struct Client *, struct Client *);
59 static void *uid_get(va_list);
60
61 /* Used for building up the isupport string,
62 * used with init_isupport, add_isupport, delete_isupport
63 */
64
65 struct Isupport
66 {
67 dlink_node node;
68 char *name;
69 char *options;
70 int number;
71 };
72
73 static dlink_list support_list = { NULL, NULL, 0 };
74 MessageFile *isupportFile;
75
76 /* memory is cheap. map 0-255 to equivalent mode */
77 unsigned int user_modes[256] =
78 {
79 /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x0F */
80 /* 0x10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1F */
81 /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2F */
82 /* 0x30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x3F */
83 0, /* @ */
84 0, /* A */
85 0, /* B */
86 0, /* C */
87 UMODE_DEAF, /* D */
88 0, /* E */
89 0, /* F */
90 UMODE_SOFTCALLERID, /* G */
91 0, /* H */
92 0, /* I */
93 0, /* J */
94 0, /* K */
95 0, /* L */
96 0, /* M */
97 0, /* N */
98 0, /* O */
99 0, /* P */
100 0, /* Q */
101 0, /* R */
102 0, /* S */
103 0, /* T */
104 0, /* U */
105 0, /* V */
106 0, /* W */
107 0, /* X */
108 0, /* Y */
109 0, /* Z 0x5A */
110 0, 0, 0, 0, 0, /* 0x5F */
111 0, /* 0x60 */
112 UMODE_ADMIN, /* a */
113 UMODE_BOTS, /* b */
114 UMODE_CCONN, /* c */
115 UMODE_DEBUG, /* d */
116 0, /* e */
117 UMODE_FULL, /* f */
118 UMODE_CALLERID, /* g */
119 0, /* h */
120 UMODE_INVISIBLE, /* i */
121 0, /* j */
122 UMODE_SKILL, /* k */
123 UMODE_LOCOPS, /* l */
124 0, /* m */
125 UMODE_NCHANGE, /* n */
126 UMODE_OPER, /* o */
127 0, /* p */
128 0, /* q */
129 UMODE_REJ, /* r */
130 UMODE_SERVNOTICE, /* s */
131 0, /* t */
132 UMODE_UNAUTH, /* u */
133 0, /* v */
134 UMODE_WALLOP, /* w */
135 UMODE_EXTERNAL, /* x */
136 UMODE_SPY, /* y */
137 UMODE_OPERWALL, /* z 0x7A */
138 0,0,0,0,0, /* 0x7B - 0x7F */
139
140 /* 0x80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x8F */
141 /* 0x90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9F */
142 /* 0xA0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xAF */
143 /* 0xB0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xBF */
144 /* 0xC0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xCF */
145 /* 0xD0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xDF */
146 /* 0xE0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xEF */
147 /* 0xF0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xFF */
148 };
149
150 void
151 assemble_umode_buffer(void)
152 {
153 unsigned int idx = 0;
154 char *umode_buffer_ptr = umode_buffer;
155
156 for (; idx < (sizeof(user_modes) / sizeof(int)); ++idx)
157 if (user_modes[idx])
158 *umode_buffer_ptr++ = idx;
159
160 *umode_buffer_ptr = '\0';
161 }
162
163 /* show_lusers()
164 *
165 * inputs - pointer to client
166 * output - NONE
167 * side effects - display to client user counts etc.
168 */
169 void
170 show_lusers(struct Client *source_p)
171 {
172 const char *from, *to;
173
174 if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
175 {
176 from = me.id;
177 to = source_p->id;
178 }
179 else
180 {
181 from = me.name;
182 to = source_p->name;
183 }
184
185 if (!ConfigServerHide.hide_servers || IsOper(source_p))
186 sendto_one(source_p, form_str(RPL_LUSERCLIENT),
187 from, to, (Count.total-Count.invisi),
188 Count.invisi, dlink_list_length(&global_serv_list));
189 else
190 sendto_one(source_p, form_str(RPL_LUSERCLIENT), from, to,
191 (Count.total-Count.invisi), Count.invisi, 1);
192
193 if (Count.oper > 0)
194 sendto_one(source_p, form_str(RPL_LUSEROP),
195 from, to, Count.oper);
196
197 if (dlink_list_length(&unknown_list) > 0)
198 sendto_one(source_p, form_str(RPL_LUSERUNKNOWN),
199 from, to, dlink_list_length(&unknown_list));
200
201 if (dlink_list_length(&global_channel_list) > 0)
202 sendto_one(source_p, form_str(RPL_LUSERCHANNELS),
203 from, to, dlink_list_length(&global_channel_list));
204
205 if (!ConfigServerHide.hide_servers || IsOper(source_p))
206 {
207 sendto_one(source_p, form_str(RPL_LUSERME),
208 from, to, Count.local, Count.myserver);
209 sendto_one(source_p, form_str(RPL_LOCALUSERS),
210 from, to, Count.local, Count.max_loc,
211 Count.local, Count.max_loc);
212 }
213 else
214 {
215 sendto_one(source_p, form_str(RPL_LUSERME),
216 from, to, Count.total, 0);
217 sendto_one(source_p, form_str(RPL_LOCALUSERS),
218 from, to, Count.total, Count.max_tot,
219 Count.total, Count.max_tot);
220 }
221
222 sendto_one(source_p, form_str(RPL_GLOBALUSERS),
223 from, to, Count.total, Count.max_tot,
224 Count.total, Count.max_tot);
225
226 if (!ConfigServerHide.hide_servers || IsOper(source_p))
227 sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
228 MaxConnectionCount, MaxClientCount, Count.totalrestartcount);
229
230 if (Count.local > MaxClientCount)
231 MaxClientCount = Count.local;
232
233 if ((Count.local + Count.myserver) > MaxConnectionCount)
234 MaxConnectionCount = Count.local + Count.myserver;
235 }
236
237 /* show_isupport()
238 *
239 * inputs - pointer to client
240 * output - NONE
241 * side effects - display to client what we support (for them)
242 */
243 void
244 show_isupport(struct Client *source_p)
245 {
246 send_message_file(source_p, isupportFile);
247 }
248
249 /*
250 ** register_local_user
251 ** This function is called when both NICK and USER messages
252 ** have been accepted for the client, in whatever order. Only
253 ** after this, is the USER message propagated.
254 **
255 ** NICK's must be propagated at once when received, although
256 ** it would be better to delay them too until full info is
257 ** available. Doing it is not so simple though, would have
258 ** to implement the following:
259 **
260 ** (actually it has been implemented already for a while) -orabidoo
261 **
262 ** 1) user telnets in and gives only "NICK foobar" and waits
263 ** 2) another user far away logs in normally with the nick
264 ** "foobar" (quite legal, as this server didn't propagate
265 ** it).
266 ** 3) now this server gets nick "foobar" from outside, but
267 ** has alread the same defined locally. Current server
268 ** would just issue "KILL foobar" to clean out dups. But,
269 ** this is not fair. It should actually request another
270 ** nick from local user or kill him/her...
271 */
272 void
273 register_local_user(struct Client *client_p, struct Client *source_p,
274 const char *nick, const char *username)
275 {
276 struct AccessItem *aconf = NULL;
277 char ipaddr[HOSTIPLEN];
278 dlink_node *m = NULL;
279
280 assert(source_p != NULL);
281 assert(MyConnect(source_p));
282 assert(source_p->username != username);
283
284 if (ConfigFileEntry.ping_cookie)
285 {
286 if (!IsPingSent(source_p) &&
287 source_p->localClient->random_ping == 0)
288 {
289 source_p->localClient->random_ping = (unsigned long)rand();
290 sendto_one(source_p, "PING :%lu",
291 source_p->localClient->random_ping);
292 SetPingSent(source_p);
293 return;
294 }
295
296 if (!HasPingCookie(source_p))
297 return;
298 }
299
300 source_p->localClient->last = CurrentTime;
301 /* Straight up the maximum rate of flooding... */
302 source_p->localClient->allow_read = MAX_FLOOD_BURST;
303
304 if (!execute_callback(client_check_cb, source_p, username, &aconf))
305 return;
306
307 if (valid_hostname(source_p->host) == 0)
308 {
309 sendto_one(source_p, ":%s NOTICE %s :*** Notice -- You have an illegal "
310 "character in your hostname", me.name, source_p->name);
311 strlcpy(source_p->host, source_p->sockhost,
312 sizeof(source_p->host));
313 }
314
315 if (!IsGotId(source_p))
316 {
317 const char *p = NULL;
318 unsigned int i = 0;
319
320 if (IsNeedIdentd(aconf))
321 {
322 ServerStats->is_ref++;
323 sendto_one(source_p, ":%s NOTICE %s :*** Notice -- You need to install "
324 "identd to use this server", me.name, source_p->name);
325 exit_client(source_p, &me, "Install identd");
326 return;
327 }
328
329 p = username;
330
331 if (!IsNoTilde(aconf))
332 source_p->username[i++] = '~';
333
334 while (*p && i < USERLEN)
335 {
336 if (*p != '[')
337 source_p->username[i++] = *p;
338 p++;
339 }
340
341 source_p->username[i] = '\0';
342 }
343
344 /* password check */
345 if (!EmptyString(aconf->passwd))
346 {
347 const char *pass = source_p->localClient->passwd;
348
349 if (!match_conf_password(pass, aconf))
350 {
351 ServerStats->is_ref++;
352 sendto_one(source_p, form_str(ERR_PASSWDMISMATCH),
353 me.name, source_p->name);
354 exit_client(source_p, &me, "Bad Password");
355 return;
356 }
357 }
358
359 /* don't free source_p->localClient->passwd here - it can be required
360 * by masked /stats I if there are auth{} blocks with need_password = no;
361 * --adx
362 */
363
364 /* report if user has &^>= etc. and set flags as needed in source_p */
365 report_and_set_user_flags(source_p, aconf);
366
367 /* Limit clients -
368 * We want to be able to have servers and F-line clients
369 * connect, so save room for "buffer" connections.
370 * Smaller servers may want to decrease this, and it should
371 * probably be just a percentage of the MAXCLIENTS...
372 * -Taner
373 */
374 /* Except "F:" clients */
375 if ((Count.local >= ServerInfo.max_clients + MAX_BUFFER) ||
376 (Count.local >= ServerInfo.max_clients && !IsExemptLimits(source_p)))
377 {
378 sendto_realops_flags(UMODE_FULL, L_ALL,
379 "Too many clients, rejecting %s[%s].",
380 nick, source_p->host);
381 ServerStats->is_ref++;
382 exit_client(source_p, &me, "Sorry, server is full - try later");
383 return;
384 }
385
386 /* valid user name check */
387 if (valid_username(source_p->username) == 0)
388 {
389 char tmpstr2[IRCD_BUFSIZE];
390
391 sendto_realops_flags(UMODE_REJ, L_ALL, "Invalid username: %s (%s@%s)",
392 nick, source_p->username, source_p->host);
393 ServerStats->is_ref++;
394 ircsprintf(tmpstr2, "Invalid username [%s]", source_p->username);
395 exit_client(source_p, &me, tmpstr2);
396 return;
397 }
398
399 assert(source_p == client_p);
400
401 /* end of valid user name check */
402 if (check_xline(source_p) || check_regexp_xline(source_p))
403 return;
404
405 if (IsDead(client_p))
406 return;
407
408 if (source_p->id[0] == '\0' && me.id[0])
409 {
410 char *id = (char *) execute_callback(uid_get_cb, source_p);
411 while (hash_find_id(id) != NULL)
412 id = uid_get(NULL);
413
414 strlcpy(source_p->id, id, sizeof(source_p->id));
415 hash_add_id(source_p);
416 }
417
418 irc_getnameinfo((struct sockaddr *)&source_p->localClient->ip,
419 source_p->localClient->ip.ss_len, ipaddr,
420 HOSTIPLEN, NULL, 0, NI_NUMERICHOST);
421
422 sendto_realops_flags(UMODE_CCONN, L_ALL,
423 "Client connecting: %s (%s@%s) [%s] {%s} [%s]",
424 nick, source_p->username, source_p->host,
425 ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
426 "255.255.255.255" : ipaddr, get_client_className(source_p),
427 source_p->info);
428
429 /* If they have died in send_* don't do anything. */
430 if (IsDead(source_p))
431 return;
432
433 if (ConfigFileEntry.invisible_on_connect)
434 {
435 source_p->umodes |= UMODE_INVISIBLE;
436 ++Count.invisi;
437 }
438
439 if (++Count.local > Count.max_loc)
440 {
441 Count.max_loc = Count.local;
442
443 if (!(Count.max_loc % 10))
444 sendto_realops_flags(UMODE_ALL, L_ALL, "New Max Local Clients: %d",
445 Count.max_loc);
446 }
447
448 SetClient(source_p);
449
450 source_p->servptr = &me;
451 dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
452
453 /* Increment our total user count here */
454 if (++Count.total > Count.max_tot)
455 Count.max_tot = Count.total;
456 Count.totalrestartcount++;
457
458 source_p->localClient->allow_read = MAX_FLOOD_BURST;
459
460 if ((m = dlinkFindDelete(&unknown_list, source_p)) != NULL)
461 {
462 free_dlink_node(m);
463 dlinkAdd(source_p, &source_p->localClient->lclient_node, &local_client_list);
464 }
465 else assert(0);
466
467 user_welcome(source_p);
468 add_user_host(source_p->username, source_p->host, 0);
469 SetUserHost(source_p);
470
471 introduce_client(client_p, source_p);
472 }
473
474 /* register_remote_user()
475 *
476 * inputs - client_p directly connected client
477 * - source_p remote or directly connected client
478 * - username to register as
479 * - host name to register as
480 * - server name
481 * - realname (gecos)
482 * output - NONE
483 * side effects - This function is called when a remote client
484 * is introduced by a server.
485 */
486 void
487 register_remote_user(struct Client *client_p, struct Client *source_p,
488 const char *username, const char *host, const char *server,
489 const char *realname)
490 {
491 struct Client *target_p = NULL;
492
493 assert(source_p != NULL);
494 assert(source_p->username != username);
495
496 strlcpy(source_p->host, host, sizeof(source_p->host));
497 strlcpy(source_p->info, realname, sizeof(source_p->info));
498 strlcpy(source_p->username, username, sizeof(source_p->username));
499
500 /* Increment our total user count here */
501 if (++Count.total > Count.max_tot)
502 Count.max_tot = Count.total;
503
504 source_p->from->serv->dep_users++;
505
506 /*
507 * coming from another server, take the servers word for it
508 */
509 source_p->servptr = find_server(server);
510
511 /* Super GhostDetect:
512 * If we can't find the server the user is supposed to be on,
513 * then simply blow the user away. -Taner
514 */
515 if (source_p->servptr == NULL)
516 {
517 sendto_realops_flags(UMODE_ALL, L_ALL,
518 "No server %s for user %s[%s@%s] from %s",
519 server, source_p->name, source_p->username,
520 source_p->host, source_p->from->name);
521 kill_client(client_p, source_p, "%s (Server doesn't exist)", me.name);
522
523 /* XXX */
524 SetKilled(source_p);
525 exit_client(source_p, &me, "Ghosted Client");
526 return;
527 }
528
529 if ((target_p = source_p->servptr) && target_p->from != source_p->from)
530 {
531 sendto_realops_flags(UMODE_DEBUG, L_ALL,
532 "Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
533 client_p->name, source_p->name, source_p->username,
534 source_p->host, source_p->servptr->name,
535 target_p->name, target_p->from->name);
536 kill_client(client_p, source_p,
537 "%s (NICK from wrong direction (%s != %s))",
538 me.name, source_p->servptr->name, target_p->from->name);
539 SetKilled(source_p);
540 exit_client(source_p, &me, "USER server wrong direction");
541 return;
542 }
543
544 SetClient(source_p);
545 dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
546 add_user_host(source_p->username, source_p->host, 1);
547 SetUserHost(source_p);
548
549 introduce_client(client_p, source_p);
550 }
551
552 /* introduce_client()
553 *
554 * inputs - client_p
555 * - source_p
556 * output - NONE
557 * side effects - This common function introduces a client to the rest
558 * of the net, either from a local client connect or
559 * from a remote connect.
560 */
561 static void
562 introduce_client(struct Client *client_p, struct Client *source_p)
563 {
564 dlink_node *server_node = NULL;
565 static char ubuf[12];
566
567 if (MyClient(source_p))
568 send_umode(source_p, source_p, 0, SEND_UMODES, ubuf);
569 else
570 send_umode(NULL, source_p, 0, SEND_UMODES, ubuf);
571
572 if (*ubuf == '\0')
573 {
574 ubuf[0] = '+';
575 ubuf[1] = '\0';
576 }
577
578 /* arghhh one could try not introducing new nicks to ll leafs
579 * but then you have to introduce them "on the fly" in SJOIN
580 * not fun.
581 * Its not going to cost much more bandwidth to simply let new
582 * nicks just ride on through.
583 */
584
585 /* We now introduce nicks "on the fly" in SJOIN anyway --
586 * you _need_ to if you aren't going to burst everyone initially.
587 *
588 * Only send to non CAP_LL servers, unless we're a lazylink leaf,
589 * in that case just send it to the uplink.
590 * -davidt
591 * rewritten to cope with SIDs .. eww eww eww --is
592 */
593
594 /* XXX THESE NEED A PREFIX!?!?!? */
595 if (!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL) &&
596 client_p != uplink)
597 {
598 if (IsCapable(uplink, CAP_TS6) && HasID(source_p))
599 {
600 sendto_one(uplink, ":%s UID %s %d %lu %s %s %s %s %s :%s",
601 source_p->servptr->id,
602 source_p->name, source_p->hopcount+1,
603 (unsigned long)source_p->tsinfo,
604 ubuf, source_p->username, source_p->host,
605 ((MyClient(source_p) && !IsIPSpoof(source_p)) ?
606 source_p->sockhost : "0"),
607 source_p->id, source_p->info);
608 }
609 else
610 {
611 sendto_one(uplink, "NICK %s %d %lu %s %s %s %s :%s",
612 source_p->name, source_p->hopcount+1,
613 (unsigned long)source_p->tsinfo,
614 ubuf, source_p->username, source_p->host,
615 source_p->servptr->name,
616 source_p->info);
617 }
618 }
619 else
620 {
621 DLINK_FOREACH(server_node, serv_list.head)
622 {
623 struct Client *server = server_node->data;
624
625 if (IsCapable(server, CAP_LL) || server == client_p)
626 continue;
627
628 if (IsCapable(server, CAP_TS6) && HasID(source_p))
629 sendto_one(server, ":%s UID %s %d %lu %s %s %s %s %s :%s",
630 source_p->servptr->id,
631 source_p->name, source_p->hopcount+1,
632 (unsigned long)source_p->tsinfo,
633 ubuf, source_p->username, source_p->host,
634 ((MyClient(source_p)&&!IsIPSpoof(source_p))?source_p->sockhost:"0"),
635 source_p->id, source_p->info);
636 else
637 sendto_one(server, "NICK %s %d %lu %s %s %s %s :%s",
638 source_p->name, source_p->hopcount+1,
639 (unsigned long)source_p->tsinfo,
640 ubuf, source_p->username, source_p->host,
641 source_p->servptr->name,
642 source_p->info);
643 }
644 }
645 }
646
647 /* valid_hostname()
648 *
649 * Inputs - pointer to hostname
650 * Output - 1 if valid, 0 if not
651 * Side effects - check hostname for validity
652 *
653 * NOTE: this doesn't allow a hostname to begin with a dot and
654 * will not allow more dots than chars.
655 */
656 int
657 valid_hostname(const char *hostname)
658 {
659 const char *p = hostname;
660
661 assert(p != NULL);
662
663 if ('.' == *p || ':' == *p)
664 return 0;
665
666 while (*p)
667 {
668 if (!IsHostChar(*p))
669 return 0;
670 p++;
671 }
672
673 return 1;
674 }
675
676 /* valid_username()
677 *
678 * Inputs - pointer to user
679 * Output - 1 if valid, 0 if not
680 * Side effects - check username for validity
681 *
682 * Absolutely always reject any '*' '!' '?' '@' in an user name
683 * reject any odd control characters names.
684 * Allow '.' in username to allow for "first.last"
685 * style of username
686 */
687 int
688 valid_username(const char *username)
689 {
690 int dots = 0;
691 const char *p = username;
692
693 assert(p != NULL);
694
695 if ('~' == *p)
696 ++p;
697
698 /* reject usernames that don't start with an alphanum
699 * i.e. reject jokers who have '-@somehost' or '.@somehost'
700 * or "-hi-@somehost", "h-----@somehost" would still be accepted.
701 */
702 if (!IsAlNum(*p))
703 return 0;
704
705 while (*++p)
706 {
707 if ((*p == '.') && ConfigFileEntry.dots_in_ident)
708 {
709 dots++;
710
711 if (dots > ConfigFileEntry.dots_in_ident)
712 return 0;
713 if (!IsUserChar(p[1]))
714 return 0;
715 }
716 else if (!IsUserChar(*p))
717 return 0;
718 }
719
720 return 1;
721 }
722
723 /* report_and_set_user_flags()
724 *
725 * inputs - pointer to source_p
726 * - pointer to aconf for this user
727 * output - NONE
728 * side effects - Report to user any special flags
729 * they are getting, and set them.
730 */
731 static void
732 report_and_set_user_flags(struct Client *source_p, const struct AccessItem *aconf)
733 {
734 /* If this user is being spoofed, tell them so */
735 if (IsConfDoSpoofIp(aconf))
736 {
737 sendto_one(source_p,
738 ":%s NOTICE %s :*** Spoofing your IP. congrats.",
739 me.name, source_p->name);
740 }
741
742 /* If this user is in the exception class, Set it "E lined" */
743 if (IsConfExemptKline(aconf))
744 {
745 SetExemptKline(source_p);
746 sendto_one(source_p,
747 ":%s NOTICE %s :*** You are exempt from K/D/G lines. congrats.",
748 me.name, source_p->name);
749 }
750
751 /* The else here is to make sure that G line exempt users
752 * do not get noticed twice.
753 */
754 else if (IsConfExemptGline(aconf))
755 {
756 SetExemptGline(source_p);
757 sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from G lines.",
758 me.name, source_p->name);
759 }
760
761 if (IsConfExemptResv(aconf))
762 {
763 SetExemptResv(source_p);
764 sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from resvs.",
765 me.name, source_p->name);
766 }
767
768 /* If this user is exempt from user limits set it "F lined" */
769 if (IsConfExemptLimits(aconf))
770 {
771 SetExemptLimits(source_p);
772 sendto_one(source_p,
773 ":%s NOTICE %s :*** You are exempt from user limits. congrats.",
774 me.name,source_p->name);
775 }
776
777 /* If this user is exempt from idle time outs */
778 if (IsConfIdlelined(aconf))
779 {
780 SetIdlelined(source_p);
781 sendto_one(source_p,
782 ":%s NOTICE %s :*** You are exempt from idle limits. congrats.",
783 me.name, source_p->name);
784 }
785
786 if (IsConfCanFlood(aconf))
787 {
788 SetCanFlood(source_p);
789 sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from flood "
790 "protection, aren't you fearsome.",
791 me.name, source_p->name);
792 }
793 }
794
795 /* do_local_user()
796 *
797 * inputs -
798 * output - NONE
799 * side effects -
800 */
801 void
802 do_local_user(const char *nick, struct Client *client_p, struct Client *source_p,
803 const char *username, const char *host, const char *server,
804 const char *realname)
805 {
806 assert(source_p != NULL);
807 assert(source_p->username != username);
808
809 if (source_p == NULL)
810 return;
811
812 if (!IsUnknown(source_p))
813 {
814 sendto_one(source_p, form_str(ERR_ALREADYREGISTRED),
815 me.name, nick);
816 return;
817 }
818
819 source_p->flags |= FLAGS_GOTUSER;
820
821 /*
822 * don't take the clients word for it, ever
823 */
824 source_p->servptr = &me;
825
826 strlcpy(source_p->info, realname, sizeof(source_p->info));
827
828 if (!IsGotId(source_p))
829 {
830 /* save the username in the client
831 * If you move this you'll break ping cookies..you've been warned
832 */
833 strlcpy(source_p->username, username, sizeof(source_p->username));
834 }
835
836 if (source_p->name[0])
837 {
838 /* NICK already received, now I have USER... */
839 register_local_user(client_p, source_p, source_p->name, username);
840 }
841 }
842
843 /* change_simple_umode()
844 *
845 * this callback can be hooked to allow special handling of
846 * certain usermodes
847 */
848 static void *
849 change_simple_umode(va_list args)
850 {
851 struct Client *source_p;
852 int what;
853 unsigned int flag;
854
855 va_arg(args, struct Client *);
856 source_p = va_arg(args, struct Client *);
857 what = va_arg(args, int);
858 flag = va_arg(args, unsigned int);
859
860 if (what == MODE_ADD)
861 source_p->umodes |= flag;
862 else
863 source_p->umodes &= ~flag;
864
865 return NULL;
866 }
867
868 /* set_user_mode()
869 *
870 * added 15/10/91 By Darren Reed.
871 * parv[0] - sender
872 * parv[1] - username to change mode for
873 * parv[2] - modes to change
874 */
875 void
876 set_user_mode(struct Client *client_p, struct Client *source_p,
877 int parc, char *parv[])
878 {
879 unsigned int flag, setflags;
880 char **p, *m, buf[IRCD_BUFSIZE];
881 struct Client *target_p;
882 int what = MODE_ADD, badflag = 0, i;
883
884 assert(!(parc < 2));
885
886 if ((target_p = find_person(client_p, parv[1])) == NULL)
887 {
888 if (MyConnect(source_p))
889 sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
890 me.name, source_p->name, parv[1]);
891 return;
892 }
893
894 if (IsServer(source_p))
895 {
896 sendto_realops_flags(UMODE_ALL, L_ADMIN, "*** Mode for User %s from %s",
897 parv[1], source_p->name);
898 return;
899 }
900
901 if (source_p != target_p || target_p->from != source_p->from)
902 {
903 sendto_one(source_p, form_str(ERR_USERSDONTMATCH),
904 me.name, source_p->name);
905 return;
906 }
907
908 if (parc < 3)
909 {
910 m = buf;
911 *m++ = '+';
912
913 for (i = 0; i < 128; i++)
914 if (source_p->umodes & user_modes[i])
915 *m++ = (char)i;
916 *m = '\0';
917
918 sendto_one(source_p, form_str(RPL_UMODEIS),
919 me.name, source_p->name, buf);
920 return;
921 }
922
923 execute_callback(entering_umode_cb, client_p, source_p);
924
925 /* find flags already set for user */
926 setflags = source_p->umodes;
927
928 /* parse mode change string(s) */
929 for (p = &parv[2]; p && *p; p++)
930 {
931 for (m = *p; *m; m++)
932 {
933 switch (*m)
934 {
935 case '+':
936 what = MODE_ADD;
937 break;
938 case '-':
939 what = MODE_DEL;
940 break;
941 case 'o':
942 if (what == MODE_ADD)
943 {
944 if (IsServer(client_p) && !IsOper(source_p))
945 {
946 ++Count.oper;
947 SetOper(source_p);
948 }
949 }
950 else
951 {
952 /* Only decrement the oper counts if an oper to begin with
953 * found by Pat Szuta, Perly , perly@xnet.com
954 */
955 if (!IsOper(source_p))
956 break;
957
958 ClearOper(source_p);
959 source_p->umodes &= ~ConfigFileEntry.oper_only_umodes;
960 Count.oper--;
961
962 if (MyConnect(source_p))
963 {
964 dlink_node *dm;
965
966 ClearOperFlags(source_p);
967
968 if ((dm = dlinkFindDelete(&oper_list, source_p)) != NULL)
969 free_dlink_node(dm);
970 }
971 }
972
973 break;
974
975 /* we may not get these,
976 * but they shouldnt be in default
977 */
978 case ' ' :
979 case '\n':
980 case '\r':
981 case '\t':
982 break;
983
984 default:
985 if ((flag = user_modes[(unsigned char)*m]))
986 {
987 if (MyConnect(source_p) && !IsOper(source_p) &&
988 (ConfigFileEntry.oper_only_umodes & flag))
989 {
990 badflag = 1;
991 }
992 else
993 execute_callback(umode_cb, client_p, source_p, what, flag);
994 }
995 else
996 {
997 if (MyConnect(source_p))
998 badflag = 1;
999 }
1000
1001 break;
1002 }
1003 }
1004 }
1005
1006 if (badflag)
1007 sendto_one(source_p, form_str(ERR_UMODEUNKNOWNFLAG),
1008 me.name, source_p->name);
1009
1010 if ((source_p->umodes & UMODE_NCHANGE) && !IsOperN(source_p))
1011 {
1012 sendto_one(source_p, ":%s NOTICE %s :*** You have no admin flag;",
1013 me.name, source_p->name);
1014 source_p->umodes &= ~UMODE_NCHANGE; /* only tcm's really need this */
1015 }
1016
1017 if (MyConnect(source_p) && (source_p->umodes & UMODE_ADMIN) &&
1018 !IsOperAdmin(source_p) && !IsOperHiddenAdmin(source_p))
1019 {
1020 sendto_one(source_p, ":%s NOTICE %s :*** You have no admin flag;",
1021 me.name, source_p->name);
1022 source_p->umodes &= ~UMODE_ADMIN;
1023 }
1024
1025 if (!(setflags & UMODE_INVISIBLE) && IsInvisible(source_p))
1026 ++Count.invisi;
1027 if ((setflags & UMODE_INVISIBLE) && !IsInvisible(source_p))
1028 --Count.invisi;
1029
1030 /*
1031 * compare new flags with old flags and send string which
1032 * will cause servers to update correctly.
1033 */
1034 send_umode_out(client_p, source_p, setflags);
1035 }
1036
1037 /* send_umode()
1038 * send the MODE string for user (user) to connection client_p
1039 * -avalon
1040 */
1041 void
1042 send_umode(struct Client *client_p, struct Client *source_p,
1043 unsigned int old, unsigned int sendmask, char *umode_buf)
1044 {
1045 int what = 0;
1046 unsigned int i;
1047 unsigned int flag;
1048 char *m = umode_buf;
1049
1050 /*
1051 * build a string in umode_buf to represent the change in the user's
1052 * mode between the new (source_p->umodes) and 'old'.
1053 */
1054 for (i = 0; i < 128; i++)
1055 {
1056 flag = user_modes[i];
1057 if (!flag)
1058 continue;
1059
1060 if (MyClient(source_p) && !(flag & sendmask))
1061 continue;
1062
1063 if ((flag & old) && !(source_p->umodes & flag))
1064 {
1065 if (what == MODE_DEL)
1066 *m++ = (char)i;
1067 else
1068 {
1069 what = MODE_DEL;
1070 *m++ = '-';
1071 *m++ = (char)i;
1072 }
1073 }
1074 else if (!(flag & old) && (source_p->umodes & flag))
1075 {
1076 if (what == MODE_ADD)
1077 *m++ = (char)i;
1078 else
1079 {
1080 what = MODE_ADD;
1081 *m++ = '+';
1082 *m++ = (char)i;
1083 }
1084 }
1085 }
1086
1087 *m = '\0';
1088
1089 if (*umode_buf && client_p)
1090 sendto_one(client_p, ":%s MODE %s :%s",
1091 source_p->name, source_p->name, umode_buf);
1092 }
1093
1094 /* send_umode_out()
1095 *
1096 * inputs -
1097 * output - NONE
1098 * side effects - Only send ubuf out to servers that know about this client
1099 */
1100 void
1101 send_umode_out(struct Client *client_p, struct Client *source_p,
1102 unsigned int old)
1103 {
1104 char buf[IRCD_BUFSIZE];
1105 dlink_node *ptr = NULL;
1106
1107 send_umode(NULL, source_p, old, IsOperHiddenAdmin(source_p) ?
1108 SEND_UMODES & ~UMODE_ADMIN : SEND_UMODES, buf);
1109
1110 if (*buf)
1111 {
1112 DLINK_FOREACH(ptr, serv_list.head)
1113 {
1114 struct Client *target_p = ptr->data;
1115
1116 if ((target_p != client_p) && (target_p != source_p))
1117 {
1118 if ((!(ServerInfo.hub && IsCapable(target_p, CAP_LL))) ||
1119 (target_p->localClient->serverMask &
1120 source_p->lazyLinkClientExists))
1121 sendto_one(target_p, ":%s MODE %s :%s",
1122 ID_or_name(source_p, target_p),
1123 ID_or_name(source_p, target_p), buf);
1124 }
1125 }
1126 }
1127
1128 if (client_p && MyClient(client_p))
1129 send_umode(client_p, source_p, old, 0xffffffff, buf);
1130 }
1131
1132 /* user_welcome()
1133 *
1134 * inputs - client pointer to client to welcome
1135 * output - NONE
1136 * side effects -
1137 */
1138 static void
1139 user_welcome(struct Client *source_p)
1140 {
1141 #if defined(__TIME__) && defined(__DATE__)
1142 static const char built_date[] = __DATE__ " at " __TIME__;
1143 #else
1144 static const char built_date[] = "unknown";
1145 #endif
1146
1147 #ifdef HAVE_LIBCRYPTO
1148 if (source_p->localClient->fd.ssl != NULL)
1149 sendto_one(source_p, ":%s NOTICE %s :*** Connected securely via %s",
1150 me.name, source_p->name,
1151 ssl_get_cipher(source_p->localClient->fd.ssl));
1152 #endif
1153
1154 sendto_one(source_p, form_str(RPL_WELCOME), me.name, source_p->name,
1155 ServerInfo.network_name, source_p->name);
1156 sendto_one(source_p, form_str(RPL_YOURHOST), me.name, source_p->name,
1157 get_listener_name(source_p->localClient->listener), ircd_version);
1158 sendto_one(source_p, form_str(RPL_CREATED),
1159 me.name, source_p->name, built_date);
1160 sendto_one(source_p, form_str(RPL_MYINFO),
1161 me.name, source_p->name, me.name, ircd_version, umode_buffer);
1162 show_isupport(source_p);
1163
1164 if (source_p->id[0] != '\0')
1165 sendto_one(source_p, form_str(RPL_YOURID), me.name,
1166 source_p->name, source_p->id);
1167
1168 show_lusers(source_p);
1169
1170 if (ConfigFileEntry.short_motd)
1171 {
1172 sendto_one(source_p, "NOTICE %s :*** Notice -- motd was last changed at %s",
1173 source_p->name, ConfigFileEntry.motd.lastChangedDate);
1174 sendto_one(source_p,
1175 "NOTICE %s :*** Notice -- Please read the motd if you haven't "
1176 "read it", source_p->name);
1177 sendto_one(source_p, form_str(RPL_MOTDSTART),
1178 me.name, source_p->name, me.name);
1179 sendto_one(source_p, form_str(RPL_MOTD),
1180 me.name, source_p->name,
1181 "*** This is the short motd ***");
1182 sendto_one(source_p, form_str(RPL_ENDOFMOTD),
1183 me.name, source_p->name);
1184 }
1185 else
1186 send_message_file(source_p, &ConfigFileEntry.motd);
1187 }
1188
1189 /* check_xline()
1190 *
1191 * inputs - pointer to client to test
1192 * outupt - 1 if exiting 0 if ok
1193 * side effects -
1194 */
1195 static int
1196 check_xline(struct Client *source_p)
1197 {
1198 struct ConfItem *conf;
1199 struct MatchItem *xconf;
1200 const char *reason;
1201
1202 if ((conf = find_matching_name_conf(XLINE_TYPE, source_p->info,
1203 NULL, NULL, 0)) != NULL)
1204 {
1205 xconf = &conf->conf.MatchItem;
1206 xconf->count++;
1207
1208 if (xconf->reason != NULL)
1209 reason = xconf->reason;
1210 else
1211 reason = "No Reason";
1212
1213 sendto_realops_flags(UMODE_REJ, L_ALL,
1214 "X-line Rejecting [%s] [%s], user %s [%s]",
1215 source_p->info, reason,
1216 get_client_name(source_p, HIDE_IP),
1217 source_p->sockhost);
1218
1219 ServerStats->is_ref++;
1220 if (REJECT_HOLD_TIME > 0)
1221 {
1222 sendto_one(source_p, ":%s NOTICE %s :Bad user info",
1223 me.name, source_p->name);
1224 source_p->localClient->reject_delay = CurrentTime + REJECT_HOLD_TIME;
1225 SetCaptured(source_p);
1226 }
1227 else
1228 exit_client(source_p, &me, "Bad user info");
1229 return 1;
1230 }
1231
1232 return 0;
1233 }
1234
1235 static int
1236 check_regexp_xline(struct Client *source_p)
1237 {
1238 struct ConfItem *conf = NULL;
1239 const char *reason = NULL;
1240
1241 if ((conf = find_matching_name_conf(RXLINE_TYPE, source_p->info, NULL, NULL, 0)))
1242 {
1243 struct MatchItem *reg = &conf->conf.MatchItem;
1244
1245 ++reg->count;
1246
1247 if (reg->reason != NULL)
1248 reason = reg->reason;
1249 else
1250 reason = "No Reason";
1251
1252 sendto_realops_flags(UMODE_REJ, L_ALL,
1253 "X-line (REGEX) Rejecting [%s] [%s], user %s [%s]",
1254 source_p->info, reason,
1255 get_client_name(source_p, HIDE_IP),
1256 source_p->sockhost);
1257
1258 ServerStats->is_ref++;
1259 exit_client(source_p, &me, "Bad user info");
1260 return 1;
1261 }
1262
1263 return 0;
1264 }
1265
1266 /* oper_up()
1267 *
1268 * inputs - pointer to given client to oper
1269 * - pointer to oper conf found
1270 * output - NONE
1271 * side effects - Blindly opers up given source_p, using conf info
1272 * all checks on passwords have already been done.
1273 * This is also used by rsa oper routines.
1274 */
1275 void
1276 oper_up(struct Client *source_p, struct ConfItem *conf)
1277 {
1278 unsigned int old = source_p->umodes;
1279 const char *operprivs = "";
1280 struct AccessItem *aconf;
1281
1282 aconf = &conf->conf.AccessItem;
1283 ++Count.oper;
1284 SetOper(source_p);
1285
1286 if (aconf->modes)
1287 source_p->umodes |= aconf->modes;
1288 else if (ConfigFileEntry.oper_umodes)
1289 source_p->umodes |= ConfigFileEntry.oper_umodes;
1290 else
1291 source_p->umodes |= (UMODE_SERVNOTICE|UMODE_OPERWALL|
1292 UMODE_WALLOP|UMODE_LOCOPS);
1293
1294 assert(dlinkFind(&oper_list, source_p) == NULL);
1295 dlinkAdd(source_p, make_dlink_node(), &oper_list);
1296
1297 operprivs = oper_privs_as_string(aconf->port);
1298 SetOFlag(source_p, aconf->port);
1299
1300 if (IsOperAdmin(source_p) || IsOperHiddenAdmin(source_p))
1301 source_p->umodes |= UMODE_ADMIN;
1302 if (!IsOperN(source_p))
1303 source_p->umodes &= ~UMODE_NCHANGE;
1304 MyFree(source_p->localClient->auth_oper);
1305 DupString(source_p->localClient->auth_oper, conf->name);
1306 sendto_realops_flags(UMODE_ALL, L_ALL, "%s (%s@%s) is now an operator",
1307 source_p->name, source_p->username, source_p->host);
1308 send_umode_out(source_p, source_p, old);
1309 sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
1310 sendto_one(source_p, ":%s NOTICE %s :*** Oper privs are %s",
1311 me.name, source_p->name, operprivs);
1312 send_message_file(source_p, &ConfigFileEntry.opermotd);
1313 }
1314
1315 /*
1316 * UID code for TS6 SID code on EFnet
1317 *
1318 */
1319
1320 static char new_uid[TOTALSIDUID+1]; /* allow for \0 */
1321 static void add_one_to_uid(int i);
1322
1323 /*
1324 * init_uid()
1325 *
1326 * inputs - NONE
1327 * output - NONE
1328 * side effects - new_uid is filled in with server id portion (sid)
1329 * (first 3 bytes) or defaulted to 'A'.
1330 * Rest is filled in with 'A' except for the last byte
1331 * which is filled in with '@'
1332 */
1333 void
1334 init_uid(void)
1335 {
1336 int i;
1337
1338 memset(new_uid, 0, sizeof(new_uid));
1339
1340 if (ServerInfo.sid != NULL)
1341 {
1342 memcpy(new_uid, ServerInfo.sid, IRCD_MIN(strlen(ServerInfo.sid),
1343 IRC_MAXSID));
1344 memcpy(&me.id, ServerInfo.sid, IRCD_MIN(strlen(ServerInfo.sid),
1345 IRC_MAXSID));
1346 hash_add_id(&me);
1347 }
1348
1349 for (i = 0; i < IRC_MAXSID; i++)
1350 if (new_uid[i] == '\0')
1351 new_uid[i] = 'A';
1352
1353 /* XXX if IRC_MAXUID != 6, this will have to be rewritten */
1354 /* Yes nenolod, I have known it was off by one ever since I wrote it
1355 * But *JUST* for you, though, it really doesn't look as *pretty*
1356 * -Dianora
1357 */
1358 memcpy(new_uid+IRC_MAXSID, "AAAAA@", IRC_MAXUID);
1359
1360 entering_umode_cb = register_callback("entering_umode", NULL);
1361 umode_cb = register_callback("changing_umode", change_simple_umode);
1362 uid_get_cb = register_callback("uid_get", uid_get);
1363 }
1364
1365 /*
1366 * uid_get
1367 *
1368 * inputs - struct Client *
1369 * output - new UID is returned to caller
1370 * side effects - new_uid is incremented by one.
1371 */
1372 static void *
1373 uid_get(va_list args)
1374 {
1375 add_one_to_uid(TOTALSIDUID-1); /* index from 0 */
1376 return ((void *) new_uid);
1377 }
1378
1379 /*
1380 * add_one_to_uid
1381 *
1382 * inputs - index number into new_uid
1383 * output - NONE
1384 * side effects - new_uid is incremented by one
1385 * note this is a recursive function
1386 */
1387 static void
1388 add_one_to_uid(int i)
1389 {
1390 if (i != IRC_MAXSID) /* Not reached server SID portion yet? */
1391 {
1392 if (new_uid[i] == 'Z')
1393 new_uid[i] = '0';
1394 else if (new_uid[i] == '9')
1395 {
1396 new_uid[i] = 'A';
1397 add_one_to_uid(i-1);
1398 }
1399 else new_uid[i] = new_uid[i] + 1;
1400 }
1401 else
1402 {
1403 /* XXX if IRC_MAXUID != 6, this will have to be rewritten */
1404 if (new_uid[i] == 'Z')
1405 memcpy(new_uid+IRC_MAXSID, "AAAAAA", IRC_MAXUID);
1406 else
1407 new_uid[i] = new_uid[i] + 1;
1408 }
1409 }
1410
1411 /*
1412 * init_isupport()
1413 *
1414 * input - NONE
1415 * output - NONE
1416 * side effects - Must be called before isupport is enabled
1417 */
1418 void
1419 init_isupport(void)
1420 {
1421 isupportFile = init_MessageLine();
1422
1423 add_isupport("CALLERID", NULL, -1);
1424 add_isupport("CASEMAPPING", CASEMAP, -1);
1425 add_isupport("KICKLEN", NULL, KICKLEN);
1426 add_isupport("MODES", NULL, MAXMODEPARAMS);
1427 add_isupport("NICKLEN", NULL, NICKLEN-1);
1428 #ifdef HALFOPS
1429 add_isupport("PREFIX", "(ohv)@%+", -1);
1430 add_isupport("STATUSMSG", "@%+", -1);
1431 #else
1432 add_isupport("PREFIX", "(ov)@+", -1);
1433 add_isupport("STATUSMSG", "@+", -1);
1434 #endif
1435 add_isupport("TOPICLEN", NULL, TOPICLEN);
1436 }
1437
1438 /*
1439 * add_isupport()
1440 *
1441 * input - name of supported function
1442 * - options if any
1443 * - number if any
1444 * output - NONE
1445 * side effects - Each supported item must call this when activated
1446 */
1447 void
1448 add_isupport(const char *name, const char *options, int n)
1449 {
1450 dlink_node *ptr;
1451 struct Isupport *support;
1452
1453 DLINK_FOREACH(ptr, support_list.head)
1454 {
1455 support = ptr->data;
1456 if (irccmp(support->name, name) == 0)
1457 {
1458 MyFree(support->name);
1459 MyFree(support->options);
1460 break;
1461 }
1462 }
1463
1464 if (ptr == NULL)
1465 {
1466 support = MyMalloc(sizeof(*support));
1467 dlinkAddTail(support, &support->node, &support_list);
1468 }
1469
1470 DupString(support->name, name);
1471 if (options != NULL)
1472 DupString(support->options, options);
1473 support->number = n;
1474
1475 rebuild_isupport_message_line();
1476 }
1477
1478 /*
1479 * delete_isupport()
1480 *
1481 * input - name of supported function
1482 * output - NONE
1483 * side effects - Each supported item must call this when deactivated
1484 */
1485 void
1486 delete_isupport(const char *name)
1487 {
1488 dlink_node *ptr;
1489 struct Isupport *support;
1490
1491 DLINK_FOREACH(ptr, support_list.head)
1492 {
1493 support = ptr->data;
1494 if (irccmp(support->name, name) == 0)
1495 {
1496 dlinkDelete(ptr, &support_list);
1497 MyFree(support->name);
1498 MyFree(support->options);
1499 MyFree(support);
1500 break;
1501 }
1502 }
1503
1504 rebuild_isupport_message_line();
1505 }
1506
1507 /*
1508 * rebuild_isupport_message_line
1509 *
1510 * input - NONE
1511 * output - NONE
1512 * side effects - Destroy the isupport MessageFile lines, and rebuild.
1513 */
1514 void
1515 rebuild_isupport_message_line(void)
1516 {
1517 char isupportbuffer[IRCD_BUFSIZE];
1518 char *p = isupportbuffer;
1519 dlink_node *ptr = NULL;
1520 int n = 0;
1521 int tokens = 0;
1522 size_t len = 0;
1523 size_t reserve = strlen(me.name) + HOSTLEN + strlen(form_str(RPL_ISUPPORT));
1524
1525 destroy_MessageLine(isupportFile);
1526
1527 DLINK_FOREACH(ptr, support_list.head)
1528 {
1529 struct Isupport *support = ptr->data;
1530
1531 p += (n = ircsprintf(p, "%s", support->name));
1532 len += n;
1533
1534 if (support->options != NULL)
1535 {
1536 p += (n = ircsprintf(p, "=%s", support->options));
1537 len += n;
1538 }
1539
1540 if (support->number > 0)
1541 {
1542 p += (n = ircsprintf(p, "=%d", support->number));
1543 len += n;
1544 }
1545
1546 *p++ = ' ';
1547 len++;
1548 *p = '\0';
1549
1550 if (++tokens == (MAXPARA-2) || len >= (sizeof(isupportbuffer)-reserve))
1551 { /* arbritrary for now */
1552 if (*--p == ' ')
1553 *p = '\0';
1554
1555 addto_MessageLine(isupportFile, isupportbuffer);
1556 p = isupportbuffer;
1557 len = 0;
1558 n = tokens = 0;
1559 }
1560 }
1561
1562 if (len != 0)
1563 {
1564 if (*--p == ' ')
1565 *p = '\0';
1566 addto_MessageLine(isupportFile, isupportbuffer);
1567 }
1568 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision