ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/user.c
Revision: 981
Committed: Sun Aug 9 19:09:03 2009 UTC (16 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_user.c
File size: 41290 byte(s)
Log Message:
- speed up processing of incoming NICK/UID bursts
- fixed archaic bug where bursting servers with missconfigured NICKLEN were able
  to desync the network's nickname database


File Contents

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

Properties

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