fixed parseModes
[NeonServV5.git] / ChanNode.c
1 #include "ChanNode.h"
2 #include "ChanUser.h"
3 #include "UserNode.h"
4
5 static struct ChanNode **chanList;
6 static int modes_with_strarg, modes_with_intarg;
7
8 //Types: http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt
9 #define CHANNEL_MODE_TYPE_A        0x01 /* ... special (addresses or users) ... */
10 #define CHANNEL_MODE_TYPE_B        0x02 /* These modes always take a parameter. */
11 #define CHANNEL_MODE_TYPE_C        0x03 /* These modes take a parameter only when set. */
12 #define CHANNEL_MODE_TYPE_D        0x04 /* These modes never take a parameter. */
13 #define CHANNEL_MODE_TYPE          0x07 /* bit mask to get the type */
14
15 #define CHANNEL_MODE_VALUE_STRING  0x10
16 #define CHANNEL_MODE_VALUE_INTEGER 0x20
17 #define CHANNEL_MODE_VALUE         0x30 /* bit mask to get the value */
18
19 #define CHANNEL_MODE_VALUE_INDEX_SHIFT 8
20 #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 */
21
22 static unsigned int valid_modes[] = { /* Thats our mode list :P */
23     1,  'b', CHANNEL_MODE_TYPE_A,
24     2,  'o', CHANNEL_MODE_TYPE_A,
25     3,  'v', CHANNEL_MODE_TYPE_A,
26     4,  'k', CHANNEL_MODE_TYPE_B | CHANNEL_MODE_VALUE_STRING,
27     5,  'a', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
28     6,  'l', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
29     7,  'f', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
30     8,  'F', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
31     9,  'c', CHANNEL_MODE_TYPE_D,
32     10, 'C', CHANNEL_MODE_TYPE_D,
33     11, 'i', CHANNEL_MODE_TYPE_D,
34     12, 'm', CHANNEL_MODE_TYPE_D,
35     13, 'M', CHANNEL_MODE_TYPE_D,
36     14, 'n', CHANNEL_MODE_TYPE_D,
37     15, 'N', CHANNEL_MODE_TYPE_D,
38     16, 'p', CHANNEL_MODE_TYPE_D,
39     17, 'r', CHANNEL_MODE_TYPE_D,
40     18, 's', CHANNEL_MODE_TYPE_D,
41     19, 't', CHANNEL_MODE_TYPE_D,
42     20, 'u', CHANNEL_MODE_TYPE_D,
43     21, 'D', CHANNEL_MODE_TYPE_D,
44     22, 'd', CHANNEL_MODE_TYPE_D,
45     23, 'R', CHANNEL_MODE_TYPE_D,
46     24, 'z', CHANNEL_MODE_TYPE_D,
47 //  ^ maximum is 32!!!
48     0x00, 0x00, 0x00
49 };
50
51 void init_ChanNode() {
52     /*
53      len pos chars 
54      26  0   a-z
55      10  26  0-9
56      10  36  {|}~[\]^_`
57      1   46  *everything else*
58      ---------------------------
59      = 47
60     */
61     chanList = calloc(47, sizeof(*chanList));
62     unsigned int *mode, flag = 1;
63     modes_with_strarg = 0;
64     modes_with_intarg = 0;
65     for (mode = valid_modes; mode[1]; mode += 3) {
66         if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING) {
67             mode[2] |= modes_with_strarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
68             modes_with_strarg++;
69         }
70         if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER) {
71             mode[2] |= modes_with_intarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
72             modes_with_intarg++;
73         }
74         mode[0] = flag;
75         flag = flag << 1;
76     }
77 }
78
79 int is_valid_chan(const char *name) {
80     unsigned int ii;
81     if (*name !='#')
82         return 0;
83     for (ii=1; name[ii]; ++ii) {
84         if ((name[ii] > 0) && (name[ii] <= 32))
85             return 0;
86         if (name[ii] == ',')
87             return 0;
88         if (name[ii] == '\xa0')
89             return 0;
90     }
91     return 1;
92 }
93
94 static int get_chanlist_entry(int name) {
95     if((name > 0 && name <= 32) || name == ',' || name == '\xa0') return -1; //invalid name
96     if(tolower(name) >= 97 && tolower(name) <= 122) {
97         return (tolower(name) - 97);
98     }
99     if(tolower(name) >= 48 && tolower(name) <= 57) {
100         return (tolower(name) - 48 + 26);
101     }
102     /* {|}~[\]^_` */
103     if(name == '{') return 36;
104     if(name == '|') return 37;
105     if(name == '}') return 38;
106     if(name == '~') return 39;
107     if(name == '[') return 40;
108     if(name == '\\') return 41;
109     if(name == ']') return 42;
110     if(name == '^') return 43;
111     if(name == '_') return 44;
112     if(name == '`') return 45;
113     return 46;
114 }
115
116 struct ChanNode* getChanByName(const char *name) { //case insensitive
117     int chanListIndex = get_chanlist_entry(name[1]);
118     if(chanListIndex == -1 || chanList[chanListIndex] == NULL)
119         return NULL;
120     struct ChanNode *chan;
121     for(chan = chanList[chanListIndex]; chan; chan = chan->next) {
122         if(!stricmp(name, chan->name))
123             return chan;
124     }
125     return NULL;
126 }
127
128 struct ChanNode* addChannel(const char *name) {
129     int chanListIndex = get_chanlist_entry(name[1]);
130     if(chanListIndex == -1 || !is_valid_chan(name))
131         return NULL;
132     struct ChanNode *chan = malloc(sizeof(*chan));
133     if (!chan)
134     {
135         perror("malloc() failed");
136         return NULL;
137     }
138     strcpy(chan->name, name);
139     chan->user = NULL;
140     chan->chanbot = NULL;
141     chan->topic[0] = 0;
142     chan->flags = 0;
143     /* mode lists */
144     chan->modes = 0;
145     chan->mode_str_args = calloc(modes_with_strarg, sizeof(char*));
146     chan->mode_int_args = calloc(modes_with_intarg, sizeof(int));
147     
148     chan->next = chanList[chanListIndex];
149     chanList[chanListIndex] = chan;
150     return chan;
151 }
152
153 void delChannel(struct ChanNode* chan, int freeChan) {
154     int chanListIndex = get_chanlist_entry(chan->name[1]);
155     if(chanListIndex == -1) return;
156     struct ChanNode *cchan, *last_chan = NULL;
157     for(cchan = chanList[chanListIndex]; cchan; cchan = cchan->next) {
158         if(cchan == chan) {
159             if(last_chan)
160                 last_chan->next = chan->next;
161             else
162                 chanList[chanListIndex] = chan->next;
163             break;
164         } else
165             last_chan = cchan;
166     }
167     if(chan->user) {
168         //free all chanusers
169         struct ChanUser *chanuser, *next;
170         for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
171             next = getChannelUsers(chan, chanuser);
172             removeChanUserFromLists(chanuser, 0, 1, 1);
173         }
174     }
175     if(freeChan)
176         freeChanNode(chan);
177     else
178         chan->next = NULL;
179 }
180
181 void freeChanNode(struct ChanNode* chan) {
182     int i;
183     for(i = 0; i < modes_with_strarg; i++) {
184         if(chan->mode_str_args[i])
185             free(chan->mode_str_args[i]);
186     }
187     free(chan->mode_str_args);
188     free(chan->mode_int_args);
189     free(chan);
190 }
191
192 void checkChannelVisibility(struct ChanNode* chan) {
193     struct ChanUser *chanuser, *next;
194     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
195         if(chanuser->user->flags & USERFLAG_ISBOT) {
196             chan->chanbot = chanuser->user;
197             return;
198         }
199     }
200     //free the channel...
201     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
202         next = getChannelUsers(chan, chanuser);
203         //remove the channel from the user's channel-list
204         removeChanUserFromLists(chanuser, 0, 1, 0);
205         if(!chanuser->user->channel) {
206             //free the user (no more channels)
207             delUser(chanuser->user, 1);
208         }
209         free(chanuser);
210     }
211     chan->user = NULL;
212     delChannel(chan, 1);
213 }
214
215 static unsigned int* getModeOptions(char mode) {
216     unsigned int *cmode;
217     for (cmode = valid_modes; cmode[1]; cmode += 3) {
218         if(cmode[1] == mode)
219             return cmode;
220     }
221     return NULL;
222 }
223
224 int isModeSet(struct ChanNode* chan, char modeChar) {
225     unsigned int *modeOpt = getModeOptions(modeChar);
226     return (chan->modes & modeOpt[0]);
227 }
228
229 void* getModeValue(struct ChanNode* chan, char modeChar) {
230     #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
231     unsigned int *modeOpt = getModeOptions(modeChar);
232     if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING)
233         return chan->mode_str_args[MODE_VALUE_INDEX];
234     if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER)
235         return &chan->mode_int_args[MODE_VALUE_INDEX];
236     return NULL;
237     #undef MODE_VALUE_INDEX
238 }
239
240 static void parseModesUserPriv(struct ChanNode* chan, unsigned char flag, int add, char *nick) {
241     struct UserNode *user = getUserByNick(nick);
242     if(user == NULL) return;
243     struct ChanUser *chanuser = getChanUser(user, chan);
244     if(chanuser == NULL) return;
245     if(add)
246         chanuser->flags |= flag;
247     else
248         chanuser->flags &= ~flag;
249 }
250
251 static void parseModesBan(struct ChanNode* chan, int add, char *mask) {
252     //to be continued...
253 }
254
255 void parseModes(struct ChanNode* chan, char *modeStr, char **argv, int argc) {
256     int i, argpos = 0, add = 1;
257     #define MODE_TYPE (modeOpt[2] & CHANNEL_MODE_TYPE)
258     #define MODE_VALUE (modeOpt[2] & CHANNEL_MODE_VALUE)
259     #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
260     unsigned int *modeOpt;
261     for(i = 0; i < strlen(modeStr); i++) {
262         if(modeStr[i] == '+') {
263             add = 1;
264             continue;
265         }
266         if(modeStr[i] == '-') {
267             add = 0;
268             continue;
269         }
270         modeOpt = getModeOptions(modeStr[i]);
271         if(!modeOpt) continue; // unknown mode?
272         if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
273             if(argpos == argc) continue;
274             //special mode ;)
275             switch(modeStr[i]) {
276                 case 'o':
277                     parseModesUserPriv(chan, CHANUSERFLAG_OPPED, add, argv[argpos]);
278                     break;
279                 case 'v':
280                     parseModesUserPriv(chan, CHANUSERFLAG_VOICED, add, argv[argpos]);
281                     break;
282                 case 'b':
283                     parseModesBan(chan, add, argv[argpos]);
284                     break;
285                 default:
286                     //we have an unknown TYPE_A mode???
287                     break;
288             }
289             argpos++;
290             continue;
291         }
292         if(add) {
293             if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
294                 if(argpos == argc) continue;
295                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
296                     if(chan->mode_str_args[MODE_VALUE_INDEX])
297                         free(chan->mode_str_args[MODE_VALUE_INDEX]);
298                     chan->mode_str_args[MODE_VALUE_INDEX] = strdup(argv[argpos++]);
299                 } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
300                     chan->mode_int_args[MODE_VALUE_INDEX] = atoi(argv[argpos++]);
301                 else
302                     argpos++; //we simply don't know what to do with the argument...
303             }
304             chan->modes |= modeOpt[0];
305         } else {
306             chan->modes &= ~modeOpt[0];
307             if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
308                 if(argpos == argc) continue;
309                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
310                     free(chan->mode_str_args[MODE_VALUE_INDEX]);
311                     chan->mode_str_args[MODE_VALUE_INDEX] = NULL;
312                 } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
313                     chan->mode_int_args[MODE_VALUE_INDEX] = 0;
314                 argpos++; //we don't need the argument when unsetting a mode...
315             }
316         }
317     }
318     #undef MODE_TYPE
319     #undef MODE_VALUE
320     #undef MODE_VALUE_INDEX
321 }
322
323 void getModeString(struct ChanNode* chan, char *modesStr) {
324     #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
325     #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
326     #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
327     char paramStr[MAXLEN];
328     modesStr[0] = '+';
329     unsigned int *mode;
330     int modePos = 1;
331     int paramPos = 0;
332     for (mode = valid_modes; mode[1]; mode += 3) {
333         if(chan->modes & mode[0]) {
334             modesStr[modePos++] = (char) mode[1];
335             if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
336                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
337                     paramPos += sprintf(paramStr + paramPos, " %s", chan->mode_str_args[MODE_VALUE_INDEX]);
338                 else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
339                     paramPos += sprintf(paramStr + paramPos, " %d", chan->mode_int_args[MODE_VALUE_INDEX]);
340             }
341         }
342     }
343     paramStr[paramPos] = '\0';
344     strcpy(modesStr + modePos, paramStr);
345     #undef MODE_TYPE
346     #undef MODE_VALUE
347     #undef MODE_VALUE_INDEX
348 }
349