Example #1
0
/* This is a reply on ISON :<current> <orig> [<alt>]
 */
static void got303(char *from, char *msg)
{
  char *tmp, *alt;
  int ison_orig = 0, ison_alt = 0;

  if (!keepnick || !strncmp(botname, origbotname, strlen(botname))) {
    return;
  }
  newsplit(&msg);
  fixcolon(msg);
  alt = get_altbotnick();
  tmp = newsplit(&msg);
  if (tmp[0] && !rfc_casecmp(botname, tmp)) {
    while ((tmp = newsplit(&msg))[0]) { /* no, it's NOT == */
      if (!rfc_casecmp(tmp, origbotname))
        ison_orig = 1;
      else if (alt[0] && !rfc_casecmp(tmp, alt))
        ison_alt = 1;
    }
    if (!ison_orig) {
      if (!nick_juped)
        putlog(LOG_MISC, "*", IRC_GETORIGNICK, origbotname);
      dprintf(DP_SERVER, "NICK %s\n", origbotname);
    } else if (alt[0] && !ison_alt && rfc_casecmp(botname, alt)) {
      putlog(LOG_MISC, "*", IRC_GETALTNICK, alt);
      dprintf(DP_SERVER, "NICK %s\n", alt);
    }
  }
}
Example #2
0
/* 438 : Nick change too fast
 */
static int got438(char *from, char *msg)
{
  newsplit(&msg);
  newsplit(&msg);
  fixcolon(msg);
  putlog(LOG_MISC, "*", "%s", msg);
  return 0;
}
Example #3
0
/* 001: welcome to IRC (use it to fix the server name) */
static int got001(char *from, char *msg)
{
  int i;
  char *key;
  struct chanset_t *chan;
  struct server_list *x = serverlist;

  /* FIXME - x should never be NULL anywhere in this function, but
   * apparently it sometimes is. */
  if (x) {
    for (i = curserv; i > 0 && x; i--)
      x = x->next;
    if (!x) {
      putlog(LOG_MISC, "*", "Invalid server list!");
    } else {
      if (x->realname)
        nfree(x->realname);
      x->realname = nmalloc(strlen(from) + 1);
      strcpy(x->realname, from);
    }
    if (realservername)
      nfree(realservername);
    realservername = nmalloc(strlen(from) + 1);
    strcpy(realservername, from);
  } else
    putlog(LOG_MISC, "*", "No server list!");

  server_online = now;
  fixcolon(msg);
  strncpyz(botname, msg, NICKLEN);
  altnick_char = 0;
  dprintf(DP_SERVER, "WHOIS %s\n", botname); /* get user@host */
  if (initserver[0])
    do_tcl("init-server", initserver); /* Call Tcl init-server */
  check_tcl_event("init-server");

  if (!x)
    return 0;

  if (module_find("irc", 0, 0)) {  /* Only join if the IRC module is loaded. */
    for (chan = chanset; chan; chan = chan->next) {
      chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
      if (!channel_inactive(chan)) {

        key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
        if (key[0])
          dprintf(DP_SERVER, "JOIN %s %s\n",
                  chan->name[0] ? chan->name : chan->dname, key);
        else
          dprintf(DP_SERVER, "JOIN %s\n",
                  chan->name[0] ? chan->name : chan->dname);
      }
    }
  }

  return 0;
}
Example #4
0
/* Pong from server.
 */
static int gotpong(char *from, char *msg)
{
  newsplit(&msg);
  fixcolon(msg);                /* Scrap server name */
  server_lag = now - my_atoul(msg);
  if (server_lag > 99999) {
    /* IRCnet lagmeter support by drummer */
    server_lag = now - lastpingtime;
  }
  return 0;
}
Example #5
0
/*
 * 465     ERR_YOUREBANNEDCREEP :You are banned from this server
 */
static int got465(char *from, char *msg)
{
  newsplit(&msg); /* 465 */

  fixcolon(msg);

  putlog(LOG_SERV, "*", "Server (%s) says I'm banned: %s", from, msg);
  putlog(LOG_SERV, "*", "Disconnecting from server.");
  nuke_server("Banned from server.");
  return 1;
}
Example #6
0
/* WALLOPS: oper's nuisance
 */
static int gotwall(char *from, char *msg)
{
  char *nick;

  fixcolon(msg);

  if (check_tcl_wall(from, msg) != 2) {
    if (strchr(from, '!')) {
      nick = splitnick(&from);
      putlog(LOG_WALL, "*", "!%s(%s)! %s", nick, from, msg);
    } else
      putlog(LOG_WALL, "*", "!%s! %s", from, msg);
  }
  return 0;
}
Example #7
0
/* Got nick change.
 */
static int gotnick(char *from, char *msg)
{
  char *nick, *alt = get_altbotnick();

  nick = splitnick(&from);
  fixcolon(msg);
  check_queues(nick, msg);
  if (match_my_nick(nick)) {
    /* Regained nick! */
    strncpyz(botname, msg, NICKLEN);
    altnick_char = 0;
    if (!strcmp(msg, origbotname)) {
      putlog(LOG_SERV | LOG_MISC, "*", "Regained nickname '%s'.", msg);
      nick_juped = 0;
    } else if (alt[0] && !strcmp(msg, alt))
      putlog(LOG_SERV | LOG_MISC, "*", "Regained alternate nickname '%s'.",
             msg);
    else if (keepnick && strcmp(nick, msg)) {
      putlog(LOG_SERV | LOG_MISC, "*", "Nickname changed to '%s'???", msg);
      if (!rfc_casecmp(nick, origbotname)) {
        putlog(LOG_MISC, "*", IRC_GETORIGNICK, origbotname);
        dprintf(DP_SERVER, "NICK %s\n", origbotname);
      } else if (alt[0] && !rfc_casecmp(nick, alt) &&
               egg_strcasecmp(botname, origbotname)) {
        putlog(LOG_MISC, "*", IRC_GETALTNICK, alt);
        dprintf(DP_SERVER, "NICK %s\n", alt);
      }
    } else
      putlog(LOG_SERV | LOG_MISC, "*", "Nickname changed to '%s'???", msg);
  } else if ((keepnick) && (rfc_casecmp(nick, msg))) {
    /* Only do the below if there was actual nick change, case doesn't count */
    if (!rfc_casecmp(nick, origbotname)) {
      putlog(LOG_MISC, "*", IRC_GETORIGNICK, origbotname);
      dprintf(DP_SERVER, "NICK %s\n", origbotname);
    } else if (alt[0] && !rfc_casecmp(nick, alt) &&
             egg_strcasecmp(botname, origbotname)) {
      putlog(LOG_MISC, "*", IRC_GETALTNICK, altnick);
      dprintf(DP_SERVER, "NICK %s\n", altnick);
    }
  }
  return 0;
}
Example #8
0
static int gotmode(char *from, char *msg)
{
  char *ch;

  ch = newsplit(&msg);
  /* Usermode changes? */
  if (strchr(CHANMETA, ch[0]) == NULL) {
    if (match_my_nick(ch) && check_mode_r) {
      /* umode +r? - D0H dalnet uses it to mean something different */
      fixcolon(msg);
      if ((msg[0] == '+') && strchr(msg, 'r')) {
        int servidx = findanyidx(serv);

        putlog(LOG_MISC | LOG_JOIN, "*",
               "%s has me i-lined (jumping)", dcc[servidx].host);
        nuke_server("i-lines suck");
      }
    }
  }
  return 0;
}
Example #9
0
/* got 251: lusers
 * <server> 251 <to> :there are 2258 users and 805 invisible on 127 servers
 */
static int got251(char *from, char *msg)
{
  int i;
  char *servs;

  if (min_servs == 0)
    return 0;                   /* No minimum limit on servers */
  newsplit(&msg);
  fixcolon(msg);                /* NOTE!!! If servlimit is not set or is 0 */
  for (i = 0; i < 8; i++)
    newsplit(&msg);             /* lusers IS NOT SENT AT ALL!! */
  servs = newsplit(&msg);
  if (strncmp(msg, "servers", 7))
    return 0;                   /* Was invalid format */
  while (*servs && (*servs < 32))
    servs++;                    /* I've seen some lame nets put bolds &
                                 * stuff in here :/ */
  i = atoi(servs);
  if (i < min_servs) {
    putlog(LOG_SERV, "*", IRC_AUTOJUMP, min_servs, i);
    nuke_server(IRC_CHANGINGSERV);
  }
  return 0;
}
Example #10
0
/* Got a private notice.
 */
static int gotnotice(char *from, char *msg)
{
  char *to, *nick, ctcpbuf[512], *p, *p1, buf[512], *uhost = buf, *ctcp;
  struct userrec *u;
  int ignoring;

  /* Notice to a channel, not handled here */
  if (msg[0] && ((strchr(CHANMETA, *msg) != NULL) || (*msg == '@')))
    return 0;

  ignoring = match_ignore(from);
  to = newsplit(&msg);
  fixcolon(msg);
  strcpy(uhost, from);
  nick = splitnick(&uhost);

  /* Check for CTCP: */
  p = strchr(msg, 1);
  while ((p != NULL) && (*p)) {
    p++;
    p1 = p;
    while ((*p != 1) && (*p != 0))
      p++;
    if (*p == 1) {
      *p = 0;
      ctcp = strcpy(ctcpbuf, p1);
      strcpy(p1 - 1, p + 1);
      if (!ignoring)
        detect_flood(nick, uhost, from, FLOOD_CTCP);
      p = strchr(msg, 1);
      if (ctcp[0] != ' ') {
        char *code = newsplit(&ctcp);

        /* CTCP reply from oper, don't interpret */
        if ((to[0] == '$') || strchr(to, '.')) {
          if (!ignoring)
            putlog(LOG_PUBLIC, "*",
                   "CTCP reply %s: %s from %s (%s) to %s", code, ctcp,
                   nick, uhost, to);
        } else {
          u = get_user_by_host(from);
          if (!ignoring || trigger_on_ignore) {
            check_tcl_ctcr(nick, uhost, u, to, code, ctcp);
            if (!ignoring)
              /* Who cares? */
              putlog(LOG_MSGS, "*",
                     "CTCP reply %s: %s from %s (%s) to %s",
                     code, ctcp, nick, uhost, to);
          }
        }
      }
    }
  }
  if (msg[0]) {

    /* Notice from oper, don't interpret */
    if ((to[0] == '$') || (strchr(to, '.') != NULL)) {
      if (!ignoring) {
        detect_flood(nick, uhost, from, FLOOD_NOTICE);
        putlog(LOG_MSGS | LOG_SERV, "*", "-%s (%s) to %s- %s",
               nick, uhost, to, msg);
      }
      return 0;
    }

    /* Server notice? */
    if ((nick[0] == 0) || (uhost[0] == 0)) {

      /* Hidden `250' connection count message from server */
      if (strncmp(msg, "Highest connection count:", 25))
        putlog(LOG_SERV, "*", "-NOTICE- %s", msg);

      return 0;
    }

    detect_flood(nick, uhost, from, FLOOD_NOTICE);
    u = get_user_by_host(from);

    if (!ignoring || trigger_on_ignore)
      if (check_tcl_notc(nick, uhost, u, botname, msg) == 2)
        return 0;

    if (!ignoring)
      putlog(LOG_MSGS, "*", "-%s (%s)- %s", nick, uhost, msg);
  }
  return 0;
}
Example #11
0
/* Got a private message.
 */
static int gotmsg(char *from, char *msg)
{
  char *to, buf[UHOSTLEN], *nick, ctcpbuf[512], *uhost = buf, *ctcp,
       *p, *p1, *code;
  struct userrec *u;
  int ctcp_count = 0;
  int ignoring;

  /* Notice to a channel, not handled here */
  if (msg[0] && ((strchr(CHANMETA, *msg) != NULL) || (*msg == '@')))
    return 0;

  ignoring = match_ignore(from);
  to = newsplit(&msg);
  fixcolon(msg);
  strncpyz(uhost, from, sizeof(buf));
  nick = splitnick(&uhost);
 
  /* Check for CTCP: */
  ctcp_reply[0] = 0;
  p = strchr(msg, 1);
  while ((p != NULL) && (*p)) {
    p++;
    p1 = p;
    while ((*p != 1) && (*p != 0))
      p++;
    if (*p == 1) {
      *p = 0;
      strncpyz(ctcpbuf, p1, sizeof(ctcpbuf));
      ctcp = ctcpbuf;

      /* remove the ctcp in msg */
      memmove(p1 - 1, p + 1, strlen(p + 1) + 1);

      if (!ignoring)
        detect_flood(nick, uhost, from,
                     strncmp(ctcp, "ACTION ", 7) ? FLOOD_CTCP : FLOOD_PRIVMSG);
      /* Respond to the first answer_ctcp */
      p = strchr(msg, 1);
      if (ctcp_count < answer_ctcp) {
        ctcp_count++;
        if (ctcp[0] != ' ') {
          code = newsplit(&ctcp);

          /* CTCP from oper, don't interpret */
          if ((to[0] == '$') || strchr(to, '.')) {
            if (!ignoring)
              putlog(LOG_PUBLIC, to, "CTCP %s: %s from %s (%s) to %s",
                     code, ctcp, nick, uhost, to);
          } else {
            u = get_user_by_host(from);
            if (!ignoring || trigger_on_ignore) {
              if (!check_tcl_ctcp(nick, uhost, u, to, code, ctcp) && !ignoring) {
                if ((lowercase_ctcp && !egg_strcasecmp(code, "DCC")) ||
                    (!lowercase_ctcp && !strcmp(code, "DCC"))) {
                  /* If it gets this far unhandled, it means that
                   * the user is totally unknown.
                   */
                  code = newsplit(&ctcp);
                  if (!strcmp(code, "CHAT")) {
                    if (!quiet_reject) {
                      if (u)
                        dprintf(DP_HELP, "NOTICE %s :I'm not accepting calls "
                                "at the moment.\n", nick);
                      else
                        dprintf(DP_HELP, "NOTICE %s :%s\n", nick,
                                DCC_NOSTRANGERS);
                    }
                    putlog(LOG_MISC, "*", "%s: %s", DCC_REFUSED, from);
                  } else
                    putlog(LOG_MISC, "*", "Refused DCC %s: %s", code, from);
                }
              }
              if (!strcmp(code, "ACTION")) {
                putlog(LOG_MSGS, "*", "Action to %s: %s %s", to, nick, ctcp);
              } else {
                putlog(LOG_MSGS, "*", "CTCP %s: %s from %s (%s)", code, ctcp,
                       nick, uhost);
              }                 /* I love a good close cascade ;) */
            }
          }
        }
      }
    }
  }
  /* Send out possible ctcp responses */
  if (ctcp_reply[0]) {
    if (ctcp_mode != 2) {
      dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
    } else {
      if (now - last_ctcp > flud_ctcp_time) {
        dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
        count_ctcp = 1;
      } else if (count_ctcp < flud_ctcp_thr) {
        dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
        count_ctcp++;
      }
      last_ctcp = now;
    }
  }
  if (msg[0]) {
    int result = 0;

    /* Msg from oper, don't interpret */
    if ((to[0] == '$') || (strchr(to, '.') != NULL)) {
      if (!ignoring) {
        detect_flood(nick, uhost, from, FLOOD_PRIVMSG);
        putlog(LOG_MSGS | LOG_SERV, "*", "[%s!%s to %s] %s",
               nick, uhost, to, msg);
      }
      return 0;
    }

    detect_flood(nick, uhost, from, FLOOD_PRIVMSG);
    u = get_user_by_host(from);
    code = newsplit(&msg);
    rmspace(msg);

    if (!ignoring || trigger_on_ignore) {
      result = check_tcl_msgm(code, nick, uhost, u, msg);

      if (!result || !exclusive_binds)
        if (check_tcl_msg(code, nick, uhost, u, msg))
          return 0;
    }

    if (!ignoring && result != 2)
      putlog(LOG_MSGS, "*", "[%s] %s %s", from, code, msg);
  }
  return 0;
}
Example #12
0
static int gotping(char *from, char *msg)
{
  fixcolon(msg);
  dprintf(DP_MODE, "PONG :%s\n", msg);
  return 0;
}
Example #13
0
static int gotmode(char *from, char *origmsg)
{
  char *nick, *ch, *op, *chg, *msg;
  char s[UHOSTLEN], buf[511];
  char ms2[3];
  int z;
  struct userrec *u;
  memberlist *m;
  struct chanset_t *chan;

  strncpy(buf, origmsg, 510);
  buf[510] = 0;
  msg = buf;
  /* Usermode changes? */
  if (msg[0] && (strchr(CHANMETA, msg[0]) != NULL)) {
    ch = newsplit(&msg);
    chg = newsplit(&msg);
    reversing = 0;
    chan = findchan(ch);
    if (!chan) {
      putlog(LOG_MISC, "*", CHAN_FORCEJOIN, ch);
      dprintf(DP_SERVER, "PART %s\n", ch);
    } else if (channel_active(chan) || channel_pending(chan)) {
      z = strlen(msg);
      if (msg[--z] == ' ')      /* I hate cosmetic bugs :P -poptix */
        msg[z] = 0;
      putlog(LOG_MODES, chan->dname, "%s: mode change '%s %s' by %s", ch, chg,
             msg, from);
      u = get_user_by_host(from);
      get_user_flagrec(u, &user, ch);
      nick = splitnick(&from);
      m = ismember(chan, nick);
      if (m)
        m->last = now;
      if (m && channel_active(chan) && (me_op(chan) || (me_halfop(chan) &&
          !chan_hasop(m))) && !(glob_friend(user) || chan_friend(user) ||
          (channel_dontkickops(chan) && (chan_op(user) || (glob_op(user) &&
          !chan_deop(user))))) && !match_my_nick(nick)) {
        if (chan_fakeop(m) || chan_fakehalfop(m)) {
          putlog(LOG_MODES, ch, CHAN_FAKEMODE, ch);
          dprintf(DP_MODE, "KICK %s %s :%s\n", ch, nick, CHAN_FAKEMODE_KICK);
          m->flags |= SENTKICK;
          reversing = 1;
        } else if (!chan_hasop(m) && !chan_hashalfop(m) &&
                 !channel_nodesynch(chan)) {
          putlog(LOG_MODES, ch, CHAN_DESYNCMODE, ch);
          dprintf(DP_MODE, "KICK %s %s :%s\n", ch, nick, CHAN_DESYNCMODE_KICK);
          m->flags |= SENTKICK;
          reversing = 1;
        }
      }
      ms2[0] = '+';
      ms2[2] = 0;
      while ((ms2[1] = *chg)) {
        int todo = 0;

        switch (*chg) {
        case '+':
          ms2[0] = '+';
          break;
        case '-':
          ms2[0] = '-';
          break;
        case 'i':
          todo = CHANINV;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'p':
          todo = CHANPRIV;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 's':
          todo = CHANSEC;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'm':
          todo = CHANMODER;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'c':
          todo = CHANNOCLR;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'C':
          todo = CHANNOCTCP;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'R':
          todo = CHANREGON;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'M':
          todo = CHANMODREG;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'r':
          todo = CHANLONLY;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'D':
          todo = CHANDELJN;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'u':
          todo = CHANSTRIP;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'N':
          todo = CHANNONOTC;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'T':
          todo = CHANNOAMSG;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'd':
          todo = CHANINVIS;
          break;
        case 't':
          todo = CHANTOPIC;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'n':
          todo = CHANNOMSG;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'a':
          todo = CHANANON;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'q':
          todo = CHANQUIET;
          if (!nick[0] && bounce_modes)
            reversing = 1;
          break;
        case 'l':
          if (!nick[0] && bounce_modes)
            reversing = 1;
          if (ms2[0] == '-') {
            check_tcl_mode(nick, from, u, chan->dname, ms2, "");
            /* The Tcl proc might have modified/removed the chan or user */
            if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
              return 0;
            if (channel_active(chan)) {
              if (reversing && (chan->channel.maxmembers != 0)) {
                simple_sprintf(s, "%d", chan->channel.maxmembers);
                add_mode(chan, '+', 'l', s);
              } else if ((chan->limit_prot != 0) && !glob_master(user) &&
                         !chan_master(user) && !match_my_nick(nick)) {
                simple_sprintf(s, "%d", chan->limit_prot);
                add_mode(chan, '+', 'l', s);
              }
            }
            chan->channel.maxmembers = 0;
          } else {
            op = newsplit(&msg);
            fixcolon(op);
            if (op == '\0')
              break;
            chan->channel.maxmembers = atoi(op);
            check_tcl_mode(nick, from, u, chan->dname, ms2,
                           int_to_base10(chan->channel.maxmembers));
            /* The Tcl proc might have modified/removed the chan or user */
            if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
              return 0;
            if (channel_pending(chan))
              break;
            if ((reversing && !(chan->mode_pls_prot & CHANLIMIT)) ||
                ((chan->mode_mns_prot & CHANLIMIT) && !glob_master(user) &&
                !chan_master(user)))
              add_mode(chan, '-', 'l', "");
            if ((chan->limit_prot != chan->channel.maxmembers) &&
                (chan->mode_pls_prot & CHANLIMIT) && (chan->limit_prot != 0) &&
                !glob_master(user) && !chan_master(user)) {
              simple_sprintf(s, "%d", chan->limit_prot);
              add_mode(chan, '+', 'l', s);
            }
          }
          break;
        case 'k':
          if (ms2[0] == '+')
            chan->channel.mode |= CHANKEY;
          else
            chan->channel.mode &= ~CHANKEY;
          op = newsplit(&msg);
          fixcolon(op);
          if (op == '\0') {
            break;
          }
          check_tcl_mode(nick, from, u, chan->dname, ms2, op);
          /* The Tcl proc might have modified/removed the chan or user */
          if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
            return 0;
          if (ms2[0] == '+') {
            set_key(chan, op);
            if (channel_active(chan))
              got_key(chan, nick, from, op);
          } else {
            if (channel_active(chan)) {
              if (reversing && chan->channel.key[0])
                add_mode(chan, '+', 'k', chan->channel.key);
              else if (chan->key_prot[0] && !glob_master(user) &&
                       !chan_master(user) && !match_my_nick(nick))
                add_mode(chan, '+', 'k', chan->key_prot);
            }
            set_key(chan, NULL);
          }
          break;
        case 'o':
          op = newsplit(&msg);
          fixcolon(op);
          if (ms2[0] == '+')
            got_op(chan, nick, from, op, u, &user);
          else
            got_deop(chan, nick, from, op, u);
          break;
        case 'h':
          op = newsplit(&msg);
          fixcolon(op);
          if (ms2[0] == '+')
            got_halfop(chan, nick, from, op, u, &user);
          else
            got_dehalfop(chan, nick, from, op, u);
          break;
        case 'v':
          op = newsplit(&msg);
          fixcolon(op);
          m = ismember(chan, op);
          if (!m) {
            if (channel_pending(chan))
              break;
            putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, op);
            chan->status |= CHAN_PEND;
            refresh_who_chan(chan->name);
          } else {
            simple_sprintf(s, "%s!%s", m->nick, m->userhost);
            get_user_flagrec(m->user ? m->user : get_user_by_host(s),
                             &victim, chan->dname);
            if (ms2[0] == '+') {
              m->flags &= ~SENTVOICE;
              m->flags |= CHANVOICE;
              check_tcl_mode(nick, from, u, chan->dname, ms2, op);
              if (!(chan = modebind_refresh(ch, from, &user, s, &victim)))
                return 0;
              if (channel_active(chan) && !glob_master(user) &&
                  !chan_master(user) && !match_my_nick(nick)) {
                if (chan_quiet(victim) ||
                    (glob_quiet(victim) && !chan_voice(victim)))
                  add_mode(chan, '-', 'v', op);
                else if (reversing)
                  add_mode(chan, '-', 'v', op);
              }
            } else {
              m->flags &= ~SENTDEVOICE;
              m->flags &= ~CHANVOICE;
              check_tcl_mode(nick, from, u, chan->dname, ms2, op);
              if (!(chan = modebind_refresh(ch, from, &user, s, &victim)))
                return 0;
              if (channel_active(chan) && !glob_master(user) &&
                  !chan_master(user) && !match_my_nick(nick)) {
                if ((channel_autovoice(chan) && !chan_quiet(victim) &&
                    (chan_voice(victim) || glob_voice(victim))) ||
                    (!chan_quiet(victim) && (glob_gvoice(victim) ||
                    chan_gvoice(victim))))
                  add_mode(chan, '+', 'v', op);
                else if (reversing)
                  add_mode(chan, '+', 'v', op);
              }
            }
          }
          break;
        case 'b':
          op = newsplit(&msg);
          fixcolon(op);
          if (ms2[0] == '+')
            got_ban(chan, nick, from, op, ch, u);
          else
            got_unban(chan, nick, from, op, ch, u);
          break;
        case 'e':
          op = newsplit(&msg);
          fixcolon(op);
          if (ms2[0] == '+')
            got_exempt(chan, nick, from, op, ch, u);
          else
            got_unexempt(chan, nick, from, op, ch, u);
          break;
        case 'I':
          op = newsplit(&msg);
          fixcolon(op);
          if (ms2[0] == '+')
            got_invite(chan, nick, from, op, ch, u);
          else
            got_uninvite(chan, nick, from, op, ch, u);
          break;
        }
        if (todo) {
          check_tcl_mode(nick, from, u, chan->dname, ms2, "");
          if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
            return 0;
          if (ms2[0] == '+')
            chan->channel.mode |= todo;
          else
            chan->channel.mode &= ~todo;
          if (channel_active(chan)) {
            if ((((ms2[0] == '+') && (chan->mode_mns_prot & todo)) ||
                ((ms2[0] == '-') && (chan->mode_pls_prot & todo))) &&
                !glob_master(user) && !chan_master(user) &&
                !match_my_nick(nick))
              add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, "");
            else if (reversing && ((ms2[0] == '+') ||
                     (chan->mode_pls_prot & todo)) && ((ms2[0] == '-') ||
                     (chan->mode_mns_prot & todo)))
              add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, "");
          }
        }
        chg++;
      }
      if (!me_op(chan) && !nick[0])
        chan->status |= CHAN_ASKEDMODES;
    }
  }
  return 0;
}