added channel mode handler
authorpk910 <philipp@zoelle1.de>
Fri, 12 Aug 2011 04:19:08 +0000 (06:19 +0200)
committerpk910 <philipp@zoelle1.de>
Fri, 12 Aug 2011 04:19:08 +0000 (06:19 +0200)
ChanNode.c
ChanNode.h
IRCEvents.h
IRCParser.c

index 372e8be5770bc2b7fe251b5bcb514772d45a6fe4..d5ef631d9c593c7511649392b1503ca236c92ec7 100644 (file)
@@ -3,6 +3,50 @@
 #include "UserNode.h"
 
 static struct ChanNode **chanList;
+static int modes_with_strarg, modes_with_intarg;
+
+//Types: http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt
+#define CHANNEL_MODE_TYPE_A        0x01 /* ... special (addresses or users) ... */
+#define CHANNEL_MODE_TYPE_B        0x02 /* These modes always take a parameter. */
+#define CHANNEL_MODE_TYPE_C        0x03 /* These modes take a parameter only when set. */
+#define CHANNEL_MODE_TYPE_D        0x04 /* These modes never take a parameter. */
+#define CHANNEL_MODE_TYPE          0x07 /* bit mask to get the type */
+
+#define CHANNEL_MODE_VALUE_STRING  0x10
+#define CHANNEL_MODE_VALUE_INTEGER 0x20
+#define CHANNEL_MODE_VALUE         0x30 /* bit mask to get the value */
+
+#define CHANNEL_MODE_VALUE_INDEX_SHIFT 8
+#define CHANNEL_MODE_VALUE_INDEX_MASK  (0xff << CHANNEL_MODE_VALUE_INDEX_SHIFT) /* this "bitrange" is reserved for storing the array indexes of the mode values */
+
+static unsigned char valid_modes[] = { /* Thats our mode list :P */
+    1,  'b', CHANNEL_MODE_TYPE_A,
+    2,  'o', CHANNEL_MODE_TYPE_A,
+    3,  'v', CHANNEL_MODE_TYPE_A,
+    4,  'k', CHANNEL_MODE_TYPE_B | CHANNEL_MODE_VALUE_STRING,
+    5,  'a', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
+    6,  'l', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
+    7,  'f', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
+    8,  'F', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
+    9,  'c', CHANNEL_MODE_TYPE_D,
+    10, 'C', CHANNEL_MODE_TYPE_D,
+    11, 'i', CHANNEL_MODE_TYPE_D,
+    12, 'm', CHANNEL_MODE_TYPE_D,
+    13, 'M', CHANNEL_MODE_TYPE_D,
+    14, 'n', CHANNEL_MODE_TYPE_D,
+    15, 'N', CHANNEL_MODE_TYPE_D,
+    16, 'p', CHANNEL_MODE_TYPE_D,
+    17, 'r', CHANNEL_MODE_TYPE_D,
+    18, 's', CHANNEL_MODE_TYPE_D,
+    19, 't', CHANNEL_MODE_TYPE_D,
+    20, 'u', CHANNEL_MODE_TYPE_D,
+    21, 'D', CHANNEL_MODE_TYPE_D,
+    22, 'd', CHANNEL_MODE_TYPE_D,
+    23, 'R', CHANNEL_MODE_TYPE_D,
+    24, 'z', CHANNEL_MODE_TYPE_D,
+//  ^ maximum is 32!!!
+    0x00, 0x00, 0x00
+};
 
 void init_ChanNode() {
     /*
@@ -15,6 +59,21 @@ void init_ChanNode() {
      = 47
     */
     chanList = calloc(47, sizeof(*chanList));
+    unsigned int *mode, flag = 1;
+    modes_with_strarg = 0;
+    modes_with_intarg = 0;
+    for (mode = valid_modes; mode[1]; mode += 3) {
+        if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING) {
+            mode[2] |= modes_with_strarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
+            modes_with_strarg++;
+        }
+        if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER) {
+            mode[2] |= modes_with_intarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
+            modes_with_intarg++;
+        }
+        mode[0] = flag;
+        flag = flag << 1;
+    }
 }
 
 int is_valid_chan(const char *name) {
@@ -81,6 +140,10 @@ struct ChanNode* addChannel(const char *name) {
     chan->chanbot = NULL;
     chan->topic[0] = 0;
     chan->flags = 0;
+    /* mode lists */
+    chan->mode_str_args = calloc(modes_with_strarg, sizeof(char*));
+    chan->mode_int_args = calloc(modes_with_intarg, sizeof(int));
+    
     chan->next = chanList[chanListIndex];
     chanList[chanListIndex] = chan;
     return chan;
@@ -109,11 +172,22 @@ void delChannel(struct ChanNode* chan, int freeChan) {
         }
     }
     if(freeChan)
-        free(chan);
+        freeChanNode(chan);
     else
         chan->next = NULL;
 }
 
+void freeChanNode(struct ChanNode* chan) {
+    int i;
+    for(i = 0; i < modes_with_strarg; i++) {
+        if(chan->mode_str_args[i])
+            free(chan->mode_str_args[i]);
+    }
+    free(chan->mode_str_args);
+    free(chan->mode_int_args);
+    free(chan);
+}
+
 void checkChannelVisibility(struct ChanNode* chan) {
     struct ChanUser *chanuser, *next;
     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
@@ -136,3 +210,81 @@ void checkChannelVisibility(struct ChanNode* chan) {
     chan->user = NULL;
     delChannel(chan, 1);
 }
+
+static int* getModeOptions(char mode) {
+    unsigned int *cmode;
+    for (cmode = valid_modes; cmode[1]; cmode += 3) {
+        if(cmode[1] == mode)
+            return cmode;
+    }
+    return NULL;
+}
+
+int isModeSet(struct ChanNode* chan, char modeChar) {
+    int *modeOpt = getModeOptions(modeChar);
+    return (chan->modes & modeOpt[0])
+}
+
+void* getModeValue(struct ChanNode* chan, char modeChar) {
+    int *modeOpt = getModeOptions(modeChar);
+    int index = (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT;
+    if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING)
+        return chan->mode_str_args[index];
+    if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER)
+        return chan->mode_int_args[index];
+    return NULL;
+}
+
+void parseModes(struct ChanNode* chan, char *modeStr, char **argv, int argc) {
+    int i, argpos = 0, add = 1;
+    #define MODE_TYPE modeOpt[2] & CHANNEL_MODE_TYPE
+    #define MODE_VALUE modeOpt[2] & CHANNEL_MODE_VALUE
+    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+    int *modeOpt;
+    for(i = 0; i < strlen(modeStr); i++) {
+        if(modeStr[i] == '+') {
+            add = 1;
+            continue;
+        }
+        if(modeStr[i] == '-') {
+            add = 0;
+            continue;
+        }
+        modeOpt = getModeOptions(modeStr[i]);
+        if(!modeOpt) continue; // unknown mode?
+        if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
+            //special mode ;)
+            continue;
+        }
+        if(add) {
+            if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
+                if(argpos == argc) continue;
+                if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+                    if(chan->mode_str_args[MODE_VALUE_INDEX])
+                        free(chan->mode_str_args[MODE_VALUE_INDEX]);
+                    chan->mode_str_args[MODE_VALUE_INDEX] = strdup(argv[argc++]);
+                } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+                    chan->mode_int_args[MODE_VALUE_INDEX] = atoi(argv[argc++]);
+                else
+                    argc++; //we simply don't know what to do with the argument...
+            }
+            chan->modes |= modeOpt[0];
+        } else {
+            chan->modes &= ~modeOpt[0];
+            if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
+                if(argpos == argc) continue;
+                if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+                    free(chan->mode_str_args[MODE_VALUE_INDEX]);
+                    chan->mode_str_args[MODE_VALUE_INDEX] = NULL;
+                } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+                    chan->mode_int_args[MODE_VALUE_INDEX] = 0;
+                argc++; //we don't need the argument when unsetting a mode...
+            }
+        }
+    }
+    #undef MODE_TYPE
+    #undef MODE_VALUE
+    #undef MODE_VALUE_INDEX
+}
+
+
index 04da48b681adc29aa4f9ba5fad10ac7b63246d0b..9c6ae869253c7933e445f47c5951c6f3739bd02d 100644 (file)
@@ -10,8 +10,12 @@ struct ChanNode {
     char name[CHANNELLEN+1];
     char topic[TOPICLEN+1];
     struct ChanUser *user;
-    char flags;
+    unsigned char flags;
+    unsigned int modes;
+    char **mode_str_args;
+    int *mode_int_args;
     struct UserNode *chanbot;
+
     struct ChanNode *next;
 };
 
@@ -20,6 +24,10 @@ int is_valid_chan(const char *name);
 struct ChanNode* getChanByName(const char *name);
 struct ChanNode* addChannel(const char *chan);
 void delChannel(struct ChanNode* chan, int freeChan);
+void freeChanNode(struct ChanNode* chan);
 void checkChannelVisibility(struct ChanNode* chan);
+int isModeSet(struct ChanNode* chan, char modeChar);
+void* getModeValue(struct ChanNode* chan, char modeChar);
+void parseModes(struct ChanNode* chan, char *modeStr, char **argv, int argc);
 
 #endif
\ No newline at end of file
index a6f519cec4d471947eb0d5bcd1f6022abdf8b4a4..4ef312d4f60b3630ad3d14e36ddc110296ed1cb3 100644 (file)
@@ -13,7 +13,7 @@ int event_part(struct ChanUser *chanuser, char *reason);
 int event_quit(struct UserNode *user, char *reason);
 int event_kick(struct UserNode *user, struct ChanUser *target, char *reason);
 int event_topic(struct UserNode *user, struct ChanNode *chan, const char *new_topic);
-int event_mode(struct UserNode *user, struct ChanNode *chan, char *modes, char **argv, int argc); /* TODO */
+int event_mode(struct UserNode *user, struct ChanNode *chan, char *modes, char **argv, int argc);
 int event_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message);
 int event_privmsg(struct UserNode *user, struct UserNode *target, char *message);
 int event_channotice(struct UserNode *user, struct ChanNode *chan, char *message);
index 83e9f603ac80041480e83d79fab51201a9d611c9..464fc7088a430272a635e9135461ce09aefa6d73 100644 (file)
@@ -312,6 +312,25 @@ static IRC_CMD(raw_invite) {
     return 1;
 }
 
+static IRC_CMD(raw_mode) {
+    if(from == NULL || argc < 2) return 0;
+    struct UserNode *user = getUserByMask(from);
+    if(user == NULL) {
+        user = createTempUser(from);
+        user->flags |= USERFLAG_ISTMPUSER;
+    }
+    if(argv[0][0] == '#') {
+        //ChannelMode
+        struct ChanNode *chan = getChanByName(argv[0]);
+        if(!chan) return;
+        event_mode(user, chan, argv[1], argv+2, argc-2);
+        parseModes(chan, argv[1], argv+2, argc-2);
+    } else {
+        //UserMode
+    }
+    return 1;
+}
+
 void parser_init() {
     //all the raws we receive...
     register_irc_function("001", raw_001);
@@ -322,6 +341,7 @@ void parser_init() {
     register_irc_function("PART", raw_part);
     register_irc_function("QUIT", raw_quit);
     register_irc_function("JOIN", raw_join);
+    register_irc_function("MODE", raw_mode);
     register_irc_function("NICK", raw_nick);
     register_irc_function("354", raw_354);
     register_irc_function("315", raw_315);