Author: Isomer <Isomer@coders.net>
[ircu2.10.12-pk.git] / ircd / s_user.c
1 /*
2  * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 1, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  */
25 #include "config.h"
26
27 #include "s_user.h"
28 #include "IPcheck.h"
29 #include "channel.h"
30 #include "class.h"
31 #include "client.h"
32 #include "hash.h"
33 #include "ircd.h"
34 #include "ircd_alloc.h"
35 #include "ircd_chattr.h"
36 #include "ircd_features.h"
37 #include "ircd_log.h"
38 #include "ircd_policy.h"
39 #include "ircd_reply.h"
40 #include "ircd_snprintf.h"
41 #include "ircd_string.h"
42 #include "list.h"
43 #include "match.h"
44 #include "motd.h"
45 #include "msg.h"
46 #include "msgq.h"
47 #include "numeric.h"
48 #include "numnicks.h"
49 #include "parse.h"
50 #include "querycmds.h"
51 #include "random.h"
52 #include "s_bsd.h"
53 #include "s_conf.h"
54 #include "s_debug.h"
55 #include "s_misc.h"
56 #include "s_serv.h" /* max_client_count */
57 #include "send.h"
58 #include "struct.h"
59 #include "support.h"
60 #include "supported.h"
61 #include "sys.h"
62 #include "userload.h"
63 #include "version.h"
64 #include "whowas.h"
65
66 #include "handlers.h" /* m_motd and m_lusers */
67
68 #include <assert.h>
69 #include <fcntl.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <sys/stat.h>
74
75
76 static int userCount = 0;
77
78 /*
79  * 'make_user' add's an User information block to a client
80  * if it was not previously allocated.
81  */
82 struct User *make_user(struct Client *cptr)
83 {
84   assert(0 != cptr);
85
86   if (!cli_user(cptr)) {
87     cli_user(cptr) = (struct User*) MyMalloc(sizeof(struct User));
88     assert(0 != cli_user(cptr));
89
90     /* All variables are 0 by default */
91     memset(cli_user(cptr), 0, sizeof(struct User));
92 #ifdef  DEBUGMODE
93     ++userCount;
94 #endif
95     cli_user(cptr)->refcnt = 1;
96   }
97   return cli_user(cptr);
98 }
99
100 /*
101  * free_user
102  *
103  * Decrease user reference count by one and release block, if count reaches 0.
104  */
105 void free_user(struct User* user)
106 {
107   assert(0 != user);
108   assert(0 < user->refcnt);
109
110   if (--user->refcnt == 0) {
111     if (user->away)
112       MyFree(user->away);
113     /*
114      * sanity check
115      */
116     assert(0 == user->joined);
117     assert(0 == user->invited);
118     assert(0 == user->channel);
119
120     MyFree(user);
121 #ifdef  DEBUGMODE
122     --userCount;
123 #endif
124   }
125 }
126
127 void user_count_memory(size_t* count_out, size_t* bytes_out)
128 {
129   assert(0 != count_out);
130   assert(0 != bytes_out);
131   *count_out = userCount;
132   *bytes_out = userCount * sizeof(struct User);
133 }
134
135
136 /*
137  * next_client
138  *
139  * Local function to find the next matching client. The search
140  * can be continued from the specified client entry. Normal
141  * usage loop is:
142  *
143  * for (x = client; x = next_client(x,mask); x = x->next)
144  *     HandleMatchingClient;
145  *
146  */
147 struct Client *next_client(struct Client *next, const char* ch)
148 {
149   struct Client *tmp = next;
150
151   if (!tmp)
152     return NULL;
153
154   next = FindClient(ch);
155   next = next ? next : tmp;
156   if (cli_prev(tmp) == next)
157     return NULL;
158   if (next != tmp)
159     return next;
160   for (; next; next = cli_next(next))
161     if (!match(ch, cli_name(next)))
162       break;
163   return next;
164 }
165
166 /*
167  * hunt_server
168  *
169  *    Do the basic thing in delivering the message (command)
170  *    across the relays to the specific server (server) for
171  *    actions.
172  *
173  *    Note:   The command is a format string and *MUST* be
174  *            of prefixed style (e.g. ":%s COMMAND %s ...").
175  *            Command can have only max 8 parameters.
176  *
177  *    server  parv[server] is the parameter identifying the
178  *            target server.
179  *
180  *    *WARNING*
181  *            parv[server] is replaced with the pointer to the
182  *            real servername from the matched client (I'm lazy
183  *            now --msa).
184  *
185  *    returns: (see #defines)
186  */
187 int hunt_server_cmd(struct Client *from, const char *cmd, const char *tok,
188                     struct Client *one, int MustBeOper, const char *pattern,
189                     int server, int parc, char *parv[])
190 {
191   struct Client *acptr;
192   char *to;
193
194   /* Assume it's me, if no server or an unregistered client */
195   if (parc <= server || EmptyString((to = parv[server])) || IsUnknown(from))
196     return (HUNTED_ISME);
197
198   if (MustBeOper && !IsPrivileged(from))
199   {
200     send_reply(from, ERR_NOPRIVILEGES);
201     return HUNTED_NOSUCH;
202   }
203
204   /* Make sure it's a server */
205   if (MyUser(from)) {
206     /* Make sure it's a server */
207     if (!strchr(to, '*')) {
208       if (0 == (acptr = FindClient(to)))
209         return HUNTED_NOSUCH;
210
211       if (cli_user(acptr))
212         acptr = cli_user(acptr)->server;
213     } else if (!(acptr = find_match_server(to))) {
214       send_reply(from, ERR_NOSUCHSERVER, to);
215       return (HUNTED_NOSUCH);
216     }
217   } else if (!(acptr = FindNServer(to)))
218     return (HUNTED_NOSUCH);        /* Server broke off in the meantime */
219
220   if (IsMe(acptr))
221     return (HUNTED_ISME);
222
223   if (MustBeOper && !IsPrivileged(from)) {
224     send_reply(from, ERR_NOPRIVILEGES);
225     return HUNTED_NOSUCH;
226   }
227
228   assert(!IsServer(from));
229
230   parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */
231
232   sendcmdto_one(from, cmd, tok, acptr, pattern, parv[1], parv[2], parv[3],
233                 parv[4], parv[5], parv[6], parv[7], parv[8]);
234
235   return (HUNTED_PASS);
236 }
237
238 int hunt_server_prio_cmd(struct Client *from, const char *cmd, const char *tok,
239                          struct Client *one, int MustBeOper,
240                          const char *pattern, int server, int parc,
241                          char *parv[])
242 {
243   struct Client *acptr;
244   char *to;
245
246   /* Assume it's me, if no server or an unregistered client */
247   if (parc <= server || EmptyString((to = parv[server])) || IsUnknown(from))
248     return (HUNTED_ISME);
249
250   /* Make sure it's a server */
251   if (MyUser(from)) {
252     /* Make sure it's a server */
253     if (!strchr(to, '*')) {
254       if (0 == (acptr = FindClient(to)))
255         return HUNTED_NOSUCH;
256
257       if (cli_user(acptr))
258         acptr = cli_user(acptr)->server;
259     } else if (!(acptr = find_match_server(to))) {
260       send_reply(from, ERR_NOSUCHSERVER, to);
261       return (HUNTED_NOSUCH);
262     }
263   } else if (!(acptr = FindNServer(to)))
264     return (HUNTED_NOSUCH);        /* Server broke off in the meantime */
265
266   if (IsMe(acptr))
267     return (HUNTED_ISME);
268
269   if (MustBeOper && !IsPrivileged(from)) {
270     send_reply(from, ERR_NOPRIVILEGES);
271     return HUNTED_NOSUCH;
272   }
273
274   assert(!IsServer(from));
275
276   parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */
277
278   sendcmdto_prio_one(from, cmd, tok, acptr, pattern, parv[1], parv[2], parv[3],
279                      parv[4], parv[5], parv[6], parv[7], parv[8]);
280
281   return (HUNTED_PASS);
282 }
283
284 /*
285  * 'do_nick_name' ensures that the given parameter (nick) is really a proper
286  * string for a nickname (note, the 'nick' may be modified in the process...)
287  *
288  * RETURNS the length of the final NICKNAME (0, if nickname is invalid)
289  *
290  * Nickname characters are in range 'A'..'}', '_', '-', '0'..'9'
291  *  anything outside the above set will terminate nickname.
292  * In addition, the first character cannot be '-' or a Digit.
293  *
294  * Note:
295  *  The '~'-character should be allowed, but a change should be global,
296  *  some confusion would result if only few servers allowed it...
297  */
298 int do_nick_name(char* nick)
299 {
300   char* ch  = nick;
301   char* end = ch + NICKLEN;
302   assert(0 != ch);
303
304   if (*ch == '-' || IsDigit(*ch))        /* first character in [0..9-] */
305     return 0;
306
307   for ( ; (ch < end) && *ch; ++ch)
308     if (!IsNickChar(*ch))
309       break;
310
311   *ch = '\0';
312
313   return (ch - nick);
314 }
315
316 /*
317  * clean_user_id
318  *
319  * Copy `source' to `dest', replacing all occurances of '~' and characters that
320  * are not `isIrcUi' by an underscore.
321  * Copies at most USERLEN - 1 characters or up till the first control character.
322  * If `tilde' is true, then a tilde is prepended to `dest'.
323  * Note that `dest' and `source' can point to the same area or to different
324  * non-overlapping areas.
325  */
326 static char *clean_user_id(char *dest, char *source, int tilde)
327 {
328   char ch;
329   char *d = dest;
330   char *s = source;
331   int rlen = USERLEN;
332
333   ch = *s++;                        /* Store first character to copy: */
334   if (tilde)
335   {
336     *d++ = '~';                        /* If `dest' == `source', then this overwrites `ch' */
337     --rlen;
338   }
339   while (ch && !IsCntrl(ch) && rlen--)
340   {
341     char nch = *s++;        /* Store next character to copy */
342     *d++ = IsUserChar(ch) ? ch : '_';        /* This possibly overwrites it */
343     if (nch == '~')
344       ch = '_';
345     else
346       ch = nch;
347   }
348   *d = 0;
349   return dest;
350 }
351
352 /*
353  * register_user
354  *
355  * This function is called when both NICK and USER messages
356  * have been accepted for the client, in whatever order. Only
357  * after this the USER message is propagated.
358  *
359  * NICK's must be propagated at once when received, although
360  * it would be better to delay them too until full info is
361  * available. Doing it is not so simple though, would have
362  * to implement the following:
363  *
364  * 1) user telnets in and gives only "NICK foobar" and waits
365  * 2) another user far away logs in normally with the nick
366  *    "foobar" (quite legal, as this server didn't propagate it).
367  * 3) now this server gets nick "foobar" from outside, but
368  *    has already the same defined locally. Current server
369  *    would just issue "KILL foobar" to clean out dups. But,
370  *    this is not fair. It should actually request another
371  *    nick from local user or kill him/her...
372  */
373 int register_user(struct Client *cptr, struct Client *sptr,
374                   const char *nick, char *username)
375 {
376   struct ConfItem* aconf;
377   char*            parv[3];
378   char*            tmpstr;
379   char*            tmpstr2;
380   char             c = 0;    /* not alphanum */
381   char             d = 'a';  /* not a digit */
382   short            upper = 0;
383   short            lower = 0;
384   short            pos = 0;
385   short            leadcaps = 0;
386   short            other = 0;
387   short            digits = 0;
388   short            badid = 0;
389   short            digitgroups = 0;
390   struct User*     user = cli_user(sptr);
391   char             ip_base64[8];
392
393   user->last = CurrentTime;
394   parv[0] = cli_name(sptr);
395   parv[1] = parv[2] = NULL;
396
397   if (MyConnect(sptr))
398   {
399     static time_t last_too_many1;
400     static time_t last_too_many2;
401
402     assert(cptr == sptr);
403     switch (conf_check_client(sptr))
404     {
405       case ACR_OK:
406         break;
407       case ACR_NO_AUTHORIZATION:
408         sendto_opmask_butone(0, SNO_UNAUTH, "Unauthorized connection from %s.",
409                              get_client_name(sptr, HIDE_IP));
410         ++ServerStats->is_ref;
411         return exit_client(cptr, sptr, &me,
412                            "No Authorization - use another server");
413       case ACR_TOO_MANY_IN_CLASS:
414         if (CurrentTime - last_too_many1 >= (time_t) 60)
415         {
416           last_too_many1 = CurrentTime;
417           sendto_opmask_butone(0, SNO_TOOMANY, "Too many connections in "
418                                "class %i for %s.", get_client_class(sptr),
419                                get_client_name(sptr, SHOW_IP));
420         }
421         ++ServerStats->is_ref;
422         IPcheck_connect_fail(cli_ip(sptr));
423         return exit_client(cptr, sptr, &me,
424                            "Sorry, your connection class is full - try "
425                            "again later or try another server");
426       case ACR_TOO_MANY_FROM_IP:
427         if (CurrentTime - last_too_many2 >= (time_t) 60)
428         {
429           last_too_many2 = CurrentTime;
430           sendto_opmask_butone(0, SNO_TOOMANY, "Too many connections from "
431                                "same IP for %s.",
432                                get_client_name(sptr, SHOW_IP));
433         }
434         ++ServerStats->is_ref;
435         return exit_client(cptr, sptr, &me,
436                            "Too many connections from your host");
437       case ACR_ALREADY_AUTHORIZED:
438         /* Can this ever happen? */
439       case ACR_BAD_SOCKET:
440         ++ServerStats->is_ref;
441         IPcheck_connect_fail(cli_ip(sptr));
442         return exit_client(cptr, sptr, &me, "Unknown error -- Try again");
443     }
444     ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN);
445     aconf = cli_confs(sptr)->value.aconf;
446
447     clean_user_id(user->username,
448         (cli_flags(sptr) & FLAGS_GOTID) ? cli_username(sptr) : username,
449         (cli_flags(sptr) & FLAGS_DOID) && !(cli_flags(sptr) & FLAGS_GOTID));
450
451     if ((user->username[0] == '\0')
452         || ((user->username[0] == '~') && (user->username[1] == '\000')))
453       return exit_client(cptr, sptr, &me, "USER: Bogus userid.");
454
455     if (!EmptyString(aconf->passwd)
456         && !(IsDigit(*aconf->passwd) && !aconf->passwd[1])
457         && strcmp(cli_passwd(sptr), aconf->passwd))
458     {
459       ServerStats->is_ref++;
460       IPcheck_connect_fail(cli_ip(sptr));
461       send_reply(sptr, ERR_PASSWDMISMATCH);
462       return exit_client(cptr, sptr, &me, "Bad Password");
463     }
464     memset(cli_passwd(sptr), 0, sizeof(cli_passwd(sptr)));
465     /*
466      * following block for the benefit of time-dependent K:-lines
467      */
468     if (find_kill(sptr)) {
469       ServerStats->is_ref++;
470       IPcheck_connect_fail(cli_ip(sptr));
471       return exit_client(cptr, sptr, &me, "K-lined");
472     }
473     /*
474      * Check for mixed case usernames, meaning probably hacked.  Jon2 3-94
475      * Summary of rules now implemented in this patch:         Ensor 11-94
476      * In a mixed-case name, if first char is upper, one more upper may
477      * appear anywhere.  (A mixed-case name *must* have an upper first
478      * char, and may have one other upper.)
479      * A third upper may appear if all 3 appear at the beginning of the
480      * name, separated only by "others" (-/_/.).
481      * A single group of digits is allowed anywhere.
482      * Two groups of digits are allowed if at least one of the groups is
483      * at the beginning or the end.
484      * Only one '-', '_', or '.' is allowed (or two, if not consecutive).
485      * But not as the first or last char.
486      * No other special characters are allowed.
487      * Name must contain at least one letter.
488      */
489     tmpstr2 = tmpstr = (username[0] == '~' ? &username[1] : username);
490     while (*tmpstr && !badid)
491     {
492       pos++;
493       c = *tmpstr;
494       tmpstr++;
495       if (IsLower(c))
496       {
497         lower++;
498       }
499       else if (IsUpper(c))
500       {
501         upper++;
502         if ((leadcaps || pos == 1) && !lower && !digits)
503           leadcaps++;
504       }
505       else if (IsDigit(c))
506       {
507         digits++;
508         if (pos == 1 || !IsDigit(d))
509         {
510           digitgroups++;
511           if (digitgroups > 2)
512             badid = 1;
513         }
514       }
515       else if (c == '-' || c == '_' || c == '.')
516       {
517         other++;
518         if (pos == 1)
519           badid = 1;
520         else if (d == '-' || d == '_' || d == '.' || other > 2)
521           badid = 1;
522       }
523       else
524         badid = 1;
525       d = c;
526     }
527     if (!badid)
528     {
529       if (lower && upper && (!leadcaps || leadcaps > 3 ||
530           (upper > 2 && upper > leadcaps)))
531         badid = 1;
532       else if (digitgroups == 2 && !(IsDigit(tmpstr2[0]) || IsDigit(c)))
533         badid = 1;
534       else if ((!lower && !upper) || !IsAlnum(c))
535         badid = 1;
536     }
537     if (badid && (!(cli_flags(sptr) & FLAGS_GOTID) ||
538         strcmp(cli_username(sptr), username) != 0))
539     {
540       ServerStats->is_ref++;
541
542       send_reply(cptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
543                  ":Your username is invalid.");
544       send_reply(cptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
545                  ":Connect with your real username, in lowercase.");
546       send_reply(cptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
547                  ":If your mail address were foo@bar.com, your username "
548                  "would be foo.");
549       return exit_client(cptr, sptr, &me, "USER: Bad username");
550     }
551     Count_unknownbecomesclient(sptr, UserStats);
552   }
553   else {
554     ircd_strncpy(user->username, username, USERLEN);
555     Count_newremoteclient(UserStats, user->server);
556   }
557   SetUser(sptr);
558
559   if (IsInvisible(sptr))
560     ++UserStats.inv_clients;
561   if (IsOper(sptr))
562     ++UserStats.opers;
563
564   if (MyConnect(sptr)) {
565     cli_handler(sptr) = CLIENT_HANDLER;
566     release_dns_reply(sptr);
567
568     send_reply(sptr, RPL_WELCOME, nick);
569     /*
570      * This is a duplicate of the NOTICE but see below...
571      */
572     send_reply(sptr, RPL_YOURHOST, cli_name(&me), version);
573     send_reply(sptr, RPL_CREATED, creation);
574     send_reply(sptr, RPL_MYINFO, cli_name(&me), version);
575     send_supported(sptr);
576     m_lusers(sptr, sptr, 1, parv);
577     update_load();
578     motd_signon(sptr);
579 /*      nextping = CurrentTime; */
580     if (cli_snomask(sptr) & SNO_NOISY)
581       set_snomask(sptr, cli_snomask(sptr) & SNO_NOISY, SNO_ADD);
582     IPcheck_connect_succeeded(sptr);
583   }
584   else
585     /* if (IsServer(cptr)) */
586   {
587     struct Client *acptr;
588
589     acptr = user->server;
590     if (cli_from(acptr) != cli_from(sptr))
591     {
592       sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (%s != %s[%s])",
593                     sptr, cli_name(&me), cli_name(user->server), cli_name(cli_from(acptr)),
594                     cli_sockhost(cli_from(acptr)));
595       cli_flags(sptr) |= FLAGS_KILLED;
596       return exit_client(cptr, sptr, &me, "NICK server wrong direction");
597     }
598     else
599       cli_flags(sptr) |= (cli_flags(acptr) & FLAGS_TS8);
600
601     /*
602      * Check to see if this user is being propogated
603      * as part of a net.burst, or is using protocol 9.
604      * FIXME: This can be speeded up - its stupid to check it for
605      * every NICK message in a burst again  --Run.
606      */
607     for (acptr = user->server; acptr != &me; acptr = cli_serv(acptr)->up) {
608       if (IsBurst(acptr) || Protocol(acptr) < 10)
609         break;
610     }
611     if (!IPcheck_remote_connect(sptr, (acptr != &me))) {
612       /*
613        * We ran out of bits to count this
614        */
615       sendcmdto_one(&me, CMD_KILL, sptr, "%C :%s (Too many connections from your host -- Ghost)",
616                     sptr, cli_name(&me));
617       return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
618     }
619   }
620   tmpstr = umode_str(sptr);
621   sendcmdto_serv_butone(user->server, CMD_NICK, cptr,
622                         "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
623                         nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
624                         user->username, user->host,
625                         *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
626                         inttobase64(ip_base64, ntohl(cli_ip(sptr).s_addr), 6),
627                         NumNick(sptr), cli_info(sptr));
628   
629   /* Send umode to client */
630   if (MyUser(sptr))
631   {
632     send_umode(cptr, sptr, 0, ALL_UMODES);
633     if (cli_snomask(sptr) != SNO_DEFAULT && (cli_flags(sptr) & FLAGS_SERVNOTICE))
634       send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
635   }
636
637   return 0;
638 }
639
640
641 static const struct UserMode {
642   unsigned int flag;
643   char         c;
644 } userModeList[] = {
645   { FLAGS_OPER,        'o' },
646   { FLAGS_LOCOP,       'O' },
647   { FLAGS_INVISIBLE,   'i' },
648   { FLAGS_WALLOP,      'w' },
649   { FLAGS_SERVNOTICE,  's' },
650   { FLAGS_DEAF,        'd' },
651   { FLAGS_CHSERV,      'k' },
652   { FLAGS_DEBUG,       'g' }
653 };
654
655 #define USERMODELIST_SIZE sizeof(userModeList) / sizeof(struct UserMode)
656
657 /*
658  * XXX - find a way to get rid of this
659  */
660 static char umodeBuf[BUFSIZE];
661
662 int set_nick_name(struct Client* cptr, struct Client* sptr,
663                   const char* nick, int parc, char* parv[])
664 {
665   if (IsServer(sptr)) {
666     int   i;
667     const char* p;
668
669     /*
670      * A server introducing a new client, change source
671      */
672     struct Client* new_client = make_client(cptr, STAT_UNKNOWN);
673     assert(0 != new_client);
674
675     cli_hopcount(new_client) = atoi(parv[2]);
676     cli_lastnick(new_client) = atoi(parv[3]);
677     if (Protocol(cptr) > 9 && parc > 7 && *parv[6] == '+') {
678       for (p = parv[6] + 1; *p; p++) {
679         for (i = 0; i < USERMODELIST_SIZE; ++i) {
680           if (userModeList[i].c == *p) {
681             cli_flags(new_client) |= userModeList[i].flag;
682             break;
683           }
684         }
685       }
686     }
687     client_set_privs(new_client); /* set privs on user */
688     /*
689      * Set new nick name.
690      */
691     strcpy(cli_name(new_client), nick);
692     cli_user(new_client) = make_user(new_client);
693     cli_user(new_client)->server = sptr;
694     SetRemoteNumNick(new_client, parv[parc - 2]);
695     /*
696      * IP# of remote client
697      */
698     cli_ip(new_client).s_addr = htonl(base64toint(parv[parc - 3]));
699
700     add_client_to_list(new_client);
701     hAddClient(new_client);
702
703     cli_serv(sptr)->ghost = 0;        /* :server NICK means end of net.burst */
704     ircd_strncpy(cli_username(new_client), parv[4], USERLEN);
705     ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
706     ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
707
708     return register_user(cptr, new_client, cli_name(new_client), parv[4]);
709   }
710   else if ((cli_name(sptr))[0]) {
711     /*
712      * Client changing its nick
713      *
714      * If the client belongs to me, then check to see
715      * if client is on any channels where it is currently
716      * banned.  If so, do not allow the nick change to occur.
717      */
718     if (MyUser(sptr)) {
719       const char* channel_name;
720       if ((channel_name = find_no_nickchange_channel(sptr))) {
721         return send_reply(cptr, ERR_BANNICKCHANGE, channel_name);
722       }
723       /*
724        * Refuse nick change if the last nick change was less
725        * then 30 seconds ago. This is intended to get rid of
726        * clone bots doing NICK FLOOD. -SeKs
727        * If someone didn't change their nick for more then 60 seconds
728        * however, allow to do two nick changes immedately after another
729        * before limiting the nick flood. -Run
730        */
731       if (CurrentTime < cli_nextnick(cptr)) {
732         cli_nextnick(cptr) += 2;
733         send_reply(cptr, ERR_NICKTOOFAST, parv[1],
734                    cli_nextnick(cptr) - CurrentTime);
735         /* Send error message */
736         sendcmdto_one(cptr, CMD_NICK, cptr, "%s", cli_name(cptr));
737         /* bounce NICK to user */
738         return 0;                /* ignore nick change! */
739       }
740       else {
741         /* Limit total to 1 change per NICK_DELAY seconds: */
742         cli_nextnick(cptr) += NICK_DELAY;
743         /* However allow _maximal_ 1 extra consecutive nick change: */
744         if (cli_nextnick(cptr) < CurrentTime)
745           cli_nextnick(cptr) = CurrentTime;
746       }
747     }
748     /*
749      * Also set 'lastnick' to current time, if changed.
750      */
751     if (0 != ircd_strcmp(parv[0], nick))
752       cli_lastnick(sptr) = (sptr == cptr) ? TStime() : atoi(parv[2]);
753
754     /*
755      * Client just changing his/her nick. If he/she is
756      * on a channel, send note of change to all clients
757      * on that channel. Propagate notice to other servers.
758      */
759     if (IsUser(sptr)) {
760       sendcmdto_common_channels(sptr, CMD_NICK, ":%s", nick);
761       add_history(sptr, 1);
762       sendcmdto_serv_butone(sptr, CMD_NICK, cptr, "%s %Tu", nick,
763                             cli_lastnick(sptr));
764     }
765     else
766       sendcmdto_one(sptr, CMD_NICK, sptr, ":%s", nick);
767
768     if ((cli_name(sptr))[0])
769       hRemClient(sptr);
770     strcpy(cli_name(sptr), nick);
771     hAddClient(sptr);
772   }
773   else {
774     /* Local client setting NICK the first time */
775
776     strcpy(cli_name(sptr), nick);
777     if (!cli_user(sptr)) {
778       cli_user(sptr) = make_user(sptr);
779       cli_user(sptr)->server = &me;
780     }
781     SetLocalNumNick(sptr);
782     hAddClient(sptr);
783
784     /*
785      * If the client hasn't gotten a cookie-ping yet,
786      * choose a cookie and send it. -record!jegelhof@cloud9.net
787      */
788     if (!cli_cookie(sptr)) {
789       do {
790         cli_cookie(sptr) = (ircrandom() & 0x7fffffff);
791       } while (!cli_cookie(sptr));
792       sendrawto_one(cptr, MSG_PING " :%u", cli_cookie(sptr));
793     }
794     else if (*(cli_user(sptr))->host && cli_cookie(sptr) == COOKIE_VERIFIED) {
795       /*
796        * USER and PONG already received, now we have NICK.
797        * register_user may reject the client and call exit_client
798        * for it - must test this and exit m_nick too !
799        */
800       cli_lastnick(sptr) = TStime();        /* Always local client */
801       if (register_user(cptr, sptr, nick, cli_user(sptr)->username) == CPTR_KILLED)
802         return CPTR_KILLED;
803     }
804   }
805   return 0;
806 }
807
808 static unsigned char hash_target(unsigned int target)
809 {
810   return (unsigned char) (target >> 16) ^ (target >> 8);
811 }
812
813 /*
814  * add_target
815  *
816  * sptr must be a local client!
817  *
818  * Cannonifies target for client `sptr'.
819  */
820 void add_target(struct Client *sptr, void *target)
821 {
822   /* Ok, this shouldn't work esp on alpha
823   */
824   unsigned char  hash = hash_target((unsigned long) target);
825   unsigned char* targets;
826   int            i;
827   assert(0 != sptr);
828   assert(cli_local(sptr));
829
830   targets = cli_targets(sptr);
831   /* 
832    * Already in table?
833    */
834   for (i = 0; i < MAXTARGETS; ++i) {
835     if (targets[i] == hash)
836       return;
837   }
838   /*
839    * New target
840    */
841   memmove(&targets[RESERVEDTARGETS + 1],
842           &targets[RESERVEDTARGETS], MAXTARGETS - RESERVEDTARGETS - 1);
843   targets[RESERVEDTARGETS] = hash;
844 }
845
846 /*
847  * check_target_limit
848  *
849  * sptr must be a local client !
850  *
851  * Returns 'true' (1) when too many targets are addressed.
852  * Returns 'false' (0) when it's ok to send to this target.
853  */
854 int check_target_limit(struct Client *sptr, void *target, const char *name,
855     int created)
856 {
857   unsigned char hash = hash_target((unsigned long) target);
858   int            i;
859   unsigned char* targets;
860
861   assert(0 != sptr);
862   assert(cli_local(sptr));
863   targets = cli_targets(sptr);
864
865   /*
866    * Same target as last time?
867    */
868   if (targets[0] == hash)
869     return 0;
870   for (i = 1; i < MAXTARGETS; ++i) {
871     if (targets[i] == hash) {
872       memmove(&targets[1], &targets[0], i);
873       targets[0] = hash;
874       return 0;
875     }
876   }
877   /*
878    * New target
879    */
880   if (!created) {
881     if (CurrentTime < cli_nexttarget(sptr)) {
882       if (cli_nexttarget(sptr) - CurrentTime < TARGET_DELAY + 8) {
883         /*
884          * No server flooding
885          */
886         cli_nexttarget(sptr) += 2;
887         send_reply(sptr, ERR_TARGETTOOFAST, name,
888                    cli_nexttarget(sptr) - CurrentTime);
889       }
890       return 1;
891     }
892     else {
893       cli_nexttarget(sptr) += TARGET_DELAY;
894       if (cli_nexttarget(sptr) < CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1)))
895         cli_nexttarget(sptr) = CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1));
896     }
897   }
898   memmove(&targets[1], &targets[0], MAXTARGETS - 1);
899   targets[0] = hash;
900   return 0;
901 }
902
903 /*
904  * whisper - called from m_cnotice and m_cprivmsg.
905  *
906  * parv[0] = sender prefix
907  * parv[1] = nick
908  * parv[2] = #channel
909  * parv[3] = Private message text
910  *
911  * Added 971023 by Run.
912  * Reason: Allows channel operators to sent an arbitrary number of private
913  *   messages to users on their channel, avoiding the max.targets limit.
914  *   Building this into m_private would use too much cpu because we'd have
915  *   to a cross channel lookup for every private message!
916  * Note that we can't allow non-chan ops to use this command, it would be
917  *   abused by mass advertisers.
918  *
919  */
920 int whisper(struct Client* source, const char* nick, const char* channel,
921             const char* text, int is_notice)
922 {
923   struct Client*     dest;
924   struct Channel*    chptr;
925   struct Membership* membership;
926
927   assert(0 != source);
928   assert(0 != nick);
929   assert(0 != channel);
930   assert(MyUser(source));
931
932   if (!(dest = FindUser(nick))) {
933     return send_reply(source, ERR_NOSUCHNICK, nick);
934   }
935   if (!(chptr = FindChannel(channel))) {
936     return send_reply(source, ERR_NOSUCHCHANNEL, channel);
937   }
938   /*
939    * compare both users channel lists, instead of the channels user list
940    * since the link is the same, this should be a little faster for channels
941    * with a lot of users
942    */
943   for (membership = cli_user(source)->channel; membership; membership = membership->next_channel) {
944     if (chptr == membership->channel)
945       break;
946   }
947   if (0 == membership) {
948     return send_reply(source, ERR_NOTONCHANNEL, chptr->chname);
949   }
950   if (!IsVoicedOrOpped(membership)) {
951     return send_reply(source, ERR_VOICENEEDED, chptr->chname);
952   }
953   /*
954    * lookup channel in destination
955    */
956   assert(0 != cli_user(dest));
957   for (membership = cli_user(dest)->channel; membership; membership = membership->next_channel) {
958     if (chptr == membership->channel)
959       break;
960   }
961   if (0 == membership || IsZombie(membership)) {
962     return send_reply(source, ERR_USERNOTINCHANNEL, cli_name(dest), chptr->chname);
963   }
964   if (is_silenced(source, dest))
965     return 0;
966           
967   if (cli_user(dest)->away)
968     send_reply(source, RPL_AWAY, cli_name(dest), cli_user(dest)->away);
969   if (is_notice)
970     sendcmdto_one(source, CMD_NOTICE, dest, "%C :%s", dest, text);
971   else
972     sendcmdto_one(source, CMD_PRIVATE, dest, "%C :%s", dest, text);
973   return 0;
974 }
975
976
977 /*
978  * added Sat Jul 25 07:30:42 EST 1992
979  */
980 void send_umode_out(struct Client *cptr, struct Client *sptr, int old,
981                     int prop)
982 {
983   int i;
984   struct Client *acptr;
985
986   send_umode(NULL, sptr, old, SEND_UMODES & ~(prop ? 0 : FLAGS_OPER));
987
988   for (i = HighestFd; i >= 0; i--) {
989     if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
990         (acptr != cptr) && (acptr != sptr) && *umodeBuf)
991       sendcmdto_one(sptr, CMD_MODE, acptr, "%s :%s", cli_name(sptr), umodeBuf);
992   }
993   if (cptr && MyUser(cptr))
994     send_umode(cptr, sptr, old, ALL_UMODES);
995 }
996
997
998 /*
999  * send_user_info - send user info userip/userhost
1000  * NOTE: formatter must put info into buffer and return a pointer to the end of
1001  * the data it put in the buffer.
1002  */
1003 void send_user_info(struct Client* sptr, char* names, int rpl, InfoFormatter fmt)
1004 {
1005   char*          name;
1006   char*          p = 0;
1007   int            arg_count = 0;
1008   int            users_found = 0;
1009   struct Client* acptr;
1010   struct MsgBuf* mb;
1011
1012   assert(0 != sptr);
1013   assert(0 != names);
1014   assert(0 != fmt);
1015
1016   mb = msgq_make(sptr, rpl_str(rpl), cli_name(&me), cli_name(sptr));
1017
1018   for (name = ircd_strtok(&p, names, " "); name; name = ircd_strtok(&p, 0, " ")) {
1019     if ((acptr = FindUser(name))) {
1020       if (users_found++)
1021         msgq_append(0, mb, " ");
1022       (*fmt)(acptr, mb);
1023     }
1024     if (5 == ++arg_count)
1025       break;
1026   }
1027   send_buffer(sptr, mb, 0);
1028   msgq_clean(mb);
1029 }
1030
1031
1032 /*
1033  * set_user_mode() added 15/10/91 By Darren Reed.
1034  *
1035  * parv[0] - sender
1036  * parv[1] - username to change mode for
1037  * parv[2] - modes to change
1038  */
1039 int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1040 {
1041   char** p;
1042   char*  m;
1043   struct Client *acptr;
1044   int what;
1045   int i;
1046   int setflags;
1047   unsigned int tmpmask = 0;
1048   int snomask_given = 0;
1049   char buf[BUFSIZE];
1050   int prop = 0;
1051
1052   what = MODE_ADD;
1053
1054   if (parc < 2)
1055     return need_more_params(sptr, "MODE");
1056
1057   if (!(acptr = FindUser(parv[1])))
1058   {
1059     if (MyConnect(sptr))
1060       send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
1061     return 0;
1062   }
1063
1064   if (IsServer(sptr) || sptr != acptr)
1065   {
1066     if (IsServer(cptr))
1067       sendwallto_group_butone(&me, WALL_WALLOPS, 0, 
1068                             "MODE for User %s from %s!%s", parv[1],
1069                             cli_name(cptr), cli_name(sptr));
1070     else
1071       send_reply(sptr, ERR_USERSDONTMATCH);
1072     return 0;
1073   }
1074
1075   if (parc < 3)
1076   {
1077     m = buf;
1078     *m++ = '+';
1079     for (i = 0; i < USERMODELIST_SIZE; ++i) {
1080       if ( (userModeList[i].flag & cli_flags(sptr)))
1081         *m++ = userModeList[i].c;
1082     }
1083     *m = '\0';
1084     send_reply(sptr, RPL_UMODEIS, buf);
1085     if ((cli_flags(sptr) & FLAGS_SERVNOTICE) && MyConnect(sptr)
1086         && cli_snomask(sptr) !=
1087         (unsigned int)(IsOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT))
1088       send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
1089     return 0;
1090   }
1091
1092   /*
1093    * find flags already set for user
1094    * why not just copy them?
1095    */
1096   setflags = cli_flags(sptr);
1097
1098   if (MyConnect(sptr))
1099     tmpmask = cli_snomask(sptr);
1100
1101   /*
1102    * parse mode change string(s)
1103    */
1104   for (p = &parv[2]; *p; p++) {       /* p is changed in loop too */
1105     for (m = *p; *m; m++) {
1106       switch (*m) {
1107       case '+':
1108         what = MODE_ADD;
1109         break;
1110       case '-':
1111         what = MODE_DEL;
1112         break;
1113       case 's':
1114         if (*(p + 1) && is_snomask(*(p + 1))) {
1115           snomask_given = 1;
1116           tmpmask = umode_make_snomask(tmpmask, *++p, what);
1117           tmpmask &= (IsAnOper(sptr) ? SNO_ALL : SNO_USER);
1118         }
1119         else
1120           tmpmask = (what == MODE_ADD) ?
1121               (IsAnOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT) : 0;
1122         if (tmpmask)
1123           SetServNotice(sptr);
1124         else
1125           ClearServNotice(sptr);
1126         break;
1127       case 'w':
1128         if (what == MODE_ADD)
1129           SetWallops(sptr);
1130         else
1131           ClearWallops(sptr);
1132         break;
1133       case 'o':
1134         if (what == MODE_ADD)
1135           SetOper(sptr);
1136         else {
1137           cli_flags(sptr) &= ~(FLAGS_OPER | FLAGS_LOCOP);
1138           if (MyConnect(sptr)) {
1139             tmpmask = cli_snomask(sptr) & ~SNO_OPER;
1140             cli_handler(sptr) = CLIENT_HANDLER;
1141           }
1142         }
1143         break;
1144       case 'O':
1145         if (what == MODE_ADD)
1146           SetLocOp(sptr);
1147         else { 
1148           cli_flags(sptr) &= ~(FLAGS_OPER | FLAGS_LOCOP);
1149           if (MyConnect(sptr)) {
1150             tmpmask = cli_snomask(sptr) & ~SNO_OPER;
1151             cli_handler(sptr) = CLIENT_HANDLER;
1152           }
1153         }
1154         break;
1155       case 'i':
1156         if (what == MODE_ADD)
1157           SetInvisible(sptr);
1158         else
1159           ClearInvisible(sptr);
1160         break;
1161       case 'd':
1162         if (what == MODE_ADD)
1163           SetDeaf(sptr);
1164         else
1165           ClearDeaf(sptr);
1166         break;
1167       case 'k':
1168         if (what == MODE_ADD)
1169           SetChannelService(sptr);
1170         else
1171           ClearChannelService(sptr);
1172         break;
1173       case 'g':
1174         if (what == MODE_ADD)
1175           SetDebug(sptr);
1176         else
1177           ClearDebug(sptr);
1178         break;
1179       default:
1180         break;
1181       }
1182     }
1183   }
1184   /*
1185    * Evaluate rules for new user mode
1186    * Stop users making themselves operators too easily:
1187    */
1188   if (!IsServer(cptr)) {
1189     if (!(setflags & FLAGS_OPER) && IsOper(sptr))
1190       ClearOper(sptr);
1191     if (!(setflags & FLAGS_LOCOP) && IsLocOp(sptr))
1192       ClearLocOp(sptr);
1193     /*
1194      * new umode; servers can set it, local users cannot;
1195      * prevents users from /kick'ing or /mode -o'ing
1196      */
1197     if (!(setflags & FLAGS_CHSERV))
1198       ClearChannelService(sptr);
1199     /*
1200      * only send wallops to opers
1201      */
1202     if (feature_bool(FEAT_WALLOPS_OPER_ONLY) && !IsAnOper(sptr) &&
1203         !(setflags & FLAGS_WALLOP))
1204       ClearWallops(sptr);
1205 #ifdef SERVNOTICE_OPER_ONLY
1206     if (MyConnect(sptr) && !IsAnOper(sptr) && !(setflags & FLAGS_SERVNOTICE)) {
1207       ClearServNotice(sptr);
1208       set_snomask(sptr, 0, SNO_SET);
1209     }
1210 #endif
1211 #ifdef DEBUG_OPER_ONLY
1212     if (!IsAnOper(sptr) && !(setflags & FLAGS_DEBUG))
1213       ClearDebug(sptr);
1214 #endif
1215   }
1216   if (MyConnect(sptr)) {
1217     if ((setflags & (FLAGS_OPER | FLAGS_LOCOP)) && !IsAnOper(sptr))
1218       det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPS);
1219
1220     if (SendServNotice(sptr)) {
1221       if (tmpmask != cli_snomask(sptr))
1222         set_snomask(sptr, tmpmask, SNO_SET);
1223       if (cli_snomask(sptr) && snomask_given)
1224         send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
1225     } else
1226       set_snomask(sptr, 0, SNO_SET);
1227   }
1228   /*
1229    * Compare new flags with old flags and send string which
1230    * will cause servers to update correctly.
1231    */
1232   if (!(setflags & FLAGS_OPER) && IsOper(sptr)) { /* user now oper */
1233     ++UserStats.opers;
1234     client_set_privs(sptr); /* may set propagate privilege */
1235   }
1236   if (HasPriv(sptr, PRIV_PROPAGATE)) /* remember propagate privilege setting */
1237     prop = 1;
1238   if ((setflags & FLAGS_OPER) && !IsOper(sptr)) { /* user no longer oper */
1239     --UserStats.opers;
1240     client_set_privs(sptr); /* will clear propagate privilege */
1241   }
1242   if ((setflags & FLAGS_INVISIBLE) && !IsInvisible(sptr))
1243     --UserStats.inv_clients;
1244   if (!(setflags & FLAGS_INVISIBLE) && IsInvisible(sptr))
1245     ++UserStats.inv_clients;
1246   send_umode_out(cptr, sptr, setflags, prop);
1247
1248   return 0;
1249 }
1250
1251 /*
1252  * Build umode string for BURST command
1253  * --Run
1254  */
1255 char *umode_str(struct Client *cptr)
1256 {
1257   char* m = umodeBuf;                /* Maximum string size: "owidg\0" */
1258   int   i;
1259   int   c_flags;
1260
1261   c_flags = cli_flags(cptr) & SEND_UMODES; /* cleaning up the original code */
1262   if (HasPriv(cptr, PRIV_PROPAGATE))
1263     c_flags |= FLAGS_OPER;
1264   else
1265     c_flags &= ~FLAGS_OPER;
1266
1267   for (i = 0; i < USERMODELIST_SIZE; ++i) {
1268     if ( (c_flags & userModeList[i].flag))
1269       *m++ = userModeList[i].c;
1270   }
1271   *m = '\0';
1272
1273   return umodeBuf;                /* Note: static buffer, gets
1274                                    overwritten by send_umode() */
1275 }
1276
1277 /*
1278  * Send the MODE string for user (user) to connection cptr
1279  * -avalon
1280  */
1281 void send_umode(struct Client *cptr, struct Client *sptr, int old, int sendmask)
1282 {
1283   int i;
1284   int flag;
1285   char *m;
1286   int what = MODE_NULL;
1287
1288   /*
1289    * Build a string in umodeBuf to represent the change in the user's
1290    * mode between the new (sptr->flag) and 'old'.
1291    */
1292   m = umodeBuf;
1293   *m = '\0';
1294   for (i = 0; i < USERMODELIST_SIZE; ++i) {
1295     flag = userModeList[i].flag;
1296     if (MyUser(sptr) && !(flag & sendmask))
1297       continue;
1298     if ( (flag & old) && !(cli_flags(sptr) & flag))
1299     {
1300       if (what == MODE_DEL)
1301         *m++ = userModeList[i].c;
1302       else
1303       {
1304         what = MODE_DEL;
1305         *m++ = '-';
1306         *m++ = userModeList[i].c;
1307       }
1308     }
1309     else if (!(flag & old) && (cli_flags(sptr) & flag))
1310     {
1311       if (what == MODE_ADD)
1312         *m++ = userModeList[i].c;
1313       else
1314       {
1315         what = MODE_ADD;
1316         *m++ = '+';
1317         *m++ = userModeList[i].c;
1318       }
1319     }
1320   }
1321   *m = '\0';
1322   if (*umodeBuf && cptr)
1323     sendcmdto_one(sptr, CMD_MODE, cptr, "%s :%s", cli_name(sptr), umodeBuf);
1324 }
1325
1326 /*
1327  * Check to see if this resembles a sno_mask.  It is if 1) there is
1328  * at least one digit and 2) The first digit occurs before the first
1329  * alphabetic character.
1330  */
1331 int is_snomask(char *word)
1332 {
1333   if (word)
1334   {
1335     for (; *word; word++)
1336       if (IsDigit(*word))
1337         return 1;
1338       else if (IsAlpha(*word))
1339         return 0;
1340   }
1341   return 0;
1342 }
1343
1344 /*
1345  * If it begins with a +, count this as an additive mask instead of just
1346  * a replacement.  If what == MODE_DEL, "+" has no special effect.
1347  */
1348 unsigned int umode_make_snomask(unsigned int oldmask, char *arg, int what)
1349 {
1350   unsigned int sno_what;
1351   unsigned int newmask;
1352   if (*arg == '+')
1353   {
1354     arg++;
1355     if (what == MODE_ADD)
1356       sno_what = SNO_ADD;
1357     else
1358       sno_what = SNO_DEL;
1359   }
1360   else if (*arg == '-')
1361   {
1362     arg++;
1363     if (what == MODE_ADD)
1364       sno_what = SNO_DEL;
1365     else
1366       sno_what = SNO_ADD;
1367   }
1368   else
1369     sno_what = (what == MODE_ADD) ? SNO_SET : SNO_DEL;
1370   /* pity we don't have strtoul everywhere */
1371   newmask = (unsigned int)atoi(arg);
1372   if (sno_what == SNO_DEL)
1373     newmask = oldmask & ~newmask;
1374   else if (sno_what == SNO_ADD)
1375     newmask |= oldmask;
1376   return newmask;
1377 }
1378
1379 static void delfrom_list(struct Client *cptr, struct SLink **list)
1380 {
1381   struct SLink* tmp;
1382   struct SLink* prv = NULL;
1383
1384   for (tmp = *list; tmp; tmp = tmp->next) {
1385     if (tmp->value.cptr == cptr) {
1386       if (prv)
1387         prv->next = tmp->next;
1388       else
1389         *list = tmp->next;
1390       free_link(tmp);
1391       break;
1392     }
1393     prv = tmp;
1394   }
1395 }
1396
1397 /*
1398  * This function sets a Client's server notices mask, according to
1399  * the parameter 'what'.  This could be even faster, but the code
1400  * gets mighty hard to read :)
1401  */
1402 void set_snomask(struct Client *cptr, unsigned int newmask, int what)
1403 {
1404   unsigned int oldmask, diffmask;        /* unsigned please */
1405   int i;
1406   struct SLink *tmp;
1407
1408   oldmask = cli_snomask(cptr);
1409
1410   if (what == SNO_ADD)
1411     newmask |= oldmask;
1412   else if (what == SNO_DEL)
1413     newmask = oldmask & ~newmask;
1414   else if (what != SNO_SET)        /* absolute set, no math needed */
1415     sendto_opmask_butone(0, SNO_OLDSNO, "setsnomask called with %d ?!", what);
1416
1417   newmask &= (IsAnOper(cptr) ? SNO_ALL : SNO_USER);
1418
1419   diffmask = oldmask ^ newmask;
1420
1421   for (i = 0; diffmask >> i; i++) {
1422     if (((diffmask >> i) & 1))
1423     {
1424       if (((newmask >> i) & 1))
1425       {
1426         tmp = make_link();
1427         tmp->next = opsarray[i];
1428         tmp->value.cptr = cptr;
1429         opsarray[i] = tmp;
1430       }
1431       else
1432         /* not real portable :( */
1433         delfrom_list(cptr, &opsarray[i]);
1434     }
1435   }
1436   cli_snomask(cptr) = newmask;
1437 }
1438
1439 /*
1440  * is_silenced : Does the actual check wether sptr is allowed
1441  *               to send a message to acptr.
1442  *               Both must be registered persons.
1443  * If sptr is silenced by acptr, his message should not be propagated,
1444  * but more over, if this is detected on a server not local to sptr
1445  * the SILENCE mask is sent upstream.
1446  */
1447 int is_silenced(struct Client *sptr, struct Client *acptr)
1448 {
1449   struct SLink *lp;
1450   struct User *user;
1451   static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
1452   static char senderip[16 + NICKLEN + USERLEN + 5];
1453
1454   if (!cli_user(acptr) || !(lp = cli_user(acptr)->silence) || !(user = cli_user(sptr)))
1455     return 0;
1456   ircd_snprintf(0, sender, sizeof(sender), "%s!%s@%s", cli_name(sptr),
1457                 user->username, user->host);
1458   ircd_snprintf(0, senderip, sizeof(senderip), "%s!%s@%s", cli_name(sptr),
1459                 user->username, ircd_ntoa((const char*) &(cli_ip(sptr))));
1460   for (; lp; lp = lp->next)
1461   {
1462     if ((!(lp->flags & CHFL_SILENCE_IPMASK) && !match(lp->value.cp, sender)) ||
1463         ((lp->flags & CHFL_SILENCE_IPMASK) && !match(lp->value.cp, senderip)))
1464     {
1465       if (!MyConnect(sptr))
1466       {
1467         sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr,
1468                       lp->value.cp);
1469       }
1470       return 1;
1471     }
1472   }
1473   return 0;
1474 }
1475
1476 /*
1477  * del_silence
1478  *
1479  * Removes all silence masks from the list of sptr that fall within `mask'
1480  * Returns -1 if none where found, 0 otherwise.
1481  */
1482 int del_silence(struct Client *sptr, char *mask)
1483 {
1484   struct SLink **lp;
1485   struct SLink *tmp;
1486   int ret = -1;
1487
1488   for (lp = &(cli_user(sptr))->silence; *lp;) {
1489     if (!mmatch(mask, (*lp)->value.cp))
1490     {
1491       tmp = *lp;
1492       *lp = tmp->next;
1493       MyFree(tmp->value.cp);
1494       free_link(tmp);
1495       ret = 0;
1496     }
1497     else
1498       lp = &(*lp)->next;
1499   }
1500   return ret;
1501 }
1502
1503 int add_silence(struct Client* sptr, const char* mask)
1504 {
1505   struct SLink *lp, **lpp;
1506   int cnt = 0, len = strlen(mask);
1507   char *ip_start;
1508
1509   for (lpp = &(cli_user(sptr))->silence, lp = *lpp; lp;)
1510   {
1511     if (0 == ircd_strcmp(mask, lp->value.cp))
1512       return -1;
1513     if (!mmatch(mask, lp->value.cp))
1514     {
1515       struct SLink *tmp = lp;
1516       *lpp = lp = lp->next;
1517       MyFree(tmp->value.cp);
1518       free_link(tmp);
1519       continue;
1520     }
1521     if (MyUser(sptr))
1522     {
1523       len += strlen(lp->value.cp);
1524       if ((len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXSILES))) ||
1525           (++cnt >= feature_int(FEAT_MAXSILES)))
1526       {
1527         send_reply(sptr, ERR_SILELISTFULL, mask);
1528         return -1;
1529       }
1530       else if (!mmatch(lp->value.cp, mask))
1531         return -1;
1532     }
1533     lpp = &lp->next;
1534     lp = *lpp;
1535   }
1536   lp = make_link();
1537   memset(lp, 0, sizeof(struct SLink));
1538   lp->next = cli_user(sptr)->silence;
1539   lp->value.cp = (char*) MyMalloc(strlen(mask) + 1);
1540   assert(0 != lp->value.cp);
1541   strcpy(lp->value.cp, mask);
1542   if ((ip_start = strrchr(mask, '@')) && check_if_ipmask(ip_start + 1))
1543     lp->flags = CHFL_SILENCE_IPMASK;
1544   cli_user(sptr)->silence = lp;
1545   return 0;
1546 }
1547
1548 int
1549 send_supported(struct Client *cptr)
1550 {
1551   char featurebuf[512];
1552
1553   ircd_snprintf(0, featurebuf, sizeof(featurebuf), FEATURES1, FEATURESVALUES1);
1554   send_reply(cptr, RPL_ISUPPORT, featurebuf);
1555   ircd_snprintf(0, featurebuf, sizeof(featurebuf), FEATURES2, FEATURESVALUES2);
1556   send_reply(cptr, RPL_ISUPPORT, featurebuf);
1557
1558   return 0; /* convenience return, if it's ever needed */
1559 }