/[svn]/branches/newio/src/s_user.c
ViewVC logotype

Contents of /branches/newio/src/s_user.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2415 - (show annotations)
Sun Jul 21 14:33:22 2013 UTC (6 years, 11 months ago) by michael
File MIME type: text/x-chdr
File size: 40769 byte(s)
- ioengine changes as of 21JUL13

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

Properties

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

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