--- /dev/null
+#include "ModeNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "UserNode.h"
+#include "BanNode.h"
+
+static int modes_with_strarg, modes_with_intarg, modes_count;
+
+unsigned int 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 | CHANNEL_MODE_KEY,
+ 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_ModeNode() {
+ unsigned int *mode, flag = 1;
+ modes_with_strarg = 0;
+ modes_with_intarg = 0;
+ modes_count = 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++;
+ }
+ modes_count++;
+ mode[0] = flag;
+ flag = flag << 1;
+ }
+}
+
+struct ModeNode *createModeNode(struct ChanNode *chan) {
+ struct ModeNode *modes = malloc(sizeof(*modes));
+ if (!modes)
+ {
+ perror("malloc() failed");
+ return NULL;
+ }
+ modes->chan = chan;
+ modes->modes = 0;
+ modes->allmodes = 0;
+ modes->mode_str_args = calloc(modes_with_strarg, sizeof(char*));
+ modes->mode_int_args = calloc(modes_with_intarg, sizeof(int));
+ return modes;
+}
+
+void freeModeNode(struct ModeNode *modes) {
+ int i;
+ for(i = 0; i < modes_with_strarg; i++) {
+ if(modes->mode_str_args[i])
+ free(modes->mode_str_args[i]);
+ }
+ free(modes->mode_str_args);
+ free(modes->mode_int_args);
+ free(modes);
+}
+
+static unsigned 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 ModeNode* modes, char modeChar) {
+ unsigned int *modeOpt = getModeOptions(modeChar);
+ return (modes->modes & modeOpt[0]);
+}
+
+int isModeAffected(struct ModeNode* modes, char modeChar) {
+ unsigned int *modeOpt = getModeOptions(modeChar);
+ return (modes->allmodes & modeOpt[0]);
+}
+
+void* getModeValue(struct ModeNode* modes, char modeChar) {
+ #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+ unsigned int *modeOpt = getModeOptions(modeChar);
+ if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING)
+ return modes->mode_str_args[MODE_VALUE_INDEX];
+ if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER)
+ return &modes->mode_int_args[MODE_VALUE_INDEX];
+ return NULL;
+ #undef MODE_VALUE_INDEX
+}
+
+unsigned int getModeType(struct ModeNode* modes, char modeChar) {
+ #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+ unsigned int *modeOpt = getModeOptions(modeChar);
+ if(!modeOpt) return 0;
+ return modeOpt[2];
+ #undef MODE_VALUE_INDEX
+}
+
+static void parseModesUserPriv(struct ModeNode* modes, unsigned char flag, int add, char *nick) {
+ if(modes->chan == NULL) return;
+ struct UserNode *user = getUserByNick(nick);
+ if(user == NULL) return;
+ struct ChanUser *chanuser = getChanUser(user, modes->chan);
+ if(chanuser == NULL) return;
+ if(add)
+ chanuser->flags |= flag;
+ else
+ chanuser->flags &= ~flag;
+}
+
+static void parseModesBan(struct ModeNode* modes, int add, char *mask) {
+ if(modes->chan == NULL) return;
+ if(add)
+ addChannelBan(modes->chan, mask);
+ else
+ removeChannelBanMask(modes->chan, mask);
+}
+
+void parseModes(struct ModeNode* modes, 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
+ unsigned 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) {
+ if(argpos == argc) continue;
+ //special mode ;)
+ switch(modeStr[i]) {
+ case 'o':
+ parseModesUserPriv(modes, CHANUSERFLAG_OPPED, add, argv[argpos]);
+ break;
+ case 'v':
+ parseModesUserPriv(modes, CHANUSERFLAG_VOICED, add, argv[argpos]);
+ break;
+ case 'b':
+ parseModesBan(modes, add, argv[argpos]);
+ break;
+ default:
+ //we have an unknown TYPE_A mode???
+ break;
+ }
+ argpos++;
+ 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(modes->mode_str_args[MODE_VALUE_INDEX])
+ free(modes->mode_str_args[MODE_VALUE_INDEX]);
+ modes->mode_str_args[MODE_VALUE_INDEX] = strdup(argv[argpos++]);
+ } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+ modes->mode_int_args[MODE_VALUE_INDEX] = atoi(argv[argpos++]);
+ else
+ argpos++; //we simply don't know what to do with the argument...
+ }
+ modes->modes |= modeOpt[0];
+ modes->allmodes |= modeOpt[0];
+ } else {
+ modes->modes &= ~modeOpt[0];
+ modes->allmodes |= modeOpt[0];
+ if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
+ if(argpos == argc) continue;
+ if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+ free(modes->mode_str_args[MODE_VALUE_INDEX]);
+ modes->mode_str_args[MODE_VALUE_INDEX] = NULL;
+ } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+ modes->mode_int_args[MODE_VALUE_INDEX] = 0;
+ argpos++; //we don't need the argument when unsetting a mode...
+ }
+ }
+ }
+ #undef MODE_TYPE
+ #undef MODE_VALUE
+ #undef MODE_VALUE_INDEX
+}
+
+void parseModeString(struct ModeNode* modes, char *modeStr) {
+ int argc = 0;
+ char *args[modes_count+1];
+ char *a, *b = modeStr;
+ do {
+ a = strstr(b, " ");
+ if(a) *a = '\0';
+ args[argc++] = b;
+ if(a) b = a+1;
+ } while(a);
+ parseModes(modes, args[0], args+1, argc-1);
+}
+
+int parseMode(struct ModeNode* modes, int add, char mode, char *param) {
+ #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
+ unsigned int *modeOpt = getModeOptions(mode);
+ if(!modeOpt) return 0;
+ if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
+ if(!param) return 0;
+ //special mode ;)
+ switch(mode) {
+ case 'o':
+ parseModesUserPriv(modes, CHANUSERFLAG_OPPED, add, param);
+ break;
+ case 'v':
+ parseModesUserPriv(modes, CHANUSERFLAG_VOICED, add, param);
+ break;
+ case 'b':
+ parseModesBan(modes, add, param);
+ break;
+ default:
+ return 0; //we have an unknown TYPE_A mode???
+ }
+ }
+ if(add) {
+ if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
+ if(!param) return 0;
+ if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+ if(modes->mode_str_args[MODE_VALUE_INDEX])
+ free(modes->mode_str_args[MODE_VALUE_INDEX]);
+ modes->mode_str_args[MODE_VALUE_INDEX] = strdup(param);
+ } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+ modes->mode_int_args[MODE_VALUE_INDEX] = atoi(param);
+ }
+ modes->modes |= modeOpt[0];
+ modes->allmodes |= modeOpt[0];
+ } else {
+ modes->modes &= ~modeOpt[0];
+ modes->allmodes |= modeOpt[0];
+ if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
+ if(!param) return 0;
+ if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+ free(modes->mode_str_args[MODE_VALUE_INDEX]);
+ modes->mode_str_args[MODE_VALUE_INDEX] = NULL;
+ } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+ modes->mode_int_args[MODE_VALUE_INDEX] = 0;
+ }
+ }
+ #undef MODE_TYPE
+ #undef MODE_VALUE
+ #undef MODE_VALUE_INDEX
+ return 1;
+}
+
+void getModeString(struct ModeNode* modes, char *modesStr) {
+ #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
+ #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
+ #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+ char paramStr[MAXLEN];
+ modesStr[0] = '+';
+ unsigned int *mode;
+ int modePos = 1;
+ int paramPos = 0;
+ for (mode = valid_modes; mode[1]; mode += 3) {
+ if(modes->modes & mode[0]) {
+ modesStr[modePos++] = (char) mode[1];
+ if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
+ if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
+ paramPos += sprintf(paramStr + paramPos, " %s", modes->mode_str_args[MODE_VALUE_INDEX]);
+ else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+ paramPos += sprintf(paramStr + paramPos, " %d", modes->mode_int_args[MODE_VALUE_INDEX]);
+ }
+ }
+ }
+ paramStr[paramPos] = '\0';
+ strcpy(modesStr + modePos, paramStr);
+ #undef MODE_TYPE
+ #undef MODE_VALUE
+ #undef MODE_VALUE_INDEX
+}
+
+void getFullModeString(struct ModeNode* modes, char *modesStr) {
+ #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
+ #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
+ #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+ char addMode[modes_count+1];
+ int addModePos = 0;
+ char addParams[MAXLEN];
+ addParams[0] = '\0';
+ int addParamsPos = 0;
+ char delMode[modes_count+1];
+ int delModePos = 0;
+ unsigned int *mode;
+ for (mode = valid_modes; mode[1]; mode += 3) {
+ if(modes->allmodes & mode[0]) {
+ if(modes->modes & mode[0]) {
+ addMode[addModePos++] = (char) mode[1];
+ if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
+ if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
+ addParamsPos += sprintf(addParams + addParamsPos, " %s", modes->mode_str_args[MODE_VALUE_INDEX]);
+ else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+ addParamsPos += sprintf(addParams + addParamsPos, " %d", modes->mode_int_args[MODE_VALUE_INDEX]);
+ }
+ } else {
+ delMode[delModePos++] = (char) mode[1];
+ }
+ }
+ }
+ addMode[addModePos] = '\0';
+ delMode[delModePos] = '\0';
+ addParams[addParamsPos] = '\0';
+ sprintf(modesStr, "%s%s%s%s%s", (addModePos ? "+" : ""), addMode, (delModePos ? "-" : ""), delMode, addParams);
+ if(*modesStr == '\0') {
+ sprintf(modesStr, "+");
+ }
+ #undef MODE_TYPE
+ #undef MODE_VALUE
+ #undef MODE_VALUE_INDEX
+}