Merge branch 'master' into KeepConn
authorpk910 <philipp@zoelle1.de>
Mon, 12 Nov 2012 00:20:49 +0000 (01:20 +0100)
committerpk910 <philipp@zoelle1.de>
Mon, 12 Nov 2012 00:20:49 +0000 (01:20 +0100)
Conflicts:
include/handlers.h
ircd/Makefile.in

13 files changed:
include/channel.h
include/handlers.h
include/msg.h
include/numeric.h
include/supported.h
ircd/Makefile.in
ircd/channel.c
ircd/m_clearmode.c
ircd/m_relay.c
ircd/m_uninvite.c [new file with mode: 0644]
ircd/parse.c
ircd/s_err.c
ircd/s_user.c

index 63cb19c8709daddeaafa14cf3de4827a9d0f8ef2..b3deec89220ee10be89162deb3e3f0f84e1bf62c 100644 (file)
@@ -139,14 +139,15 @@ typedef signed long long long64;
 #define MODE_AUDITORIUM 0x200000000LLU /**< +u Auditorium */
 #define MODE_NOFLOOD    0x400000000LLU /**< +f NoFlood */
 #define MODE_SSLCHAN    0x800000000LLU /**< +S SSL Channel */
+#define MODE_BANEXCEPTION 0x1000000000LLU /**< +e Ban exception */
 /** mode flags which take another parameter (With PARAmeterS)
  */
-#define MODE_WPARAS     (MODE_CHANOP|MODE_HALFOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS|MODE_ALTCHAN|MODE_ACCESS|MODE_NOFLOOD)
+#define MODE_WPARAS     (MODE_CHANOP|MODE_HALFOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS|MODE_ALTCHAN|MODE_ACCESS|MODE_NOFLOOD|MODE_BANEXCEPTION)
 
 /** Available Channel modes */
-#define infochanmodes feature_bool(FEAT_OPLEVELS) ? "AcCbhiklmMnNopsStuUvrDRzQu" : "cCbhiklmMnNopsStuvrDRzQu"
+#define infochanmodes feature_bool(FEAT_OPLEVELS) ? "AcCbehiklmMnNopsStuUvrDRzQu" : "cCbehiklmMnNopsStuvrDRzQu"
 /** Available Channel modes that take parameters */
-#define infochanmodeswithparams feature_bool(FEAT_OPLEVELS) ? "AbfhkloUvFa" : "bfhklovFa"
+#define infochanmodeswithparams feature_bool(FEAT_OPLEVELS) ? "AbefhkloUvFa" : "befhklovFa"
 
 #define HoldChannel(x)          (!(x))
 /** name invisible */
index 19b64ceb1d8adab8b81701c8d3b5ef471279cdd3..79a052d913e9be4b63bbe11170f91d030e83ac31 100644 (file)
@@ -135,6 +135,7 @@ extern int m_svsjoin(struct Client*, struct Client*, int, char*[]);
 extern int m_time(struct Client*, struct Client*, int, char*[]);
 extern int m_topic(struct Client*, struct Client*, int, char*[]);
 extern int m_trace(struct Client*, struct Client*, int, char*[]);
+extern int m_uninvite(struct Client*, struct Client*, int, char*[]);
 extern int m_unregistered(struct Client*, struct Client*, int, char*[]);
 extern int m_unsupported(struct Client*, struct Client*, int, char*[]);
 extern int m_user(struct Client*, struct Client*, int, char*[]);
@@ -237,6 +238,7 @@ extern int ms_svspart(struct Client*, struct Client*, int, char*[]);
 extern int ms_topic(struct Client*, struct Client*, int, char*[]);
 extern int ms_trace(struct Client*, struct Client*, int, char*[]);
 extern int ms_unzombie(struct Client*, struct Client*, int, char*[]);
+extern int ms_uninvite(struct Client*, struct Client*, int, char*[]);
 extern int ms_uping(struct Client*, struct Client*, int, char*[]);
 extern int ms_version(struct Client*, struct Client*, int, char*[]);
 extern int ms_wallchops(struct Client*, struct Client*, int, char*[]);
index 4afde55c7ee02a2babee5679359acc57b447f622..f6151105ce11bfda46b944afc34bd1c362f503f5 100644 (file)
@@ -88,6 +88,10 @@ struct Client;
 #define TOK_INVITE              "I"
 #define CMD_INVITE             MSG_INVITE, TOK_INVITE
 
+#define MSG_UNINVITE            "UNINVITE"        /* INVI */
+#define TOK_UNINVITE            "UI"
+#define CMD_UNINVITE   MSG_UNINVITE, TOK_UNINVITE
+
 #define MSG_VERSION             "VERSION"       /* VERS */
 #define TOK_VERSION             "V"
 #define CMD_VERSION            MSG_VERSION, TOK_VERSION
index 6de836346df470b0c6f6c2a3a1dd463ea5886f6d..d979e5fc7266ece7ed7d2b9d181aa2db6b6275b5 100644 (file)
@@ -264,12 +264,13 @@ extern const struct Numeric* get_error_numeric(int err);
 #define RPL_USERIP           340        /* Undernet extension */
 #define RPL_INVITING         341
 /*      RPL_SUMMONING        342           removed from RFC1459 */
+#define RPL_UNINVITE         343
 
 #define RPL_ISSUEDINVITE     345        /* Undernet extension */
 #define RPL_INVITELIST       346        /* IRCnet, Undernet extension */
 #define RPL_ENDOFINVITELIST  347        /* IRCnet, Undernet extension */
-/*      RPL_EXCEPTLIST       348           IRCnet extension */
-/*      RPL_ENDOFEXCEPTLIST  349           IRCnet extension */
+#define RPL_EXCEPTLIST       348        /* IRCnet extension */
+#define RPL_ENDOFEXCEPTLIST  349        /* IRCnet extension */
 
 #define RPL_VERSION          351
 #define RPL_WHOREPLY         352        /* See also RPL_ENDOFWHO */
@@ -376,6 +377,7 @@ extern const struct Numeric* get_error_numeric(int err);
 /*      ERR_SUMMONDISABLED   445           removed from RFC1459 */
 /*      ERR_USERSDISABLED    446           removed from RFC1459 */
 /*     ERR_NONICKCHANGE     447         unreal */
+#define ERR_USERNOTINVITED    448
 
 #define ERR_NOTREGISTERED    451
 /*      ERR_IDCOLLISION      452           IRCnet extension ? */
index 5bbd5be1f3d30c491e9ee2ee49fa6978da345a79..87807a17a435bd5a2815238febea1fedf9ba3cee 100644 (file)
@@ -65,7 +65,7 @@
 #define FEATURESVALUES2 NICKLEN, TOPICLEN, AWAYLEN, TOPICLEN, \
                         feature_int(FEAT_CHANNELLEN), CHANNELLEN, \
                         (feature_bool(FEAT_LOCAL_CHANNELS) ? "#&" : "#"), "(ohv)@%+", "@%+", \
-                        (feature_bool(FEAT_OPLEVELS) ? "b,AkU,alfF,cCimMnNprstuDdRz" : "b,k,alfF,cCimMnNprstuDdRz"), \
+                        (feature_bool(FEAT_OPLEVELS) ? "be,AkU,alfF,cCimMnNprstuDdRz" : "be,k,alfF,cCimMnNprstuDdRz"), \
                         "rfc1459", feature_str(FEAT_NETWORK)
 
 #endif /* INCLUDED_supported_h */
index c3361889b420c1336be6d78935c9f45baba34910..c9057a28a12fc2129d9b1443546b05a7d66df13a 100644 (file)
@@ -181,6 +181,7 @@ IRCD_SRC = \
        m_topic.c \
        m_trace.c \
        m_unzombie.c \
+       m_uninvite.c \
        m_uping.c \
        m_user.c \
        m_userhost.c \
index b82d8e0780b25c4e3d0f8a92cb7ff71fd72a6d63..02cdd96c52ad48fde34a1197cae6fad234022881 100644 (file)
@@ -1318,11 +1318,31 @@ static void send_ban_list(struct Client* cptr, struct Channel* chptr)
   assert(0 != chptr);
 
   for (lp = chptr->banlist; lp; lp = lp->next)
-    send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr, lp->who, lp->when);
+    if ((lp->flags & BAN_EXCEPTION) != BAN_EXCEPTION)
+      send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr, lp->who, lp->when);
 
   send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
 }
 
+/** send an exception list to a client for a channel
+ *
+ * @param cptr Client to send the banlist to.
+ * @param chptr Channel whose exception list to send.
+ */
+static void send_exception_list(struct Client* cptr, struct Channel* chptr)
+{
+  struct Ban* lp;
+
+  assert(0 != cptr);
+  assert(0 != chptr);
+
+  for (lp = chptr->banlist; lp; lp = lp->next)
+    if ((lp->flags & BAN_EXCEPTION) == BAN_EXCEPTION)
+      send_reply(cptr, RPL_EXCEPTLIST, chptr->chname, lp->banstr, lp->who, lp->when);
+
+  send_reply(cptr, RPL_ENDOFEXCEPTLIST, chptr->chname);
+}
+
 /** Get a channel block, creating if necessary.
  *  Get Channel block for chname (and allocate a new channel
  *  block, if it didn't exists before).
@@ -1632,6 +1652,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
        MODE_QUARANTINE,  'Q',
        MODE_AUDITORIUM,  'u',
     MODE_SSLCHAN,     'S',
+/*     MODE_BANEXCEPTION 'e', */
     0x0, 0x0
   };
   static ulong64 local_flags[] = {
@@ -1728,14 +1749,14 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
           bufptr[(*bufptr_i)++] = 'v';
        totalbuflen -= IRCD_MAX(9, tmp) + 1;
       }
-    } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD)) {
+    } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION)) {
       tmp = strlen(MB_STRING(mbuf, i));
 
       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
        MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
       else {
        char mode_char;
-       switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD))
+       switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION))
        {
          case MODE_APASS:
            mode_char = 'A';
@@ -1749,8 +1770,11 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
          case MODE_NOFLOOD:
                mode_char = 'f';
                break;
+      case MODE_BAN:
+        mode_char = 'b';
+           break;
          default:
-           mode_char = 'b';
+           mode_char = 'e';
            break;
        }
        bufptr[(*bufptr_i)++] = mode_char;
@@ -1826,7 +1850,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
        build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
 
       /* deal with bans... */
-      else if (MB_TYPE(mbuf, i) & (MODE_BAN))
+      else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_BANEXCEPTION))
        build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
 
       /* deal with keys... */
@@ -1942,7 +1966,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
        build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
 
       /* deal with modes that take strings */
-      else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD))
+      else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION))
        build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
 
       /*
@@ -2258,6 +2282,7 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf)
        MODE_AUDITORIUM, 'u',
     MODE_SSLCHAN,    'S',
        MODE_NOFLOOD,   'f',
+/*  MODE_BANEXCEPTION, 'e', */
     0x0, 0x0
   };
   ulong64 add;
@@ -2369,6 +2394,7 @@ mode_invite_clear(struct Channel *chan)
 #define DONE_ALTCHAN   0x800   /**< We've set the altchan */
 #define DONE_ACCESS    0x1000  /**< We've set the access */
 #define DONE_NOFLOOD   0x2000  /**< We've set the noflood options */
+#define DONE_EXCEPTLIST 0x4000  /**< We've sent the exception list */
 
 struct ParseState {
   struct ModeBuf *mbuf;
@@ -3322,9 +3348,14 @@ mode_parse_ban(struct ParseState *state, ulong64 *flag_p)
   struct Ban *ban, *newban;
 
   if (state->parc <= 0) { /* Not enough args, send ban list */
-    if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
-      send_ban_list(state->sptr, state->chptr);
-      state->done |= DONE_BANLIST;
+    if (MyUser(state->sptr)) {
+      if (*flag_p == MODE_BANEXCEPTION && !(state->done & DONE_EXCEPTLIST)) {
+        send_exception_list(state->sptr, state->chptr);
+        state->done |= DONE_EXCEPTLIST;
+      } else if (*flag_p == MODE_BAN && !(state->done & DONE_BANLIST)) {
+        send_ban_list(state->sptr, state->chptr);
+        state->done |= DONE_BANLIST;
+      }
     }
     return;
   }
@@ -3390,9 +3421,9 @@ mode_process_bans(struct ParseState *state)
 
     if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
       if (prevban)
-       prevban->next = 0; /* Break the list; ban isn't a real ban */
+        prevban->next = 0; /* Break the list; ban isn't a real ban */
       else
-       state->chptr->banlist = 0;
+        state->chptr->banlist = 0;
 
       count--;
       len -= banlen;
@@ -3401,59 +3432,57 @@ mode_process_bans(struct ParseState *state)
     } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
       char *bandup;
       DupString(bandup, ban->banstr);
-      modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN, bandup, 1);
+      modebuf_mode_string(state->mbuf, MODE_DEL | ((ban->flags & BAN_EXCEPTION) ? MODE_BANEXCEPTION : MODE_BAN), bandup, 1);
 
       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
-       if (prevban) /* clip it out of the list... */
-         prevban->next = ban->next;
-       else
-         state->chptr->banlist = ban->next;
+        if (prevban) /* clip it out of the list... */
+          prevban->next = ban->next;
+        else
+          state->chptr->banlist = ban->next;
 
-       count--;
-       len -= banlen;
+        count--;
+        len -= banlen;
         free_ban(ban);
 
-       changed++;
-       continue; /* next ban; keep prevban like it is */
+        changed++;
+        continue; /* next ban; keep prevban like it is */
       } else
-       ban->flags &= BAN_IPMASK; /* unset other flags */
+        ban->flags &= (BAN_IPMASK | BAN_EXCEPTION); /* unset other flags */
     } else if (ban->flags & BAN_ADD) { /* adding a ban? */
       if (prevban)
-       prevban->next = 0; /* Break the list; ban isn't a real ban */
+        prevban->next = 0; /* Break the list; ban isn't a real ban */
       else
-       state->chptr->banlist = 0;
+        state->chptr->banlist = 0;
 
       /* If we're supposed to ignore it, do so. */
-      if (ban->flags & BAN_OVERLAPPED &&
-         !(state->flags & MODE_PARSE_BOUNCE)) {
-       count--;
-       len -= banlen;
+      if (ban->flags & BAN_OVERLAPPED && !(state->flags & MODE_PARSE_BOUNCE)) {
+        count--;
+        len -= banlen;
       } else {
-       if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
-           (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
-            count > feature_int(FEAT_MAXBANS))) {
-         send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
-                    ban->banstr);
-         count--;
-         len -= banlen;
-       } else {
+        if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
+            (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
+            count > feature_int(FEAT_MAXBANS))) {
+          send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname, ban->banstr);
+          count--;
+          len -= banlen;
+        } else {
           char *bandup;
-         /* add the ban to the buffer */
+          /* add the ban to the buffer */
           DupString(bandup, ban->banstr);
-          modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN, bandup, 1);
+          modebuf_mode_string(state->mbuf, MODE_ADD | ((ban->flags & BAN_EXCEPTION) ? MODE_BANEXCEPTION : MODE_BAN), bandup, 1);
 
-         if (state->flags & MODE_PARSE_SET) { /* create a new ban */
-           newban = make_ban(ban->banstr);
+          if (state->flags & MODE_PARSE_SET) { /* create a new ban */
+            newban = make_ban(ban->banstr);
             strcpy(newban->who, ban->who);
-           newban->when = ban->when;
-           newban->flags = ban->flags & BAN_IPMASK;
+            newban->when = ban->when;
+            newban->flags = ban->flags & (BAN_IPMASK | BAN_EXCEPTION);
 
-           newban->next = state->chptr->banlist; /* and link it in */
-           state->chptr->banlist = newban;
+            newban->next = state->chptr->banlist; /* and link it in */
+            state->chptr->banlist = newban;
 
-           changed++;
-         }
-       }
+            changed++;
+          }
+        }
       }
     }
 
@@ -3802,6 +3831,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
        MODE_AUDITORIUM,    'u',
     MODE_SSLCHAN,       'S',
        MODE_NOFLOOD,       'f',
+    MODE_BANEXCEPTION,  'e',
     MODE_ADD,          '+',
     MODE_DEL,          '-',
     0x0, 0x0
@@ -3892,6 +3922,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
        mode_parse_upass(&state, flag_p);
        break;
       case 'b': /* deal with bans */
+      case 'e': /* and exceptions */
        mode_parse_ban(&state, flag_p);
         break;
 
index 26955743a3b84318bcf8e7456452172cd8a813c3..2e02bb0253ca9acf7baf31c3d313a7eb7e3991f1 100644 (file)
@@ -128,6 +128,7 @@ do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr,
     MODE_NOCOLOUR,      'c',
     MODE_NOCTCP,        'C',
     MODE_NOAMSGS,       'M',
+    MODE_BANEXCEPTION,  'e',
     0x0, 0x0
   };
   int *flag_p;
@@ -194,12 +195,12 @@ do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr,
   }
 
   /* Deal with users on the channel */
-  if (del_mode & (MODE_BAN | MODE_CHANOP | MODE_HALFOP | MODE_VOICE))
+  if (del_mode & (MODE_BAN | MODE_BANEXCEPTION | MODE_CHANOP | MODE_HALFOP | MODE_VOICE))
     for (member = chptr->members; member; member = member->next_member) {
       if (IsZombie(member)) /* we ignore zombies */
        continue;
 
-      if (del_mode & MODE_BAN) /* If we cleared bans, clear the valid flags */
+      if (del_mode & (MODE_BAN | MODE_BANEXCEPTION)) /* If we cleared bans, clear the valid flags */
        ClearBanValid(member);
 
       /* Drop channel operator status */
@@ -285,7 +286,7 @@ int
 mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
   struct Channel *chptr;
-  char *control = "ovpsmikbl"; /* default control string */
+  char *control = "ovpsmikble"; /* default control string */
   const char *chname, *qreason;
   int force = 0;
 
index 9996719bc6fd97b7c5ff66db764870928bfbdc09..3f0dcf6699cd8a37ac5c6ddf89b6e8f64c439ad1 100644 (file)
 
 static void loc_handler_LR(const char *num, char *parv[], signed int parc) {
     if(num[0] != '!') return;
-       if(parc > 0)
-               auth_loc_reply(&num[3], NULL, NULL, NULL, 0);
-       else
-               auth_loc_reply(&num[3], NULL, NULL, &parv[0] , parc);
+    if(parc > 0)
+        auth_loc_reply(&num[3], NULL, NULL, NULL, 0);
+    else
+        auth_loc_reply(&num[3], NULL, NULL, &parv[0] , parc);
 }
 
 static void loc_handler_LA(const char *num, char *parv[], signed int parc) {
     if(num[0] != '!' || parc < 1) return;
-       char *fakehost = NULL;
-       if (parc > 1 && strcmp(parv[1], "0") != 0) // 0 = no fakehost
-               fakehost=parv[1];
+    char *fakehost = NULL;
+    if (parc > 1 && strcmp(parv[1], "0") != 0) // 0 = no fakehost
+        fakehost=parv[1];
 
     if(parc > 2)
         auth_loc_reply(&num[3], parv[0], fakehost, &parv[2] , parc - 2);
@@ -55,77 +55,79 @@ static void mode_a_join(struct Client* cptr, char *channel, int flags) {
     struct Channel *chptr;
     if (!(chptr = FindChannel(channel))) {
         if (((channel[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(channel) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
-         //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
+            //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
         } else if ((chptr = get_channel(cptr, channel, CGT_CREATE))) {
-           struct JoinBuf create;
-           joinbuf_init(&create, cptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
-           joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
-                  do_names(cptr, chptr, NAMES_ALL|NAMES_EON);
-           joinbuf_flush(&create);
-               }
-       } else {
+            struct JoinBuf create;
+            joinbuf_init(&create, cptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
+            joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
+            do_names(cptr, chptr, NAMES_ALL|NAMES_EON);
+            joinbuf_flush(&create);
+        }
+    } else {
         struct JoinBuf join;
+        if(find_member_link(chptr, cptr))
+            return; //we have already joined this channel
         joinbuf_init(&join, cptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
-               joinbuf_join(&join, chptr, flags);
-               del_invite(cptr, chptr);
+        joinbuf_join(&join, chptr, flags);
+        del_invite(cptr, chptr);
         if (chptr->topic[0]) {
             send_reply(cptr, RPL_TOPIC, chptr->chname, chptr->topic);
             send_reply(cptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time);
         }
         do_names(cptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
         joinbuf_flush(&join);
-       }
+    }
 }
 
 static void mode_a_check_altchan(struct Client* sptr, char *channel) {
-       struct Channel *chptrb;
-       if (!(chptrb = FindChannel(channel))) {
-      if (((channel[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(channel) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
-        //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
-      } else if ((chptrb = get_channel(sptr, channel, CGT_CREATE))) {
-           struct JoinBuf create;
-        joinbuf_init(&create, sptr, sptr, JOINBUF_TYPE_CREATE, 0, TStime());
-        joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
-               do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
-               joinbuf_flush(&create);
-         }
-       } else {
-      if(find_member_link(chptrb, sptr))
-        return; //we have already joined this channel
-         //first of all check if we may even join this channel
-         int err2 = 0;
-         int flags = 0;
-         if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
-        /* Joining a zombie channel (zannel): give ops and increment TS. */
-        flags = CHFL_CHANOP;
-        chptrb->creationtime++;
-      } else if (IsInvited(sptr, chptrb)) {
-         /* Invites and key=OVERRIDE bypass these other checks. */
-      } else if (chptrb->mode.mode & MODE_INVITEONLY)
-        err2 = ERR_INVITEONLYCHAN;
-      else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
-        err2 = ERR_CHANNELISFULL;
-      else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
-        err2 = ERR_NEEDREGGEDNICK;
-      else if ((chptrb->mode.mode & MODE_SSLCHAN) && !IsSSL(sptr))
-        err2 = ERR_SSLCHANNEL;
-      else if (find_ban(sptr, chptrb->banlist))
-        err2 = ERR_BANNEDFROMCHAN;
-      else if (*chptrb->mode.key) //Fix this!
-        err2 = ERR_BADCHANNELKEY;
-         if(!err2) {
-           struct JoinBuf join;
-        joinbuf_init(&join, sptr, sptr, JOINBUF_TYPE_JOIN, 0, 0);
-           joinbuf_join(&join, chptrb, flags);
-           del_invite(sptr, chptrb);
-        if (chptrb->topic[0]) {
-          send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
-          send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
+    struct Channel *chptrb;
+    if (!(chptrb = FindChannel(channel))) {
+        if (((channel[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(channel) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
+            //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
+        } else if ((chptrb = get_channel(sptr, channel, CGT_CREATE))) {
+            struct JoinBuf create;
+            joinbuf_init(&create, sptr, sptr, JOINBUF_TYPE_CREATE, 0, TStime());
+            joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
+            do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
+            joinbuf_flush(&create);
+        }
+    } else {
+        if(find_member_link(chptrb, sptr))
+            return; //we have already joined this channel
+        //first of all check if we may even join this channel
+        int err2 = 0;
+        int flags = 0;
+        if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
+            /* Joining a zombie channel (zannel): give ops and increment TS. */
+            flags = CHFL_CHANOP;
+            chptrb->creationtime++;
+        } else if (IsInvited(sptr, chptrb)) {
+             /* Invites and key=OVERRIDE bypass these other checks. */
+        } else if (chptrb->mode.mode & MODE_INVITEONLY)
+            err2 = ERR_INVITEONLYCHAN;
+        else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
+            err2 = ERR_CHANNELISFULL;
+        else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
+            err2 = ERR_NEEDREGGEDNICK;
+        else if ((chptrb->mode.mode & MODE_SSLCHAN) && !IsSSL(sptr))
+            err2 = ERR_SSLCHANNEL;
+        else if (find_ban(sptr, chptrb->banlist))
+            err2 = ERR_BANNEDFROMCHAN;
+        else if (*chptrb->mode.key) //Fix this!
+            err2 = ERR_BADCHANNELKEY;
+        if(!err2) {
+            struct JoinBuf join;
+            joinbuf_init(&join, sptr, sptr, JOINBUF_TYPE_JOIN, 0, 0);
+            joinbuf_join(&join, chptrb, flags);
+            del_invite(sptr, chptrb);
+            if (chptrb->topic[0]) {
+                send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
+                send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
+            }
+            do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
+            joinbuf_flush(&join);
         }
-        do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
-               joinbuf_flush(&join);
-         }
-   }
+    }
 }
 
 /** RELAY
@@ -200,48 +202,45 @@ signed int ms_relay(struct Client* cptr, struct Client* sptr, signed int parc, c
     }
 
     /* Call subcommand handler. */
-    if(strcmp("LR", parv[2]) == 0) loc_handler_LR(parv[1], &parv[3], parc - 3);
-    else if(strcmp("LA", parv[2]) == 0 && parc > 3) loc_handler_LA(parv[1], &parv[3], parc - 3);
-       else if(strcmp("SM", parv[2]) == 0 && parc > 3) {
-     #ifndef UNRESTRICTED_SERV
-        struct Client *acptr;
-        if(acptr = findNUser(parv[3])) {
-         if (IsChannelPrefix(*parv[4])) {
-       relay_channel_message(acptr, parv[4], parv[parc - 1], 1);
-      } else {
-          relay_private_message(acptr, parv[4], parv[parc - 1]);
-         }
-        }
-     #endif
-       } else if(strcmp("UC", parv[2]) == 0 && parc > 3) {
-        struct Client *acptr;
-        if(acptr = findNUser(parv[3])) {
-         send_reply(acptr, ERR_UNKNOWNCOMMAND, parv[4]);
-        }
-       } else if(strcmp("SI", parv[2]) == 0 && parc > 3) {
-     #ifndef UNRESTRICTED_SERV
-        struct Client *acptr;
-        if(acptr = findNUser(parv[3])) {
-         parse_simul_client(acptr, parv[parc - 1]);
-        }
-     #endif
-       } else if(strcmp("JAA", parv[2]) == 0 && parc > 2) {
-        struct Client *acptr;
-        if(acptr = findNUser(parv[1])) {
-         mode_a_join(acptr,parv[3],strtoul(parv[4], 0, 10));
-        }
-       } else if(strcmp("JAR", parv[2]) == 0 && parc > 2) {
-        struct Client *acptr;
-        struct Channel *chptr;
-        if(acptr = findNUser(parv[1])) {
-         if(IsChannelName(parv[3]) && strIsIrcCh(parv[3]) && 
-         (chptr = FindChannel(parv[3])) && chptr->mode.altchan && 
-            IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
-       mode_a_check_altchan(acptr,chptr->mode.altchan);
-         }
-         send_reply(acptr, ERR_JOINACCESS, parv[3], feature_str(FEAT_ERR_JOINACCESS));
-        }
-       }
+    if(strcmp("LR", parv[2]) == 0) 
+        loc_handler_LR(parv[1], &parv[3], parc - 3);
+    else if(strcmp("LA", parv[2]) == 0 && parc > 3) 
+        loc_handler_LA(parv[1], &parv[3], parc - 3);
+    else if(strcmp("SM", parv[2]) == 0 && parc > 3) {
+#ifndef UNRESTRICTED_SERV
+        struct Client *acptr;
+        if(acptr = findNUser(parv[3])) {
+            if (IsChannelPrefix(*parv[4]))
+                relay_channel_message(acptr, parv[4], parv[parc - 1], 1);
+            else
+                relay_private_message(acptr, parv[4], parv[parc - 1]);
+        }
+#endif
+    } else if(strcmp("UC", parv[2]) == 0 && parc > 3) {
+        struct Client *acptr;
+        if(acptr = findNUser(parv[3]))
+            send_reply(acptr, ERR_UNKNOWNCOMMAND, parv[4]);
+    } else if(strcmp("SI", parv[2]) == 0 && parc > 3) {
+#ifndef UNRESTRICTED_SERV
+        struct Client *acptr;
+        if(acptr = findNUser(parv[3]))
+            parse_simul_client(acptr, parv[parc - 1]);
+#endif
+    } else if(strcmp("JAA", parv[2]) == 0 && parc > 2) {
+        struct Client *acptr;
+        if(acptr = findNUser(parv[1]))
+            mode_a_join(acptr,parv[3],strtoul(parv[4], 0, 10));
+    } else if(strcmp("JAR", parv[2]) == 0 && parc > 2) {
+        struct Client *acptr;
+        struct Channel *chptr;
+        if(acptr = findNUser(parv[1])) {
+            if(IsChannelName(parv[3]) && strIsIrcCh(parv[3]) && 
+              (chptr = FindChannel(parv[3])) && chptr->mode.altchan && 
+              IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan))
+                mode_a_check_altchan(acptr,chptr->mode.altchan);
+            send_reply(acptr, ERR_JOINACCESS, parv[3], feature_str(FEAT_ERR_JOINACCESS));
+        }
+    }
 
     return 0;
 }
diff --git a/ircd/m_uninvite.c b/ircd/m_uninvite.c
new file mode 100644 (file)
index 0000000..bfb8f54
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_uninvite.c
+ * Written by Philipp Kreil.
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_uninvite - generic message handler
+ *
+ *   parv[0] - sender prefix
+ *   parv[1] - user to uninvite
+ *   parv[2] - channel name
+ *
+ */
+int m_uninvite(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  struct Channel *chptr;
+  
+  if (parc < 3 || EmptyString(parv[2]))
+    return need_more_params(sptr, "UNINVITE");
+
+  if (!(acptr = FindUser(parv[1]))) {
+    send_reply(sptr, ERR_NOSUCHNICK, parv[1]);
+    return 0;
+  }
+
+  if (!IsChannelName(parv[2])
+      || !strIsIrcCh(parv[2])
+      || !(chptr = FindChannel(parv[2]))) {
+    send_reply(sptr, ERR_NOSUCHCHANNEL, parv[2]);
+    return 0;
+  }
+
+  if (!find_channel_member(sptr, chptr)) {
+    send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
+    return 0;
+  }
+
+  if (find_channel_member(acptr, chptr)) {
+    send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname);
+    return 0;
+  }
+
+  if (!is_chan_op(sptr, chptr) && !is_halfop(sptr, chptr)) {
+    send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
+    return 0;
+  }
+
+  if(!IsInvited(acptr, chptr)) {
+    send_reply(sptr, ERR_USERNOTINVITED, cli_name(acptr), chptr->chname);
+    return 0;
+  }
+
+  /* If we get here, it was a VALID and meaningful UNINVITE */
+
+  send_reply(sptr, RPL_UNINVITE, cli_name(acptr), chptr->chname);
+
+  if (MyConnect(acptr)) {
+    del_invite(acptr, chptr);
+    sendcmdto_one(sptr, CMD_UNINVITE, acptr, "%s %H", cli_name(acptr), chptr);
+  } else if (!IsLocalChannel(chptr->chname)) {
+    sendcmdto_one(sptr, CMD_UNINVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime);
+  }
+
+  return 0;
+}
+
+/*
+ * ms_uninvite - server message handler
+ *
+ *   parv[0] - sender prefix
+ *   parv[1] - user to invite
+ *   parv[2] - channel name
+ *   parv[3] - (optional) channel timestamp
+ *
+ */
+int ms_uninvite(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  struct Channel *chptr;
+  time_t uninvite_ts;
+  
+  if (IsServer(sptr)) {
+    /*
+     * this will blow up if we get an uninvite from a server
+     * we look for channel membership in sptr below. 
+     */
+    return protocol_violation(sptr,"Server attempting to uninvite");
+  }
+  if (parc < 3 || EmptyString(parv[2])) {
+    /*
+     * should have been handled upstream, ignore it.
+     */
+    protocol_violation(sptr,"Too few arguments to uninvite");
+    return need_more_params(sptr,"UNINVITE");
+  }
+  if (!IsGlobalChannel(parv[2])) {
+    /*
+     * should not be sent
+     */
+    return protocol_violation(sptr, "Uninvite from a non-standard channel %s",parv[2]);
+  }
+  if (!(acptr = FindUser(parv[1]))) {
+    send_reply(sptr, ERR_NOSUCHNICK, parv[1]);
+    return 0;
+  }
+
+  if (!(chptr = FindChannel(parv[2]))) {
+    send_reply(sptr, ERR_NOSUCHCHANNEL, parv[2]);
+    return 0;
+  }
+
+  if (parc > 3) {
+    uninvite_ts = atoi(parv[3]);
+    if (uninvite_ts > chptr->creationtime)
+      return 0;
+  } else if (IsBurstOrBurstAck(cptr))
+    return 0;
+
+  if (!IsChannelService(sptr) && !find_channel_member(sptr, chptr)) {
+    send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
+    return 0;
+  }
+
+  if (find_channel_member(acptr, chptr)) {
+    send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname);
+    return 0;
+  }
+
+  if(!IsInvited(acptr, chptr)) {
+    send_reply(sptr, ERR_USERNOTINVITED, cli_name(acptr), chptr->chname);
+    return 0;
+  }
+
+  if (MyConnect(acptr)) {
+    del_invite(acptr, chptr);
+    sendcmdto_one(sptr, CMD_UNINVITE, acptr, "%s %H", cli_name(acptr), chptr);
+  } else {
+    sendcmdto_one(sptr, CMD_UNINVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr,
+                  chptr->creationtime);
+  }
+
+  return 0;
+}
index c8a032216377a63e722bea1184362836be6cf844..519049c328a9969b9da6a5c146195809ad82e669 100644 (file)
@@ -218,6 +218,13 @@ struct Message msgtab[] = {
     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
     { m_unregistered, m_invite, ms_invite, m_invite, m_ignore }
   },
+  {
+    MSG_UNINVITE,
+    TOK_UNINVITE,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_uninvite, ms_uninvite, m_uninvite, m_ignore }
+  },
   {
     MSG_KICK,
     TOK_KICK,
index bc7d0ffbd4347d677789b550fc1aa3ccc3d53537..c8a3e58c2434255f470606fb24d0ec172996c647 100644 (file)
@@ -718,7 +718,7 @@ static Numeric replyTable[] = {
 /* 342 */
   { 0 },
 /* 343 */
-  { 0 },
+  { RPL_UNINVITE, "%s %s", "343" },
 /* 344 */
   { 0 },
 /* 345 */
@@ -728,9 +728,9 @@ static Numeric replyTable[] = {
 /* 347 */
   { RPL_ENDOFINVITELIST, ":End of Invite List", "347" },
 /* 348 */
-  { 0 },
+  { RPL_EXCEPTLIST, "%s %s %s %Tu", "348" },
 /* 349 */
-  { 0 },
+  { RPL_ENDOFEXCEPTLIST, "%s :End of Channel Exception List", "349" },
 /* 350 */
   { 0 },
 /* 351 */
@@ -928,7 +928,7 @@ static Numeric replyTable[] = {
 /* 447 */
   { 0 },
 /* 448 */
-  { 0 },
+  { ERR_USERNOTINVITED, "%s %s :is not invited to channel", "448" },
 /* 449 */
   { 0 },
 /* 450 */
index f42cf9a0130438611eb59540029820c7ee176904..2c9a9bce35be8aeaa46866eab9ef0925ba10f38e 100644 (file)
@@ -1070,6 +1070,25 @@ hide_hostmask(struct Client *cptr, unsigned int flag)
     else {
         SetDelayedJoin(chan);
     }
+    
+    /*
+    * Check if the client is actually overriding a ban with the
+    * mask change, if so, kick him out of the channel.
+    * We have to proceed that way to ensure data consistency (join + kick)
+    */
+    if (find_ban(cptr, chan->channel->banlist)) {
+      /* Silentely kick in case of delayed join */
+      if (chan->channel->mode.mode & MODE_DELJOINS) {
+        sendcmdto_one(&his, CMD_KICK, cptr, "%H %C :Ban override", chan->channel, cptr);
+        CheckDelayedJoins(chan->channel);
+        
+      } else {
+        /* Otherwise publicly kick */
+        sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Ban override", chan->channel, cptr);
+        sendcmdto_channel_butserv_butone(&his, CMD_KICK, chan->channel, NULL, 0, "%H %C :Ban override", chan->channel, cptr);
+        make_zombie(chan, cptr, &me, &me, chan->channel);
+      }
+    }
   }
   return 0;
 }