From: pk910 Date: Fri, 12 Aug 2011 04:19:08 +0000 (+0200) Subject: added channel mode handler X-Git-Tag: v5.3~595 X-Git-Url: http://git.pk910.de/?a=commitdiff_plain;h=67383d1a44dcee7e63fb278519f0fac97ff8f70c;p=NeonServV5.git added channel mode handler --- diff --git a/ChanNode.c b/ChanNode.c index 372e8be..d5ef631 100644 --- a/ChanNode.c +++ b/ChanNode.c @@ -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 +} + + diff --git a/ChanNode.h b/ChanNode.h index 04da48b..9c6ae86 100644 --- a/ChanNode.h +++ b/ChanNode.h @@ -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 diff --git a/IRCEvents.h b/IRCEvents.h index a6f519c..4ef312d 100644 --- a/IRCEvents.h +++ b/IRCEvents.h @@ -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); diff --git a/IRCParser.c b/IRCParser.c index 83e9f60..464fc70 100644 --- a/IRCParser.c +++ b/IRCParser.c @@ -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);