muhstik

- irc flooding solution
git clone git://git.acid.vegas/muhstik.git
Log | Files | Refs | Archive | README

clone.c (35649B)

      1 /* Muhstik, Copyright (C) 2001-2002, Louis Bavoil <mulder@gmx.fr>       */
      2 /*                        2003, roadr (bigmac@home.sirklabs.hu)         */
      3 /*                        2009-2011, Leon Kaiser <literalka@gnaa.eu>    */
      4 /*                                                                      */
      5 /* This program is free software; you can redistribute it and/or        */
      6 /* modify it under the terms of the GNU Library General Public License  */
      7 /* as published by the Free Software Foundation; either version 2       */
      8 /* of the License, or (at your option) any later version.               */
      9 /*                                                                      */
     10 /* This program is distributed in the hope that it will be useful,      */
     11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
     12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
     13 /* GNU Library General Public License for more details.                 */
     14 
     15 /* {{{ Header includes */
     16 #include <stdio.h>
     17 #include <stdlib.h>
     18 #include <stdarg.h>
     19 #include <unistd.h>
     20 #include <time.h>
     21 
     22 #include "../include/globals.h"
     23 #include "../include/load.h"
     24 #include "../include/control.h"
     25 #include "../include/print.h"
     26 #include "../include/proxy.h"
     27 #include "../include/string.h"
     28 #include "../include/lists.h"
     29 #include "../include/net.h"
     30 #include "../include/mass.h"
     31 #include "../include/muhstik.h"
     32 /* }}} */
     33 /* {{{ Variables */
     34 /* {{{ External variables */
     35 extern config_t conf;
     36 extern char *hostname;
     37 extern char *channel[];
     38 extern char *chankey[];
     39 extern int mass_ch;
     40 extern char *mass_reas;
     41 extern char *target;
     42 extern int echo_mode;
     43 extern const char *strtype[];
     44 /* }}} */
     45 /*{{{ Global variables */
     46 char *op_nick;
     47 clone_t *cl[MAX_CLONES];
     48 char *broth[MAX_BROTHERS];
     49 queue public_queue;
     50 queue names_op[MAX_CHANS];
     51 queue names[MAX_CHANS];
     52 time_t lastlock;
     53 /* }}} */
     54 /* }}} */
     55 /*{{{ Function prototypes */
     56 /* {{{ void do_jupe(clone_t *clone, char *nick); */
     57 /**
     58  * do_jupe()
     59  * Function prototype for `do_jupe()'.
     60  */
     61 void do_jupe(clone_t *clone, char *nick);
     62 /* }}} */
     63 /* }}} */
     64 /* {{{ free()ing and closing functions */
     65 /* {{{ void close_sock(clone_t *clone) */
     66 void close_sock(clone_t *clone)
     67 {
     68      if (clone->sock != -1)
     69      {
     70           close(clone->sock); /* XXX: free()? -- Leon */
     71      }
     72 }
     73 /* }}} */
     74 /* {{{ void free_clone(clone_t *clone) */
     75 void free_clone(clone_t *clone)
     76 {
     77      int id = clone->id;
     78 
     79      close_sock(clone);
     80 
     81      /* Free the clone memory */
     82      free(clone->jupes);
     83      free(clone->nick);
     84      free(clone->ident);
     85      free(clone->real);
     86      free(clone->proxy);
     87      free(clone->server);
     88      free(clone->server_pass);
     89      free(clone->server_ident);
     90      free(clone->save);
     91      clear_queue(&clone->queue);
     92      free(clone);
     93 
     94      /* Free its slot */
     95      cl[id] = NULL;
     96 }
     97 /* }}} */
     98 /* }}} */
     99 /* {{{ faux boolean functions */
    100 /* {{{ int not_a_clone(char *s) */
    101 /**
    102  * not_a_clone()
    103  * @return boolean value representing whether or not the nick is a clone
    104  *          controlled by this muhstik iteration.
    105  */
    106 int not_a_clone(char *s)
    107 {
    108      register int i;
    109      clone_t **pcl;
    110      char **pt;
    111 
    112      for (i = 0, pcl = cl; i < MAX_CLONES; ++i, ++pcl)
    113      {
    114           if (*pcl && !StrCompare((*pcl)->nick, s))
    115           {
    116                return 0;
    117           }
    118      }
    119 
    120      for (i = 0, pt = broth; i < MAX_BROTHERS; ++i, ++pt)
    121      {
    122           if (*pt && !StrCompare(*pt, s))
    123           {
    124                return 0;
    125           }
    126      }
    127 
    128      return 1;
    129 }
    130 /* }}} */
    131 /* {{{ int not_a_mast(char *s) */
    132 int not_a_mast(char *s)
    133 {
    134      register int i;
    135      char **pm;
    136 
    137      for (i = 0, pm = conf.prot; i < MAX_PROTS; ++i, ++pm)
    138      {
    139           if (*pm && !StrCompare(*pm, s))
    140           {
    141                return 0;
    142           }
    143      }
    144 
    145      return 1;
    146 }
    147 /* }}} */
    148 /* {{{ int is_enemy(char *s) */
    149 /**
    150  * is_enemy()
    151  * @return boolean value representing whether or not the nickname `s' is neither
    152  *          a clone nor a master.
    153  */
    154 int is_enemy(char *s)
    155 {
    156      return (not_a_clone(s) && not_a_mast(s));
    157 }
    158 /* }}} */
    159 /* {{{ int is_op(clone_t *clone, int chid) */
    160 /**
    161  * is_op()
    162  * @return boolean value representing whether or not `clone' is an op in channel
    163  *          `chid'.
    164  */
    165 int is_op(clone_t *clone, int chid)
    166 {
    167      return (clone && clone->online && clone->op[chid]);
    168 }
    169 /* }}} */
    170 /* }}} */
    171 /* {{{ Functions for opped clones */
    172 /* {{{ void op(clone_t *clone, int chid, char *s) */
    173 /**
    174  * op()
    175  * Op the nick `s' in the channel with channelid `chid' assigned to it.
    176  */
    177 void op(clone_t *clone, int chid, char *s)
    178 {
    179      send2server(clone, "MODE %s +o %s\n", channel[chid], s);
    180 }
    181 /* }}} */
    182 /* {{{ void deop(clone_t *clone, int chid, char *nick) */
    183 /**
    184  * deop()
    185  * Deop the nick `s' in the channel with channelid `chid' assigned to it.
    186  */
    187 void deop(clone_t *clone, int chid, char *nick)
    188 {
    189      send2server(clone, "MODE %s -o %s\n", channel[chid], nick);
    190 }
    191 /* }}} */
    192 /* {{{ int deop_enemy(clone_t *clone, int chid, char *nick) */
    193 /**
    194  * deop_enemy()
    195  * Deop enemy nick `nick' in channel with channelid `chid' assigned to it.
    196  * @return boolean indicating success of the deopping.
    197  */
    198 int deop_enemy(clone_t *clone, int chid, char *nick)
    199 {
    200      /* Don't try to deop a server */
    201      if (!nick[0])
    202      {
    203           return 1;
    204      }
    205 
    206      if (is_enemy(nick))
    207      {
    208           deop(clone, chid, nick);
    209           return 1;
    210      }
    211 
    212      return 0;
    213 }
    214 /* }}} */
    215 /* {{{ void kick(clone_t *clone, int chid, char *s, char *reas, int mode) */
    216 /**
    217  * kick()
    218  * Kick the nick `s' from the channel with channelid `chid' with reason `reas'.
    219  */
    220 void kick(clone_t *clone, int chid, char *s, char *reas, int mode)
    221 {
    222      char tmp[BIGBUF];
    223 
    224      snprintf(tmp, sizeof(tmp), "KICK %s %s :%s\n", channel[chid], s, reas ? reas : KICK_REAS);
    225      if (!mode)
    226      {
    227           send_sock(clone->sock, "%s", tmp);
    228      }
    229      else
    230      {
    231           send2server(clone, "%s", tmp);
    232      }
    233 }
    234 /* }}} */
    235 /* {{{ void ban(clone_t *clone, int chid, char *s, int mode) */
    236 /**
    237  * ban()
    238  * Ban host `s' from channel with channelid `chid' assigned to it.
    239  */
    240 void ban(clone_t *clone, int chid, char *s, int mode)
    241 {
    242      char tmp[BIGBUF];
    243 
    244      sscanf(s, "%*[^@]@%s", s);
    245      snprintf(tmp, sizeof(tmp), "MODE %s +b *!*@%s\n", channel[chid], s);
    246 
    247      if (!mode)
    248      {
    249           send_sock(clone->sock, "%s", tmp);
    250      }
    251      else
    252      {
    253           send2server(clone, "%s", tmp);
    254      }
    255 }
    256 /* }}} */
    257 /* {{{ void kickban(clone_t *clone, char *s) */
    258 void kickban(clone_t *clone, char *s)
    259 {
    260      send_sock(clone->sock, "WHOIS %s\n", s);
    261      clone->wait_whois = 1;
    262 }
    263 /* }}} */
    264 /* {{{ void unban(clone_t *clone, int chid, char *s) */
    265 /**
    266  * unban()
    267  * Unban host `s' from the channel with channelid `chid' assigned to it.
    268  */
    269 void unban(clone_t *clone, int chid, char *s)
    270 {
    271      send_sock(clone->sock, "MODE %s -b %s\n", channel[chid], s);
    272 }
    273 /* }}} */
    274 /* }}} */
    275 /* {{{ Misc clone->IRC communication functions */
    276 /* {{{ void join(clone_t *clone, char *dest) */
    277 /**
    278  * join()
    279  * Join channel `dest'.
    280  */
    281 void join(clone_t *clone, char *dest)
    282 {
    283      int chid;
    284 
    285      if ((chid = getchid(dest)) == -1)
    286      {
    287           return;
    288      }
    289 
    290      clone->op[chid] = 0;
    291      clone->needop[chid] = 0;
    292 
    293      if (chankey[chid] == NULL)
    294      {
    295           send_sock(clone->sock, "JOIN %s\n", dest);
    296      }
    297      else
    298      {
    299           send_sock(clone->sock, "JOIN %s :%s\n", dest, chankey[chid]);
    300      }
    301 }
    302 /* }}} */
    303 /* {{{ void echo(clone_t *clone, char *chan, char *buf) */
    304 void echo(clone_t *clone, char *chan, char *buf)
    305 {
    306      register int i;
    307      char **pchan;
    308 
    309      if (echo_mode == 0)
    310      {
    311           /* Echo the to the current channel */
    312           send_sock(clone->sock, "PRIVMSG %s %s", chan, buf);
    313      }
    314      else
    315      {
    316           /* Echo to all the active channels */
    317           for (i = 0, pchan = channel; i < MAX_CHANS; ++i, ++pchan)
    318           {
    319                if (*pchan)
    320                {
    321                     send_sock(clone->sock, "PRIVMSG %s %s", *pchan, buf);
    322                }
    323           }
    324      }
    325 }
    326 /* }}} */
    327 /* {{{ void send_irc_nick(clone_t *clone, char *nick) */
    328 /**
    329  * send_irc_nick()
    330  * Change `clone's nick to `nick'.
    331  */
    332 void send_irc_nick(clone_t *clone, char *nick)
    333 {
    334      send_sock(clone->sock, "NICK %s\n", nick);
    335 }
    336 /* }}} */
    337 /* }}} */
    338 /* {{{ Functions for initializing clones */
    339 /* {{{ void register_clone(clone_t *clone) */
    340 void register_clone(clone_t *clone)
    341 {
    342      char *ident;
    343 
    344      if (clone->server_ident)
    345      {
    346           ident = clone->server_ident;
    347      }
    348      else
    349      {
    350           ident = clone->ident;
    351      }
    352 
    353      send_sock(clone->sock, "USER %s 0 0 :%s\n", ident, clone->real);
    354 
    355      if (clone->server_pass)
    356      {
    357           send_sock(clone->sock, "PASS %s\n", clone->server_pass);
    358      }
    359 
    360      send_sock(clone->sock, "MODE %s +i\n", clone->nick);
    361 }
    362 /* }}} */
    363 /* {{{ int main_clone(void *arg) */
    364 int main_clone(void *arg)
    365 {
    366      clone_t *clone;
    367      clone = (clone_t *) arg;
    368 
    369      if (conf.debug)
    370      {
    371           if (clone->type != NOSPOOF)
    372           {
    373                print(1, 0, 0, "%s launched: host=%s server=%s", strtype[clone->type], clone->proxy, clone->server);
    374           }
    375           else
    376           {
    377                print(1, 0, 0, "direct connection launched: server=%s", clone->server);
    378           }
    379      }
    380 
    381      if (clone->type == NOSPOOF || clone->type == VHOST)
    382      {
    383           if (connect_clone(clone, clone->server, clone->server_port))
    384           {
    385                return 1;
    386           }
    387      }
    388      else
    389      {
    390           if (connect_clone(clone, clone->proxy, clone->proxy_port))
    391           {
    392                return 1;
    393           }
    394      }
    395 
    396      clone->status = WAIT_CONNECT;
    397      return 0;
    398 }
    399 /* }}} */
    400 /* }}} */
    401 /* {{{ Functions for parsing and acting on that parsing */
    402 /* {{{ int parse_deco(clone_t *clone, char *buf) */
    403 int parse_deco(clone_t *clone, char *buf)
    404 {
    405      if (!clone->online)
    406      {
    407           if (!StrCmpPrefix(buf, "ERROR"))
    408           {
    409                if (strstr(buf, "Too many user connections") || strstr(buf, "Too many host connections") ||
    410                    strstr(buf, "Too many connections") || strstr(buf, "This server is full") || strstr(buf, "Invalid username")) /* 468 = invalidusername */
    411                {
    412                     if (clone->save)
    413                     {
    414                          save_host(clone);
    415                     }
    416                }
    417           }
    418           if (conf.debug)
    419           {
    420                print_prefix(clone, 4, 0);
    421                print(0, 4, 0, "%s", buf);
    422           }
    423           return 1;
    424      }
    425 
    426      clone->online = 0;
    427 
    428      if (conf.verbose)
    429      {
    430           print_prefix(clone, 4, 0);
    431           print(0, 4, 0, "%s", buf);
    432      }
    433 
    434      if (conf.max_reco < 0 || clone->reco < conf.max_reco)
    435      {
    436           if (conf.verbose)
    437           {
    438                print_prefix(clone, 0, 0);
    439                print(1, 0, 0, "is trying to reconnect");
    440           }
    441           clone->alarm = time(NULL) + conf.wait_reco;
    442           if (conf.max_reco > 0)
    443           {
    444                ++clone->reco;
    445           }
    446           close_sock(clone);
    447           main_clone(clone);
    448           return 0;
    449      }
    450 
    451      return 1;
    452 }
    453 /* }}} */
    454 /* {{{ void save_host(clone_t *clone) */
    455 void save_host(clone_t *clone)
    456 {
    457      FILE *f;
    458      char ip[MEDBUF];
    459      char line[MEDBUF];
    460 
    461      if (clone->type == NOSPOOF)
    462      {
    463           return;
    464      }
    465 
    466      host2ip(ip, clone->proxy, sizeof(ip));
    467 
    468      if (clone->type == PROXY || clone->type == SOCKS4 || clone->type == SOCKS5)
    469      {
    470           snprintf(line, sizeof(line), "%s:%d\n", ip, clone->proxy_port);
    471      }
    472      else
    473      {
    474           snprintf(line, sizeof(line), "%s\n", ip);
    475      }
    476 
    477      if (!occur_file(line, clone->save) && (f = fopen(clone->save, "a+")))
    478      {
    479           fputs(line, f);
    480           fclose(f);
    481      }
    482 }
    483 /* }}} */
    484 /* {{{ void parse_irc_connect(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    485 void parse_irc_connect(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    486 {
    487      int chid;
    488 
    489      if (clone->save)
    490      {
    491           save_host(clone);
    492      }
    493 
    494      if (clone->type != NOSPOOF)
    495      {
    496           print(1, 3, 0, "clone available: nick=%s; %s=%s; server=%s", clone->nick, strtype[clone->type], clone->proxy, clone->server);
    497      }
    498      else
    499      {
    500           print(1, 3, 0, "clone available: nick=%s; server=%s", clone->nick, clone->server);
    501      }
    502 
    503      if (conf.scan || clone->mode == M_QUIT)
    504      {
    505           free_clone(clone);
    506           return;
    507      }
    508 
    509      clone->online = 1;
    510 
    511      if (clone->mode == M_NORMAL)
    512      {
    513           for (chid = 0; chid < MAX_CHANS; ++chid)
    514           {
    515                if (channel[chid])
    516                {
    517                     join(clone, channel[chid]);
    518                }
    519           }
    520      }
    521 }
    522 /* }}} */
    523 /* {{{ Jupe functions */
    524 /* {{{ void parse_irc_isupport(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    525 void parse_irc_isupport(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    526 {
    527      char *mspec_str = NULL;
    528 
    529      if (NULL != (mspec_str = strstr(buf, "MONITOR=")))
    530      {
    531           sscanf(mspec_str, "MONITOR=%u", &(clone->monitor_tmax));
    532           if (0 == clone->monitor_tmax)
    533           {
    534                return;
    535           }
    536 
    537           clone->jupes = xmalloc((conf.nick_length + 1) * clone->monitor_tmax);
    538           bzero(clone->jupes, (conf.nick_length + 1) * clone->monitor_tmax);
    539      }
    540 }
    541 /* }}} */
    542 /* {{{ void parse_irc_moffline(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    543 void parse_irc_moffline(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    544 {
    545      char *pnick0 = buf;
    546      char *pnick = pnick0;
    547 
    548      if(!((NULL != (pnick0 = strchr(pnick0, ':'))) && *(++pnick0)))
    549      {
    550           return;
    551      }
    552 
    553      pnick = pnick0;
    554      strsep(&(pnick0), "\r\n");
    555      pnick0 = pnick;
    556 
    557      while(NULL != (pnick = strsep(&(pnick0), ",")))
    558      {
    559           do_jupe(clone, pnick);
    560      }
    561 }
    562 /* }}} */
    563 /* {{{ void do_jupe(clone_t *clone, char *nick) */
    564 void do_jupe(clone_t *clone, char *nick)
    565 {
    566      int i;
    567      clone_t **pcl;
    568 
    569      if (occur_table(nick, conf.juping, MAX_JUPES))
    570      {
    571           return;
    572      }
    573 
    574      print_prefix(clone, 0, 0);
    575      print(1, 0, 0, "nickname `%s' is available, trying to grab", nick);
    576 
    577      for (i = 0, pcl = cl; i < MAX_CLONES; ++i, ++pcl)
    578      {
    579           if ((*pcl) && (*pcl)->online && (*pcl)->grabbing == 0)
    580           {
    581                send_irc_nick((*pcl), nick);
    582                print_prefix((*pcl), 0, 0);
    583                print(1, 0, 0, "Nice nick, I think I'll take it.");
    584                (*pcl)->grabbing = 1;
    585                add_table(nick, conf.juping, MAX_JUPES);
    586                return;
    587           }
    588      }
    589 
    590      print_prefix(clone, 0, 0);
    591      print(1, 0, 0, "no clones left that aren't juping", nick);
    592 }
    593 /* }}} */
    594 /* }}} */
    595 /* {{{ void parse_irc_kickban(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    596 void parse_irc_kickban(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    597 {
    598      char *toban;
    599      char *tokick;
    600 
    601      if (!clone->wait_whois)
    602      {
    603           return;
    604      }
    605 
    606      clone->lastsend = time(NULL);
    607      clone->wait_whois = 0;
    608 
    609      strsep(&buf, DELIM);
    610      if (!(tokick = strsep(&buf, DELIM)))
    611      {
    612           return;
    613      }
    614 
    615      strsep(&buf, DELIM);
    616      if (!(toban = strsep(&buf, DELIM)))
    617      {
    618           return;
    619      }
    620 
    621      ban(clone, mass_ch, toban, 0);
    622      kick(clone, mass_ch, tokick, mass_reas ? mass_reas : NULL, 0);
    623 }
    624 /* }}} */
    625 /* {{{ void parse_irc_nick(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    626 void parse_irc_nick(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    627 {
    628      char *dest;
    629      int chid;
    630 
    631      strsep(&buf, ":");
    632      if (!(dest = strsep(&buf, DELIM)))
    633      {
    634           return;
    635      }
    636 
    637      if (!StrCompare(nick, clone->nick))
    638      {
    639           StrCopy(clone->nick, dest, conf.nick_length+1);
    640      }
    641 
    642      if (target && !StrCompare(nick, target))
    643      {
    644           free(target);
    645           target = StrDuplicate(dest);
    646      }
    647 
    648      update_table(nick, dest, broth, MAX_BROTHERS);
    649      update_table(nick, dest, conf.prot, MAX_PROTS);
    650 
    651      update_pattern_table(nick, dest, conf.aop, MAX_AOPS);
    652 
    653      for (chid = 0; chid < MAX_CHANS; ++chid)
    654      {
    655           update_queue(nick, dest, &names[chid]);
    656           update_queue(nick, dest, &names_op[chid]);
    657      }
    658 }
    659 /* }}} */
    660 /* {{{ void parse_irc_control(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    661 void parse_irc_control(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    662 {
    663      char buffer[BIGBUF];
    664      char is_aop;
    665 
    666      snprintf(buffer, sizeof(buffer), "%s %s %s %s", from, cmd, clone->nick, buf);
    667      is_aop = (match_table(from, conf.aop, MAX_AOPS) != -1);
    668 
    669      if (is_aop && conf.notice)
    670      {
    671           if (conf.verbose)
    672           {
    673                print(0, 5, 0, "%s", buffer);
    674           }
    675           buf = strstr(buffer, " :") + 2; /* don't interfere with IPv6 IP */
    676           op_nick = StrDuplicate(nick);
    677           interpret(buf, -clone->id - 2);
    678      }
    679 }
    680 /* }}} */
    681 /* {{{ void parse_irc_notice(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    682 void parse_irc_notice(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    683 {
    684      char parm[MINIBUF];
    685      strsep(&buf, DELIM);
    686 
    687      /* Skip mIRC DCC info */
    688      if (!StrParam(parm, sizeof(parm), buf, 0))
    689      {
    690           if (!StrCompare(parm, ":dcc"))
    691           {
    692                return;
    693           }
    694      }
    695 
    696      parse_irc_control (clone, cmd, nick, from, buf);
    697 }
    698 /* }}} */
    699 /* {{{ void parse_irc_privmsg(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    700 void parse_irc_privmsg(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    701 {
    702      int chid;
    703      char *dest;
    704      char *parm;
    705 
    706      dest = strsep(&buf, DELIM);
    707      if (!StrCompare(dest, clone->nick))
    708      {
    709           parse_irc_control(clone, cmd, nick, from, buf);
    710           return;
    711      }
    712 
    713      if (target && !StrCompare(nick,target))
    714      {
    715           echo(clone, dest, buf);
    716           return;
    717      }
    718 
    719      if ((chid = getchid(dest)) == -1)
    720      {
    721           return;
    722      }
    723 
    724      if (conf.aggressive && is_enemy(nick))
    725      {
    726           kick(clone, chid, nick, NULL, 1);
    727           return;
    728      }
    729 
    730      if (!(parm = strsep(&buf, DELIM)))
    731      {
    732           return;
    733      }
    734 
    735      if (!StrCompare(parm,":!op"))
    736      {
    737           if (match_table(from, conf.aop, MAX_AOPS) != -1)
    738           {
    739                if (clone->op[chid])
    740                {
    741                     op(clone, chid, nick);
    742                }
    743           }
    744      }
    745 }
    746 /* }}} */
    747 /* {{{ void join_scan(scan_t *scan, char *from) */
    748 void join_scan(scan_t *scan, char *from)
    749 {
    750      char *host;
    751      char ip[MINIBUF];
    752      char line[MEDBUF];
    753 
    754      if (!(host = strchr(from, '@')))
    755      {
    756           return;
    757      }
    758 
    759      host2ip(ip, ++host, sizeof(ip));
    760 
    761      if (scan->type == PROXY)
    762      {
    763           snprintf(line, sizeof(line), "%s:%d\n", ip, scan->proxy_port);
    764      }
    765      else
    766      {
    767           snprintf(line, sizeof(line), "%s\n", ip);
    768      }
    769 
    770      if (!occur_file(line, scan->save))
    771      {
    772           load_host(scan->type, host, scan->proxy_port, scan->server, scan->server_port, NULL, NULL, scan->save, scan->mode);
    773      }
    774 }
    775 /* }}} */
    776 /* {{{ void parse_irc_join(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    777 void parse_irc_join(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    778 {
    779      int i;
    780      int is_aop;
    781      int chid;
    782      char *chan;
    783      char *reas;
    784 
    785      strsep(&buf, ":");
    786      chan = strsep(&buf, DELIM);
    787 
    788      if ((chid = getchid(chan)) == -1)
    789      {
    790           return;
    791      }
    792 
    793      if (!StrCompare(nick, clone->nick))
    794      {
    795           if (!clone->restricted)
    796           {
    797                clone->needop[chid] = 1;
    798           }
    799           return;
    800      }
    801 
    802      is_aop = (match_table(from, conf.aop, MAX_AOPS) != -1);
    803      if (is_aop && !occur_table(nick, conf.prot, MAX_PROTS))
    804      {
    805           if (add_table(nick, conf.prot, MAX_PROTS) != -1)
    806           {
    807                if (conf.verbose)
    808                {
    809                     print(1, 0, 0, "%s added to the protected nicks (aop)", nick);
    810                }
    811           }
    812      }
    813 
    814      uniq_add_queue(nick, &names[chid]);
    815 
    816      if (clone->op[chid])
    817      {
    818           if (is_aop || !not_a_clone(nick))
    819           {
    820                op(clone, chid, nick);
    821                return;
    822           }
    823           if ((i = match_table(from, conf.shit, MAX_SHITS)) != -1)
    824           {
    825                ban(clone, chid, from, 1);
    826                if ((reas = strchr(conf.shit[i], ':')))
    827                {
    828                     kick(clone, chid, nick, reas+1, 1);
    829                }
    830                else
    831                {
    832                     kick(clone, chid, nick, SHIT_REAS, 1);
    833                }
    834                return;
    835           }
    836      }
    837 
    838      if (clone->scan)
    839      {
    840           join_scan(clone->scan, from);
    841      }
    842 }
    843 /* }}} */
    844 /* {{{ void parse_irc_error_invite(clone_t *clone, int chid) */
    845 void parse_irc_error_invite(clone_t *clone, int chid)
    846 {
    847      clone_t *one;
    848 
    849      if ((one = getop(chid)))
    850      {
    851           send_sock(one->sock, "INVITE %s %s\n", clone->nick, channel[chid]);
    852      }
    853 }
    854 /* }}} */
    855 /* {{{ void parse_irc_error(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    856 void parse_irc_error(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    857 {
    858      int chid;
    859      char *chan;
    860      char buffer[BIGBUF];
    861 
    862      snprintf(buffer, sizeof(buffer), "%s %s %s", from, cmd, buf);
    863 
    864      if (conf.verbose)
    865      {
    866           print(0, 5, 0, "%s", buffer);
    867      }
    868 
    869      if (!StrCompare(cmd,"484")) /* ischanservice */
    870      {
    871           clone->restricted = 1;
    872           return;
    873      }
    874 
    875      strsep(&buf, DELIM);
    876      chan = strsep(&buf, DELIM);
    877 
    878      if ((chid = getchid(chan)) == -1)
    879      {
    880           return;
    881      }
    882 
    883      if (!StrCompare(cmd,"471") || !StrCompare(cmd,"473")) /* +l or +i */
    884      {
    885           parse_irc_error_invite(clone, chid);
    886      }
    887 
    888      if (!StrCompare(cmd,"372") || !StrCompare(cmd,"375") || !StrCompare(cmd,"376")) /* MOTD numerics. */
    889      {
    890           return; /* These errors would otherwise kill good clones. */
    891      }
    892 
    893      clone->alarm = time(NULL) + conf.rejoin;
    894 
    895      if (occur_table(channel[chid], channel, MAX_CHANS))
    896      {
    897           join(clone, channel[chid]);
    898      }
    899 }
    900 /* }}} */
    901 /* {{{ void parse_irc_kick(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    902 void parse_irc_kick(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    903 {
    904      int chid;
    905      char *chan;
    906      char *kicked;
    907 
    908      chan = strsep(&buf, DELIM);
    909      kicked = strsep(&buf, DELIM);
    910 
    911      if ((chid = getchid(chan)) == -1)
    912      {
    913           return;
    914      }
    915 
    916      remove_queue(kicked, &names_op[chid]);
    917      remove_queue(kicked, &names[chid]);
    918 
    919      if (!StrCompare(kicked, clone->nick))
    920      {
    921           clone->op[chid] = 0;
    922           clone->needop[chid] = 0;
    923           join(clone, channel[chid]);
    924      }
    925      else if (!conf.peace && clone->op[chid])
    926      {
    927           if (!conf.aggressive)
    928           {
    929                deop_enemy(clone, chid, nick);
    930           }
    931           else
    932           {
    933                massdeop(clone, chid);
    934           }
    935      }
    936 }
    937 /* }}} */
    938 /* {{{ void parse_irc_part(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    939 void parse_irc_part(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    940 {
    941      char *chan;
    942      int chid;
    943 
    944      chan = strsep(&buf, DELIM);
    945      if ((chid = getchid(chan)) == -1)
    946      {
    947           return;
    948      }
    949 
    950      remove_queue(nick, &names_op[chid]);
    951      remove_queue(nick, &names[chid]);
    952 }
    953 /* }}} */
    954 /* {{{ void parse_irc_mode(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
    955 void parse_irc_mode(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
    956 {
    957      int chid;
    958      char *chan;
    959      char *mode;
    960      char *parm;
    961      int i;
    962      int x = 1;        /* by default it's + */
    963 
    964      if (clone->restricted)
    965      {
    966           return;
    967      }
    968 
    969      chan = strsep(&buf, DELIM);
    970      mode = strsep(&buf, DELIM);
    971 
    972      if (!StrCompare(chan, clone->nick))
    973      {
    974           return;
    975      }
    976 
    977      if ((chid = getchid(chan)) == -1)
    978      {
    979           return;
    980      }
    981 
    982      if (conf.aggressive && !clone->op[chid])
    983      {
    984           clone->needop[chid] = 1;
    985      }
    986 
    987      for (i = 0; mode[i]; ++i)
    988      {
    989           switch (mode[i])
    990           {
    991                case '+':
    992                     x = 1;
    993                     break;
    994                case '-':
    995                     x = -1;
    996                     break;
    997                case 'b':
    998                case 'e':
    999                case 'I':
   1000                case 'k':
   1001                case 'l':
   1002                case 'h':        /* do we really need this? */
   1003                case 'v':
   1004                     parm = strsep(&buf, DELIM);
   1005                     break;
   1006                case 'o':
   1007                     parm = strsep(&buf, DELIM);
   1008                     if (x == 1)        /* +o */
   1009                     {
   1010                          uniq_add_queue(parm, &names_op[chid]);
   1011                          remove_queue(parm, &names[chid]);
   1012                          if (!clone->op[chid] && !StrCompare(clone->nick, parm))
   1013                          {
   1014                               clone->op[chid] = 1;
   1015                               clone->needop[chid] = 0;
   1016                               massop(clone, chid);
   1017                          }
   1018                          if (!conf.aggressive && !conf.peace)
   1019                          {
   1020                               if (clone->op[chid] && deop_enemy(clone, chid, nick))
   1021                               {
   1022                                    if (is_enemy(parm))
   1023                                    {
   1024                                         deop(clone, chid, parm);
   1025                                    }
   1026                               }
   1027                          }
   1028                     }
   1029                     else                /* -o */
   1030                     {
   1031                          uniq_add_queue(parm, &names[chid]);
   1032                          remove_queue(parm, &names_op[chid]);
   1033                          if (clone->op[chid] && !StrCompare(clone->nick, parm))
   1034                          {
   1035                               clone->op[chid] = 0;
   1036                               clone->needop[chid] = 1;
   1037                          }
   1038                          else if (clone->op[chid])
   1039                          {
   1040                               if (!conf.aggressive && !conf.peace)
   1041                               {
   1042                                    deop_enemy(clone, chid, nick);
   1043                               }
   1044                               if (StrCompare(nick, parm) && !is_enemy(parm))
   1045                               {
   1046                                    op(clone, chid, parm);
   1047                               }
   1048                          }
   1049                     }
   1050                break;
   1051           }
   1052      }
   1053 
   1054      if (conf.aggressive && !conf.peace && clone->op[chid])
   1055      {
   1056           massdeop(clone, chid);
   1057      }
   1058 }
   1059 /* }}} */
   1060 /* {{{ void parse_irc_names(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
   1061 void parse_irc_names(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
   1062 {
   1063      int chid;
   1064      char *chan;
   1065      char parm[MINIBUF];
   1066      register int i;
   1067 
   1068      strsep(&buf, DELIM);
   1069      strsep(&buf, DELIM);
   1070      chan = strsep(&buf, DELIM);
   1071      strsep(&buf, ":");
   1072 
   1073      if ((chid = getchid(chan)) == -1)
   1074      {
   1075           return;
   1076      }
   1077 
   1078      for (i = 0; !StrParam(parm, sizeof(parm), buf, i); ++i)
   1079      {
   1080           if (parm[0] == '@')
   1081           {
   1082                uniq_add_queue(parm+1, &names_op[chid]);
   1083           }
   1084           else if (parm[0] == '+')
   1085           {
   1086                uniq_add_queue(parm+1, &names[chid]);
   1087           }
   1088           else
   1089           {
   1090                uniq_add_queue(parm, &names[chid]);
   1091           }
   1092      }
   1093 
   1094      if (clone->restricted)
   1095      {
   1096           return;
   1097      }
   1098 
   1099      snprintf(parm, sizeof(parm), "@%s", clone->nick);
   1100      if (is_in(parm, buf))
   1101      {
   1102           clone->op[chid] = 1;
   1103           clone->needop[chid] = 0;
   1104      }
   1105 }
   1106 /* }}} */
   1107 /* {{{ void parse_irc_topic(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
   1108 void parse_irc_topic(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
   1109 {
   1110      int chid;
   1111      char *chan;
   1112 
   1113      if (conf.peace)
   1114      {
   1115           return;
   1116      }
   1117 
   1118      chan = strsep(&buf, DELIM);
   1119      if ((chid = getchid(chan)) == -1)
   1120      {
   1121           return;
   1122      }
   1123 
   1124      if (clone->op[chid])
   1125      {
   1126           deop_enemy(clone, chid, nick);
   1127      }
   1128 }
   1129 /* }}} */
   1130 /* {{{ void parse_irc_unban(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
   1131 void parse_irc_unban(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
   1132 {
   1133      char *chan;
   1134      char *toban;
   1135      int chid;
   1136 
   1137      strsep(&buf, DELIM);
   1138      chan = strsep(&buf, DELIM);
   1139 
   1140      if ((chid = getchid(chan)) == -1)
   1141      {
   1142           return;
   1143      }
   1144 
   1145      if (!(toban = strsep(&buf, DELIM)))
   1146      {
   1147           return;
   1148      }
   1149 
   1150      unban(clone, chid, toban);
   1151 }
   1152 /* }}} */
   1153 /* {{{ void parse_irc_quit(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */
   1154 void parse_irc_quit(clone_t *clone, char *cmd, char *nick, char *from, char *buf)
   1155 {
   1156      int chid;
   1157 
   1158      if (!remove_table(nick, conf.prot, MAX_PROTS))
   1159      {
   1160           if (conf.verbose)
   1161           {
   1162                print(1, 0, 0, "%s not protected anymore (quit)", nick);
   1163           }
   1164      }
   1165 
   1166      for (chid = 0; chid < MAX_CHANS; ++chid)
   1167      {
   1168           remove_queue(nick, &names_op[chid]);
   1169           remove_queue(nick, &names[chid]);
   1170      }
   1171 }
   1172 /* }}} */
   1173 /* {{{ Constants */
   1174 #define IDENT1 "IDENTIFY"
   1175 #define IDENT2 "choose another one"
   1176 #define IDENT3 "Please choose a different nickname"
   1177 /* }}} */
   1178 /* {{{ int nick_error(char *cmd, char *nick, char *buf) */
   1179 int nick_error(char *cmd, char *nick, char *buf)
   1180 {
   1181      if (conf.dalnet && !StrCompare(nick, "nickserv"))
   1182      {
   1183           if (strstr(buf, IDENT1) || strstr(buf, IDENT2) || strstr(buf, IDENT3))
   1184           {
   1185                return 1;
   1186           }
   1187      }
   1188 /* XXX: There *has* to be a better way to compact this. -- Leon */
   1189      if (!StrCompare(cmd, "431") || !StrCompare(cmd, "432") || !StrCompare(cmd, "433") || !StrCompare(cmd, "436") || !StrCompare(cmd, "437") || !StrCompare(cmd, "438"))
   1190      {
   1191           return 1;
   1192      }
   1193 
   1194      return 0;
   1195 }
   1196 /* }}} */
   1197 /* {{{ void parse_irc(clone_t *clone, char *buf) */
   1198 void parse_irc(clone_t *clone, char *buf)
   1199 {
   1200      char *from;
   1201      char *parm;
   1202      char nick[MINIBUF+1];
   1203 /* NOTE: 431, 432, 433, 436, 437, & 438 are covered by ``nick_error()'' */
   1204      static msg_t msg[] =
   1205           { { "JOIN",     parse_irc_join         },
   1206             { "PART",     parse_irc_part         },
   1207             { "QUIT",     parse_irc_quit         },
   1208             { "NICK",     parse_irc_nick         },
   1209             { "PRIVMSG",  parse_irc_privmsg      },
   1210             { "NOTICE",   parse_irc_notice       },
   1211             { "KICK",     parse_irc_kick         },
   1212             { "MODE",     parse_irc_mode         },
   1213             { "TOPIC",    parse_irc_topic        },
   1214             { "001",      parse_irc_connect      },
   1215             { "005",      parse_irc_isupport     },
   1216             { "311",      parse_irc_kickban      },
   1217             { "353",      parse_irc_names        },
   1218             { "367",      parse_irc_unban        },
   1219             { "372",      parse_irc_error        },
   1220             { "471",      parse_irc_error        },
   1221             { "472",      parse_irc_error        },
   1222             { "473",      parse_irc_error        },
   1223             { "474",      parse_irc_error        },
   1224             { "475",      parse_irc_error        },
   1225             { "484",      parse_irc_error        },
   1226             { "731",      parse_irc_moffline     },
   1227             { NULL,       NULL,                  }
   1228           };
   1229      msg_t *pmsg;
   1230 /* TODO:
   1231    367 => "banlist",
   1232    368 => "endofbanlist",
   1233    404 => "cannotsendtochan",
   1234    "INVITE"/"KILL"
   1235 */
   1236 
   1237      if (!StrCmpPrefix(buf, "PING"))
   1238      {
   1239           buf[1] = 'O';
   1240           send(clone->sock, buf, strlen(buf), 0);
   1241           return;
   1242      }
   1243 
   1244      if (!strsep(&buf, ":"))
   1245      {
   1246           return;
   1247      }
   1248 
   1249      if (!(from = strsep(&buf, DELIM)))
   1250      {
   1251           return;
   1252      }
   1253 
   1254      if (!(parm = strsep(&buf, DELIM)))
   1255      {
   1256           return;
   1257      }
   1258 
   1259      if (strchr(from, '!'))
   1260      {
   1261           sscanf(from, "%"MINIBUF_TXT"[^!]", nick);
   1262      }
   1263      else
   1264      {
   1265           nick[0] = 0;
   1266      }
   1267 
   1268      if (nick_error(parm, nick, buf))
   1269      {
   1270           randget(clone, &clone->nick2, conf.nick_length, conf.use_wordlist, conf.nicks, MAX_NICKS);
   1271           if (conf.verbose)
   1272           {
   1273                print(1, 0, 0, "nickname error for %s, changing to %s.", clone->nick, clone->nick2);
   1274           }
   1275           if (!clone->online)
   1276           {
   1277                StrCopy(clone->nick, clone->nick2, conf.nick_length+1);
   1278           }
   1279           send_irc_nick(clone, clone->nick2);
   1280           free(clone->nick2);
   1281           return;
   1282      }
   1283 
   1284      for (pmsg = msg; pmsg->parm; ++pmsg)
   1285      {
   1286           if (!StrCompare(parm, pmsg->parm))
   1287           {
   1288                pmsg->function(clone, parm, nick, from, buf);
   1289                return;
   1290           }
   1291      }
   1292 }
   1293 /* }}} */
   1294 /* }}} */
   1295 /* {{{ send_*() functions */
   1296 /* {{{ void send_join(char *buffer) */
   1297 void send_join(char *buffer)
   1298 {
   1299      register int id;
   1300      clone_t **pcl;
   1301      char *chan;
   1302 
   1303      if (!strsep(&buffer, DELIM))
   1304      {
   1305           return;
   1306      }
   1307 
   1308      if (!(chan=strsep(&buffer, DELIM)))
   1309      {
   1310           return;
   1311      }
   1312 
   1313      for (id = 0, pcl = cl; id < MAX_CLONES; ++id, ++pcl)
   1314      {
   1315           if (*pcl && (*pcl)->online)
   1316           {
   1317                join(*pcl, chan);
   1318           }
   1319      }
   1320 }
   1321 /* }}} */
   1322 /* {{{ void send_nick() */
   1323 void send_nick()
   1324 {
   1325      register int id;
   1326      clone_t **pcl;
   1327 
   1328      for (id = 0, pcl = cl; id < MAX_CLONES; ++id, ++pcl)
   1329      {
   1330           if (*pcl && (*pcl)->online && (*pcl)->grabbing == 0)
   1331           {
   1332                randget(*pcl, &(*pcl)->nick2, conf.nick_length, conf.use_wordlist, conf.nicks, MAX_NICKS);
   1333                send_irc_nick(*pcl, (*pcl)->nick2);
   1334                free((*pcl)->nick2);
   1335           }
   1336      }
   1337 }
   1338 /* }}} */
   1339 /* {{{ void send2clones(char *buffer) */
   1340 void send2clones(char *buffer)
   1341 {
   1342      register int id;
   1343      clone_t **pcl;
   1344 
   1345      if (!StrCmpPrefix(buffer, "join"))
   1346      {
   1347           send_join(buffer);
   1348      }
   1349      else if (!StrCmpPrefix(buffer, NICKS))
   1350      {
   1351           send_nick();
   1352      }
   1353      else
   1354      {
   1355           for (id = 0, pcl = cl; id < MAX_CLONES; ++id, ++pcl)
   1356           {
   1357                if (*pcl && (*pcl)->online)
   1358                {
   1359                     send((*pcl)->sock, buffer, strlen(buffer), 0);
   1360                }
   1361           }
   1362      }
   1363 }
   1364 /* }}} */
   1365 /* {{{ void send2server(clone_t *clone, const char *fmt, ...) */
   1366 void send2server(clone_t *clone, const char *fmt, ...)
   1367 {
   1368      static int lastlock = 0;
   1369      clone_t **pcl;
   1370      time_t now;
   1371      int i;
   1372      int j;
   1373      int n;
   1374      char tosend[BIGBUF];
   1375      va_list ap;
   1376 
   1377      now = time(NULL);
   1378 
   1379      /* Synchronization of the queues */
   1380      if (lastlock != now)
   1381      {
   1382           lastlock = now;
   1383           clear_queue(&public_queue);
   1384 
   1385           for (i = 0, pcl = cl; i < MAX_CLONES; ++i, ++pcl)
   1386           {
   1387                if (*pcl)
   1388                {
   1389                     clear_queue(&(*pcl)->queue);
   1390                }
   1391           }
   1392      }
   1393 
   1394      va_start(ap, fmt);
   1395      n = vsnprintf(tosend, sizeof(tosend), fmt, ap);
   1396      va_end(ap);
   1397 
   1398      /* Each clone has its own send queue. */
   1399      /* Before trying to send anything, it puts it in. */
   1400      add_queue(tosend, &clone->queue);
   1401 
   1402      /* If the public queue has more occurences of the message, it has */
   1403      /* already been sent to IRC. */
   1404      i = occur_queue(tosend, &clone->queue) + conf.repeat;
   1405      j = occur_queue(tosend, &public_queue);
   1406 
   1407      if (i <= j)
   1408      {
   1409           return;
   1410      }
   1411 
   1412      add_queue(tosend, &public_queue);
   1413 
   1414      send(clone->sock, tosend, strlen(tosend), 0);
   1415      clone->lastsend = now;
   1416 }
   1417 /* }}} */
   1418 /* }}} */