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