ircd/s_user.c
author Chris Porter <chris@warp13.co.uk>
Mon Mar 24 01:33:32 2008 +0000 (4 years ago)
changeset 147 2da2b881d9f5
parent 14489defd4c9708
child 1507afd40e93981
permissions -rw-r--r--
Apply remote crash exploit fix to public repo.
     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 /** @file
    24  * @brief Miscellaneous user-related helper functions.
    25  * @version $Id: s_user.c,v 1.99.2.11 2007/08/21 01:13:15 entrope Exp $
    26  */
    27 #include "config.h"
    28 
    29 #include "s_user.h"
    30 #include "IPcheck.h"
    31 #include "channel.h"
    32 #include "class.h"
    33 #include "client.h"
    34 #include "hash.h"
    35 #include "ircd.h"
    36 #include "ircd_alloc.h"
    37 #include "ircd_chattr.h"
    38 #include "ircd_features.h"
    39 #include "ircd_log.h"
    40 #include "ircd_reply.h"
    41 #include "ircd_snprintf.h"
    42 #include "ircd_string.h"
    43 #include "list.h"
    44 #include "match.h"
    45 #include "motd.h"
    46 #include "msg.h"
    47 #include "msgq.h"
    48 #include "numeric.h"
    49 #include "numnicks.h"
    50 #include "parse.h"
    51 #include "querycmds.h"
    52 #include "random.h"
    53 #include "s_auth.h"
    54 #include "s_bsd.h"
    55 #include "s_conf.h"
    56 #include "s_debug.h"
    57 #include "s_misc.h"
    58 #include "s_serv.h" /* max_client_count */
    59 #include "send.h"
    60 #include "struct.h"
    61 #include "supported.h"
    62 #include "sys.h"
    63 #include "userload.h"
    64 #include "version.h"
    65 #include "whowas.h"
    66 
    67 #include "handlers.h" /* m_motd and m_lusers */
    68 
    69 /* #include <assert.h> -- Now using assert in ircd_log.h */
    70 #include <fcntl.h>
    71 #include <stdio.h>
    72 #include <stdlib.h>
    73 #include <string.h>
    74 #include <sys/stat.h>
    75 
    76 static char *IsVhost(char *hostmask, int oper);
    77 static char *IsVhostPass(char *hostmask);
    78 
    79 /** Count of allocated User structures. */
    80 static int userCount = 0;
    81 
    82 /** Makes sure that \a cptr has a User information block.
    83  * If cli_user(cptr) != NULL, does nothing.
    84  * @param[in] cptr Client to attach User struct to.
    85  * @return User struct associated with \a cptr.
    86  */
    87 struct User *make_user(struct Client *cptr)
    88 {
    89   assert(0 != cptr);
    90 
    91   if (!cli_user(cptr)) {
    92     cli_user(cptr) = (struct User*) MyMalloc(sizeof(struct User));
    93     assert(0 != cli_user(cptr));
    94 
    95     /* All variables are 0 by default */
    96     memset(cli_user(cptr), 0, sizeof(struct User));
    97     ++userCount;
    98     cli_user(cptr)->refcnt = 1;
    99   }
   100   return cli_user(cptr);
   101 }
   102 
   103 /** Dereference \a user.
   104  * User structures are reference-counted; if the refcount of \a user
   105  * becomes zero, free it.
   106  * @param[in] user User to dereference.
   107  */
   108 void free_user(struct User* user)
   109 {
   110   assert(0 != user);
   111   assert(0 < user->refcnt);
   112 
   113   if (--user->refcnt == 0) {
   114     if (user->away)
   115       MyFree(user->away);
   116     if (user->opername)
   117       MyFree(user->opername);
   118     /*
   119      * sanity check
   120      */
   121     assert(0 == user->joined);
   122     assert(0 == user->invited);
   123     assert(0 == user->channel);
   124 
   125     MyFree(user);
   126     assert(userCount>0);
   127     --userCount;
   128   }
   129 }
   130 
   131 /** Find number of User structs allocated and memory used by them.
   132  * @param[out] count_out Receives number of User structs allocated.
   133  * @param[out] bytes_out Receives number of bytes used by User structs.
   134  */
   135 void user_count_memory(size_t* count_out, size_t* bytes_out)
   136 {
   137   assert(0 != count_out);
   138   assert(0 != bytes_out);
   139   *count_out = userCount;
   140   *bytes_out = userCount * sizeof(struct User);
   141 }
   142 
   143 
   144 /** Find the next client (starting at \a next) with a name that matches \a ch.
   145  * Normal usage loop is:
   146  * for (x = client; x = next_client(x,mask); x = x->next)
   147  *     HandleMatchingClient;
   148  *
   149  * @param[in] next First client to check.
   150  * @param[in] ch Name mask to check against.
   151  * @return Next matching client found, or NULL if none.
   152  */
   153 struct Client *next_client(struct Client *next, const char* ch)
   154 {
   155   struct Client *tmp = next;
   156 
   157   if (!tmp)
   158     return NULL;
   159 
   160   next = FindClient(ch);
   161   next = next ? next : tmp;
   162   if (cli_prev(tmp) == next)
   163     return NULL;
   164   if (next != tmp)
   165     return next;
   166   for (; next; next = cli_next(next))
   167     if (!match(ch, cli_name(next)))
   168       break;
   169   return next;
   170 }
   171 
   172 /** Find the destination server for a command, and forward it if that is not us.
   173  *
   174  * \a server may be a nickname, server name, server mask (if \a from
   175  * is a local user) or server numnick (if \a is a server or remote
   176  * user).
   177  *
   178  * @param[in] from Client that sent the command to us.
   179  * @param[in] cmd Long-form command text.
   180  * @param[in] tok Token-form command text.
   181  * @param[in] one Client that originated the command (ignored).
   182  * @param[in] MustBeOper If non-zero and \a from is not an operator, return HUNTED_NOSUCH.
   183  * @param[in] pattern Format string of arguments to command.
   184  * @param[in] server Index of target name or mask in \a parv.
   185  * @param[in] parc Number of valid elements in \a parv (must be less than 9).
   186  * @param[in] parv Array of arguments to command.
   187  * @return One of HUNTED_ISME, HUNTED_NOSUCH or HUNTED_PASS.
   188  */
   189 int hunt_server_cmd(struct Client *from, const char *cmd, const char *tok,
   190                     struct Client *one, int MustBeOper, const char *pattern,
   191                     int server, int parc, char *parv[])
   192 {
   193   struct Client *acptr;
   194   char *to;
   195 
   196   /* Assume it's me, if no server or an unregistered client */
   197   if (parc <= server || EmptyString((to = parv[server])) || IsUnknown(from))
   198     return (HUNTED_ISME);
   199 
   200   if (MustBeOper && (!IsPrivileged(from) || (IsAnOper(from) && !HasPriv(from, PRIV_SERVERINFO))))
   201   {
   202     send_reply(from, ERR_NOPRIVILEGES);
   203     return HUNTED_NOSUCH;
   204   }
   205 
   206   /* Make sure it's a server */
   207   if (MyUser(from)) {
   208     /* Make sure it's a server */
   209     if (!strchr(to, '*')) {
   210       if (0 == (acptr = FindClient(to))) {
   211         send_reply(from, ERR_NOSUCHSERVER, to);
   212         return HUNTED_NOSUCH;
   213       }
   214 
   215       if (cli_user(acptr))
   216         acptr = cli_user(acptr)->server;
   217     } else if (!(acptr = find_match_server(to))) {
   218       send_reply(from, ERR_NOSUCHSERVER, to);
   219       return (HUNTED_NOSUCH);
   220     }
   221   } else if (!(acptr = FindNServer(to))) {
   222     send_reply(from, SND_EXPLICIT | ERR_NOSUCHSERVER, "* :Server has disconnected");
   223     return (HUNTED_NOSUCH);        /* Server broke off in the meantime */
   224   }
   225 
   226   if (IsMe(acptr))
   227     return (HUNTED_ISME);
   228 
   229   if (MustBeOper && !IsPrivileged(from)) {
   230     send_reply(from, ERR_NOPRIVILEGES);
   231     return HUNTED_NOSUCH;
   232   }
   233 
   234   /* assert(!IsServer(from)); */
   235 
   236   parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */
   237 
   238   sendcmdto_one(from, cmd, tok, acptr, pattern, parv[1], parv[2], parv[3],
   239                 parv[4], parv[5], parv[6], parv[7], parv[8]);
   240 
   241   return (HUNTED_PASS);
   242 }
   243 
   244 /** Find the destination server for a command, and forward it (as a
   245  * high-priority command) if that is not us.
   246  *
   247  * \a server may be a nickname, server name, server mask (if \a from
   248  * is a local user) or server numnick (if \a is a server or remote
   249  * user).
   250  * Unlike hunt_server_cmd(), this appends the message to the
   251  * high-priority message queue for the destination server.
   252  *
   253  * @param[in] from Client that sent the command to us.
   254  * @param[in] cmd Long-form command text.
   255  * @param[in] tok Token-form command text.
   256  * @param[in] one Client that originated the command (ignored).
   257  * @param[in] MustBeOper If non-zero and \a from is not an operator, return HUNTED_NOSUCH.
   258  * @param[in] pattern Format string of arguments to command.
   259  * @param[in] server Index of target name or mask in \a parv.
   260  * @param[in] parc Number of valid elements in \a parv (must be less than 9).
   261  * @param[in] parv Array of arguments to command.
   262  * @return One of HUNTED_ISME, HUNTED_NOSUCH or HUNTED_PASS.
   263  */
   264 int hunt_server_prio_cmd(struct Client *from, const char *cmd, const char *tok,
   265 			 struct Client *one, int MustBeOper,
   266 			 const char *pattern, int server, int parc,
   267 			 char *parv[])
   268 {
   269   struct Client *acptr;
   270   char *to;
   271 
   272   /* Assume it's me, if no server or an unregistered client */
   273   if (parc <= server || EmptyString((to = parv[server])) || IsUnknown(from))
   274     return (HUNTED_ISME);
   275 
   276   /* Make sure it's a server */
   277   if (MyUser(from)) {
   278     /* Make sure it's a server */
   279     if (!strchr(to, '*')) {
   280       if (0 == (acptr = FindClient(to))) {
   281         send_reply(from, ERR_NOSUCHSERVER, to);
   282         return HUNTED_NOSUCH;
   283       }
   284 
   285       if (cli_user(acptr))
   286         acptr = cli_user(acptr)->server;
   287     } else if (!(acptr = find_match_server(to))) {
   288       send_reply(from, ERR_NOSUCHSERVER, to);
   289       return (HUNTED_NOSUCH);
   290     }
   291   } else if (!(acptr = FindNServer(to)))
   292     return (HUNTED_NOSUCH);        /* Server broke off in the meantime */
   293 
   294   if (IsMe(acptr))
   295     return (HUNTED_ISME);
   296 
   297   if (MustBeOper && !IsPrivileged(from)) {
   298     send_reply(from, ERR_NOPRIVILEGES);
   299     return HUNTED_NOSUCH;
   300   }
   301 
   302   /* assert(!IsServer(from)); SETTIME to particular destinations permitted */
   303 
   304   parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */
   305 
   306   sendcmdto_prio_one(from, cmd, tok, acptr, pattern, parv[1], parv[2], parv[3],
   307 		     parv[4], parv[5], parv[6], parv[7], parv[8]);
   308 
   309   return (HUNTED_PASS);
   310 }
   311 
   312 
   313 /*
   314  * register_user
   315  *
   316  * This function is called when both NICK and USER messages
   317  * have been accepted for the client, in whatever order. Only
   318  * after this the USER message is propagated.
   319  *
   320  * NICK's must be propagated at once when received, although
   321  * it would be better to delay them too until full info is
   322  * available. Doing it is not so simple though, would have
   323  * to implement the following:
   324  *
   325  * 1) user telnets in and gives only "NICK foobar" and waits
   326  * 2) another user far away logs in normally with the nick
   327  *    "foobar" (quite legal, as this server didn't propagate it).
   328  * 3) now this server gets nick "foobar" from outside, but
   329  *    has already the same defined locally. Current server
   330  *    would just issue "KILL foobar" to clean out dups. But,
   331  *    this is not fair. It should actually request another
   332  *    nick from local user or kill him/her...
   333  */
   334 /** Finish registering a user who has sent both NICK and USER.
   335  * For local connections, possibly check IAuth; make sure there is a
   336  * matching Client config block; clean the username field; check
   337  * K/k-lines; check for "hacked" looking usernames; assign a numnick;
   338  * and send greeting (WELCOME, ISUPPORT, MOTD, etc).
   339  * For all connections, update the invisible user and operator counts;
   340  * run IPcheck against their address; and forward the NICK.
   341  *
   342  * @param[in] cptr Client who introduced the user.
   343  * @param[in,out] sptr Client who has been fully introduced.
   344  * @return Zero or CPTR_KILLED.
   345  */
   346 int register_user(struct Client *cptr, struct Client *sptr)
   347 {
   348   char*            parv[4];
   349   char*            tmpstr;
   350   struct User*     user = cli_user(sptr);
   351   char             ip_base64[25];
   352   int ipv6andopername[] = {FLAG_IPV6,FLAG_OPERNAME};
   353 
   354   user->last = CurrentTime;
   355   parv[0] = cli_name(sptr);
   356   parv[1] = parv[2] = NULL;
   357 
   358   if (MyConnect(sptr))
   359   {
   360     assert(cptr == sptr);
   361 
   362     Count_unknownbecomesclient(sptr, UserStats);
   363 
   364     if (MyConnect(sptr) && feature_bool(FEAT_AUTOINVISIBLE))
   365       SetInvisible(sptr);
   366     
   367     if(MyConnect(sptr) && feature_bool(FEAT_SETHOST_AUTO)) {
   368       if (conf_check_slines(sptr)) {
   369         send_reply(sptr, RPL_USINGSLINE);
   370         SetSetHost(sptr);
   371       }
   372     }
   373 
   374     SetUser(sptr);
   375     cli_handler(sptr) = CLIENT_HANDLER;
   376     SetLocalNumNick(sptr);
   377     send_reply(sptr,
   378                RPL_WELCOME,
   379                feature_str(FEAT_NETWORK),
   380                feature_str(FEAT_PROVIDER) ? " via " : "",
   381                feature_str(FEAT_PROVIDER) ? feature_str(FEAT_PROVIDER) : "",
   382                cli_name(sptr));
   383     /*
   384      * This is a duplicate of the NOTICE but see below...
   385      */
   386     send_reply(sptr, RPL_YOURHOST, cli_name(&me), version);
   387     send_reply(sptr, RPL_CREATED, creation);
   388     send_reply(sptr, RPL_MYINFO, cli_name(&me), version, infousermodes,
   389                infochanmodes, infochanmodeswithparams);
   390     send_supported(sptr);
   391     m_lusers(sptr, sptr, 1, parv);
   392     update_load();
   393     motd_signon(sptr);
   394     if (cli_snomask(sptr) & SNO_NOISY)
   395       set_snomask(sptr, cli_snomask(sptr) & SNO_NOISY, SNO_ADD);
   396     if (feature_bool(FEAT_CONNEXIT_NOTICES))
   397       sendto_opmask_butone(0, SNO_CONNEXIT,
   398                            "Client connecting: %s (%s@%s) [%s] {%s} [%s] <%s%s>",
   399                            cli_name(sptr), user->username, user->host,
   400                            cli_sock_ip(sptr), get_client_class(sptr),
   401                            cli_info(sptr), NumNick(cptr) /* two %s's */);
   402 
   403     IPcheck_connect_succeeded(sptr);
   404     /*
   405      * Set user's initial modes
   406      */
   407     tmpstr = (char*)client_get_default_umode(sptr);
   408     if (tmpstr) {
   409       char *umodev[] = { NULL, NULL, NULL, NULL };
   410       umodev[2] = tmpstr;
   411       set_user_mode(cptr, sptr, 1, umodev, ALLOWMODES_ANY);
   412     }
   413 
   414   }
   415   else {
   416     struct Client *acptr = user->server;
   417 
   418     if (cli_from(acptr) != cli_from(sptr))
   419     {
   420       sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (%s != %s[%s])",
   421                     sptr, cli_name(&me), cli_name(user->server), cli_name(cli_from(acptr)),
   422                     cli_sockhost(cli_from(acptr)));
   423       SetFlag(sptr, FLAG_KILLED);
   424       return exit_client(cptr, sptr, &me, "NICK server wrong direction");
   425     }
   426     else if (HasFlag(acptr, FLAG_TS8))
   427       SetFlag(sptr, FLAG_TS8);
   428 
   429     /*
   430      * Check to see if this user is being propagated
   431      * as part of a net.burst, or is using protocol 9.
   432      * FIXME: This can be sped up - its stupid to check it for
   433      * every NICK message in a burst again  --Run.
   434      */
   435     for (; acptr != &me; acptr = cli_serv(acptr)->up)
   436     {
   437       if (IsBurst(acptr) || Protocol(acptr) < 10)
   438         break;
   439     }
   440     if (!IPcheck_remote_connect(sptr, (acptr != &me)))
   441     {
   442       /*
   443        * We ran out of bits to count this
   444        */
   445       sendcmdto_one(&me, CMD_KILL, sptr, "%C :%s (Too many connections from your host -- Ghost)",
   446                     sptr, cli_name(&me));
   447       return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
   448     }
   449 
   450     if(MyConnect(sptr) && feature_bool(FEAT_SETHOST_AUTO)) {
   451       if (conf_check_slines(sptr)) {
   452         send_reply(sptr, RPL_USINGSLINE);
   453         SetSetHost(sptr);
   454       }
   455     }
   456 
   457     SetUser(sptr);
   458   }
   459 
   460   /* If they get both +x and an account during registration, hide
   461    * their hostmask here.  Calling hide_hostmask() from IAuth's
   462    * account assignment causes a numeric reply during registration.
   463    */
   464   if (HasHiddenHost(sptr))
   465     hide_hostmask(sptr, FLAG_HIDDENHOST);
   466   if (IsInvisible(sptr))
   467     ++UserStats.inv_clients;
   468   if (IsOper(sptr))
   469     ++UserStats.opers;
   470 
   471   tmpstr = umode_str(sptr, 0);
   472 
   473   /* Do not send oper name and send full IP address to IPv6-grokking servers. */
   474   sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
   475                              FLAG_IPV6, FLAG_OPERNAME,
   476                              "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
   477                              cli_name(sptr), cli_hopcount(sptr) + 1,
   478                              cli_lastnick(sptr),
   479                              user->realusername, user->realhost,
   480                              *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
   481                              iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
   482                              NumNick(sptr), cli_info(sptr));
   483   /* Do not send oper name and send fake IPv6 addresses to pre-IPv6 servers. */
   484   sendcmdto_flagarray_serv_butone(user->server, CMD_NICK, cptr,
   485                              NULL, 0, ipv6andopername, 2,
   486                              "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
   487                              cli_name(sptr), cli_hopcount(sptr) + 1,
   488                              cli_lastnick(sptr),
   489                              user->realusername, user->realhost,
   490                              *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
   491                              iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
   492                              NumNick(sptr), cli_info(sptr));
   493 
   494   tmpstr = umode_str(sptr, 1);
   495   /* Send oper name and full IP address to IPv6-grokking servers. */
   496   sendcmdto_flagarray_serv_butone(user->server, CMD_NICK, cptr,
   497                              ipv6andopername, 2, NULL, 0,
   498                              "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
   499                              cli_name(sptr), cli_hopcount(sptr) + 1,
   500                              cli_lastnick(sptr),
   501                              user->realusername, user->realhost,
   502                              *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
   503                              iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
   504                              NumNick(sptr), cli_info(sptr));
   505   /* Send oper name and fake IPv6 addresses to pre-IPv6 servers. */
   506   sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
   507                              FLAG_OPERNAME, FLAG_IPV6,
   508                              "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
   509                              cli_name(sptr), cli_hopcount(sptr) + 1,
   510                              cli_lastnick(sptr),
   511                              user->realusername, user->realhost,
   512                              *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
   513                              iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
   514                              NumNick(sptr), cli_info(sptr));
   515 
   516   /* Send user mode to client */
   517   if (MyUser(sptr))
   518   {
   519     static struct Flags flags; /* automatically initialized to zeros */
   520     /* To avoid sending +r to the client due to auth-on-connect, set
   521      * the "old" FLAG_ACCOUNT bit to match the client's value.
   522      */
   523     if (IsAccount(cptr))
   524       FlagSet(&flags, FLAG_ACCOUNT);
   525     else
   526       FlagClr(&flags, FLAG_ACCOUNT);
   527     client_set_privs(sptr, NULL);
   528     send_umode(cptr, sptr, &flags, ALL_UMODES, 0);
   529     if ((cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
   530       send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
   531   }
   532   return 0;
   533 }
   534 
   535 /** List of user mode characters. */
   536 static const struct UserMode {
   537   unsigned int flag; /**< User mode constant. */
   538   char         c;    /**< Character corresponding to the mode. */
   539 } userModeList[] = {
   540   { FLAG_OPER,        'o' },
   541   { FLAG_LOCOP,       'O' },
   542   { FLAG_INVISIBLE,   'i' },
   543   { FLAG_WALLOP,      'w' },
   544   { FLAG_SERVNOTICE,  's' },
   545   { FLAG_DEAF,        'd' },
   546   { FLAG_CHSERV,      'k' },
   547   { FLAG_DEBUG,       'g' },
   548   { FLAG_ACCOUNT,     'r' },
   549   { FLAG_HIDDENHOST,  'x' },
   550   { FLAG_ACCOUNTONLY, 'R' },
   551   { FLAG_XTRAOP,      'X' },
   552   { FLAG_NOCHAN,      'n' },
   553   { FLAG_NOIDLE,      'I' },
   554   { FLAG_SETHOST,     'h' },
   555   { FLAG_PARANOID,    'P' }
   556 };
   557 
   558 /** Length of #userModeList. */
   559 #define USERMODELIST_SIZE sizeof(userModeList) / sizeof(struct UserMode)
   560 
   561 /*
   562  * XXX - find a way to get rid of this
   563  */
   564 /** Nasty global buffer used for communications with umode_str() and others. */
   565 static char umodeBuf[BUFSIZE];
   566 
   567 /** Try to set a user's nickname.
   568  * If \a sptr is a server, the client is being introduced for the first time.
   569  * @param[in] cptr Client to set nickname.
   570  * @param[in] sptr Client sending the NICK.
   571  * @param[in] nick New nickname.
   572  * @param[in] parc Number of arguments to NICK.
   573  * @param[in] parv Argument list to NICK.
   574  * @return CPTR_KILLED if \a cptr was killed, else 0.
   575  */
   576 int set_nick_name(struct Client* cptr, struct Client* sptr,
   577                   const char* nick, int parc, char* parv[])
   578 {
   579   if (IsServer(sptr)) {
   580     /*
   581      * A server introducing a new client, change source
   582      */
   583     struct Client* new_client = make_client(cptr, STAT_UNKNOWN);
   584     assert(0 != new_client);
   585 
   586     cli_hopcount(new_client) = atoi(parv[2]);
   587     cli_lastnick(new_client) = atoi(parv[3]);
   588 
   589     /*
   590      * Set new nick name.
   591      */
   592     strcpy(cli_name(new_client), nick);
   593     cli_user(new_client) = make_user(new_client);
   594     cli_user(new_client)->server = sptr;
   595     SetRemoteNumNick(new_client, parv[parc - 2]);
   596     /*
   597      * IP# of remote client
   598      */
   599     base64toip(parv[parc - 3], &cli_ip(new_client));
   600 
   601     add_client_to_list(new_client);
   602     hAddClient(new_client);
   603 
   604     cli_serv(sptr)->ghost = 0;        /* :server NICK means end of net.burst */
   605     ircd_strncpy(cli_username(new_client), parv[4], USERLEN);
   606     ircd_strncpy(cli_user(new_client)->username, parv[4], USERLEN);
   607     ircd_strncpy(cli_user(new_client)->realusername, parv[4], USERLEN);
   608     ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
   609     ircd_strncpy(cli_user(new_client)->realhost, parv[5], HOSTLEN);
   610     ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
   611 
   612     Count_newremoteclient(UserStats, sptr);
   613 
   614     if (parc > 7 && *parv[6] == '+') {
   615       /* (parc-4) -3 for the ip, numeric nick, realname */
   616       set_user_mode(cptr, new_client, parc-7, parv+4, ALLOWMODES_ANY);
   617     }
   618 
   619     return register_user(cptr, new_client);
   620   }
   621   else if ((cli_name(sptr))[0]) {
   622     /*
   623      * Client changing its nick
   624      *
   625      * If the client belongs to me, then check to see
   626      * if client is on any channels where it is currently
   627      * banned.  If so, do not allow the nick change to occur.
   628      */
   629     if (MyUser(sptr)) {
   630       const char* channel_name;
   631       struct Membership *member;
   632       if ((channel_name = find_no_nickchange_channel(sptr)) && !IsXtraOp(sptr)) {
   633         return send_reply(cptr, ERR_BANNICKCHANGE, channel_name);
   634       }
   635       /*
   636        * Refuse nick change if the last nick change was less
   637        * then 30 seconds ago. This is intended to get rid of
   638        * clone bots doing NICK FLOOD. -SeKs
   639        * If someone didn't change their nick for more then 60 seconds
   640        * however, allow to do two nick changes immediately after another
   641        * before limiting the nick flood. -Run
   642        */
   643       if (CurrentTime < cli_nextnick(cptr))
   644       {
   645         cli_nextnick(cptr) += 2;
   646         send_reply(cptr, ERR_NICKTOOFAST, parv[1],
   647                    cli_nextnick(cptr) - CurrentTime);
   648         /* Send error message */
   649         sendcmdto_one(cptr, CMD_NICK, cptr, "%s", cli_name(cptr));
   650         /* bounce NICK to user */
   651         return 0;                /* ignore nick change! */
   652       }
   653       else {
   654         /* Limit total to 1 change per NICK_DELAY seconds: */
   655         cli_nextnick(cptr) += NICK_DELAY;
   656         /* However allow _maximal_ 1 extra consecutive nick change: */
   657         if (cli_nextnick(cptr) < CurrentTime)
   658           cli_nextnick(cptr) = CurrentTime;
   659       }
   660       /* Invalidate all bans against the user so we check them again */
   661       for (member = (cli_user(cptr))->channel; member;
   662 	   member = member->next_channel)
   663 	ClearBanValid(member);
   664     }
   665     /*
   666      * Also set 'lastnick' to current time, if changed.
   667      */
   668     if (0 != ircd_strcmp(parv[0], nick))
   669       cli_lastnick(sptr) = (sptr == cptr) ? TStime() : atoi(parv[2]);
   670 
   671     /*
   672      * Client just changing his/her nick. If he/she is
   673      * on a channel, send note of change to all clients
   674      * on that channel. Propagate notice to other servers.
   675      */
   676     if (IsUser(sptr)) {
   677       sendcmdto_common_channels_butone(sptr, CMD_NICK, NULL, ":%s", nick);
   678       add_history(sptr, 1);
   679       sendcmdto_serv_butone(sptr, CMD_NICK, cptr, "%s %Tu", nick,
   680                             cli_lastnick(sptr));
   681     }
   682     else
   683       sendcmdto_one(sptr, CMD_NICK, sptr, ":%s", nick);
   684 
   685     if ((cli_name(sptr))[0])
   686       hRemClient(sptr);
   687     strcpy(cli_name(sptr), nick);
   688     hAddClient(sptr);
   689   }
   690   else {
   691     /* Local client setting NICK the first time */
   692     strcpy(cli_name(sptr), nick);
   693     hAddClient(sptr);
   694     return auth_set_nick(cli_auth(sptr), nick);
   695   }
   696   return 0;
   697 }
   698 
   699 /** Calculate the hash value for a target.
   700  * @param[in] target Pointer to target, cast to unsigned int.
   701  * @return Hash value constructed from the pointer.
   702  */
   703 static unsigned char hash_target(unsigned int target)
   704 {
   705   return (unsigned char) (target >> 16) ^ (target >> 8);
   706 }
   707 
   708 /** Records \a target as a recent target for \a sptr.
   709  * @param[in] sptr User who has sent to a new target.
   710  * @param[in] target Target to add.
   711  */
   712 void
   713 add_target(struct Client *sptr, void *target)
   714 {
   715   /* Ok, this shouldn't work esp on alpha
   716   */
   717   unsigned char  hash = hash_target((unsigned long) target);
   718   unsigned char* targets;
   719   int            i;
   720   assert(0 != sptr);
   721   assert(cli_local(sptr));
   722 
   723   targets = cli_targets(sptr);
   724 
   725   /* 
   726    * Already in table?
   727    */
   728   for (i = 0; i < MAXTARGETS; ++i) {
   729     if (targets[i] == hash)
   730       return;
   731   }
   732   /*
   733    * New target
   734    */
   735   memmove(&targets[RESERVEDTARGETS + 1],
   736           &targets[RESERVEDTARGETS], MAXTARGETS - RESERVEDTARGETS - 1);
   737   targets[RESERVEDTARGETS] = hash;
   738 }
   739 
   740 /** Check whether \a sptr can send to or join \a target yet.
   741  * @param[in] sptr User trying to join a channel or send a message.
   742  * @param[in] target Target of the join or message.
   743  * @param[in] name Name of the target.
   744  * @param[in] created If non-zero, trying to join a new channel.
   745  * @return Non-zero if too many target changes; zero if okay to send.
   746  */
   747 int check_target_limit(struct Client *sptr, void *target, const char *name,
   748     int created)
   749 {
   750   unsigned char hash = hash_target((unsigned long) target);
   751   int            i;
   752   unsigned char* targets;
   753 
   754   assert(0 != sptr);
   755   assert(cli_local(sptr));
   756   targets = cli_targets(sptr);
   757 
   758   /* If user is invited to channel, give him/her a free target */
   759   if (IsChannelName(name) && IsInvited(sptr, target))
   760     return 0;
   761 
   762   /* opers always have a free target */
   763   if (IsAnOper(sptr))
   764     return 0;
   765 
   766   /*
   767    * Same target as last time?
   768    */
   769   if (targets[0] == hash)
   770     return 0;
   771   for (i = 1; i < MAXTARGETS; ++i) {
   772     if (targets[i] == hash) {
   773       memmove(&targets[1], &targets[0], i);
   774       targets[0] = hash;
   775       return 0;
   776     }
   777   }
   778   /*
   779    * New target
   780    */
   781   if (!created) {
   782     if (CurrentTime < cli_nexttarget(sptr)) {
   783       if (cli_nexttarget(sptr) - CurrentTime < TARGET_DELAY + 8) {
   784         /*
   785          * No server flooding
   786          */
   787         cli_nexttarget(sptr) += 2;
   788         send_reply(sptr, ERR_TARGETTOOFAST, name,
   789                    cli_nexttarget(sptr) - CurrentTime);
   790       }
   791       return 1;
   792     }
   793     else {
   794       cli_nexttarget(sptr) += TARGET_DELAY;
   795       if (cli_nexttarget(sptr) < CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1)))
   796         cli_nexttarget(sptr) = CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1));
   797     }
   798   }
   799   memmove(&targets[1], &targets[0], MAXTARGETS - 1);
   800   targets[0] = hash;
   801   return 0;
   802 }
   803 
   804 /** Allows a channel operator to avoid target change checks when
   805  * sending messages to users on their channel.
   806  * @param[in] source User sending the message.
   807  * @param[in] nick Destination of the message.
   808  * @param[in] channel Name of channel being sent to.
   809  * @param[in] text Message to send.
   810  * @param[in] is_notice If non-zero, use CNOTICE instead of CPRIVMSG.
   811  */
   812 /* Added 971023 by Run. */
   813 int whisper(struct Client* source, const char* nick, const char* channel,
   814             const char* text, int is_notice)
   815 {
   816   struct Client*     dest;
   817   struct Channel*    chptr;
   818   struct Membership* membership;
   819 
   820   assert(0 != source);
   821   assert(0 != nick);
   822   assert(0 != channel);
   823   assert(MyUser(source));
   824 
   825   if (!(dest = FindUser(nick))) {
   826     return send_reply(source, ERR_NOSUCHNICK, nick);
   827   }
   828   if (!(chptr = FindChannel(channel))) {
   829     return send_reply(source, ERR_NOSUCHCHANNEL, channel);
   830   }
   831   /*
   832    * compare both users channel lists, instead of the channels user list
   833    * since the link is the same, this should be a little faster for channels
   834    * with a lot of users
   835    */
   836   for (membership = cli_user(source)->channel; membership; membership = membership->next_channel) {
   837     if (chptr == membership->channel)
   838       break;
   839   }
   840   if (0 == membership) {
   841     return send_reply(source, ERR_NOTONCHANNEL, chptr->chname);
   842   }
   843   if (!IsVoicedOrOpped(membership)) {
   844     return send_reply(source, ERR_VOICENEEDED, chptr->chname);
   845   }
   846   /*
   847    * lookup channel in destination
   848    */
   849   assert(0 != cli_user(dest));
   850   for (membership = cli_user(dest)->channel; membership; membership = membership->next_channel) {
   851     if (chptr == membership->channel)
   852       break;
   853   }
   854   if (0 == membership || IsZombie(membership)) {
   855     return send_reply(source, ERR_USERNOTINCHANNEL, cli_name(dest), chptr->chname);
   856   }
   857   if (is_silenced(source, dest))
   858     return 0;
   859 
   860   if (IsAccountOnly(dest) && !IsAccount(source) && !IsOper(source)) {
   861     if(!is_notice)
   862       send_reply(source, ERR_ACCOUNTONLY, cli_name(source), feature_str(FEAT_URLREG));
   863     return 0;
   864   }
   865           
   866   if (is_notice)
   867     sendcmdto_one(source, CMD_NOTICE, dest, "%C :%s", dest, text);
   868   else
   869   {
   870     if (cli_user(dest)->away)
   871       send_reply(source, RPL_AWAY, cli_name(dest), cli_user(dest)->away);
   872     sendcmdto_one(source, CMD_PRIVATE, dest, "%C :%s", dest, text);
   873   }
   874   return 0;
   875 }
   876 
   877 
   878 /** Send a user mode change for \a cptr to neighboring servers.
   879  * @param[in] cptr User whose mode is changing.
   880  * @param[in] sptr Client who sent us the mode change message.
   881  * @param[in] old Prior set of user flags.
   882  * @param[in] prop If non-zero, also include FLAG_OPER.
   883  */
   884 void send_umode_out(struct Client *cptr, struct Client *sptr,
   885                     struct Flags *old, int prop)
   886 {
   887   int i;
   888   struct Client *acptr;
   889 
   890   send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 0);
   891 
   892   for (i = HighestFd; i >= 0; i--)
   893   {
   894     if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
   895         (acptr != cptr) && (acptr != sptr) && !IsSendOperName(acptr) && *umodeBuf)
   896         sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
   897   }
   898 
   899   send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 1);
   900 
   901   for (i = HighestFd; i >= 0; i--)
   902   {
   903     if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
   904         (acptr != cptr) && (acptr != sptr) && IsSendOperName(acptr) && *umodeBuf)
   905         sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
   906   }
   907 
   908   if (cptr && MyUser(cptr))
   909     send_umode(cptr, sptr, old, ALL_UMODES, 0);
   910 }
   911 
   912 
   913 /** Call \a fmt for each Client named in \a names.
   914  * @param[in] sptr Client requesting information.
   915  * @param[in] names Space-delimited list of nicknames.
   916  * @param[in] rpl Base reply string for messages.
   917  * @param[in] fmt Formatting callback function.
   918  */
   919 void send_user_info(struct Client* sptr, char* names, int rpl, InfoFormatter fmt)
   920 {
   921   char*          name;
   922   char*          p = 0;
   923   int            arg_count = 0;
   924   int            users_found = 0;
   925   struct Client* acptr;
   926   struct MsgBuf* mb;
   927 
   928   assert(0 != sptr);
   929   assert(0 != names);
   930   assert(0 != fmt);
   931 
   932   mb = msgq_make(sptr, rpl_str(rpl), cli_name(&me), cli_name(sptr));
   933 
   934   for (name = ircd_strtok(&p, names, " "); name; name = ircd_strtok(&p, 0, " ")) {
   935     if ((acptr = FindUser(name))) {
   936       if (users_found++)
   937 	msgq_append(0, mb, " ");
   938       (*fmt)(acptr, sptr, mb);
   939     }
   940     if (5 == ++arg_count)
   941       break;
   942   }
   943   send_buffer(sptr, mb, 0);
   944   msgq_clean(mb);
   945 }
   946 
   947 /** Set \a flag on \a cptr and possibly hide the client's hostmask.
   948  * @param[in,out] cptr User who is getting a new flag.
   949  * @param[in] flag Some flag that affects host-hiding (FLAG_HIDDENHOST, FLAG_ACCOUNT).
   950  * @return Zero.
   951  */
   952 int
   953 hide_hostmask(struct Client *cptr, unsigned int flag)
   954 {
   955   struct Membership *chan;
   956 
   957   switch (flag) {
   958   case FLAG_HIDDENHOST:
   959     /* Local users cannot set +x unless FEAT_HOST_HIDING is true. */
   960     if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING))
   961       return 0;
   962     break;
   963   case FLAG_ACCOUNT:
   964     /* Invalidate all bans against the user so we check them again */
   965     for (chan = (cli_user(cptr))->channel; chan;
   966          chan = chan->next_channel)
   967       ClearBanValid(chan);
   968     break;
   969   default:
   970     return 0;
   971   }
   972 
   973   SetFlag(cptr, flag);
   974   if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || HasSetHost(cptr))
   975     return 0;
   976 
   977   sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered");
   978   ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
   979                 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
   980 
   981   /* ok, the client is now fully hidden, so let them know -- hikari */
   982   if (MyConnect(cptr))
   983    send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->host);
   984 
   985   /*
   986    * Go through all channels the client was on, rejoin him
   987    * and set the modes, if any
   988    */
   989   for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel)
   990   {
   991     if (IsZombie(chan))
   992       continue;
   993     /* Send a JOIN unless the user's join has been delayed. */
   994     if (!IsDelayedJoin(chan))
   995       sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
   996                                          "%H", chan->channel);
   997     if (IsChanOp(chan) && HasVoice(chan))
   998       sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
   999                                        "%H +ov %C %C", chan->channel, cptr,
  1000                                        cptr);
  1001     else if (IsChanOp(chan) || HasVoice(chan))
  1002       sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
  1003         "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
  1004   }
  1005   return 0;
  1006 }
  1007 
  1008 /*
  1009  * set_hostmask() - derived from hide_hostmask()
  1010  *
  1011  */
  1012 int set_hostmask(struct Client *cptr, char *hostmask, char *password)
  1013 {
  1014   int restore = 0;
  1015   int freeform = 0;
  1016   char *host, *new_vhost, *vhost_pass;
  1017   char hiddenhost[USERLEN + HOSTLEN + 2];
  1018   struct Membership *chan;
  1019 
  1020   Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
  1021 
  1022   /* sethost enabled? */
  1023   if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) {
  1024     send_reply(cptr, ERR_DISABLED, "SETHOST");
  1025     return 0;
  1026   }
  1027 
  1028   /* sethost enabled for users? */
  1029   if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
  1030     send_reply(cptr, ERR_NOPRIVILEGES);
  1031     return 0;
  1032   }
  1033  
  1034   /* MODE_DEL: restore original hostmask */
  1035   if (EmptyString(hostmask)) {
  1036     /* is already sethost'ed? and only opers can remove a sethost */
  1037     if (IsSetHost(cptr) && IsAnOper(cptr)) {
  1038       restore = 1;
  1039       sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
  1040       /* If they are +rx, we need to return to their +x host, not their "real" host */
  1041       if (HasHiddenHost(cptr))
  1042         ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
  1043           cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
  1044       else
  1045         strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
  1046       strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
  1047       /* log it */
  1048       if (MyConnect(cptr))
  1049         log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
  1050             "SETHOST (%s@%s) by (%#R): restoring real hostmask",
  1051             cli_user(cptr)->username, cli_user(cptr)->host, cptr);
  1052     } else
  1053       return 0;
  1054   /* MODE_ADD: set a new hostmask */
  1055   } else {
  1056     /* chop up ident and host.cc */
  1057     if ((host = strrchr(hostmask, '@'))) { /* oper can specifiy ident@host.cc */
  1058       *host++ = '\0';
  1059       if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host)) && (0 == strcmp(hostmask, cli_user(cptr)->username))) {
  1060         ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
  1061             cli_user(cptr)->username, cli_user(cptr)->host);
  1062         send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
  1063         return 0;
  1064       }
  1065     } else { /* user can only specifiy host.cc [password] */
  1066       host = hostmask;
  1067       if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host))) {
  1068         ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
  1069             cli_user(cptr)->username, cli_user(cptr)->host);
  1070         send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
  1071         return 0;
  1072       }
  1073     }
  1074     /*
  1075      * Oper sethost
  1076      */
  1077     if (MyConnect(cptr)) {
  1078       if (IsAnOper(cptr)) {
  1079         if ((new_vhost = IsVhost(host, 1)) == NULL) {
  1080           if (!HasPriv(cptr, PRIV_FREEFORM)) {
  1081             send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
  1082             log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
  1083                 "SETHOST (%s@%s) by (%#R): no such s-line",
  1084                 (host != hostmask) ? hostmask : cli_user(cptr)->username, host, cptr);
  1085             return 0;
  1086           } else /* freeform active, log and go */
  1087             freeform = 1;
  1088         }
  1089         sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
  1090         /* set the new ident and host */
  1091         if (host != hostmask) /* oper only specified host.cc */
  1092           strncpy(cli_user(cptr)->username, hostmask, USERLEN);
  1093         strncpy(cli_user(cptr)->host, host, HOSTLEN);
  1094         /* log it */
  1095         log_write(LS_SETHOST, (freeform) ? L_NOTICE : L_INFO,
  1096             (freeform) ? 0 : LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)%s",
  1097             cli_user(cptr)->username, cli_user(cptr)->host, cptr,
  1098             (freeform) ? ": using freeform" : "");
  1099       /*
  1100        * plain user sethost, handled here
  1101        */
  1102       } else {
  1103         /* empty password? */
  1104         if (EmptyString(password)) {
  1105           send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
  1106           return 0;
  1107         }
  1108         /* no such s-line */
  1109         if ((new_vhost = IsVhost(host, 0)) == NULL) {
  1110           send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
  1111           log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s %s) by (%#R): no such s-line",
  1112               cli_user(cptr)->username, host, password, cptr);
  1113           return 0;
  1114         }
  1115         /* no password */
  1116         if ((vhost_pass = IsVhostPass(new_vhost)) == NULL) {
  1117           send_reply(cptr, ERR_PASSWDMISMATCH);
  1118           log_write(LS_SETHOST, L_INFO, 0, "SETHOST (%s@%s %s) by (%#R): trying to use an oper s-line",
  1119               cli_user(cptr)->username, host, password, cptr);
  1120           return 0;
  1121         }
  1122         /* incorrect password */
  1123         if (strCasediff(vhost_pass, password)) {
  1124           send_reply(cptr, ERR_PASSWDMISMATCH);
  1125           log_write(LS_SETHOST, L_NOTICE, 0, "SETHOST (%s@%s %s) by (%#R): incorrect password",
  1126               cli_user(cptr)->username, host, password, cptr);
  1127           return 0;
  1128         }
  1129         sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
  1130         /* set the new host */
  1131         strncpy(cli_user(cptr)->host, new_vhost, HOSTLEN);
  1132         /* log it */
  1133         log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
  1134             cli_user(cptr)->username, cli_user(cptr)->host, cptr);
  1135       }
  1136     } else { /* remote user */
  1137         sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
  1138         if (host != hostmask) /* oper only specified host.cc */
  1139           strncpy(cli_user(cptr)->username, hostmask, USERLEN);
  1140         strncpy(cli_user(cptr)->host, host, HOSTLEN);
  1141     }
  1142   }
  1143 
  1144   if (restore)
  1145     ClearSetHost(cptr);
  1146   else
  1147     SetSetHost(cptr);
  1148 
  1149   if (MyConnect(cptr)) {
  1150     ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
  1151       cli_user(cptr)->username, cli_user(cptr)->host);
  1152     send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
  1153   }
  1154 
  1155 #if 0
  1156   /* Code copied from hide_hostmask().  This is the old (pre-delayedjoin) 
  1157    * version.  Switch this in if you're not using the delayed join patch. */
  1158   /*
  1159    * Go through all channels the client was on, rejoin him
  1160    * and set the modes, if any
  1161    */
  1162   for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
  1163     if (IsZombie(chan))
  1164       continue;
  1165     sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr,
  1166       "%H", chan->channel);
  1167     if (IsChanOp(chan) && HasVoice(chan)) {
  1168       sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
  1169         "%H +ov %C %C", chan->channel, cptr, cptr);
  1170     } else if (IsChanOp(chan) || HasVoice(chan)) {
  1171       sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
  1172         "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
  1173     }
  1174   }
  1175 #endif
  1176 
  1177   /*
  1178    * Go through all channels the client was on, rejoin him
  1179    * and set the modes, if any
  1180    */
  1181   for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
  1182     if (IsZombie(chan))
  1183       continue;
  1184     /* If this channel has delayed joins and the user has no modes, just set
  1185      * the delayed join flag rather than showing the join, even if the user
  1186      * was visible before */
  1187     if (!IsChanOp(chan) && !HasVoice(chan)
  1188         && (chan->channel->mode.mode & MODE_DELJOINS)) {
  1189       SetDelayedJoin(chan);
  1190     } else {
  1191       sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
  1192         "%H", chan->channel);
  1193     }
  1194     if (IsChanOp(chan) && HasVoice(chan)) {
  1195       sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
  1196         "%H +ov %C %C", chan->channel, cptr, cptr);
  1197     } else if (IsChanOp(chan) || HasVoice(chan)) {
  1198       sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
  1199         "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
  1200     }
  1201   }
  1202   return 1;
  1203 }
  1204 
  1205 /** Set a user's mode.  This function checks that \a cptr is trying to
  1206  * set his own mode, prevents local users from setting inappropriate
  1207  * modes through this function, and applies any other side effects of
  1208  * a successful mode change.
  1209  *
  1210  * @param[in,out] cptr User setting someone's mode.
  1211  * @param[in] sptr Client who sent the mode change message.
  1212  * @param[in] parc Number of parameters in \a parv.
  1213  * @param[in] parv Parameters to MODE.
  1214  * @param[in] allow_modes ALLOWMODES_ANY for any mode, ALLOWMODES_DEFAULT for 
  1215  *                        only permitting legitimate default user modes.
  1216  * @return Zero.
  1217  */
  1218 int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, 
  1219 		char *parv[], int allow_modes)
  1220 {
  1221   char** p;
  1222   char*  m;
  1223   int what;
  1224   int i;
  1225   struct Flags setflags;
  1226   unsigned int tmpmask = 0;
  1227   int snomask_given = 0;
  1228   char buf[BUFSIZE];
  1229   char *hostmask, *password;
  1230   int prop = 0;
  1231   int do_host_hiding = 0;
  1232   int do_set_host = 0;
  1233   size_t opernamelen;
  1234   char *opername = 0;
  1235   char* account = NULL;
  1236 
  1237   hostmask = password = NULL;
  1238   what = MODE_ADD;
  1239 
  1240   if (parc < 3)
  1241   {
  1242     m = buf;
  1243     *m++ = '+';
  1244     for (i = 0; i < USERMODELIST_SIZE; i++)
  1245     {
  1246       if (HasFlag(sptr, userModeList[i].flag) &&
  1247           ((userModeList[i].flag != FLAG_ACCOUNT) &&
  1248           (userModeList[i].flag != FLAG_SETHOST)))
  1249         *m++ = userModeList[i].c;
  1250     }
  1251     *m = '\0';
  1252     send_reply(sptr, RPL_UMODEIS, buf);
  1253     if (HasFlag(sptr, FLAG_SERVNOTICE) && MyConnect(sptr)
  1254         && cli_snomask(sptr) !=
  1255         (unsigned int)(IsOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT))
  1256       send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
  1257     return 0;
  1258   }
  1259 
  1260   /*
  1261    * find flags already set for user
  1262    * why not just copy them?
  1263    */
  1264   setflags = cli_flags(sptr);
  1265 
  1266   if (MyConnect(sptr))
  1267     tmpmask = cli_snomask(sptr);
  1268 
  1269   /*
  1270    * parse mode change string(s)
  1271    */
  1272   for (p = &parv[2]; *p && p<&parv[parc]; p++) {       /* p is changed in loop too */
  1273     for (m = *p; *m; m++) {
  1274       switch (*m) {
  1275       case '+':
  1276         what = MODE_ADD;
  1277         break;
  1278       case '-':
  1279         what = MODE_DEL;
  1280         break;
  1281       case 's':
  1282         if (*(p + 1) && is_snomask(*(p + 1))) {
  1283           snomask_given = 1;
  1284           tmpmask = umode_make_snomask(tmpmask, *++p, what);
  1285           tmpmask &= (IsAnOper(sptr) ? SNO_ALL : SNO_USER);
  1286         }
  1287         else
  1288           tmpmask = (what == MODE_ADD) ?
  1289               (IsAnOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT) : 0;
  1290         if (tmpmask)
  1291 	  SetServNotice(sptr);
  1292         else
  1293 	  ClearServNotice(sptr);
  1294         break;
  1295       case 'w':
  1296         if (what == MODE_ADD)
  1297           SetWallops(sptr);
  1298         else
  1299           ClearWallops(sptr);
  1300         break;
  1301       case 'o':
  1302         if (what == MODE_ADD) {
  1303           SetOper(sptr);
  1304           if (IsServer(cptr) && IsSendOperName(cptr)) {
  1305             if (*(p + 1)) {
  1306               opername = *++p;
  1307               if (cli_user(sptr)->opername)
  1308                 MyFree(cli_user(sptr)->opername);
  1309               if ((opername[0] == NOOPERNAMECHARACTER) && (opername[1] == '\0')) {
  1310                 cli_user(sptr)->opername = NULL;
  1311               } else {
  1312                 opernamelen = strlen(opername);
  1313                 if (opernamelen > ACCOUNTLEN) {
  1314                   protocol_violation(cptr, "Received opername (%s) longer than %d for %s; ignoring.", opername, ACCOUNTLEN, cli_name(sptr));
  1315                   cli_user(sptr)->opername = NULL;
  1316                 } else {
  1317                   cli_user(sptr)->opername = (char*) MyMalloc(opernamelen + 1);
  1318                   assert(0 != cli_user(sptr)->opername);
  1319                   ircd_strncpy(cli_user(sptr)->opername,opername,ACCOUNTLEN);
  1320                 }
  1321               }
  1322             }
  1323           }
  1324         } else {
  1325           ClrFlag(sptr, FLAG_OPER);
  1326           ClrFlag(sptr, FLAG_LOCOP);
  1327           if (MyConnect(sptr))
  1328           {
  1329             tmpmask = cli_snomask(sptr) & ~SNO_OPER;
  1330             cli_handler(sptr) = CLIENT_HANDLER;
  1331           }
  1332         }
  1333         break;
  1334       case 'O':
  1335         if (what == MODE_ADD)
  1336           SetLocOp(sptr);
  1337         else
  1338         { 
  1339           ClrFlag(sptr, FLAG_OPER);
  1340           ClrFlag(sptr, FLAG_LOCOP);
  1341           if (MyConnect(sptr))
  1342           {
  1343             tmpmask = cli_snomask(sptr) & ~SNO_OPER;
  1344             cli_handler(sptr) = CLIENT_HANDLER;
  1345           }
  1346         }
  1347         break;
  1348       case 'i':
  1349         if (what == MODE_ADD)
  1350           SetInvisible(sptr);
  1351         else
  1352           if (!feature_bool(FEAT_AUTOINVISIBLE) || IsOper(sptr)) /* Don't allow non-opers to -i if FEAT_AUTOINVISIBLE is set */
  1353             ClearInvisible(sptr);
  1354         break;
  1355       case 'd':
  1356         if (what == MODE_ADD)
  1357           SetDeaf(sptr);
  1358         else
  1359           ClearDeaf(sptr);
  1360         break;
  1361       case 'k':
  1362         if (what == MODE_ADD)
  1363           SetChannelService(sptr);
  1364         else
  1365           ClearChannelService(sptr);
  1366         break;
  1367       case 'X':
  1368         if (what == MODE_ADD)
  1369           SetXtraOp(sptr);
  1370         else
  1371           ClearXtraOp(sptr);
  1372         break;
  1373       case 'n':
  1374         if (what == MODE_ADD)
  1375           SetNoChan(sptr);
  1376         else
  1377           ClearNoChan(sptr);
  1378         break;
  1379       case 'I':
  1380         if (what == MODE_ADD)
  1381           SetNoIdle(sptr);
  1382         else
  1383           ClearNoIdle(sptr);
  1384         break;
  1385       case 'g':
  1386         if (what == MODE_ADD)
  1387           SetDebug(sptr);
  1388         else
  1389           ClearDebug(sptr);
  1390         break;
  1391       case 'x':
  1392         if (what == MODE_ADD)
  1393           do_host_hiding = 1;
  1394          break;
  1395       case 'h':
  1396          if (what == MODE_ADD) {
  1397            if (*(p + 1) && is_hostmask(*(p + 1))) {
  1398              do_set_host = 1;
  1399              hostmask = *++p;
  1400              /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
  1401              if (*(p+1))
  1402                password = *++p;
  1403              else
  1404                password = NULL;
  1405            } else {
  1406              if (!*(p+1))
  1407                send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
  1408              else {
  1409                send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
  1410                p++; /* Swallow the arg anyway */
  1411              }
  1412            }
  1413          } else { /* MODE_DEL */
  1414            do_set_host = 1;
  1415            hostmask = NULL;
  1416            password = NULL;
  1417          }
  1418          break;
  1419       case 'R':
  1420         if (what == MODE_ADD)
  1421           SetAccountOnly(sptr);
  1422         else
  1423           ClearAccountOnly(sptr);
  1424         break;
  1425       case 'P':
  1426 	if (what == MODE_ADD)
  1427           SetParanoid(sptr);
  1428         else
  1429           ClearParanoid(sptr);
  1430 	break;
  1431       case 'r':
  1432 	if ((what == MODE_ADD) && *(p + 1)) {
  1433 	  account = *(++p);
  1434 	  SetAccount(sptr);
  1435 	}
  1436 	/* There is no -r */
  1437 	break;
  1438       default:
  1439         send_reply(sptr, ERR_UMODEUNKNOWNFLAG, *m);
  1440         break;
  1441       }
  1442     }
  1443   }
  1444   /*
  1445    * Evaluate rules for new user mode
  1446    * Stop users making themselves operators too easily:
  1447    */
  1448   if (!IsServer(cptr))
  1449   {
  1450     if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr))
  1451       ClearOper(sptr);
  1452     if (!FlagHas(&setflags, FLAG_LOCOP) && IsLocOp(sptr))
  1453       ClearLocOp(sptr);
  1454     if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr))
  1455       ClrFlag(sptr, FLAG_ACCOUNT);
  1456     /*
  1457      * new umode; servers can set it, local users cannot;
  1458      * prevents users from /kick'ing or /mode -o'ing
  1459      */
  1460     if (!FlagHas(&setflags, FLAG_CHSERV) && !(IsOper(sptr) && HasPriv(sptr, PRIV_CHANSERV)))
  1461       ClearChannelService(sptr);
  1462     if (!FlagHas(&setflags, FLAG_XTRAOP) && !(IsOper(sptr) && HasPriv(sptr, PRIV_XTRA_OPER)))
  1463       ClearXtraOp(sptr);
  1464     if (!FlagHas(&setflags, FLAG_NOCHAN) && !(IsOper(sptr) || feature_bool(FEAT_USER_HIDECHANS)))
  1465       ClearNoChan(sptr);
  1466     if (!FlagHas(&setflags, FLAG_NOIDLE) && !((IsOper(sptr) && HasPriv(sptr, PRIV_NOIDLE)) || feature_bool(FEAT_USER_HIDEIDLETIME)))
  1467       ClearNoIdle(sptr);
  1468     if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID)))
  1469       ClearParanoid(sptr);
  1470 
  1471     /*
  1472      * only send wallops to opers
  1473      */
  1474     if (feature_bool(FEAT_WALLOPS_OPER_ONLY) && !IsAnOper(sptr) &&
  1475 	!FlagHas(&setflags, FLAG_WALLOP))
  1476       ClearWallops(sptr);
  1477     if (feature_bool(FEAT_HIS_SNOTICES_OPER_ONLY) && MyConnect(sptr) &&
  1478         !IsAnOper(sptr) && !FlagHas(&setflags, FLAG_SERVNOTICE))
  1479     {
  1480       ClearServNotice(sptr);
  1481       set_snomask(sptr, 0, SNO_SET);
  1482     }
  1483     if (feature_bool(FEAT_HIS_DEBUG_OPER_ONLY) &&
  1484         !IsAnOper(sptr) && !FlagHas(&setflags, FLAG_DEBUG))
  1485       ClearDebug(sptr);
  1486   }
  1487   if (MyConnect(sptr))
  1488   {
  1489     if ((FlagHas(&setflags, FLAG_OPER) || FlagHas(&setflags, FLAG_LOCOP)) &&
  1490         !IsAnOper(sptr))
  1491       det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPERATOR);
  1492 
  1493     if (SendServNotice(sptr))
  1494     {
  1495       if (tmpmask != cli_snomask(sptr))
  1496 	set_snomask(sptr, tmpmask, SNO_SET);
  1497       if (cli_snomask(sptr) && snomask_given)
  1498 	send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
  1499     }
  1500     else
  1501       set_snomask(sptr, 0, SNO_SET);
  1502   }
  1503   /*
  1504    * Compare new flags with old flags and send string which
  1505    * will cause servers to update correctly.
  1506    */
  1507   if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr)) {
  1508       int len = ACCOUNTLEN;
  1509       char *pts, *ts;
  1510       if ((ts = strchr(account, ':'))) {
  1511 	len = (ts++) - account;
  1512 	cli_user(sptr)->acc_create = atoi(ts);
  1513         if ((pts = strchr(ts, ':')))
  1514 	  cli_user(sptr)->acc_id = strtoul(pts + 1, NULL, 10);
  1515         Debug((DEBUG_DEBUG, "Received timestamped account in user mode; "
  1516 	      "account \"%s\", timestamp %Tu, id %lu", account,
  1517 	      cli_user(sptr)->acc_create,
  1518 	      cli_user(sptr)->acc_id));
  1519       }
  1520       ircd_strncpy(cli_user(sptr)->account, account, len);
  1521   }
  1522   if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
  1523     hide_hostmask(sptr, FLAG_HIDDENHOST);
  1524   if (do_set_host) {
  1525     /* We clear the flag in the old mask, so that the +h will be sent */
  1526     /* Only do this if we're SETTING +h and it succeeded */
  1527     if (set_hostmask(sptr, hostmask, password) && hostmask)
  1528       FlagClr(&setflags, FLAG_SETHOST);
  1529   }
  1530 
  1531   if (IsRegistered(sptr)) {
  1532     if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr)) {
  1533       /* user now oper */
  1534       ++UserStats.opers;
  1535       client_set_privs(sptr, NULL); /* may set propagate privilege */
  1536     }
  1537     /* remember propagate privilege setting */
  1538     if (HasPriv(sptr, PRIV_PROPAGATE)) {
  1539       prop = 1;
  1540     }
  1541     if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr)) {
  1542       /* user no longer oper */
  1543       assert(UserStats.opers > 0);
  1544       --UserStats.opers;
  1545       client_set_privs(sptr, NULL); /* will clear propagate privilege */
  1546       if (cli_user(sptr)->opername) {
  1547         MyFree(cli_user(sptr)->opername);
  1548         cli_user(sptr)->opername = NULL;
  1549       }
  1550     }
  1551     if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr)) {
  1552       assert(UserStats.inv_clients > 0);
  1553       --UserStats.inv_clients;
  1554     }
  1555     if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr)) {
  1556       ++UserStats.inv_clients;
  1557     }
  1558     assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
  1559     assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
  1560     send_umode_out(cptr, sptr, &setflags, prop);
  1561   }
  1562 
  1563   return 0;
  1564 }
  1565 
  1566 /** Build a mode string to describe modes for \a cptr.
  1567  * @param[in] cptr Some user.
  1568  * @return Pointer to a static buffer.
  1569  */
  1570 char *umode_str(struct Client *cptr, int opernames)
  1571 {
  1572   /* Maximum string size: "owidgrx\0" */
  1573   char *m = umodeBuf;
  1574   int i;
  1575   struct Flags c_flags = cli_flags(cptr);
  1576 
  1577   if (!HasPriv(cptr, PRIV_PROPAGATE))
  1578     FlagClr(&c_flags, FLAG_OPER);
  1579 
  1580   for (i = 0; i < USERMODELIST_SIZE; ++i)
  1581   {
  1582     if (FlagHas(&c_flags, userModeList[i].flag) &&
  1583         userModeList[i].flag >= FLAG_GLOBAL_UMODES)
  1584       *m++ = userModeList[i].c;
  1585   }
  1586 
  1587   if (opernames && IsOper(cptr))
  1588   {
  1589     *m++ = ' ';
  1590     if (cli_user(cptr)->opername) {
  1591       char* t = cli_user(cptr)->opername;
  1592       while ((*m++ = *t++))
  1593         ; /* Empty loop */
  1594       m--; /* Step back over the '\0' */
  1595     } else {
  1596       *m++ = NOOPERNAMECHARACTER;
  1597     }
  1598   }
  1599 
  1600   if (IsAccount(cptr))
  1601   {
  1602     char* t = cli_user(cptr)->account;
  1603 
  1604     *m++ = ' ';
  1605     while ((*m++ = *t++))
  1606       ; /* Empty loop */
  1607 
  1608     if (cli_user(cptr)->acc_create) {
  1609       char nbuf[30];
  1610       Debug((DEBUG_DEBUG, "Sending timestamped account in user mode for "
  1611 	     "account \"%s\"; timestamp %Tu", cli_user(cptr)->account,
  1612 	     cli_user(cptr)->acc_create));
  1613       if(cli_user(cptr)->acc_id) {
  1614         ircd_snprintf(0, t = nbuf, sizeof(nbuf), ":%Tu:%lu",
  1615                       cli_user(cptr)->acc_create, cli_user(cptr)->acc_id);
  1616       } else {
  1617         ircd_snprintf(0, t = nbuf, sizeof(nbuf), ":%Tu",
  1618                       cli_user(cptr)->acc_create);
  1619       }
  1620       m--; /* back up over previous nul-termination */
  1621       while ((*m++ = *t++))
  1622 	; /* Empty loop */
  1623     }
  1624     m--; /* Step back over the '\0' */
  1625   }
  1626 
  1627   if (IsSetHost(cptr)) {
  1628     *m++ = ' ';
  1629     ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(cptr)->username,
  1630          cli_user(cptr)->host);
  1631   } else
  1632     *m = '\0';
  1633   return umodeBuf;                /* Note: static buffer, gets
  1634                                    overwritten by send_umode() */
  1635 }
  1636 
  1637 /** Send a mode change string for \a sptr to \a cptr.
  1638  * @param[in] cptr Destination of mode change message.
  1639  * @param[in] sptr User whose mode has changed.
  1640  * @param[in] old Pre-change set of modes for \a sptr.
  1641  * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER,
  1642  * SEND_UMODES, to select which changed user modes to send.
  1643  */
  1644 void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
  1645                 int sendset, int opernames)
  1646 {
  1647   int i;
  1648   int flag;
  1649   int needhost = 0;
  1650   int needoper = 0;
  1651   char *m;
  1652   int what = MODE_NULL;
  1653 
  1654   /*
  1655    * Build a string in umodeBuf to represent the change in the user's
  1656    * mode between the new (cli_flags(sptr)) and 'old', but skipping
  1657    * the modes indicated by sendset.
  1658    */
  1659   m = umodeBuf;
  1660   *m = '\0';
  1661   for (i = 0; i < USERMODELIST_SIZE; ++i)
  1662   {
  1663     flag = userModeList[i].flag;
  1664     if (FlagHas(old, flag)
  1665         == HasFlag(sptr, flag))
  1666       continue;
  1667     switch (sendset)
  1668     {
  1669     case ALL_UMODES:
  1670       break;
  1671     case SEND_UMODES_BUT_OPER:
  1672       if (flag == FLAG_OPER)
  1673         continue;
  1674       /* and fall through */
  1675     case SEND_UMODES:
  1676       if (flag < FLAG_GLOBAL_UMODES)
  1677         continue;
  1678       break;      
  1679     }
  1680     /* Special case for OPER.. */
  1681     if (flag == FLAG_OPER) {
  1682       /* If we're setting +o, add the opername later */
  1683       if (!FlagHas(old, flag))
  1684       	needoper++;
  1685     }
  1686     /* Special case for SETHOST.. */
  1687     if (flag == FLAG_SETHOST) {
  1688       /* Don't send to users */
  1689       if (cptr && MyUser(cptr))
  1690       	continue;
  1691       
  1692       /* If we're setting +h, add the parameter later */
  1693       if (!FlagHas(old, flag))	
  1694       	needhost++;    
  1695     }
  1696     if (FlagHas(old, flag))
  1697     {
  1698       if (what == MODE_DEL)
  1699         *m++ = userModeList[i].c;
  1700       else
  1701       {
  1702         what = MODE_DEL;
  1703         *m++ = '-';
  1704         *m++ = userModeList[i].c;
  1705       }
  1706     }
  1707     else /* !FlagHas(old, flag) */
  1708     {
  1709       if (what == MODE_ADD)
  1710         *m++ = userModeList[i].c;
  1711       else
  1712       {
  1713         what = MODE_ADD;
  1714         *m++ = '+';
  1715         *m++ = userModeList[i].c;
  1716       }
  1717     }
  1718   }
  1719   if (opernames && needoper) {
  1720     *m++ = ' ';
  1721     if (cli_user(sptr)->opername) {
  1722       char* t = cli_user(sptr)->opername;
  1723       while ((*m++ = *t++))
  1724         ; /* Empty loop */
  1725       m--; /* Step back over the '\0' */
  1726     } else {
  1727       *m++ = NOOPERNAMECHARACTER;
  1728     }
  1729   }
  1730   if (needhost) {
  1731     *m++ = ' ';
  1732     ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username,
  1733          cli_user(sptr)->host);
  1734   } else
  1735     *m = '\0';
  1736   if (*umodeBuf && cptr)
  1737     sendcmdto_one(sptr, CMD_MODE, cptr, "%s %s", cli_name(sptr), umodeBuf);
  1738 }
  1739 
  1740 /**
  1741  * Check to see if this resembles a sno_mask.  It is if 1) there is
  1742  * at least one digit and 2) The first digit occurs before the first
  1743  * alphabetic character.
  1744  * @param[in] word Word to check for sno_mask-ness.
  1745  * @return Non-zero if \a word looks like a server notice mask; zero if not.
  1746  */
  1747 int is_snomask(char *word)
  1748 {
  1749   if (word)
  1750   {
  1751     for (; *word; word++)
  1752       if (IsDigit(*word))
  1753         return 1;
  1754       else if (IsAlpha(*word))
  1755         return 0;
  1756   }
  1757   return 0;
  1758 }
  1759 
  1760  /*
  1761   * Check to see if it resembles a valid hostmask.
  1762   */
  1763 int is_hostmask(char *word)
  1764 {
  1765   int i = 0;
  1766   char *host;
  1767 
  1768   Debug((DEBUG_INFO, "is_hostmask() %s", word));
  1769 
  1770   if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
  1771     return 0;
  1772 
  1773   /* if a host is specified, make sure it's valid */
  1774   host = strrchr(word, '@');
  1775   if (host) {
  1776      if (strlen(++host) < 1)
  1777        return 0;
  1778      if (strlen(host) > HOSTLEN)
  1779        return 0;
  1780   }
  1781 
  1782   if (word) {
  1783     if ('@' == *word)	/* no leading @'s */
  1784         return 0;
  1785 
  1786     if ('#' == *word) {	/* numeric index given? */
  1787       for (word++; *word; word++) {
  1788         if (!IsDigit(*word))
  1789           return 0;
  1790       }
  1791       return 1;
  1792     }
  1793 
  1794     /* normal hostmask, account for at most one '@' */
  1795     for (; *word; word++) {
  1796       if ('@' == *word) {
  1797         i++;
  1798         continue;
  1799       }
  1800       if (!IsHostChar(*word))
  1801         return 0;
  1802     }
  1803     return (1 < i) ? 0 : 1; /* no more than on '@' */
  1804   }
  1805   return 0;
  1806 }
  1807 
  1808  /*
  1809   * IsVhost() - Check if given host is a valid spoofhost
  1810   * (ie: configured thru a S:line)
  1811   */
  1812 static char *IsVhost(char *hostmask, int oper)
  1813 {
  1814   unsigned int i = 0, y = 0;
  1815   struct sline *sconf;
  1816 
  1817   Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
  1818 
  1819   if (EmptyString(hostmask))
  1820     return NULL;
  1821 
  1822   /* spoofhost specified as index, ie: #27 */
  1823   if ('#' == hostmask[0]) {
  1824     y = atoi(hostmask + 1);
  1825     for (i = 0, sconf = GlobalSList; sconf; sconf = sconf->next) {
  1826       if (!oper && EmptyString(sconf->passwd))
  1827         continue;
  1828       if (y == ++i)
  1829         return sconf->spoofhost;
  1830     }
  1831     return NULL;
  1832   }
  1833 
  1834   /* spoofhost specified as host, ie: host.cc */
  1835   for (sconf = GlobalSList; sconf; sconf = sconf->next)
  1836     if (strCasediff(hostmask, sconf->spoofhost) == 0)
  1837       return sconf->spoofhost;
  1838 
  1839   return NULL;
  1840 }
  1841 
  1842  /*
  1843   * IsVhostPass() - Check if given spoofhost has a password
  1844   * associated with it, and if, return the password (cleartext)
  1845   */
  1846 static char *IsVhostPass(char *hostmask)
  1847 {
  1848   struct sline *sconf;
  1849 
  1850   Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
  1851 
  1852   if (EmptyString(hostmask))
  1853     return NULL;
  1854 
  1855   for (sconf = GlobalSList; sconf; sconf = sconf->next)
  1856     if (strCasediff(hostmask, sconf->spoofhost) == 0) {
  1857       Debug((DEBUG_INFO, "sconf->passwd %s", sconf->passwd));
  1858       return EmptyString(sconf->passwd) ? NULL : sconf->passwd;
  1859     }
  1860 
  1861   return NULL;
  1862 }
  1863 
  1864 /** Update snomask \a oldmask according to \a arg and \a what.
  1865  * @param[in] oldmask Original user mask.
  1866  * @param[in] arg Update string (either a number or '+'/'-' followed by a number).
  1867  * @param[in] what MODE_ADD if adding the mask.
  1868  * @return New value of service notice mask.
  1869  */
  1870 unsigned int umode_make_snomask(unsigned int oldmask, char *arg, int what)
  1871 {
  1872   unsigned int sno_what;
  1873   unsigned int newmask;
  1874   if (*arg == '+')
  1875   {
  1876     arg++;
  1877     if (what == MODE_ADD)
  1878       sno_what = SNO_ADD;
  1879     else
  1880       sno_what = SNO_DEL;
  1881   }
  1882   else if (*arg == '-')
  1883   {
  1884     arg++;
  1885     if (what == MODE_ADD)
  1886       sno_what = SNO_DEL;
  1887     else
  1888       sno_what = SNO_ADD;
  1889   }
  1890   else
  1891     sno_what = (what == MODE_ADD) ? SNO_SET : SNO_DEL;
  1892   /* pity we don't have strtoul everywhere */
  1893   newmask = (unsigned int)atoi(arg);
  1894   if (sno_what == SNO_DEL)
  1895     newmask = oldmask & ~newmask;
  1896   else if (sno_what == SNO_ADD)
  1897     newmask |= oldmask;
  1898   return newmask;
  1899 }
  1900 
  1901 /** Remove \a cptr from the singly linked list \a list.
  1902  * @param[in] cptr Client to remove from list.
  1903  * @param[in,out] list Pointer to head of list containing \a cptr.
  1904  */
  1905 static void delfrom_list(struct Client *cptr, struct SLink **list)
  1906 {
  1907   struct SLink* tmp;
  1908   struct SLink* prv = NULL;
  1909 
  1910   for (tmp = *list; tmp; tmp = tmp->next) {
  1911     if (tmp->value.cptr == cptr) {
  1912       if (prv)
  1913         prv->next = tmp->next;
  1914       else
  1915         *list = tmp->next;
  1916       free_link(tmp);
  1917       break;
  1918     }
  1919     prv = tmp;
  1920   }
  1921 }
  1922 
  1923 /** Set \a cptr's server notice mask, according to \a what.
  1924  * @param[in,out] cptr Client whose snomask is updating.
  1925  * @param[in] newmask Base value for new snomask.
  1926  * @param[in] what One of SNO_ADD, SNO_DEL, SNO_SET, to choose operation.
  1927  */
  1928 void set_snomask(struct Client *cptr, unsigned int newmask, int what)
  1929 {
  1930   unsigned int oldmask, diffmask;        /* unsigned please */
  1931   int i;
  1932   struct SLink *tmp;
  1933 
  1934   oldmask = cli_snomask(cptr);
  1935 
  1936   if (what == SNO_ADD)
  1937     newmask |= oldmask;
  1938   else if (what == SNO_DEL)
  1939     newmask = oldmask & ~newmask;
  1940   else if (what != SNO_SET)        /* absolute set, no math needed */
  1941     sendto_opmask_butone(0, SNO_OLDSNO, "setsnomask called with %d ?!", what);
  1942 
  1943   newmask &= (IsAnOper(cptr) ? SNO_ALL : SNO_USER);
  1944 
  1945   diffmask = oldmask ^ newmask;
  1946 
  1947   for (i = 0; diffmask >> i; i++) {
  1948     if (((diffmask >> i) & 1))
  1949     {
  1950       if (((newmask >> i) & 1))
  1951       {
  1952         tmp = make_link();
  1953         tmp->next = opsarray[i];
  1954         tmp->value.cptr = cptr;
  1955         opsarray[i] = tmp;
  1956       }
  1957       else
  1958         /* not real portable :( */
  1959         delfrom_list(cptr, &opsarray[i]);
  1960     }
  1961   }
  1962   cli_snomask(cptr) = newmask;
  1963 }
  1964 
  1965 /** Check whether \a sptr is allowed to send a message to \a acptr.
  1966  * If \a sptr is a remote user, it means some server has an outdated
  1967  * SILENCE list for \a acptr, so send the missing SILENCE mask(s) back
  1968  * in the direction of \a sptr.  Skip the check if \a sptr is a server.
  1969  * @param[in] sptr Client trying to send a message.
  1970  * @param[in] acptr Destination of message.
  1971  * @return Non-zero if \a sptr is SILENCEd by \a acptr, zero if not.
  1972  */
  1973 int is_silenced(struct Client *sptr, struct Client *acptr)
  1974 {
  1975   struct Ban *found;
  1976   struct User *user;
  1977   size_t buf_used, slen;
  1978   char buf[BUFSIZE];
  1979 
  1980   if (IsServer(sptr) || !(user = cli_user(acptr))
  1981       || !(found = find_ban(sptr, user->silence)))
  1982     return 0;
  1983   assert(!(found->flags & BAN_EXCEPTION));
  1984   if (!MyConnect(sptr)) {
  1985     /* Buffer positive silence to send back. */
  1986     buf_used = strlen(found->banstr);
  1987     memcpy(buf, found->banstr, buf_used);
  1988     /* Add exceptions to buffer. */
  1989     for (found = user->silence; found; found = found->next) {
  1990       if (!(found->flags & BAN_EXCEPTION))
  1991         continue;
  1992       slen = strlen(found->banstr);
  1993       if (buf_used + slen + 4 > 400) {
  1994         buf[buf_used] = '\0';
  1995         sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr, buf);
  1996         buf_used = 0;
  1997       }
  1998       if (buf_used)
  1999         buf[buf_used++] = ',';
  2000       buf[buf_used++] = '+';
  2001       buf[buf_used++] = '~';
  2002       memcpy(buf + buf_used, found->banstr, slen);
  2003       buf_used += slen;
  2004     }
  2005     /* Flush silence buffer. */
  2006     if (buf_used) {
  2007       buf[buf_used] = '\0';
  2008       sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr, buf);
  2009       buf_used = 0;
  2010     }
  2011   }
  2012   return 1;
  2013 }
  2014 
  2015 /** Send RPL_ISUPPORT lines to \a cptr.
  2016  * @param[in] cptr Client to send ISUPPORT to.
  2017  * @return Zero.
  2018  */
  2019 int
  2020 send_supported(struct Client *cptr)
  2021 {
  2022   char featurebuf[512];
  2023 
  2024   ircd_snprintf(0, featurebuf, sizeof(featurebuf), FEATURES1, FEATURESVALUES1);
  2025   send_reply(cptr, RPL_ISUPPORT, featurebuf);
  2026   ircd_snprintf(0, featurebuf, sizeof(featurebuf), FEATURES2, FEATURESVALUES2);
  2027   send_reply(cptr, RPL_ISUPPORT, featurebuf);
  2028 
  2029   return 0; /* convenience return, if it's ever needed */
  2030 }
  2031 
  2032 /* vim: shiftwidth=2 
  2033  */