added simple channel ban cache
[NeonServV5.git] / ChanNode.c
1 #include "ChanNode.h"
2 #include "ChanUser.h"
3 #include "UserNode.h"
4 #include "modcmd.h"
5
6 static struct ChanNode **chanList;
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_ChanNode() {
53     /*
54      len pos chars 
55      26  0   a-z
56      10  26  0-9
57      10  36  {|}~[\]^_`
58      1   46  *everything else*
59      ---------------------------
60      = 47
61     */
62     chanList = calloc(47, sizeof(*chanList));
63     unsigned int *mode, flag = 1;
64     modes_with_strarg = 0;
65     modes_with_intarg = 0;
66     for (mode = valid_modes; mode[1]; mode += 3) {
67         if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING) {
68             mode[2] |= modes_with_strarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
69             modes_with_strarg++;
70         }
71         if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER) {
72             mode[2] |= modes_with_intarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
73             modes_with_intarg++;
74         }
75         mode[0] = flag;
76         flag = flag << 1;
77     }
78 }
79
80 void free_ChanNode() {
81     //kamikaze free all channels and chanusers
82     int i;
83     struct ChanNode *chan, *next;
84     struct ChanUser *chanuser, *next_chanuser;
85     for(i = 0; i < 47; i++) {
86         for(chan = chanList[i]; chan; chan = next) {
87             next = chan->next;
88             for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next_chanuser) {
89                 next_chanuser = getChannelUsers(chan, chanuser);
90                 free(chanuser);
91             }
92             freeChanNode(chan);
93         }
94     }
95     free(chanList);
96 }
97
98 int is_valid_chan(const char *name) {
99     unsigned int ii;
100     if (*name !='#')
101         return 0;
102     for (ii=1; name[ii]; ++ii) {
103         if ((name[ii] > 0) && (name[ii] <= 32))
104             return 0;
105         if (name[ii] == ',')
106             return 0;
107         if (name[ii] == '\xa0')
108             return 0;
109     }
110     return 1;
111 }
112
113 static int get_chanlist_entry(int name) {
114     if((name > 0 && name <= 32) || name == ',' || name == '\xa0') return -1; //invalid name
115     if(tolower(name) >= 97 && tolower(name) <= 122) {
116         return (tolower(name) - 97);
117     }
118     if(tolower(name) >= 48 && tolower(name) <= 57) {
119         return (tolower(name) - 48 + 26);
120     }
121     /* {|}~[\]^_` */
122     if(name == '{') return 36;
123     if(name == '|') return 37;
124     if(name == '}') return 38;
125     if(name == '~') return 39;
126     if(name == '[') return 40;
127     if(name == '\\') return 41;
128     if(name == ']') return 42;
129     if(name == '^') return 43;
130     if(name == '_') return 44;
131     if(name == '`') return 45;
132     return 46;
133 }
134
135 struct ChanNode* getChanByName(const char *name) { //case insensitive
136     int chanListIndex = get_chanlist_entry(name[1]);
137     if(chanListIndex == -1 || chanList[chanListIndex] == NULL)
138         return NULL;
139     struct ChanNode *chan;
140     for(chan = chanList[chanListIndex]; chan; chan = chan->next) {
141         if(!stricmp(name, chan->name))
142             return chan;
143     }
144     return NULL;
145 }
146
147 struct ChanNode* addChannel(const char *name) {
148     int chanListIndex = get_chanlist_entry(name[1]);
149     if(chanListIndex == -1 || !is_valid_chan(name))
150         return NULL;
151     struct ChanNode *chan = malloc(sizeof(*chan));
152     if (!chan)
153     {
154         perror("malloc() failed");
155         return NULL;
156     }
157     strcpy(chan->name, name);
158     chan->user = NULL;
159     chan->bans = NULL;
160     chan->usercount = 0;
161     chan->chanbot = NULL;
162     chan->topic[0] = 0;
163     chan->flags = 0;
164     /* mode lists */
165     chan->modes = 0;
166     chan->trigger = NULL;
167     chan->mode_str_args = calloc(modes_with_strarg, sizeof(char*));
168     chan->mode_int_args = calloc(modes_with_intarg, sizeof(int));
169     
170     chan->next = chanList[chanListIndex];
171     chanList[chanListIndex] = chan;
172     return chan;
173 }
174
175 void delChannel(struct ChanNode* chan, int freeChan) {
176     int chanListIndex = get_chanlist_entry(chan->name[1]);
177     if(chanListIndex == -1) return;
178     struct ChanNode *cchan, *last_chan = NULL;
179     for(cchan = chanList[chanListIndex]; cchan; cchan = cchan->next) {
180         if(cchan == chan) {
181             if(last_chan)
182                 last_chan->next = chan->next;
183             else
184                 chanList[chanListIndex] = chan->next;
185             break;
186         } else
187             last_chan = cchan;
188     }
189     if(chan->user) {
190         //free all chanusers
191         struct ChanUser *chanuser, *next;
192         for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
193             next = getChannelUsers(chan, chanuser);
194             removeChanUserFromLists(chanuser, 0, 1, 1);
195         }
196     }
197     if(freeChan)
198         freeChanNode(chan);
199     else
200         chan->next = NULL;
201 }
202
203 void freeChanNode(struct ChanNode* chan) {
204     int i;
205     for(i = 0; i < modes_with_strarg; i++) {
206         if(chan->mode_str_args[i])
207             free(chan->mode_str_args[i]);
208     }
209     if(chan->trigger) {
210         struct trigger_cache *trigger, *next_trigger;
211         for(trigger = chan->trigger; trigger; trigger = next_trigger) {
212             next_trigger = trigger;
213             free(trigger->trigger);
214             free(trigger);
215         }
216     }
217     free(chan->mode_str_args);
218     free(chan->mode_int_args);
219     free(chan);
220 }
221
222 void checkChannelVisibility(struct ChanNode* chan) {
223     struct ChanUser *chanuser, *next;
224     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
225         if(chanuser->user->flags & USERFLAG_ISBOT) {
226             chan->chanbot = chanuser->user;
227             return;
228         }
229     }
230     //free the channel...
231     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
232         next = getChannelUsers(chan, chanuser);
233         //remove the channel from the user's channel-list
234         removeChanUserFromLists(chanuser, 0, 1, 0);
235         if(!chanuser->user->channel) {
236             //free the user (no more channels)
237             delUser(chanuser->user, 1);
238         }
239         free(chanuser);
240     }
241     chan->user = NULL;
242     delChannel(chan, 1);
243 }
244
245 static unsigned int* getModeOptions(char mode) {
246     unsigned int *cmode;
247     for (cmode = valid_modes; cmode[1]; cmode += 3) {
248         if(cmode[1] == mode)
249             return cmode;
250     }
251     return NULL;
252 }
253
254 int isModeSet(struct ChanNode* chan, char modeChar) {
255     unsigned int *modeOpt = getModeOptions(modeChar);
256     return (chan->modes & modeOpt[0]);
257 }
258
259 void* getModeValue(struct ChanNode* chan, char modeChar) {
260     #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
261     unsigned int *modeOpt = getModeOptions(modeChar);
262     if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING)
263         return chan->mode_str_args[MODE_VALUE_INDEX];
264     if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER)
265         return &chan->mode_int_args[MODE_VALUE_INDEX];
266     return NULL;
267     #undef MODE_VALUE_INDEX
268 }
269
270 static void parseModesUserPriv(struct ChanNode* chan, unsigned char flag, int add, char *nick) {
271     struct UserNode *user = getUserByNick(nick);
272     if(user == NULL) return;
273     struct ChanUser *chanuser = getChanUser(user, chan);
274     if(chanuser == NULL) return;
275     if(add)
276         chanuser->flags |= flag;
277     else
278         chanuser->flags &= ~flag;
279 }
280
281 static void parseModesBan(struct ChanNode* chan, int add, char *mask) {
282     if(add)
283         addChannelBan(chan, mask);
284     else
285         removeChannelBanMask(chan, mask);
286 }
287
288 void parseModes(struct ChanNode* chan, char *modeStr, char **argv, int argc) {
289     int i, argpos = 0, add = 1;
290     #define MODE_TYPE (modeOpt[2] & CHANNEL_MODE_TYPE)
291     #define MODE_VALUE (modeOpt[2] & CHANNEL_MODE_VALUE)
292     #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
293     unsigned int *modeOpt;
294     for(i = 0; i < strlen(modeStr); i++) {
295         if(modeStr[i] == '+') {
296             add = 1;
297             continue;
298         }
299         if(modeStr[i] == '-') {
300             add = 0;
301             continue;
302         }
303         modeOpt = getModeOptions(modeStr[i]);
304         if(!modeOpt) continue; // unknown mode?
305         if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
306             if(argpos == argc) continue;
307             //special mode ;)
308             switch(modeStr[i]) {
309                 case 'o':
310                     parseModesUserPriv(chan, CHANUSERFLAG_OPPED, add, argv[argpos]);
311                     break;
312                 case 'v':
313                     parseModesUserPriv(chan, CHANUSERFLAG_VOICED, add, argv[argpos]);
314                     break;
315                 case 'b':
316                     parseModesBan(chan, add, argv[argpos]);
317                     break;
318                 default:
319                     //we have an unknown TYPE_A mode???
320                     break;
321             }
322             argpos++;
323             continue;
324         }
325         if(add) {
326             if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
327                 if(argpos == argc) continue;
328                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
329                     if(chan->mode_str_args[MODE_VALUE_INDEX])
330                         free(chan->mode_str_args[MODE_VALUE_INDEX]);
331                     chan->mode_str_args[MODE_VALUE_INDEX] = strdup(argv[argpos++]);
332                 } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
333                     chan->mode_int_args[MODE_VALUE_INDEX] = atoi(argv[argpos++]);
334                 else
335                     argpos++; //we simply don't know what to do with the argument...
336             }
337             chan->modes |= modeOpt[0];
338         } else {
339             chan->modes &= ~modeOpt[0];
340             if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
341                 if(argpos == argc) continue;
342                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
343                     free(chan->mode_str_args[MODE_VALUE_INDEX]);
344                     chan->mode_str_args[MODE_VALUE_INDEX] = NULL;
345                 } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
346                     chan->mode_int_args[MODE_VALUE_INDEX] = 0;
347                 argpos++; //we don't need the argument when unsetting a mode...
348             }
349         }
350     }
351     #undef MODE_TYPE
352     #undef MODE_VALUE
353     #undef MODE_VALUE_INDEX
354 }
355
356 void getModeString(struct ChanNode* chan, char *modesStr) {
357     #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
358     #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
359     #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
360     char paramStr[MAXLEN];
361     modesStr[0] = '+';
362     unsigned int *mode;
363     int modePos = 1;
364     int paramPos = 0;
365     for (mode = valid_modes; mode[1]; mode += 3) {
366         if(chan->modes & mode[0]) {
367             modesStr[modePos++] = (char) mode[1];
368             if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
369                 if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
370                     paramPos += sprintf(paramStr + paramPos, " %s", chan->mode_str_args[MODE_VALUE_INDEX]);
371                 else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
372                     paramPos += sprintf(paramStr + paramPos, " %d", chan->mode_int_args[MODE_VALUE_INDEX]);
373             }
374         }
375     }
376     paramStr[paramPos] = '\0';
377     strcpy(modesStr + modePos, paramStr);
378     #undef MODE_TYPE
379     #undef MODE_VALUE
380     #undef MODE_VALUE_INDEX
381 }