moved all modes to an extra ModeNode struct
[NeonServV5.git] / ModeNode.c
1 #include "ModeNode.h"
2 #include "ChanNode.h"
3 #include "ChanUser.h"
4 #include "UserNode.h"
5 #include "BanNode.h"
6
7 static int modes_with_strarg, modes_with_intarg;
8
9 //Types: http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt
10 #define CHANNEL_MODE_TYPE_A        0x01 /* ... special (addresses or users) ... */
11 #define CHANNEL_MODE_TYPE_B        0x02 /* These modes always take a parameter. */
12 #define CHANNEL_MODE_TYPE_C        0x03 /* These modes take a parameter only when set. */
13 #define CHANNEL_MODE_TYPE_D        0x04 /* These modes never take a parameter. */
14 #define CHANNEL_MODE_TYPE          0x07 /* bit mask to get the type */
15
16 #define CHANNEL_MODE_VALUE_STRING  0x10
17 #define CHANNEL_MODE_VALUE_INTEGER 0x20
18 #define CHANNEL_MODE_VALUE         0x30 /* bit mask to get the value */
19
20 #define CHANNEL_MODE_VALUE_INDEX_SHIFT 8
21 #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 */
22
23 static unsigned int valid_modes[] = { /* Thats our mode list :P */
24     1,  'b', CHANNEL_MODE_TYPE_A,
25     2,  'o', CHANNEL_MODE_TYPE_A,
26     3,  'v', CHANNEL_MODE_TYPE_A,
27     4,  'k', CHANNEL_MODE_TYPE_B | CHANNEL_MODE_VALUE_STRING,
28     5,  'a', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
29     6,  'l', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
30     7,  'f', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
31     8,  'F', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
32     9,  'c', CHANNEL_MODE_TYPE_D,
33     10, 'C', CHANNEL_MODE_TYPE_D,
34     11, 'i', CHANNEL_MODE_TYPE_D,
35     12, 'm', CHANNEL_MODE_TYPE_D,
36     13, 'M', CHANNEL_MODE_TYPE_D,
37     14, 'n', CHANNEL_MODE_TYPE_D,
38     15, 'N', CHANNEL_MODE_TYPE_D,
39     16, 'p', CHANNEL_MODE_TYPE_D,
40     17, 'r', CHANNEL_MODE_TYPE_D,
41     18, 's', CHANNEL_MODE_TYPE_D,
42     19, 't', CHANNEL_MODE_TYPE_D,
43     20, 'u', CHANNEL_MODE_TYPE_D,
44     21, 'D', CHANNEL_MODE_TYPE_D,
45     22, 'd', CHANNEL_MODE_TYPE_D,
46     23, 'R', CHANNEL_MODE_TYPE_D,
47     24, 'z', CHANNEL_MODE_TYPE_D,
48 //  ^ maximum is 32!!!
49     0x00, 0x00, 0x00
50 };
51
52 void init_ModeNode() {
53     unsigned int *mode, flag = 1;
54     modes_with_strarg = 0;
55     modes_with_intarg = 0;
56     for (mode = valid_modes; mode[1]; mode += 3) {
57         if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING) {
58             mode[2] |= modes_with_strarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
59             modes_with_strarg++;
60         }
61         if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER) {
62             mode[2] |= modes_with_intarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
63             modes_with_intarg++;
64         }
65         mode[0] = flag;
66         flag = flag << 1;
67     }
68 }
69
70 struct ModeNode *createModeNode(struct ChanNode *chan) {
71     struct ModeNode *modes = malloc(sizeof(*modes));
72     if (!modes)
73     {
74         perror("malloc() failed");
75         return NULL;
76     }
77     modes->chan = chan;
78     modes->modes = 0;
79     modes->mode_str_args = calloc(modes_with_strarg, sizeof(char*));
80     modes->mode_int_args = calloc(modes_with_intarg, sizeof(int));
81     return modes;
82 }
83
84 void freeModeNode(struct ModeNode *modes) {
85     int i;
86     for(i = 0; i < modes_with_strarg; i++) {
87         if(modes->mode_str_args[i])
88             free(modes->mode_str_args[i]);
89     }
90     free(modes->mode_str_args);
91     free(modes->mode_int_args);
92     free(modes);
93 }
94
95 static unsigned int* getModeOptions(char mode) {
96     unsigned int *cmode;
97     for (cmode = valid_modes; cmode[1]; cmode += 3) {
98         if(cmode[1] == mode)
99             return cmode;
100     }
101     return NULL;
102 }
103
104 int isModeSet(struct ModeNode* modes, char modeChar) {
105     unsigned int *modeOpt = getModeOptions(modeChar);
106     return (modes->modes & modeOpt[0]);
107 }
108
109 void* getModeValue(struct ModeNode* modes, char modeChar) {
110     #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
111     unsigned int *modeOpt = getModeOptions(modeChar);
112     if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING)
113         return modes->mode_str_args[MODE_VALUE_INDEX];
114     if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER)
115         return &modes->mode_int_args[MODE_VALUE_INDEX];
116     return NULL;
117     #undef MODE_VALUE_INDEX
118 }
119
120 static void parseModesUserPriv(struct ModeNode* modes, unsigned char flag, int add, char *nick) {
121     if(modes->chan == NULL) return;
122     struct UserNode *user = getUserByNick(nick);
123     if(user == NULL) return;
124     struct ChanUser *chanuser = getChanUser(user, modes->chan);
125     if(chanuser == NULL) return;
126     if(add)
127         chanuser->flags |= flag;
128     else
129         chanuser->flags &= ~flag;
130 }
131
132 static void parseModesBan(struct ModeNode* modes, int add, char *mask) {
133     if(modes->chan == NULL) return;
134     if(add)
135         addChannelBan(modes->chan, mask);
136     else
137         removeChannelBanMask(modes->chan, mask);
138 }
139
140 void parseModes(struct ModeNode* modes, char *modeStr, char **argv, int argc) {
141     int i, argpos = 0, add = 1;
142     #define MODE_TYPE (modeOpt[2] & CHANNEL_MODE_TYPE)
143     #define MODE_VALUE (modeOpt[2] & CHANNEL_MODE_VALUE)
144     #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
145     unsigned int *modeOpt;
146     for(i = 0; i < strlen(modeStr); i++) {
147         if(modeStr[i] == '+') {
148             add = 1;
149             continue;
150         }
151         if(modeStr[i] == '-') {
152             add = 0;
153             continue;
154         }
155         modeOpt = getModeOptions(modeStr[i]);
156         if(!modeOpt) continue; // unknown mode?
157         if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
158             if(argpos == argc) continue;
159             //special mode ;)
160             switch(modeStr[i]) {
161                 case 'o':
162                     parseModesUserPriv(modes, CHANUSERFLAG_OPPED, add, argv[argpos]);
163                     break;
164                 case 'v':
165                     parseModesUserPriv(modes, CHANUSERFLAG_VOICED, add, argv[argpos]);
166                     break;
167                 case 'b':
168                     parseModesBan(modes, add, argv[argpos]);
169                     break;
170                 default:
171                     //we have an unknown TYPE_A mode???
172                     break;
173             }
174             argpos++;
175             continue;
176         }
177         if(add) {
178             if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
179                 if(argpos == argc) continue;
180                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
181                     if(modes->mode_str_args[MODE_VALUE_INDEX])
182                         free(modes->mode_str_args[MODE_VALUE_INDEX]);
183                     modes->mode_str_args[MODE_VALUE_INDEX] = strdup(argv[argpos++]);
184                 } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
185                     modes->mode_int_args[MODE_VALUE_INDEX] = atoi(argv[argpos++]);
186                 else
187                     argpos++; //we simply don't know what to do with the argument...
188             }
189             modes->modes |= modeOpt[0];
190         } else {
191             modes->modes &= ~modeOpt[0];
192             if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
193                 if(argpos == argc) continue;
194                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
195                     free(modes->mode_str_args[MODE_VALUE_INDEX]);
196                     modes->mode_str_args[MODE_VALUE_INDEX] = NULL;
197                 } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
198                     modes->mode_int_args[MODE_VALUE_INDEX] = 0;
199                 argpos++; //we don't need the argument when unsetting a mode...
200             }
201         }
202     }
203     #undef MODE_TYPE
204     #undef MODE_VALUE
205     #undef MODE_VALUE_INDEX
206 }
207
208 void getModeString(struct ModeNode* modes, char *modesStr) {
209     #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
210     #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
211     #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
212     char paramStr[MAXLEN];
213     modesStr[0] = '+';
214     unsigned int *mode;
215     int modePos = 1;
216     int paramPos = 0;
217     for (mode = valid_modes; mode[1]; mode += 3) {
218         if(modes->modes & mode[0]) {
219             modesStr[modePos++] = (char) mode[1];
220             if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
221                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
222                     paramPos += sprintf(paramStr + paramPos, " %s", modes->mode_str_args[MODE_VALUE_INDEX]);
223                 else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
224                     paramPos += sprintf(paramStr + paramPos, " %d", modes->mode_int_args[MODE_VALUE_INDEX]);
225             }
226         }
227     }
228     paramStr[paramPos] = '\0';
229     strcpy(modesStr + modePos, paramStr);
230     #undef MODE_TYPE
231     #undef MODE_VALUE
232     #undef MODE_VALUE_INDEX
233 }