#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() {
/*
= 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) {
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;
}
}
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)) {
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
+}
+
+