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