"Fossies" - the Fresh Open Source Software Archive

Member "bahamut-2.1.5/src/m_services.c" (28 May 2020, 35249 Bytes) of package /linux/privat/bahamut-2.1.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "m_services.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.1.4_vs_2.1.5.

    1 /* m_services.c - Because s_user.c was just crazy.
    2  *   Copyright (C) 1990 Jarkko Oikarinen and
    3  *                      University of Oulu, Computing Center
    4  *
    5  *   See file AUTHORS in IRC package for additional names of
    6  *   the programmers.
    7  *
    8  *   This program is free softwmare; you can redistribute it and/or modify
    9  *   it under the terms of the GNU General Public License as published by
   10  *   the Free Software Foundation; either version 1, or (at your option)
   11  *   any later version.
   12  *
   13  *   This program is distributed in the hope that it will be useful,
   14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  *   GNU General Public License for more details.
   17  *
   18  *   You should have received a copy of the GNU General Public License
   19  *   along with this program; if not, write to the Free Software
   20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   21  */
   22 
   23 #include "struct.h"
   24 #include "common.h"
   25 #include "sys.h"
   26 #include "numeric.h"
   27 #include "msg.h"
   28 #include "channel.h"
   29 #include <sys/stat.h>
   30 #include <fcntl.h>
   31 #include "h.h"
   32 #include "userban.h"
   33 #include "clones.h"
   34 #include "memcount.h"
   35 
   36 /* Externally defined stuffs */
   37 extern int user_modes[];
   38 extern int check_channelname(aClient *, unsigned char *); /* for m_aj */
   39 extern aChannel *get_channel(aClient *, char *, int, int *); /* for m_aj */
   40 extern Link *find_channel_link(Link *, aChannel *); /* for m_aj */
   41 extern void add_user_to_channel(aChannel *, aClient *, int); /* for m_aj */
   42 extern void read_motd(char *); /* defined in s_serv.c */
   43 extern void read_shortmotd(char *); /* defined in s_serv.c */
   44 
   45 int svspanic = 0; /* Services panic */
   46 int svsnoop = 0; /* Services disabled all o:lines (off by default) */
   47 int uhm_type = 0; /* User host-masking type (off by default) */
   48 int uhm_umodeh = 0; /* Let users set umode +H (off by default) */
   49 int services_jr = 0; /* Redirect join requests to services (disabled by default) */
   50 
   51 /*
   52  * the services aliases. *
   53  *
   54  * NICKSERV     - /nickserv * CHANSERV  - /chanserv * OPERSERV  -
   55  * /operserv * MEMOSERV         - /memoserv * SERVICES  - /services *
   56  * IDENTIFY     - /identify * taz's code -mjs
   57  */
   58 
   59 /* Code provided by orabidoo */
   60 /*
   61  * a random number generator loosely based on RC5; assumes ints are at
   62  * least 32 bit
   63  */
   64 
   65 static unsigned long 
   66 my_rand()
   67 {
   68     static unsigned long s = 0, t = 0, k = 12345678;
   69     int         i;
   70 
   71     if (s == 0 && t == 0)
   72     {
   73         s = (unsigned long) getpid();
   74         t = (unsigned long) time(NULL);
   75     }
   76     for (i = 0; i < 12; i++)
   77     {
   78         s = (((s ^ t) << (t & 31)) | ((s ^ t) >> (31 - (t & 31)))) + k;
   79         k += s + t;
   80         t = (((t ^ s) << (s & 31)) | ((t ^ s) >> (31 - (s & 31)))) + k;
   81         k += s + t;
   82     }
   83     return s;
   84 }
   85 
   86 /* alias message handler */
   87 int m_aliased(aClient *cptr, aClient *sptr, int parc, char *parv[], AliasInfo *ai)
   88 {
   89     if (parc < 2 || *parv[1] == 0)
   90     {
   91         sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
   92         return -1;
   93     }
   94 
   95     /* second check is to avoid message loops when admins get stupid */
   96     if (!ai->client || ai->client->from == sptr->from)
   97     {
   98         sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0],
   99                    ai->nick);
  100         return 0;
  101     }
  102 
  103     if((svspanic>1 && !IsOper(sptr)) || (svspanic>0 && !IsARegNick(sptr) && !IsOper(sptr)))
  104     {
  105         if(MyClient(sptr))
  106             sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0],
  107                        ai->nick);
  108         return 0;
  109     }
  110 
  111     sendto_alias(ai, sptr, "%s", parv[1]);
  112 
  113     return 0;
  114 }
  115 
  116 /* m_services -- see df465+taz */
  117 int m_services(aClient *cptr, aClient *sptr, int parc, char *parv[])
  118 {
  119     char       *tmps;
  120     int         aidx = AII_NS;
  121 
  122     if (parc < 2 || *parv[1] == '\0')
  123     {
  124     sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
  125     return -1;
  126     }
  127     if ((strlen(parv[1]) >= 4) && (!myncmp(parv[1], "help", 4)))
  128     {
  129     sendto_one(sptr, ":services!service@%s NOTICE %s :For ChanServ "
  130            "help use: /chanserv help", Services_Name,
  131            sptr->name);
  132     sendto_one(sptr, ":services!service@%s NOTICE %s :For NickServ "
  133            "help use: /nickserv help", Services_Name,
  134            sptr->name);
  135     sendto_one(sptr, ":services!service@%s NOTICE %s :For MemoServ "
  136            "help use: /memoserv help", Services_Name,
  137            sptr->name);
  138     return 0;
  139     }
  140     if ((tmps = (char *) strchr(parv[1], ' ')))
  141     {
  142     for(; *tmps == ' '; tmps++); /* er.. before this for loop, the next
  143                       * comparison would always compare '#' 
  144                       * with ' '.. oops. - lucas
  145                       */
  146     if (*tmps == '#')
  147         aidx = AII_CS;
  148     }
  149     return m_aliased(cptr, sptr, parc, parv, &aliastab[aidx]);
  150 }
  151 
  152 /* m_identify  df465+taz */
  153 int m_identify(aClient *cptr, aClient *sptr, int parc, char *parv[])
  154 {
  155     int aidx = AII_NS;
  156 
  157     if (parc < 2 || *parv[1] == '\0')
  158     {
  159     sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
  160     return -1;
  161     }
  162 
  163     if (*parv[1] == '#')
  164         aidx = AII_CS;
  165 
  166     if (!aliastab[aidx].client)
  167     {
  168         sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0],
  169                    aliastab[aidx].nick);
  170         return 0;
  171     }
  172 
  173     sendto_alias(&aliastab[aidx], sptr, "IDENTIFY %s", parv[1]);
  174 
  175     return 0;
  176 }
  177 
  178 /* s_svsnick - Pretty straight forward.  Mostly straight outta df
  179  *  - Raistlin
  180  * parv[0] = sender
  181  * parv[1] = old nickname
  182  * parv[2] = new nickname
  183  * parv[3] = timestamp
  184  */
  185 int m_svsnick(aClient *cptr, aClient *sptr, int parc, char *parv[])
  186 {
  187     aClient *acptr, *ocptr;
  188     char newnick[NICKLEN + 1];
  189 
  190     if (!IsULine(sptr)||parc < 4||(strlen(parv[2]) > NICKLEN)) 
  191     return 0;
  192 
  193     if(hunt_server(cptr, sptr, ":%s SVSNICK %s %s :%s", 1, parc, parv) != HUNTED_ISME)
  194     return 0;
  195 
  196     /* can't find them? oh well. */
  197     if ((acptr = find_person(parv[1], NULL)) == NULL)
  198     return 0;
  199 
  200     strncpyzt(newnick, parv[2], NICKLEN+1);
  201 
  202     /* does the nick we're changing them to already exist? */
  203     /* Try to make a unique nickname */
  204     if((ocptr = find_client(newnick, NULL)) != NULL)
  205     {
  206         int tries = 0, nprefix;
  207 
  208         do 
  209         {
  210         nprefix = my_rand() % 99999;
  211         ircsnprintf(newnick, NICKLEN, "%s-%d", parv[2], nprefix);
  212             tries++;
  213         } while (((ocptr = find_client(newnick, NULL)) != NULL) && (tries < 10));
  214 
  215     /* well, we tried.. */
  216         if(ocptr)
  217         {
  218            if(IsUnknown(ocptr))
  219               return exit_client(ocptr, ocptr, &me, "SVSNICK Override");
  220            else
  221               return exit_client(acptr, acptr, &me, "SVSNICK Collide");
  222         }
  223     }
  224 
  225     if(acptr->umode & UMODE_r)
  226     {
  227     unsigned int oldumode;
  228     char mbuf[BUFSIZE];
  229 
  230     oldumode = acptr->umode;
  231     acptr->umode &= ~UMODE_r;
  232 
  233         send_umode(acptr, acptr, oldumode, ALL_UMODES, mbuf, sizeof(mbuf));
  234     }
  235 
  236     acptr->tsinfo = atoi(parv[3]);
  237 #ifdef ANTI_NICK_FLOOD
  238     acptr->last_nick_change = atoi(parv[3]);
  239 #endif
  240     sendto_common_channels(acptr, ":%s NICK :%s", parv[1], newnick);
  241     add_history(acptr, 1);
  242     sendto_serv_butone(NULL, ":%s NICK %s :%ld", parv[1], newnick,
  243                (long)acptr->tsinfo);
  244     if(acptr->name[0]) 
  245     {
  246         del_from_client_hash_table(acptr->name, acptr);
  247         hash_check_watch(acptr, RPL_LOGOFF);
  248     }
  249     strcpy(acptr->name, newnick);
  250     add_to_client_hash_table(acptr->name, acptr);
  251     hash_check_watch(acptr, RPL_LOGON);
  252     flush_user_banserial(acptr);
  253 
  254     return 0;
  255 }
  256 
  257 /* channel_svsmode:
  258  * parv[0] sender
  259  * parv[1] channel
  260  * parv[2] modes
  261  * parv[3] nick
  262  * parv[4] nickts
  263  * currently, only a mode of -b is supported.
  264  * services should use MODE for regular channel modes.
  265  * 2/5/00 lucas
  266  * preconditions: parc >= 3, sptr is ulined
  267  */
  268 int channel_svsmode(aClient *cptr, aClient *sptr, int parc, char *parv[])
  269 {
  270     aChannel *chptr;
  271     aClient *acptr = NULL;
  272     char *m, *nick = NULL;
  273     char change = '+';
  274     ts_val nickts = 0;
  275     int sendmsg = 1;
  276 
  277     if(!(chptr = find_channel(parv[1], NULL)))
  278     return 0;
  279 
  280     if(parc >= 4)
  281     {
  282     nick = parv[3];
  283     if(parc > 4)
  284         nickts = atol(parv[4]);
  285     }
  286 
  287     if(nick)
  288     {
  289     acptr = find_person(nick, NULL);
  290     if(!acptr || (nickts && acptr->tsinfo != nickts))
  291         return 0;
  292     }
  293 
  294     for(m = parv[2]; *m; m++)
  295     switch(*m)
  296     {
  297     case '+':
  298     case '-':
  299             change = *m;
  300             break;
  301 
  302     case 'b':
  303             if(nick && MyClient(acptr) && change == '-')
  304             {
  305         remove_matching_bans(chptr, acptr, &me);
  306         sendmsg--;
  307             }
  308             break;
  309 
  310 #ifdef EXEMPT_LISTS
  311     case 'e':
  312             if (nick && MyClient(acptr) && change == '-')
  313             {
  314                 remove_matching_exempts(chptr, acptr, &me);
  315                 sendmsg--;
  316             }
  317             break;
  318 #endif
  319 
  320 #ifdef INVITE_LISTS
  321     case 'I':
  322             if (nick && MyClient(acptr) && change == '-')
  323             {
  324                 remove_matching_invites(chptr, acptr, &me);
  325                 sendmsg--;
  326             }
  327             break;
  328 #endif
  329 
  330     default:
  331             sendmsg++;
  332             break;
  333     }
  334 
  335     if(!sendmsg) return 0;
  336 
  337     if(nick)
  338     sendto_serv_butone(cptr, ":%s SVSMODE %s %s %s %ld", parv[0], parv[1],
  339                parv[2], nick, acptr->tsinfo);
  340     else
  341     sendto_serv_butone(cptr, ":%s SVSMODE %s %s", parv[0], parv[1], 
  342                parv[2]);
  343 
  344     return 0;
  345 }
  346 
  347 /* m_svsmode - df function integrated
  348  *  - Raistlin
  349  * -- Behaviour changed - Epi (11/30/99)
  350  * parv[0] - sender
  351  * parv[1] - nick
  352  * parv[2] - TS (or mode, depending on svs version)
  353  * parv[3] - mode (or services id if old svs version)
  354  * parv[4] - optional arguement (services id)
  355  */
  356 int m_svsmode(aClient *cptr, aClient *sptr, int parc, char *parv[])
  357 {
  358     int            flag, *s, what, oldumode;
  359     char          *m, *modes, *optarg;
  360     aClient       *acptr;
  361     ts_val         ts = 0;
  362 
  363     if (!IsULine(sptr) || (parc < 3))
  364     return 0;
  365 
  366     if (parv[1][0] == '#')
  367     return channel_svsmode(cptr, sptr, parc, parv);
  368 
  369     if ((parc >= 4) && ((parv[3][0] == '+') || (parv[3][0] == '-')))
  370     {
  371     ts = atol(parv[2]);
  372     modes = parv[3];
  373     optarg = (parc > 4) ? parv[4] : NULL;
  374     }
  375     else
  376     {
  377     modes = parv[2];
  378     optarg = (parc > 3) ? parv[3] : NULL;
  379     }
  380 
  381     if (!(acptr = find_person(parv[1], NULL)))
  382     return 0;
  383 
  384     if (ts && (ts != acptr->tsinfo))
  385     return 0;
  386 
  387     what = MODE_ADD;
  388     oldumode = acptr->umode;
  389     for (m = modes; *m; m++)
  390     switch(*m)
  391     {
  392     case '+':
  393         what = MODE_ADD;
  394         break;
  395     case '-':
  396         what = MODE_DEL;
  397         break;
  398     case ' ':
  399     case '\n':
  400     case '\r':
  401     case '\t':
  402         break;
  403     case 'd':
  404         if (optarg && IsDigit(*optarg))
  405         acptr->user->servicestamp = strtoul(optarg, NULL, 0);
  406         break;
  407     case 'T':
  408         if (optarg && IsDigit(*optarg))
  409         acptr->user->servicetype = strtoul(optarg, NULL, 0);
  410         break;
  411     default:
  412         for (s = user_modes; (flag = *s); s += 2)
  413         {
  414         if (*m == (char)(*(s+1)))
  415         {
  416             if (what == MODE_ADD)
  417             {
  418                 if((flag & (UMODE_o|UMODE_O)) && !IsAnOper(acptr))
  419                 {
  420                      Count.oper++;
  421                      if(MyConnect(acptr))
  422                          add_to_list(&oper_list, acptr);
  423                 }
  424                 if((flag & (UMODE_o|UMODE_O|UMODE_a|UMODE_A)) && optarg && MyConnect(acptr))
  425                 {
  426                      if(*optarg == '+')
  427                          acptr->oflag |= atol(optarg);
  428                      else if(*optarg == '-')
  429                          acptr->oflag &= ~(atol(optarg) * -1);
  430                      else
  431                          acptr->oflag = atol(optarg);
  432                 }
  433                 acptr->umode |= flag;
  434             }
  435             else if (acptr->umode & flag)
  436             {
  437                 acptr->umode &= ~flag;
  438 
  439                 /* deopering ok */
  440                 if (MyConnect(acptr) && (flag & (UMODE_o|UMODE_O))
  441                     && !IsAnOper(acptr))
  442                 {
  443                     acptr->oflag = 0;
  444                     remove_from_list(&oper_list, acptr, NULL);
  445                 }
  446             }
  447 
  448             break;
  449         }
  450         }
  451         break;
  452     }
  453 
  454     if (optarg)
  455     sendto_serv_butone(cptr, ":%s SVSMODE %s %ld %s %s",
  456                parv[0], parv[1], acptr->tsinfo, modes, optarg);
  457     else
  458     sendto_serv_butone(cptr, ":%s SVSMODE %s %ld %s",
  459                parv[0], parv[1], acptr->tsinfo, modes);
  460 
  461     if (MyClient(acptr) && (oldumode != acptr->umode))
  462     {
  463         char buf[BUFSIZE];
  464         send_umode(acptr, acptr, oldumode, ALL_UMODES, buf, sizeof(buf));
  465     }
  466 
  467     return 0;
  468 }
  469 
  470 /* m_svshold
  471  *   Adds a temporary local nick ban.
  472  * parv[0] - sender
  473  * parv[1] - nick/channel
  474  * parv[2] - duration (0 to remove existing ban)
  475  * parv[3] - optional reason
  476  */
  477 int m_svshold(aClient *cptr, aClient *sptr, int parc, char *parv[])
  478 {
  479     struct simBan *ban, *oban;
  480     char *reason, *mask;
  481     int length;
  482 
  483     if(!IsULine(sptr) || parc < 3)
  484         return 0;
  485 
  486     mask = parv[1];
  487     length = strtol(parv[2], NULL, 0);
  488     reason = (parc < 4) ? "Nickname is reserved, try again later" : parv[3];
  489 
  490     /* marked local so netbursts don't propagate it */
  491     if(*mask == '#')
  492         ban = make_simpleban(SBAN_LOCAL|SBAN_CHAN|SBAN_TEMPORARY|SBAN_SVSHOLD, parv[1]);
  493     else
  494         ban = make_simpleban(SBAN_LOCAL|SBAN_NICK|SBAN_TEMPORARY|SBAN_SVSHOLD, parv[1]);
  495     if(!ban)
  496     {
  497     sendto_realops_lev(DEBUG_LEV, "make_simpleban(%s) failed on svshold", mask);
  498     return 0;
  499     }
  500     ban->reason = NULL;
  501     
  502     if((oban = find_simban_exact(ban)) != NULL)
  503     {
  504     simban_free(ban);
  505     ban = NULL;
  506 
  507     if(length <= 0)
  508     {
  509         remove_simban(oban);
  510         simban_free(oban);
  511     }
  512     else
  513     {
  514         if(oban->reason)
  515         MyFree(oban->reason);
  516         oban->reason = (char *) MyMalloc(strlen(reason) + 1);
  517         strcpy(oban->reason, reason);
  518         oban->timeset = NOW;
  519         oban->duration = length;
  520     }
  521     }
  522     else if(length > 0)
  523     {
  524     ban->reason = (char *) MyMalloc(strlen(reason) + 1);
  525     strcpy(ban->reason, reason);
  526     ban->timeset = NOW;
  527     ban->duration = length;
  528     add_simban(ban);
  529     }
  530     else
  531     simban_free(ban);
  532 
  533     if(parc < 4)
  534     sendto_serv_butone(cptr, ":%s SVSHOLD %s %s", sptr->name, parv[1], parv[2]);
  535     else
  536     sendto_serv_butone(cptr, ":%s SVSHOLD %s %s :%s", sptr->name, parv[1], parv[2], parv[3]);
  537 
  538     return 0;
  539 }
  540 
  541 
  542 /* m_svsclone
  543 *   Sets a clone limit for an IP mask (1.2.3.4 or 1.2.3.*).
  544 * parv[0] - sender
  545 * parv[1] - mask
  546 * parv[2] - duration (0 to revert to default limit)
  547 */
  548 int
  549 m_svsclone(aClient *cptr, aClient *sptr, int parc, char *parv[])
  550 {
  551     int d;
  552 
  553     if (parc != 3)
  554         return 0;
  555 
  556     if (!(IsServer(sptr) || IsULine(sptr)))
  557         return 0;
  558 
  559     d = atoi(parv[2]);
  560     clones_set(parv[1], CLIM_HARD_GLOBAL, d);
  561     sendto_serv_butone(cptr, ":%s SVSCLONE %s %s", parv[0], parv[1], parv[2]);
  562 
  563     return 0;
  564 }
  565 
  566 
  567 /* m_svspanic
  568  *   Stops users from sending commands to u:lined servers.
  569  * parv[0] - sender
  570  * parv[1] - 2/1/0 (0 - all users can use services, 1 - only +r users can use services, 2 - only opers (+o) can use services)
  571  */
  572 int m_svspanic(aClient *cptr, aClient *sptr, int parc, char *parv[])
  573 {
  574     if(!IsULine(sptr) || parc < 2)
  575         return 0;
  576 
  577     svspanic = atoi(parv[1]);
  578 
  579     sendto_serv_butone(cptr, ":%s SVSPANIC %s", sptr->name, parv[1]);
  580 
  581     return 0;
  582 }
  583 
  584 /* m_chankill
  585  *   Destroy a channel completely, removing all local users
  586  *   with a kick and propegating the chankill out.  The user will
  587  *   not see anyone else get kicked before they do.
  588  * parv[0] - sender (Ulined client)
  589  * parv[1] - channel
  590  * parv[2] - kick reason
  591  */
  592 int m_chankill(aClient *cptr, aClient *sptr, int parc, char *parv[])
  593 {
  594     aChannel *chptr = NULL;
  595     chanMember *cur = NULL, *next = NULL;
  596 
  597     if(!IsULine(sptr) || parc < 2)  /* we can kick without a reason. */
  598         return 0;
  599     if(!(chptr = find_channel(parv[1], NULL)))
  600         return 0;
  601     cur = chptr->members;
  602     while(cur)
  603     {
  604         next = cur->next;
  605         if(MyClient(cur->cptr)) /* tell our clients that the channel is gone */
  606             sendto_prefix_one(cur->cptr, sptr, ":%s KICK %s %s :%s", parv[0],
  607                               parv[1], cur->cptr->name,
  608                               (parc == 3) ? parv[2] : "");
  609         remove_user_from_channel(cur->cptr, chptr);
  610         cur = next;
  611     }
  612     /* at this point, the channel should not exist locally */
  613     sendto_serv_butone(cptr, ":%s CHANKILL %s :%s", parv[0], parv[1],
  614                        (parc == 3) ? parv[2] : "");
  615     return 0;
  616 }
  617 
  618 /* m_svshost - Lets services change a user's host.
  619  * -Kobi_S 30/01/2010
  620  */
  621 int m_svshost(aClient *cptr, aClient *sptr, int parc, char *parv[])
  622 {
  623     aClient *acptr;
  624 
  625     if(!IsServer(sptr) || parc<3 || *parv[2]==0)
  626         return 0; /* Not a server or not enough parameters */
  627 
  628     if(!(acptr = find_person(parv[1], NULL)))
  629         return 0; /* Target user doesn't exist */
  630 
  631     if(!IsULine(sptr))
  632     {
  633         if(cptr->from!=acptr->from)
  634             return 0; /* Wrong direction */
  635     }
  636 
  637     if(strlen(parv[2]) > HOSTLEN)
  638         return 0; /* The requested host is too long */
  639 
  640 #ifdef USER_HOSTMASKING
  641     strcpy(acptr->user->mhost, parv[2]); /* Set the requested (masked) host */
  642     acptr->flags |= FLAGS_SPOOFED;
  643 #else
  644     /* Save the real hostname if it's a local client */
  645     if(MyClient(acptr))
  646     {
  647         if(!acptr->user->real_oper_host)
  648         {
  649             acptr->user->real_oper_host =
  650                 MyMalloc(strlen(acptr->user->host) + 1);
  651             strcpy(acptr->user->real_oper_host, acptr->user->host);
  652         }
  653         if(!acptr->user->real_oper_username)
  654         {
  655             acptr->user->real_oper_username =
  656                 MyMalloc(strlen(acptr->user->username) + 1);
  657             strcpy(acptr->user->real_oper_username, acptr->user->username);
  658         }
  659         if(!acptr->user->real_oper_ip)
  660         {
  661             acptr->user->real_oper_ip =
  662                 MyMalloc(strlen(acptr->hostip) + 1);
  663             strcpy(acptr->user->real_oper_ip, acptr->hostip);
  664         }
  665         strcpy(acptr->sockhost, parv[2]);
  666     }
  667     strcpy(acptr->user->host, parv[2]); /* Set the requested host */
  668 #endif
  669 
  670     /* Pass it to all the other servers */
  671     sendto_serv_butone(cptr, ":%s SVSHOST %s %s", parv[0], parv[1], parv[2]);
  672 
  673     return 0;
  674 }
  675 
  676 /* m_svsnoop - Let services (temporary) disable all o:lines on a given server.
  677  * parv[1] = server name
  678  * parv[2] = +/-
  679  */
  680 int m_svsnoop(aClient *cptr, aClient *sptr, int parc, char *parv[])
  681 {
  682     if(!IsULine(sptr) || parc<3)
  683         return 0; /* Not a u:lined server or not enough parameters */
  684 
  685     if(hunt_server(cptr, sptr, ":%s SVSNOOP %s :%s", 1, parc, parv) != HUNTED_ISME)
  686         return 0;
  687 
  688     if(parv[2][0] == '+')
  689         svsnoop = 1;
  690     else
  691         svsnoop = 0;
  692 
  693     return 0;
  694 }
  695 
  696 /* m_svstag - Lets services add "tags" to users
  697  * parv[1] = nick
  698  * parv[2] = ts
  699  * parv[3] = [-][raw]
  700  * parv[4] = required umode(s) to see the tag
  701  * parv[5] = tag line
  702  * -Kobi_S 23/03/2013
  703  */
  704 int m_svstag(aClient *cptr, aClient *sptr, int parc, char *parv[])
  705 {
  706     aClient *acptr;
  707     ServicesTag *servicestag;
  708     int *s, flag;
  709     char *m;
  710     long ts;
  711 
  712     if(!IsServer(sptr) || parc<4)
  713         return 0; /* Not a server or not enough parameters */
  714 
  715     if(!(acptr = find_person(parv[1], NULL)))
  716         return 0; /* Target user doesn't exist */
  717 
  718     if(!IsULine(sptr))
  719     {
  720         if(cptr->from!=acptr->from)
  721             return 0; /* Wrong direction (from a non-u:lined server) */
  722     }
  723 
  724     ts = atol(parv[2]);
  725     if (ts && (ts != acptr->tsinfo))
  726         return 0; /* TS info doesn't match the client */
  727 
  728     if(*parv[3] == '-')
  729     {
  730         /* Remove all current tags */
  731         while(acptr->user->servicestag) {
  732             servicestag = acptr->user->servicestag;
  733             acptr->user->servicestag = servicestag->next;
  734             MyFree(servicestag->tag);
  735             MyFree(servicestag);
  736         }
  737 
  738         if(parv[3][1] == '\0')
  739         {
  740             /* If we only got "SVSTAG nick ts -", we'll just pass it to the other servers (we already cleared the old tags) */
  741             sendto_serv_butone(cptr, ":%s SVSTAG %s %s %s", parv[0], parv[1], parv[2], parv[3]);
  742             return 0;
  743         }
  744     }
  745 
  746     if(parc<6) return 0; /* Not enough parameters (sanity check) */
  747 
  748     servicestag = acptr->user->servicestag;
  749     if(servicestag)
  750     {
  751         while(servicestag->next) {
  752             servicestag = servicestag->next;
  753         }
  754     }
  755 
  756     if(servicestag)
  757     {
  758         /* The user already has a servicestag */
  759         servicestag->next = MyMalloc(sizeof(ServicesTag));
  760         servicestag = servicestag->next;
  761     }
  762     else
  763     {
  764         /* This is the first servicestag for the user... */
  765         acptr->user->servicestag = MyMalloc(sizeof(ServicesTag));
  766         servicestag = acptr->user->servicestag;
  767     }
  768     servicestag->raw = abs(atoi(parv[3]));
  769     servicestag->umode = 0;
  770 
  771     /* parse the usermodes (stolen from m_nick) */
  772     m = &parv[4][0];
  773     if(*m == '+') m++; /* Skip the first plus... */
  774     while (*m)
  775     {
  776         for (s = user_modes; (flag = *s); s += 2)
  777             if (*m == *(s + 1))
  778             {
  779                 servicestag->umode |= flag;
  780                 break;
  781             }
  782         m++;
  783     }
  784 
  785     servicestag->tag =  MyMalloc(strlen(parv[5]) + 1);
  786     strcpy(servicestag->tag, parv[5]);
  787     servicestag->next = NULL;
  788 
  789     /* Pass it to all the other servers */
  790     sendto_serv_butone(cptr, ":%s SVSTAG %s %s %s %s :%s", parv[0], parv[1], parv[2], parv[3], parv[4], parv[5]);
  791 
  792     return 0;
  793 }
  794 
  795 /* m_svsuhm
  796  *   Define the running user host-masking type
  797  * parv[0] - sender
  798  * parv[1] - host-masking type (number)
  799  * parv[2] - optional umode +H status (0=disabled,1=enabled with auto +H on connect,2=enabled with no auto +H)
  800  */
  801 int m_svsuhm(aClient *cptr, aClient *sptr, int parc, char *parv[])
  802 {
  803     if(!IsServer(sptr) || parc < 2)
  804         return 0;
  805 
  806     if(!IsULine(sptr))
  807     {
  808         if(aliastab[AII_OS].client && aliastab[AII_OS].client->from!=cptr->from)
  809             return 0; /* Wrong direction (from a non-u:lined server) */
  810     }
  811 
  812     uhm_type = atoi(parv[1]);
  813 
  814     if(parc > 2)
  815     {
  816         uhm_umodeh = atoi(parv[2]);
  817         sendto_serv_butone(cptr, ":%s SVSUHM %s %s", sptr->name, parv[1], parv[2]);
  818     }
  819     else sendto_serv_butone(cptr, ":%s SVSUHM %s", sptr->name, parv[1]);
  820 
  821     return 0;
  822 }
  823 
  824 struct FlagList xflags_list[] =
  825 {
  826   { "NO_NOTICE",         XFLAG_NO_NOTICE         },
  827   { "NO_CTCP",           XFLAG_NO_CTCP           },
  828   { "NO_PART_MSG",       XFLAG_NO_PART_MSG       },
  829   { "NO_QUIT_MSG",       XFLAG_NO_QUIT_MSG       },
  830   { "EXEMPT_OPPED",      XFLAG_EXEMPT_OPPED      },
  831   { "EXEMPT_VOICED",     XFLAG_EXEMPT_VOICED     },
  832   { "EXEMPT_IDENTD",     XFLAG_EXEMPT_IDENTD     },
  833   { "EXEMPT_REGISTERED", XFLAG_EXEMPT_REGISTERED },
  834   { "EXEMPT_INVITES",    XFLAG_EXEMPT_INVITES    },
  835   { "EXEMPT_WEBIRC",     XFLAG_EXEMPT_WEBIRC     },
  836   { "HIDE_MODE_LISTS",   XFLAG_HIDE_MODE_LISTS   },
  837   { "NO_NICK_CHANGE",    XFLAG_NO_NICK_CHANGE    },
  838   { "NO_UTF8",           XFLAG_NO_UTF8           },
  839   { "SJR",               XFLAG_SJR               },
  840   { "USER_VERBOSE",      XFLAG_USER_VERBOSE      },
  841   { "USER_VERBOSEV2",    XFLAG_USER_VERBOSE      },
  842   { "OPER_VERBOSE",      XFLAG_OPER_VERBOSE      },
  843   { "OPER_VERBOSEV2",    XFLAG_OPER_VERBOSE      },
  844   { NULL,                0                       }
  845 };
  846 
  847 /* m_svsxcf
  848  *   Control eXtended Channel Flags.
  849  * parv[0] - sender
  850  * parv[1] - channel
  851  * parv[2] - optional setting:value or DEFAULT
  852  * parv[3] - optional setting:value
  853  * ...
  854  * parv[parc-1] - optional setting:value
  855  *
  856  * Settings:
  857  *   JOIN_CONNECT_TIME - Number of seconds the user must be online to be able to join
  858  *   TALK_CONNECT_TIME - Number of seconds the user must be online to be able to talk on the channel
  859  *   TALK_JOIN_TIME    - Number of seconds the user must be on the channel to be able to tlak on the channel
  860  *   MAX_BANS          - Will let us increase the ban limit for specific channels
  861  *   MAX_INVITES       - Will let us increase the invite limit for specific channels
  862  *   MAX_MSG_TIME      - Maximum number of messages that can be sent in x seconds, msgs:time
  863  *
  864  * 1/0 (on/off) options:
  865  *   NO_NOTICE         - no notices can be sent to the channel (on/off)
  866  *   NO_CTCP           - no ctcps can be sent to the channel (on/off)
  867  *   NO_PART_MSG       - no /part messages (on/off)
  868  *   NO_QUIT_MSG       - no /quit messages (on/off)
  869  *   HIDE_MODE_LISTS   - hide /mode #channel +b/+I/+e lists from non-ops (on/off)
  870  *   SJR               - enable services join request for this channel (must also be enabled globally) 
  871  *   NO_NICK_CHANGE    - no nick changes allowed on this channel (on/off)
  872  *   EXEMPT_OPPED      - exempt opped users (on/off)
  873  *   EXEMPT_VOICED     - exempt voiced users (on/off)
  874  *   EXEMPT_IDENTD     - exempt users with identd (on/off)
  875  *   EXEMPT_REGISTERED - exempt users with umode +r (on/off)
  876  *   EXEMPT_INVITES    - exempt users who are +I'ed (on/off)
  877  *   EXEMPT_WEBIRC     - exempt webirc users (on/off)
  878  *   USER_VERBOSE      - send failed command messages to #channel-relay (on/off)
  879  *   OPER_VERBOSE      - send failed command messages to +f opers (on/off)
  880  *
  881  * Special option:
  882  *   GREETMSG - A message that will be sent when a user joins the channel
  883  */
  884 int m_svsxcf(aClient *cptr, aClient *sptr, int parc, char *parv[])
  885 {
  886     aChannel *chptr;
  887     char *opt, *value;
  888     struct FlagList *xflag;
  889     int i; /* Counter for the option:value loop */
  890     char pbuf[512];
  891 
  892     if(!IsServer(sptr) || parc < 2)
  893         return 0;
  894 
  895     if(!(chptr = find_channel(parv[1], NULL)))
  896         return 0;
  897 
  898     if(!IsULine(sptr))
  899     {
  900         if(aliastab[AII_CS].client && aliastab[AII_CS].client->from!=cptr->from)
  901         {
  902             /*
  903              * We don't accept commands from a non-services direction.
  904              * Also, we remove non-existed xflagss if they come from this location.
  905              * Note: we don't need to worry about existed xflags on the other side
  906              * because they will be overrided anyway.
  907              */
  908             if(!(chptr->xflags & XFLAG_SET))
  909             {
  910                 sendto_one(cptr, ":%s SVSXCF %s", me.name, parv[1]);
  911             }
  912             return 0; /* Wrong direction (from a non-u:lined server) */
  913         }
  914     }
  915 
  916     make_parv_copy(pbuf, parc, parv);
  917     sendto_serv_butone(cptr, ":%s SVSXCF %s", parv[0], pbuf);
  918 
  919     i = 2;
  920 
  921     if(parc<3 || !strcasecmp(parv[2],"DEFAULT"))
  922     {
  923         /* Reset all the extended channel flags back to their defaults... */
  924         chptr->join_connect_time = 0;
  925         chptr->talk_connect_time = 0;
  926         chptr->talk_join_time = 0;
  927         chptr->max_bans = MAXBANS;
  928         chptr->max_invites = MAXINVITELIST;
  929         chptr->max_messages = 0;
  930         chptr->max_messages_time = 0;
  931         chptr->xflags = 0;
  932         if(chptr->greetmsg)
  933           MyFree(chptr->greetmsg);
  934         i++;
  935     }
  936 
  937     for(; i<parc; i++)
  938     {
  939         opt = parv[i];
  940         if((value = strchr(parv[i],':')))
  941         {
  942             *value = '\0';
  943             value++;
  944             if(!*value) continue; /* Just in case someone does something like option: with no value */
  945             if(!parv[i][0]) continue; /* Just in case someone does something like :value with no option */
  946             if(!strcasecmp(opt,"JOIN_CONNECT_TIME")) { chptr->join_connect_time = atoi(value); chptr->xflags |= XFLAG_SET; }
  947             else if(!strcasecmp(opt,"TALK_CONNECT_TIME")) { chptr->talk_connect_time = atoi(value); chptr->xflags |= XFLAG_SET; }
  948             else if(!strcasecmp(opt,"TALK_JOIN_TIME")) { chptr->talk_join_time = atoi(value); chptr->xflags |= XFLAG_SET; }
  949             else if(!strcasecmp(opt,"MAX_BANS")) { chptr->max_bans = atoi(value); chptr->xflags |= XFLAG_SET; }
  950             else if(!strcasecmp(opt,"MAX_INVITES")) { chptr->max_invites = atoi(value); chptr->xflags |= XFLAG_SET; }
  951             else if(!strcasecmp(opt,"MAX_MSG_TIME"))
  952             {
  953                 char *mmt_value;
  954                 mmt_value = opt;
  955 
  956                 if ((mmt_value = strchr(value, ':')))
  957                 {
  958                     *mmt_value = '\0';
  959                     mmt_value++;
  960 
  961                     chptr->max_messages = atoi(value);
  962                     chptr->max_messages_time = atoi(mmt_value);
  963                     chptr->xflags |= XFLAG_SET;
  964                 }
  965             }
  966 
  967             else
  968             {
  969                 for(xflag = xflags_list; xflag->option; xflag++)
  970                 {
  971                     if(!strcasecmp(opt,xflag->option))
  972                     {
  973                         if((atoi(value) == 1) || !strcasecmp(value,"on"))
  974                         {
  975                           chptr->xflags |= xflag->flag;
  976                           chptr->xflags |= XFLAG_SET;
  977                         }
  978                         else
  979                           chptr->xflags &= ~(xflag->flag);
  980                     }
  981                 }
  982             }
  983         }
  984         else if(!strcasecmp(parv[i],"GREETMSG"))
  985         {
  986             i++;
  987             if(i > parc)
  988             {
  989                 if(chptr->greetmsg)
  990                   MyFree(chptr->greetmsg);
  991                 break;
  992             }
  993             chptr->greetmsg = (char *)MyMalloc(strlen(parv[i]) + 1);
  994             strcpy(chptr->greetmsg, parv[i]);
  995             chptr->xflags |= XFLAG_SET;
  996         }
  997     }
  998 
  999     return 0;
 1000 }
 1001 
 1002 /* m_aj - Approve channel join by services (mostly stolen from bahamut-irctoo)
 1003  * parv[1] = [@+]nick
 1004  * parv[2] = nick TS
 1005  * parv[3] = channel
 1006  * parv[4] = optional channel TS
 1007  * -Kobi_S 16/07/2005
 1008  */
 1009 int m_aj(aClient *cptr, aClient *sptr, int parc, char *parv[])
 1010 {
 1011     aClient *acptr;
 1012     aChannel *chptr;
 1013     Link *lp;
 1014     int flags = 0;
 1015     ts_val newts;
 1016     int created;
 1017     char *fnick;
 1018     char *nick;
 1019     ts_val nickts;
 1020 
 1021     if(!IsULine(sptr))
 1022         return 0; /* Only to be used by u:lined servers */
 1023 
 1024     if(parc < 4 || *parv[1] == 0)
 1025         return 0;
 1026 
 1027     fnick = nick = parv[1];
 1028     nickts = atol(parv[2]);
 1029 
 1030     while(*nick == '@' || *nick == '%' || *nick == '+')
 1031     {
 1032         switch(*nick)
 1033         {
 1034             case '@':
 1035                 flags |= CHFL_CHANOP;
 1036                 break;
 1037 #ifdef USE_HALFOPS
 1038             case '%':
 1039                 flags |= CHFL_HALFOP;
 1040                 break;
 1041 #endif
 1042             case '+':
 1043                 flags |= CHFL_VOICE;
 1044                 break;
 1045         }
 1046         nick++;
 1047     }
 1048 
 1049     if(!(acptr = find_client(nick, NULL)))
 1050         return 0; /* Can't find the target nick */
 1051 
 1052     if(nickts && acptr->tsinfo != nickts)
 1053         return 0; /* tsinfo doesn't match */
 1054 
 1055     if(*parv[3] == '0' && !atoi(parv[3]))
 1056     {
 1057         if(acptr->user->channel == NULL)
 1058             return 0; /* Target nick isn't on any channels */
 1059         while ((lp = acptr->user->channel))
 1060         {
 1061             chptr = lp->value.chptr;
 1062             sendto_channel_butserv(chptr, acptr, ":%s PART %s", acptr->name, chptr->chname);
 1063             remove_user_from_channel(acptr, chptr);
 1064         }
 1065     }
 1066     else
 1067     {
 1068         if(!check_channelname(acptr, (unsigned char *)parv[3]))
 1069             return 0; /* Invalid channel name */
 1070         chptr = get_channel(acptr, parv[3], CREATE, &created);
 1071         if(!chptr)
 1072             return 0; /* Shouldn't happen! */
 1073         if(parc>4)
 1074         {
 1075             newts = atol(parv[4]);
 1076             if(created || newts < chptr->channelts)
 1077                 chptr->channelts = newts;
 1078         }
 1079         if(!IsMember(acptr, chptr))
 1080         {
 1081             add_user_to_channel(chptr, acptr, flags);
 1082             sendto_channel_butserv(chptr, acptr, ":%s JOIN :%s", acptr->name, parv[3]);
 1083             if(MyClient(acptr))
 1084             {
 1085                 del_invite(acptr, chptr);
 1086                 if(chptr->topic[0] != '\0')
 1087                 {
 1088                     sendto_one(acptr, rpl_str(RPL_TOPIC), me.name, acptr->name,
 1089                                chptr->chname, chptr->topic);
 1090                     sendto_one(acptr, rpl_str(RPL_TOPICWHOTIME), me.name, acptr->name,
 1091                                chptr->chname, chptr->topic_nick, chptr->topic_time);
 1092                 }
 1093                 parv[0] = acptr->name;
 1094                 parv[1] = chptr->chname;
 1095                 m_names(acptr, acptr, 2, parv);
 1096                 if(chptr->greetmsg)
 1097                 {
 1098                     sendto_one(sptr, ":%s!%s@%s PRIVMSG %s :%s", Network_Name, Network_Name, DEFAULT_STAFF_ADDRESS, chptr->chname, chptr->greetmsg);
 1099                 }
 1100             }
 1101             if(flags)
 1102             {
 1103                 if(flags & CHFL_CHANOP)
 1104                  sendto_channel_butserv(chptr, sptr, ":%s MODE %s +o %s", sptr->name,
 1105                                         chptr->chname, acptr->name);
 1106 #ifdef USE_HALFOPS
 1107                 if(flags & CHFL_HALFOP)
 1108                  sendto_channel_butserv(chptr, sptr, ":%s MODE %s +h %s", sptr->name,
 1109                                         chptr->chname, acptr->name);
 1110 #endif
 1111                 if(flags & CHFL_VOICE)
 1112                  sendto_channel_butserv(chptr, sptr, ":%s MODE %s +v %s", sptr->name,
 1113                                         chptr->chname, acptr->name);
 1114             }
 1115         }
 1116     }
 1117 
 1118     /* Pass it to all the other servers... */
 1119     if(parc>4)
 1120         sendto_serv_butone(cptr, ":%s AJ %s %ld %s %s", sptr->name, fnick, nickts, parv[3], parv[4]);
 1121     else
 1122         sendto_serv_butone(cptr, ":%s AJ %s %ld %s", sptr->name, fnick, nickts, parv[3]);
 1123 
 1124     return 0;
 1125 }
 1126 
 1127 /* m_sjr - Check the join (request) with services (mostly stolen from bahamut-irctoo)
 1128  * -Kobi_S 16/07/2005
 1129  */
 1130 int m_sjr(aClient *cptr, aClient *sptr, int parc, char *parv[], AliasInfo *ai)
 1131 {
 1132     if(MyClient(sptr))
 1133         return 0; /* Don't let local users use it without permission */
 1134 
 1135     if(parc < 3 || *parv[2] == 0)
 1136         return 0;
 1137 
 1138     if(!ai->client || ai->client->from == sptr->from)
 1139         return 0; /* Check to avoid message loops when admins get stupid */
 1140 
 1141     if(parc<4)
 1142         sendto_one(ai->client->from, ":%s SJR %s %s", sptr->name, parv[1], parv[2]);
 1143     else
 1144         sendto_one(ai->client->from, ":%s SJR %s %s :%s", sptr->name, parv[1], parv[2], parv[3]);
 1145 
 1146     return 0;
 1147 }
 1148 
 1149 /* m_svsctrl - Lets services control join requests (will be extended to support other settings in the future)
 1150  * parv[0] - sender
 1151  * parv[1] - setting
 1152  * parv[2] - value
 1153  */
 1154 int m_svsctrl(aClient *cptr, aClient *sptr, int parc, char *parv[])
 1155 {
 1156     if(!IsULine(sptr) || parc<4)
 1157         return 0;
 1158 
 1159     if(parc==4 && (hunt_server(cptr, sptr, ":%s SVSCTRL %s %s :%s", 1, parc, parv) != HUNTED_ISME))
 1160         return 0;
 1161     if(parc==5 && (hunt_server(cptr, sptr, ":%s SVSCTRL %s %s %s :%s", 1, parc, parv) != HUNTED_ISME))
 1162         return 0;
 1163     if(parc==6 && (hunt_server(cptr, sptr, ":%s SVSCTRL %s %s %s %s :%s", 1, parc, parv) != HUNTED_ISME))
 1164         return 0;
 1165     if(parc==7 && (hunt_server(cptr, sptr, ":%s SVSCTRL %s %s %s %s %s :%s", 1, parc, parv) != HUNTED_ISME))
 1166         return 0;
 1167     if(parc==8 && (hunt_server(cptr, sptr, ":%s SVSCTRL %s %s %s %s %s %s :%s", 1, parc, parv) != HUNTED_ISME))
 1168         return 0;
 1169     if(parc==9 && (hunt_server(cptr, sptr, ":%s SVSCTRL %s %s %s %s %s %s %s :%s", 1, parc, parv) != HUNTED_ISME))
 1170         return 0;
 1171     if(parc!=4 && parc!=5 && parc!=6 && parc!=7 && parc!=8 && parc!=9) return 0; /* Just in case... */
 1172 
 1173     if(!mycmp(parv[2], "SJR"))
 1174     {
 1175         services_jr = atoi(parv[3]);
 1176         return 0;
 1177     }
 1178 
 1179     return 0;
 1180 }
 1181 
 1182 u_long
 1183 memcount_m_services(MCm_services *mc)
 1184 {
 1185     mc->file = __FILE__;
 1186 
 1187     return 0;
 1188 }
 1189