/[svn]/ircd-hybrid/src/s_user.c
ViewVC logotype

Annotation of /ircd-hybrid/src/s_user.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 502 - (hide annotations)
Fri Mar 3 19:49:25 2006 UTC (15 years, 3 months ago) by michael
File MIME type: text/x-chdr
File size: 39354 byte(s)
- Implemented CAP command handler based uppon ircu's m_cap()
- Added somewhat outdated draft-mitchell-irc-capabilities-01.txt until
  I get the latest version from kev.
- Added "multi-prefix" cap so clients supporting "multi-prefix"
  may recieve multi prefixed NAMES replies, e.g. @%+nick1 @+nick2 ..
- Fixed "make clean" for src/conf/

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 "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 db 101 #include "s_user.h"
37 adx 30 #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 michael 221 #include "watch.h"
46 adx 30
47     int MaxClientCount = 1;
48     int MaxConnectionCount = 1;
49     struct Callback *entering_umode_cb = NULL;
50     struct Callback *umode_cb = NULL;
51     struct Callback *uid_get_cb = NULL;
52    
53     static char umode_buffer[IRCD_BUFSIZE];
54    
55     static void user_welcome(struct Client *);
56     static void report_and_set_user_flags(struct Client *, const struct AccessItem *);
57     static int check_xline(struct Client *);
58     static int check_regexp_xline(struct Client *);
59     static void introduce_client(struct Client *, struct Client *);
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 michael 55 (Count.total-Count.invisi), Count.invisi, 1);
192 adx 30
193     if (Count.oper > 0)
194     sendto_one(source_p, form_str(RPL_LUSEROP),
195 michael 55 from, to, Count.oper);
196 adx 30
197     if (dlink_list_length(&unknown_list) > 0)
198     sendto_one(source_p, form_str(RPL_LUSERUNKNOWN),
199 michael 55 from, to, dlink_list_length(&unknown_list));
200 adx 30
201     if (dlink_list_length(&global_channel_list) > 0)
202     sendto_one(source_p, form_str(RPL_LUSERCHANNELS),
203 michael 55 from, to, dlink_list_length(&global_channel_list));
204 adx 30
205     if (!ConfigServerHide.hide_servers || IsOper(source_p))
206     {
207     sendto_one(source_p, form_str(RPL_LUSERME),
208 michael 55 from, to, Count.local, Count.myserver);
209 adx 30 sendto_one(source_p, form_str(RPL_LOCALUSERS),
210 michael 55 from, to, Count.local, Count.max_loc,
211     Count.local, Count.max_loc);
212 adx 30 }
213     else
214     {
215     sendto_one(source_p, form_str(RPL_LUSERME),
216 michael 55 from, to, Count.total, 0);
217 adx 30 sendto_one(source_p, form_str(RPL_LOCALUSERS),
218 michael 55 from, to, Count.total, Count.max_tot,
219 adx 30 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 michael 55 MaxConnectionCount, MaxClientCount, Count.totalrestartcount);
229 adx 30
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 michael 458 register_local_user(struct Client *source_p, const char *username)
274 adx 30 {
275 michael 129 struct AccessItem *aconf = NULL;
276 adx 30 char ipaddr[HOSTIPLEN];
277    
278     assert(source_p != NULL);
279     assert(MyConnect(source_p));
280     assert(source_p->username != username);
281 michael 502 assert(!source_p->localClient->registration);
282 adx 30
283     if (ConfigFileEntry.ping_cookie)
284     {
285 michael 502 if (!IsPingSent(source_p) && !source_p->localClient->random_ping)
286 adx 30 {
287     source_p->localClient->random_ping = (unsigned long)rand();
288     sendto_one(source_p, "PING :%lu",
289     source_p->localClient->random_ping);
290     SetPingSent(source_p);
291     return;
292     }
293    
294     if (!HasPingCookie(source_p))
295     return;
296     }
297    
298     source_p->localClient->last = CurrentTime;
299     /* Straight up the maximum rate of flooding... */
300     source_p->localClient->allow_read = MAX_FLOOD_BURST;
301    
302 michael 129 if (!execute_callback(client_check_cb, source_p, username, &aconf))
303 adx 30 return;
304    
305 adx 365 attach_class(source_p, aconf->class_ptr);
306    
307 adx 30 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 michael 458 source_p->name, source_p->host);
381 adx 30 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 michael 458 source_p->name, source_p->username, source_p->host);
393 adx 30 ServerStats->is_ref++;
394     ircsprintf(tmpstr2, "Invalid username [%s]", source_p->username);
395     exit_client(source_p, &me, tmpstr2);
396     return;
397     }
398    
399     /* end of valid user name check */
400     if (check_xline(source_p) || check_regexp_xline(source_p))
401     return;
402    
403     if (source_p->id[0] == '\0' && me.id[0])
404     {
405     char *id = (char *) execute_callback(uid_get_cb, source_p);
406     while (hash_find_id(id) != NULL)
407     id = uid_get(NULL);
408    
409     strlcpy(source_p->id, id, sizeof(source_p->id));
410     hash_add_id(source_p);
411     }
412    
413     irc_getnameinfo((struct sockaddr *)&source_p->localClient->ip,
414     source_p->localClient->ip.ss_len, ipaddr,
415     HOSTIPLEN, NULL, 0, NI_NUMERICHOST);
416    
417     sendto_realops_flags(UMODE_CCONN, L_ALL,
418     "Client connecting: %s (%s@%s) [%s] {%s} [%s]",
419 michael 458 source_p->name, source_p->username, source_p->host,
420 adx 30 ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
421 db 128 "255.255.255.255" : ipaddr, get_client_className(source_p),
422 adx 30 source_p->info);
423    
424     if (ConfigFileEntry.invisible_on_connect)
425 michael 158 {
426 adx 30 source_p->umodes |= UMODE_INVISIBLE;
427 michael 158 ++Count.invisi;
428     }
429 adx 30
430 michael 158 if (++Count.local > Count.max_loc)
431 adx 30 {
432     Count.max_loc = Count.local;
433    
434     if (!(Count.max_loc % 10))
435     sendto_realops_flags(UMODE_ALL, L_ALL, "New Max Local Clients: %d",
436     Count.max_loc);
437     }
438    
439     SetClient(source_p);
440    
441     source_p->servptr = &me;
442     dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
443    
444     /* Increment our total user count here */
445     if (++Count.total > Count.max_tot)
446     Count.max_tot = Count.total;
447 michael 458 ++Count.totalrestartcount;
448 adx 30
449     source_p->localClient->allow_read = MAX_FLOOD_BURST;
450    
451 michael 471 assert(dlinkFind(&unknown_list, source_p) != NULL);
452 adx 30
453 michael 471 dlinkDelete(&source_p->localClient->lclient_node, &unknown_list);
454     dlinkAdd(source_p, &source_p->localClient->lclient_node, &local_client_list);
455    
456 adx 30 user_welcome(source_p);
457     add_user_host(source_p->username, source_p->host, 0);
458     SetUserHost(source_p);
459    
460 michael 458 introduce_client(source_p, source_p);
461 adx 30 }
462    
463     /* register_remote_user()
464     *
465     * inputs - client_p directly connected client
466     * - source_p remote or directly connected client
467     * - username to register as
468     * - host name to register as
469     * - server name
470     * - realname (gecos)
471     * output - NONE
472     * side effects - This function is called when a remote client
473     * is introduced by a server.
474     */
475     void
476     register_remote_user(struct Client *client_p, struct Client *source_p,
477 michael 55 const char *username, const char *host, const char *server,
478     const char *realname)
479 adx 30 {
480 michael 55 struct Client *target_p = NULL;
481 adx 30
482     assert(source_p != NULL);
483     assert(source_p->username != username);
484    
485     strlcpy(source_p->host, host, sizeof(source_p->host));
486     strlcpy(source_p->info, realname, sizeof(source_p->info));
487     strlcpy(source_p->username, username, sizeof(source_p->username));
488    
489     /* Increment our total user count here */
490     if (++Count.total > Count.max_tot)
491     Count.max_tot = Count.total;
492    
493     source_p->from->serv->dep_users++;
494    
495     /*
496     * coming from another server, take the servers word for it
497     */
498     source_p->servptr = find_server(server);
499    
500     /* Super GhostDetect:
501     * If we can't find the server the user is supposed to be on,
502     * then simply blow the user away. -Taner
503     */
504     if (source_p->servptr == NULL)
505     {
506     sendto_realops_flags(UMODE_ALL, L_ALL,
507     "No server %s for user %s[%s@%s] from %s",
508     server, source_p->name, source_p->username,
509     source_p->host, source_p->from->name);
510     kill_client(client_p, source_p, "%s (Server doesn't exist)", me.name);
511    
512     /* XXX */
513     SetKilled(source_p);
514     exit_client(source_p, &me, "Ghosted Client");
515     return;
516     }
517    
518     if ((target_p = source_p->servptr) && target_p->from != source_p->from)
519     {
520     sendto_realops_flags(UMODE_DEBUG, L_ALL,
521     "Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
522     client_p->name, source_p->name, source_p->username,
523     source_p->host, source_p->servptr->name,
524     target_p->name, target_p->from->name);
525     kill_client(client_p, source_p,
526     "%s (NICK from wrong direction (%s != %s))",
527     me.name, source_p->servptr->name, target_p->from->name);
528     SetKilled(source_p);
529     exit_client(source_p, &me, "USER server wrong direction");
530     return;
531     }
532    
533     SetClient(source_p);
534     dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
535     add_user_host(source_p->username, source_p->host, 1);
536     SetUserHost(source_p);
537    
538     introduce_client(client_p, source_p);
539     }
540    
541     /* introduce_client()
542     *
543     * inputs - client_p
544     * - source_p
545     * output - NONE
546     * side effects - This common function introduces a client to the rest
547     * of the net, either from a local client connect or
548     * from a remote connect.
549     */
550     static void
551     introduce_client(struct Client *client_p, struct Client *source_p)
552     {
553 michael 55 dlink_node *server_node = NULL;
554 adx 30 static char ubuf[12];
555    
556     if (MyClient(source_p))
557     send_umode(source_p, source_p, 0, SEND_UMODES, ubuf);
558     else
559     send_umode(NULL, source_p, 0, SEND_UMODES, ubuf);
560    
561 michael 221 hash_check_watch(source_p, RPL_LOGON);
562    
563 adx 30 if (*ubuf == '\0')
564     {
565     ubuf[0] = '+';
566     ubuf[1] = '\0';
567     }
568    
569 michael 398 DLINK_FOREACH(server_node, serv_list.head)
570     {
571     struct Client *server = server_node->data;
572 adx 30
573 michael 398 if (server == client_p)
574     continue;
575 adx 30
576 michael 398 if (IsCapable(server, CAP_TS6) && HasID(source_p))
577     sendto_one(server, ":%s UID %s %d %lu %s %s %s %s %s :%s",
578 adx 30 source_p->servptr->id,
579     source_p->name, source_p->hopcount+1,
580 michael 398 (unsigned long)source_p->tsinfo,
581 adx 30 ubuf, source_p->username, source_p->host,
582 michael 398 ((MyClient(source_p)&&!IsIPSpoof(source_p))?source_p->sockhost:"0"),
583 adx 30 source_p->id, source_p->info);
584     else
585 michael 398 sendto_one(server, "NICK %s %d %lu %s %s %s %s :%s",
586 adx 30 source_p->name, source_p->hopcount+1,
587 michael 398 (unsigned long)source_p->tsinfo,
588 adx 30 ubuf, source_p->username, source_p->host,
589 michael 398 source_p->servptr->name,
590 adx 30 source_p->info);
591     }
592     }
593    
594     /* valid_hostname()
595     *
596     * Inputs - pointer to hostname
597     * Output - 1 if valid, 0 if not
598     * Side effects - check hostname for validity
599     *
600     * NOTE: this doesn't allow a hostname to begin with a dot and
601     * will not allow more dots than chars.
602     */
603     int
604     valid_hostname(const char *hostname)
605     {
606     const char *p = hostname;
607    
608     assert(p != NULL);
609    
610 michael 55 if ('.' == *p || ':' == *p)
611     return 0;
612 adx 30
613     while (*p)
614     {
615     if (!IsHostChar(*p))
616 michael 55 return 0;
617 adx 30 p++;
618     }
619    
620 michael 55 return 1;
621 adx 30 }
622    
623     /* valid_username()
624     *
625     * Inputs - pointer to user
626     * Output - 1 if valid, 0 if not
627     * Side effects - check username for validity
628     *
629     * Absolutely always reject any '*' '!' '?' '@' in an user name
630     * reject any odd control characters names.
631     * Allow '.' in username to allow for "first.last"
632     * style of username
633     */
634     int
635     valid_username(const char *username)
636     {
637     int dots = 0;
638     const char *p = username;
639    
640     assert(p != NULL);
641    
642     if ('~' == *p)
643     ++p;
644    
645     /* reject usernames that don't start with an alphanum
646     * i.e. reject jokers who have '-@somehost' or '.@somehost'
647     * or "-hi-@somehost", "h-----@somehost" would still be accepted.
648     */
649     if (!IsAlNum(*p))
650 michael 55 return 0;
651 adx 30
652     while (*++p)
653     {
654     if ((*p == '.') && ConfigFileEntry.dots_in_ident)
655     {
656     dots++;
657    
658     if (dots > ConfigFileEntry.dots_in_ident)
659 michael 55 return 0;
660 adx 30 if (!IsUserChar(p[1]))
661 michael 55 return 0;
662 adx 30 }
663     else if (!IsUserChar(*p))
664 michael 55 return 0;
665 adx 30 }
666    
667 michael 55 return 1;
668 adx 30 }
669    
670     /* report_and_set_user_flags()
671     *
672     * inputs - pointer to source_p
673     * - pointer to aconf for this user
674     * output - NONE
675     * side effects - Report to user any special flags
676     * they are getting, and set them.
677     */
678     static void
679     report_and_set_user_flags(struct Client *source_p, const struct AccessItem *aconf)
680     {
681     /* If this user is being spoofed, tell them so */
682     if (IsConfDoSpoofIp(aconf))
683     {
684     sendto_one(source_p,
685     ":%s NOTICE %s :*** Spoofing your IP. congrats.",
686     me.name, source_p->name);
687     }
688    
689     /* If this user is in the exception class, Set it "E lined" */
690     if (IsConfExemptKline(aconf))
691     {
692     SetExemptKline(source_p);
693     sendto_one(source_p,
694     ":%s NOTICE %s :*** You are exempt from K/D/G lines. congrats.",
695     me.name, source_p->name);
696     }
697    
698     /* The else here is to make sure that G line exempt users
699     * do not get noticed twice.
700     */
701     else if (IsConfExemptGline(aconf))
702     {
703     SetExemptGline(source_p);
704     sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from G lines.",
705     me.name, source_p->name);
706     }
707    
708     if (IsConfExemptResv(aconf))
709     {
710     SetExemptResv(source_p);
711     sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from resvs.",
712     me.name, source_p->name);
713     }
714    
715     /* If this user is exempt from user limits set it "F lined" */
716     if (IsConfExemptLimits(aconf))
717     {
718     SetExemptLimits(source_p);
719     sendto_one(source_p,
720     ":%s NOTICE %s :*** You are exempt from user limits. congrats.",
721     me.name,source_p->name);
722     }
723    
724     /* If this user is exempt from idle time outs */
725     if (IsConfIdlelined(aconf))
726     {
727     SetIdlelined(source_p);
728     sendto_one(source_p,
729     ":%s NOTICE %s :*** You are exempt from idle limits. congrats.",
730     me.name, source_p->name);
731     }
732    
733     if (IsConfCanFlood(aconf))
734     {
735     SetCanFlood(source_p);
736     sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from flood "
737     "protection, aren't you fearsome.",
738     me.name, source_p->name);
739     }
740     }
741    
742     /* change_simple_umode()
743     *
744     * this callback can be hooked to allow special handling of
745     * certain usermodes
746     */
747 adx 211 void *
748 adx 30 change_simple_umode(va_list args)
749     {
750     struct Client *source_p;
751     int what;
752     unsigned int flag;
753    
754     va_arg(args, struct Client *);
755     source_p = va_arg(args, struct Client *);
756     what = va_arg(args, int);
757     flag = va_arg(args, unsigned int);
758    
759     if (what == MODE_ADD)
760     source_p->umodes |= flag;
761     else
762     source_p->umodes &= ~flag;
763    
764     return NULL;
765     }
766    
767     /* set_user_mode()
768     *
769     * added 15/10/91 By Darren Reed.
770     * parv[0] - sender
771     * parv[1] - username to change mode for
772     * parv[2] - modes to change
773     */
774     void
775     set_user_mode(struct Client *client_p, struct Client *source_p,
776     int parc, char *parv[])
777     {
778     unsigned int flag, setflags;
779     char **p, *m, buf[IRCD_BUFSIZE];
780     struct Client *target_p;
781     int what = MODE_ADD, badflag = 0, i;
782 michael 55
783     assert(!(parc < 2));
784    
785 adx 30 if ((target_p = find_person(client_p, parv[1])) == NULL)
786     {
787     if (MyConnect(source_p))
788     sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
789     me.name, source_p->name, parv[1]);
790     return;
791     }
792    
793     if (IsServer(source_p))
794     {
795     sendto_realops_flags(UMODE_ALL, L_ADMIN, "*** Mode for User %s from %s",
796     parv[1], source_p->name);
797     return;
798     }
799    
800     if (source_p != target_p || target_p->from != source_p->from)
801     {
802     sendto_one(source_p, form_str(ERR_USERSDONTMATCH),
803     me.name, source_p->name);
804     return;
805     }
806    
807     if (parc < 3)
808     {
809     m = buf;
810     *m++ = '+';
811    
812     for (i = 0; i < 128; i++)
813     if (source_p->umodes & user_modes[i])
814     *m++ = (char)i;
815     *m = '\0';
816    
817     sendto_one(source_p, form_str(RPL_UMODEIS),
818     me.name, source_p->name, buf);
819     return;
820     }
821    
822     execute_callback(entering_umode_cb, client_p, source_p);
823    
824     /* find flags already set for user */
825     setflags = source_p->umodes;
826    
827     /* parse mode change string(s) */
828     for (p = &parv[2]; p && *p; p++)
829     {
830     for (m = *p; *m; m++)
831     {
832     switch (*m)
833     {
834     case '+':
835     what = MODE_ADD;
836     break;
837     case '-':
838     what = MODE_DEL;
839     break;
840     case 'o':
841     if (what == MODE_ADD)
842     {
843     if (IsServer(client_p) && !IsOper(source_p))
844     {
845     ++Count.oper;
846     SetOper(source_p);
847     }
848     }
849     else
850     {
851     /* Only decrement the oper counts if an oper to begin with
852     * found by Pat Szuta, Perly , perly@xnet.com
853     */
854     if (!IsOper(source_p))
855     break;
856    
857     ClearOper(source_p);
858     source_p->umodes &= ~ConfigFileEntry.oper_only_umodes;
859     Count.oper--;
860    
861     if (MyConnect(source_p))
862     {
863     dlink_node *dm;
864    
865     ClearOperFlags(source_p);
866    
867     if ((dm = dlinkFindDelete(&oper_list, source_p)) != NULL)
868     free_dlink_node(dm);
869     }
870     }
871    
872     break;
873    
874     /* we may not get these,
875     * but they shouldnt be in default
876     */
877     case ' ' :
878     case '\n':
879     case '\r':
880     case '\t':
881     break;
882    
883     default:
884     if ((flag = user_modes[(unsigned char)*m]))
885     {
886     if (MyConnect(source_p) && !IsOper(source_p) &&
887     (ConfigFileEntry.oper_only_umodes & flag))
888     {
889     badflag = 1;
890     }
891     else
892 michael 55 execute_callback(umode_cb, client_p, source_p, what, flag);
893 adx 30 }
894     else
895     {
896     if (MyConnect(source_p))
897     badflag = 1;
898     }
899    
900     break;
901     }
902     }
903     }
904    
905     if (badflag)
906     sendto_one(source_p, form_str(ERR_UMODEUNKNOWNFLAG),
907     me.name, source_p->name);
908    
909     if ((source_p->umodes & UMODE_NCHANGE) && !IsOperN(source_p))
910     {
911     sendto_one(source_p, ":%s NOTICE %s :*** You have no admin flag;",
912     me.name, source_p->name);
913     source_p->umodes &= ~UMODE_NCHANGE; /* only tcm's really need this */
914     }
915    
916     if (MyConnect(source_p) && (source_p->umodes & UMODE_ADMIN) &&
917     !IsOperAdmin(source_p) && !IsOperHiddenAdmin(source_p))
918     {
919     sendto_one(source_p, ":%s NOTICE %s :*** You have no admin flag;",
920     me.name, source_p->name);
921     source_p->umodes &= ~UMODE_ADMIN;
922     }
923    
924     if (!(setflags & UMODE_INVISIBLE) && IsInvisible(source_p))
925     ++Count.invisi;
926     if ((setflags & UMODE_INVISIBLE) && !IsInvisible(source_p))
927     --Count.invisi;
928    
929 michael 55 /*
930     * compare new flags with old flags and send string which
931 adx 30 * will cause servers to update correctly.
932     */
933     send_umode_out(client_p, source_p, setflags);
934     }
935    
936     /* send_umode()
937     * send the MODE string for user (user) to connection client_p
938     * -avalon
939     */
940     void
941     send_umode(struct Client *client_p, struct Client *source_p,
942     unsigned int old, unsigned int sendmask, char *umode_buf)
943     {
944     int what = 0;
945     unsigned int i;
946     unsigned int flag;
947     char *m = umode_buf;
948    
949 michael 55 /*
950     * build a string in umode_buf to represent the change in the user's
951 adx 30 * mode between the new (source_p->umodes) and 'old'.
952     */
953     for (i = 0; i < 128; i++)
954     {
955     flag = user_modes[i];
956     if (!flag)
957     continue;
958    
959     if (MyClient(source_p) && !(flag & sendmask))
960     continue;
961    
962     if ((flag & old) && !(source_p->umodes & flag))
963     {
964     if (what == MODE_DEL)
965     *m++ = (char)i;
966     else
967     {
968     what = MODE_DEL;
969     *m++ = '-';
970     *m++ = (char)i;
971     }
972     }
973     else if (!(flag & old) && (source_p->umodes & flag))
974     {
975     if (what == MODE_ADD)
976     *m++ = (char)i;
977     else
978     {
979     what = MODE_ADD;
980     *m++ = '+';
981     *m++ = (char)i;
982     }
983     }
984     }
985    
986     *m = '\0';
987    
988     if (*umode_buf && client_p)
989     sendto_one(client_p, ":%s MODE %s :%s",
990     source_p->name, source_p->name, umode_buf);
991     }
992    
993     /* send_umode_out()
994     *
995     * inputs -
996     * output - NONE
997     * side effects - Only send ubuf out to servers that know about this client
998     */
999     void
1000     send_umode_out(struct Client *client_p, struct Client *source_p,
1001     unsigned int old)
1002     {
1003 michael 398 char buf[IRCD_BUFSIZE] = { '\0' };
1004 adx 30 dlink_node *ptr = NULL;
1005    
1006     send_umode(NULL, source_p, old, IsOperHiddenAdmin(source_p) ?
1007     SEND_UMODES & ~UMODE_ADMIN : SEND_UMODES, buf);
1008    
1009 michael 398 if (buf[0] != '\0')
1010 adx 30 {
1011     DLINK_FOREACH(ptr, serv_list.head)
1012     {
1013     struct Client *target_p = ptr->data;
1014    
1015     if ((target_p != client_p) && (target_p != source_p))
1016 michael 398 sendto_one(target_p, ":%s MODE %s :%s",
1017     ID_or_name(source_p, target_p),
1018     ID_or_name(source_p, target_p), buf);
1019 adx 30 }
1020     }
1021    
1022     if (client_p && MyClient(client_p))
1023     send_umode(client_p, source_p, old, 0xffffffff, buf);
1024     }
1025    
1026     /* user_welcome()
1027     *
1028     * inputs - client pointer to client to welcome
1029     * output - NONE
1030     * side effects -
1031     */
1032     static void
1033     user_welcome(struct Client *source_p)
1034     {
1035     #if defined(__TIME__) && defined(__DATE__)
1036     static const char built_date[] = __DATE__ " at " __TIME__;
1037     #else
1038     static const char built_date[] = "unknown";
1039     #endif
1040    
1041     #ifdef HAVE_LIBCRYPTO
1042     if (source_p->localClient->fd.ssl != NULL)
1043     sendto_one(source_p, ":%s NOTICE %s :*** Connected securely via %s",
1044     me.name, source_p->name,
1045     ssl_get_cipher(source_p->localClient->fd.ssl));
1046     #endif
1047    
1048     sendto_one(source_p, form_str(RPL_WELCOME), me.name, source_p->name,
1049     ServerInfo.network_name, source_p->name);
1050     sendto_one(source_p, form_str(RPL_YOURHOST), me.name, source_p->name,
1051 michael 55 get_listener_name(source_p->localClient->listener), ircd_version);
1052 adx 30 sendto_one(source_p, form_str(RPL_CREATED),
1053 michael 55 me.name, source_p->name, built_date);
1054 adx 30 sendto_one(source_p, form_str(RPL_MYINFO),
1055     me.name, source_p->name, me.name, ircd_version, umode_buffer);
1056     show_isupport(source_p);
1057    
1058     if (source_p->id[0] != '\0')
1059     sendto_one(source_p, form_str(RPL_YOURID), me.name,
1060     source_p->name, source_p->id);
1061    
1062     show_lusers(source_p);
1063    
1064     if (ConfigFileEntry.short_motd)
1065     {
1066     sendto_one(source_p, "NOTICE %s :*** Notice -- motd was last changed at %s",
1067     source_p->name, ConfigFileEntry.motd.lastChangedDate);
1068     sendto_one(source_p,
1069     "NOTICE %s :*** Notice -- Please read the motd if you haven't "
1070     "read it", source_p->name);
1071     sendto_one(source_p, form_str(RPL_MOTDSTART),
1072     me.name, source_p->name, me.name);
1073     sendto_one(source_p, form_str(RPL_MOTD),
1074     me.name, source_p->name,
1075     "*** This is the short motd ***");
1076     sendto_one(source_p, form_str(RPL_ENDOFMOTD),
1077     me.name, source_p->name);
1078     }
1079     else
1080     send_message_file(source_p, &ConfigFileEntry.motd);
1081     }
1082    
1083     /* check_xline()
1084     *
1085     * inputs - pointer to client to test
1086     * outupt - 1 if exiting 0 if ok
1087     * side effects -
1088     */
1089     static int
1090     check_xline(struct Client *source_p)
1091     {
1092     struct ConfItem *conf;
1093     struct MatchItem *xconf;
1094     const char *reason;
1095    
1096     if ((conf = find_matching_name_conf(XLINE_TYPE, source_p->info,
1097     NULL, NULL, 0)) != NULL)
1098     {
1099 db 139 xconf = &conf->conf.MatchItem;
1100 adx 30 xconf->count++;
1101    
1102     if (xconf->reason != NULL)
1103     reason = xconf->reason;
1104     else
1105     reason = "No Reason";
1106    
1107     sendto_realops_flags(UMODE_REJ, L_ALL,
1108 michael 55 "X-line Rejecting [%s] [%s], user %s [%s]",
1109     source_p->info, reason,
1110     get_client_name(source_p, HIDE_IP),
1111     source_p->sockhost);
1112 adx 30
1113     ServerStats->is_ref++;
1114 michael 55 if (REJECT_HOLD_TIME > 0)
1115 adx 30 {
1116     sendto_one(source_p, ":%s NOTICE %s :Bad user info",
1117 michael 55 me.name, source_p->name);
1118 adx 30 source_p->localClient->reject_delay = CurrentTime + REJECT_HOLD_TIME;
1119     SetCaptured(source_p);
1120     }
1121     else
1122     exit_client(source_p, &me, "Bad user info");
1123     return 1;
1124     }
1125    
1126     return 0;
1127     }
1128    
1129     static int
1130     check_regexp_xline(struct Client *source_p)
1131     {
1132     struct ConfItem *conf = NULL;
1133     const char *reason = NULL;
1134    
1135     if ((conf = find_matching_name_conf(RXLINE_TYPE, source_p->info, NULL, NULL, 0)))
1136     {
1137 db 139 struct MatchItem *reg = &conf->conf.MatchItem;
1138 adx 30
1139     ++reg->count;
1140    
1141     if (reg->reason != NULL)
1142     reason = reg->reason;
1143     else
1144     reason = "No Reason";
1145    
1146     sendto_realops_flags(UMODE_REJ, L_ALL,
1147     "X-line (REGEX) Rejecting [%s] [%s], user %s [%s]",
1148     source_p->info, reason,
1149     get_client_name(source_p, HIDE_IP),
1150     source_p->sockhost);
1151    
1152     ServerStats->is_ref++;
1153     exit_client(source_p, &me, "Bad user info");
1154     return 1;
1155     }
1156    
1157     return 0;
1158     }
1159    
1160     /* oper_up()
1161     *
1162     * inputs - pointer to given client to oper
1163 db 101 * - pointer to oper conf found
1164 adx 30 * output - NONE
1165 db 128 * side effects - Blindly opers up given source_p, using conf info
1166 adx 30 * all checks on passwords have already been done.
1167 db 128 * This is also used by rsa oper routines.
1168 adx 30 */
1169     void
1170 db 101 oper_up(struct Client *source_p, struct ConfItem *conf)
1171 adx 30 {
1172     unsigned int old = source_p->umodes;
1173     const char *operprivs = "";
1174 db 128 struct AccessItem *aconf;
1175 adx 30
1176 db 139 aconf = &conf->conf.AccessItem;
1177 michael 55 ++Count.oper;
1178 adx 30 SetOper(source_p);
1179    
1180 db 128 if (aconf->modes)
1181     source_p->umodes |= aconf->modes;
1182 michael 55 else if (ConfigFileEntry.oper_umodes)
1183 adx 30 source_p->umodes |= ConfigFileEntry.oper_umodes;
1184     else
1185     source_p->umodes |= (UMODE_SERVNOTICE|UMODE_OPERWALL|
1186 michael 55 UMODE_WALLOP|UMODE_LOCOPS);
1187 adx 30
1188     assert(dlinkFind(&oper_list, source_p) == NULL);
1189     dlinkAdd(source_p, make_dlink_node(), &oper_list);
1190    
1191 db 128 operprivs = oper_privs_as_string(aconf->port);
1192     SetOFlag(source_p, aconf->port);
1193 adx 30
1194     if (IsOperAdmin(source_p) || IsOperHiddenAdmin(source_p))
1195     source_p->umodes |= UMODE_ADMIN;
1196     if (!IsOperN(source_p))
1197     source_p->umodes &= ~UMODE_NCHANGE;
1198 michael 129 MyFree(source_p->localClient->auth_oper);
1199     DupString(source_p->localClient->auth_oper, conf->name);
1200 adx 30 sendto_realops_flags(UMODE_ALL, L_ALL, "%s (%s@%s) is now an operator",
1201     source_p->name, source_p->username, source_p->host);
1202     send_umode_out(source_p, source_p, old);
1203     sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
1204     sendto_one(source_p, ":%s NOTICE %s :*** Oper privs are %s",
1205     me.name, source_p->name, operprivs);
1206     send_message_file(source_p, &ConfigFileEntry.opermotd);
1207     }
1208    
1209     /*
1210 db 101 * UID code for TS6 SID code on EFnet
1211 adx 30 *
1212     */
1213    
1214 adx 211 char new_uid[TOTALSIDUID + 1] = {0};
1215    
1216 adx 30 static void add_one_to_uid(int i);
1217    
1218     /*
1219     * init_uid()
1220     *
1221     * inputs - NONE
1222     * output - NONE
1223     * side effects - new_uid is filled in with server id portion (sid)
1224     * (first 3 bytes) or defaulted to 'A'.
1225 db 128 * Rest is filled in with 'A' except for the last byte
1226     * which is filled in with '@'
1227 adx 30 */
1228     void
1229     init_uid(void)
1230     {
1231     int i;
1232    
1233     if (ServerInfo.sid != NULL)
1234     {
1235 adx 211 memcpy(new_uid, ServerInfo.sid, IRC_MAXSID);
1236     memcpy(&me.id, ServerInfo.sid, IRC_MAXSID);
1237 adx 30 hash_add_id(&me);
1238     }
1239    
1240     for (i = 0; i < IRC_MAXSID; i++)
1241     if (new_uid[i] == '\0')
1242     new_uid[i] = 'A';
1243    
1244     /* XXX if IRC_MAXUID != 6, this will have to be rewritten */
1245     /* Yes nenolod, I have known it was off by one ever since I wrote it
1246     * But *JUST* for you, though, it really doesn't look as *pretty*
1247     * -Dianora
1248     */
1249     memcpy(new_uid+IRC_MAXSID, "AAAAA@", IRC_MAXUID);
1250     }
1251    
1252     /*
1253     * uid_get
1254     *
1255     * inputs - struct Client *
1256     * output - new UID is returned to caller
1257     * side effects - new_uid is incremented by one.
1258     */
1259 adx 211 void *
1260 adx 30 uid_get(va_list args)
1261     {
1262 michael 55 add_one_to_uid(TOTALSIDUID-1); /* index from 0 */
1263 adx 30 return ((void *) new_uid);
1264     }
1265    
1266     /*
1267     * add_one_to_uid
1268     *
1269     * inputs - index number into new_uid
1270     * output - NONE
1271     * side effects - new_uid is incremented by one
1272     * note this is a recursive function
1273     */
1274     static void
1275     add_one_to_uid(int i)
1276     {
1277 michael 55 if (i != IRC_MAXSID) /* Not reached server SID portion yet? */
1278 adx 30 {
1279     if (new_uid[i] == 'Z')
1280     new_uid[i] = '0';
1281     else if (new_uid[i] == '9')
1282     {
1283     new_uid[i] = 'A';
1284     add_one_to_uid(i-1);
1285     }
1286     else new_uid[i] = new_uid[i] + 1;
1287     }
1288     else
1289     {
1290     /* XXX if IRC_MAXUID != 6, this will have to be rewritten */
1291     if (new_uid[i] == 'Z')
1292     memcpy(new_uid+IRC_MAXSID, "AAAAAA", IRC_MAXUID);
1293     else
1294     new_uid[i] = new_uid[i] + 1;
1295     }
1296     }
1297    
1298     /*
1299     * init_isupport()
1300     *
1301     * input - NONE
1302     * output - NONE
1303     * side effects - Must be called before isupport is enabled
1304     */
1305     void
1306     init_isupport(void)
1307     {
1308     isupportFile = init_MessageLine();
1309    
1310     add_isupport("CALLERID", NULL, -1);
1311     add_isupport("CASEMAPPING", CASEMAP, -1);
1312     add_isupport("KICKLEN", NULL, KICKLEN);
1313     add_isupport("MODES", NULL, MAXMODEPARAMS);
1314     add_isupport("NICKLEN", NULL, NICKLEN-1);
1315     #ifdef HALFOPS
1316     add_isupport("PREFIX", "(ohv)@%+", -1);
1317     add_isupport("STATUSMSG", "@%+", -1);
1318     #else
1319     add_isupport("PREFIX", "(ov)@+", -1);
1320     add_isupport("STATUSMSG", "@+", -1);
1321     #endif
1322     add_isupport("TOPICLEN", NULL, TOPICLEN);
1323     }
1324    
1325     /*
1326     * add_isupport()
1327     *
1328     * input - name of supported function
1329     * - options if any
1330     * - number if any
1331     * output - NONE
1332     * side effects - Each supported item must call this when activated
1333     */
1334     void
1335     add_isupport(const char *name, const char *options, int n)
1336     {
1337     dlink_node *ptr;
1338     struct Isupport *support;
1339    
1340     DLINK_FOREACH(ptr, support_list.head)
1341     {
1342     support = ptr->data;
1343     if (irccmp(support->name, name) == 0)
1344     {
1345     MyFree(support->name);
1346     MyFree(support->options);
1347     break;
1348     }
1349     }
1350    
1351     if (ptr == NULL)
1352     {
1353     support = MyMalloc(sizeof(*support));
1354     dlinkAddTail(support, &support->node, &support_list);
1355     }
1356    
1357     DupString(support->name, name);
1358     if (options != NULL)
1359     DupString(support->options, options);
1360     support->number = n;
1361    
1362     rebuild_isupport_message_line();
1363     }
1364    
1365     /*
1366     * delete_isupport()
1367     *
1368     * input - name of supported function
1369     * output - NONE
1370     * side effects - Each supported item must call this when deactivated
1371     */
1372     void
1373     delete_isupport(const char *name)
1374     {
1375     dlink_node *ptr;
1376     struct Isupport *support;
1377    
1378     DLINK_FOREACH(ptr, support_list.head)
1379     {
1380     support = ptr->data;
1381     if (irccmp(support->name, name) == 0)
1382     {
1383     dlinkDelete(ptr, &support_list);
1384     MyFree(support->name);
1385     MyFree(support->options);
1386     MyFree(support);
1387     break;
1388     }
1389     }
1390    
1391     rebuild_isupport_message_line();
1392     }
1393    
1394     /*
1395     * rebuild_isupport_message_line
1396     *
1397     * input - NONE
1398     * output - NONE
1399     * side effects - Destroy the isupport MessageFile lines, and rebuild.
1400     */
1401     void
1402     rebuild_isupport_message_line(void)
1403     {
1404     char isupportbuffer[IRCD_BUFSIZE];
1405     char *p = isupportbuffer;
1406     dlink_node *ptr = NULL;
1407     int n = 0;
1408     int tokens = 0;
1409     size_t len = 0;
1410     size_t reserve = strlen(me.name) + HOSTLEN + strlen(form_str(RPL_ISUPPORT));
1411    
1412     destroy_MessageLine(isupportFile);
1413    
1414     DLINK_FOREACH(ptr, support_list.head)
1415     {
1416     struct Isupport *support = ptr->data;
1417    
1418     p += (n = ircsprintf(p, "%s", support->name));
1419     len += n;
1420    
1421     if (support->options != NULL)
1422     {
1423     p += (n = ircsprintf(p, "=%s", support->options));
1424     len += n;
1425     }
1426    
1427     if (support->number > 0)
1428     {
1429     p += (n = ircsprintf(p, "=%d", support->number));
1430     len += n;
1431     }
1432    
1433     *p++ = ' ';
1434     len++;
1435     *p = '\0';
1436    
1437     if (++tokens == (MAXPARA-2) || len >= (sizeof(isupportbuffer)-reserve))
1438     { /* arbritrary for now */
1439     if (*--p == ' ')
1440 michael 55 *p = '\0';
1441 adx 30
1442     addto_MessageLine(isupportFile, isupportbuffer);
1443     p = isupportbuffer;
1444     len = 0;
1445     n = tokens = 0;
1446     }
1447     }
1448    
1449     if (len != 0)
1450     {
1451     if (*--p == ' ')
1452     *p = '\0';
1453     addto_MessageLine(isupportFile, isupportbuffer);
1454     }
1455     }

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28