fixed renameAccount function (merging mode)
[NeonServV5.git] / src / tools.c
1 /* tools.c - NeonServ v5.6
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #include "tools.h"
18 #include "UserNode.h"
19 #include "ChanNode.h"
20 #include "lang.h"
21 #include "ClientSocket.h"
22 #include "IPNode.h"
23
24 static const struct default_language_entry msgtab[] = {
25     {"TIME_MASK_2_ITEMS", "%s and %s"}, /* {ARGS: "2 days", "1 hour"} */
26     {"TIME_MASK_3_ITEMS", "%s, %s and %s"}, /* {ARGS: "2 days", "1 hour", "20 minutes"} */
27     {"TIME_YEAR", "year"},
28     {"TIME_YEARS", "years"},
29     {"TIME_MONTH", "month"},
30     {"TIME_MONTHS", "months"},
31     {"TIME_WEEK", "week"},
32     {"TIME_WEEKS", "weeks"},
33     {"TIME_DAY", "day"},
34     {"TIME_DAYS", "days"},
35     {"TIME_HOUR", "hour"},
36     {"TIME_HOURS", "hours"},
37     {"TIME_MINUTE", "minute"},
38     {"TIME_MINUTES", "minutes"},
39     {"TIME_SECOND", "second"},
40     {"TIME_SECONDS", "seconds"},
41     {NULL, NULL}
42 };
43
44 /* copied from IRCU 2.10.12 match.c */
45 /*
46  * Compare if a given string (name) matches the given
47  * mask (which can contain wild cards: '*' - match any
48  * number of chars, '?' - match any single character.
49  *
50  * return  0, if match
51  *         1, if no match
52  *
53  *  Originally by Douglas A Lewis (dalewis@acsu.buffalo.edu)
54  *  Rewritten by Timothy Vogelsang (netski), net@astrolink.org
55  */
56 int match(const char *mask, const char *name)
57 {
58   const char *m = mask, *n = name;
59   const char *m_tmp = mask, *n_tmp = name;
60   int star_p;
61
62   for (;;) switch (*m) {
63   case '\0':
64     if (!*n)
65       return 0;
66   backtrack:
67     if (m_tmp == mask)
68       return 1;
69     m = m_tmp;
70     n = ++n_tmp;
71     if (*n == '\0')
72       return 1;
73     break;
74   case '\\':
75     m++;
76     /* allow escaping to force capitalization */
77     if (*m++ != *n++)
78       goto backtrack;
79     break;
80   case '*': case '?':
81     for (star_p = 0; ; m++) {
82       if (*m == '*')
83         star_p = 1;
84       else if (*m == '?') {
85         if (!*n++)
86           goto backtrack;
87       } else break;
88     }
89     if (star_p) {
90       if (!*m)
91         return 0;
92       else if (*m == '\\') {
93         m_tmp = ++m;
94         if (!*m)
95           return 1;
96         for (n_tmp = n; *n && *n != *m; n++) ;
97       } else {
98         m_tmp = m;
99         for (n_tmp = n; *n && tolower(*n) != tolower(*m); n++) ;
100       }
101     }
102     /* and fall through */
103   default:
104     if (!*n)
105       return *m != '\0';
106     if (tolower(*m) != tolower(*n))
107       goto backtrack;
108     m++;
109     n++;
110     break;
111   }
112 }
113
114
115 //TABLES
116 struct Table *table_init(int width, int length, int flags) {
117     int row;
118     struct Table *table = malloc(sizeof(*table));
119     table->contents = malloc(length * sizeof(*table->contents));
120     for(row = 0; row < length; row++) {
121         table->contents[row] = calloc(width, sizeof(*table->contents[row]));
122     }
123     table->length = length;
124     table->width = width;
125     table->flags = flags;
126     table->col_flags = calloc(width, sizeof(int));
127     table->entrys = 0;
128     table->maxwidth = calloc(width, sizeof(int));
129     table->table_lines = NULL;
130     return table;
131 }
132
133 int table_add(struct Table *table, char **entry) {
134     int col;
135     if(table->entrys == table->length) return 0;
136     for(col = 0; col < table->width; col++) {
137         table->contents[table->entrys][col] = ((table->flags & TABLE_FLAG_USE_POINTER) || !entry[col] ? entry[col] : strdup(entry[col]));
138         if(table->contents[table->entrys][col])
139             table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
140         if(entry[col] && strlen(entry[col]) > table->maxwidth[col])
141             table->maxwidth[col] = strlen(entry[col]);
142     }
143     table->entrys++;
144     return 1;
145 }
146
147 int table_change(struct Table *table, int row, char **entry) {
148     int col;
149     if(row >= table->length) return 0;
150     for(col = 0; col < table->width; col++) {
151         if(table->contents[row][col] && !(table->flags & TABLE_FLAG_USE_POINTER))
152             free(table->contents[row][col]);
153         table->contents[row][col] = ((table->flags & TABLE_FLAG_USE_POINTER) || !entry[col] ? entry[col] : strdup(entry[col]));
154         if(table->contents[row][col])
155             table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
156         if(entry[col] && strlen(entry[col]) > table->maxwidth[col])
157             table->maxwidth[col] = strlen(entry[col]);
158     }
159     return 1;
160 }
161
162 int table_change_field(struct Table *table, int row, int col, char *entry) {
163     if(row >= table->length) return 0;
164     if(col >= table->width) return 0;
165     if(table->contents[row][col] && !(table->flags & TABLE_FLAG_USE_POINTER))
166         free(table->contents[row][col]);
167     table->contents[row][col] = (((table->flags & TABLE_FLAG_USE_POINTER) || !entry) ? entry : strdup(entry));
168     if(table->contents[row][col])
169         table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
170     if(entry && strlen(entry) > table->maxwidth[col])
171         table->maxwidth[col] = strlen(entry);
172     return 1;
173 }
174
175 int table_set_bold(struct Table *table, int collum, int bold) {
176     if(bold)
177         table->col_flags[collum] |= TABLE_FLAG_COL_BOLD;
178     else
179         table->col_flags[collum] &= ~TABLE_FLAG_COL_BOLD;
180     return 1;
181 }
182
183 char **table_end(struct Table *table) {
184     int row, col, tablewidth = 0, pos,i,j,k;
185     if(!table->entrys) return NULL;
186     for(col = 0; col < table->width; col++) {
187         tablewidth += table->maxwidth[col]+1;
188         if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
189             tablewidth += 2;
190     }
191     table->table_lines = malloc(table->entrys * sizeof(table->table_lines));
192     for(row = 0; row < table->entrys; row++) {
193         table->table_lines[row] = malloc(tablewidth * sizeof(*table->table_lines[row]));
194         pos = 0;
195         for(col = 0; col < table->width; col++) {
196             if(!(table->col_flags[col] & TABLE_FLAG_COL_CONTENTS)) continue;
197             if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
198                 table->table_lines[row][pos++] = '\002';
199             i = 0;
200             j = 0;
201             if(table->contents[row][col]) {
202                 for(; i < strlen(table->contents[row][col]); i++) {
203                     table->table_lines[row][pos++] = table->contents[row][col][i];
204                     if(table->contents[row][col][i] == '\002') j++;
205                     else if(table->contents[row][col][i] == '\003') {
206                         j++;
207                         for(k = 1; k <= 2; k++) {
208                             if(isdigit(table->contents[row][col][i+k]))
209                                 j++;
210                             else 
211                                 break;
212                         }
213                     }
214                 }
215             } else if(table->col_flags[col] & TABLE_FLAG_COL_SKIP_NULL)
216                 continue;
217             i -= j;
218             if(col < table->width-1) {
219                 for(;i < table->maxwidth[col]; i++) {
220                     table->table_lines[row][pos++] = ' ';
221                 }
222                 table->table_lines[row][pos++] = ' ';
223             } else
224                 table->table_lines[row][pos++] = '\0';
225             
226             if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
227                 table->table_lines[row][pos++] = '\002';
228         }
229     }
230     return table->table_lines;
231 }
232
233 void table_free(struct Table *table) {
234     int row, col;
235     for(row = 0; row < table->length; row++) {
236         if(!(table->flags & TABLE_FLAG_USE_POINTER) && table->entrys > row) {
237             for(col = 0; col < table->width; col++) {
238                 if(table->contents[row][col])
239                     free(table->contents[row][col]);
240             }
241         }
242         free(table->contents[row]);
243     }
244     free(table->contents);
245     free(table->col_flags);
246     free(table->maxwidth);
247     if(table->table_lines) {
248         for(row = 0; row < table->entrys; row++) {
249             free(table->table_lines[row]);
250         }
251         free(table->table_lines);
252     }
253     free(table);
254 }
255
256 char* timeToStr(struct UserNode *user, int seconds, int items, char *buf) {
257     char item[items][MAXLEN];
258     int tmp, citem = 0;
259     if(citem != items && seconds >= 31536000) { //60*60*24*365 = 31536000
260         
261         tmp = seconds / 31536000;
262         sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_YEAR" : "TIME_YEARS"));
263         seconds -= tmp * 31536000;
264     }
265     if(citem != items && seconds >= 86400) { //60*60*24 = 86400
266         tmp = seconds / 86400;
267         sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_DAY" : "TIME_DAYS"));
268         seconds -= tmp * 86400;
269     }
270     if(citem != items && seconds >= 3600) { //60*60 = 3600
271         tmp = seconds / 3600;
272         sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_HOUR" : "TIME_HOURS"));
273         seconds -= tmp * 3600;
274     }
275     if(citem != items && seconds >= 60) {
276         tmp = seconds / 60;
277         sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_MINUTE" : "TIME_MINUTES"));
278         seconds -= tmp * 60;
279     }
280     if(citem != items && seconds >= 1) {
281         sprintf(item[citem++], "%d %s", seconds, get_language_string(user, seconds == 1 ? "TIME_SECOND" : "TIME_SECONDS"));
282     }
283     if(citem == 2) {
284         build_language_string(user, buf, "TIME_MASK_2_ITEMS", item[0], item[1]);
285     } else if(citem == 3) {
286         build_language_string(user, buf, "TIME_MASK_3_ITEMS", item[0], item[1], item[2]);
287     } else {
288         int i, ii, p = 0;
289         for(i = 0; i < citem; i++) {
290             for(ii = 0; ii < strlen(item[i]); ii++) {
291                 buf[p++] = item[i][ii];
292             }
293             buf[p++] = ' ';
294         }
295         buf[(p ? p-1 : 0)] = '\0';
296     }
297     return buf;
298 }
299
300 int strToTime(struct UserNode *user, char *str) {
301     /*
302     * y = year = 365 days
303     * M = month = 30 days
304     * w = week = 7 days
305     * d = day
306     * h = hour
307     * m = minute
308     * (s) = second
309     */
310     int total_time = 0, cvalue;
311     char *p, tmpchar;
312     int unit_multiplikator;
313     while(*str) {
314         p = str;
315         while(*p && !isdigit(*p)) //skip leading chars
316             p++;
317         str = p;
318         while(*p && isdigit(*p)) //get the value
319             p++;
320         tmpchar = *p;
321         *p = '\0';
322         cvalue = isdigit(*str) ? atoi(str) : 0;
323         *p = tmpchar;
324         while(*p == ' ') //skip spaces
325             p++;
326         str = p;
327         while(*p && !isdigit(*p)) //get the unit
328             p++;
329         tmpchar = *p;
330         *p = '\0';
331         if(p - str > 1) { //unit has more than one char
332             if(!stricmp(str, "year") || !stricmp(str, "year") || !stricmp(str, get_language_string(user, "TIME_YEAR")) || !stricmp(str, get_language_string(user, "TIME_YEARS")))
333                 unit_multiplikator = 31536000; //60*60*24*365 = 31536000
334             else if(!stricmp(str, "month") || !stricmp(str, "months") || !stricmp(str, get_language_string(user, "TIME_MONTH")) || !stricmp(str, get_language_string(user, "TIME_MONTHS")))
335                 unit_multiplikator = 2592000; //60*60*24*30 = 2592000
336             else if(!stricmp(str, "week") || !stricmp(str, "weeks") || !stricmp(str, get_language_string(user, "TIME_WEEK")) || !stricmp(str, get_language_string(user, "TIME_WEEKS")))
337                 unit_multiplikator = 604800; //60*60*24*7 = 604800
338             else if(!stricmp(str, "day") || !stricmp(str, "days") || !stricmp(str, get_language_string(user, "TIME_DAY")) || !stricmp(str, get_language_string(user, "TIME_DAYS")))
339                 unit_multiplikator = 86400; //60*60*24 = 86400
340             else if(!stricmp(str, "hour") || !stricmp(str, "hours") || !stricmp(str, get_language_string(user, "TIME_HOUR")) || !stricmp(str, get_language_string(user, "TIME_HOURS")))
341                 unit_multiplikator = 3600; //60*60 = 3600
342             else if(!stricmp(str, "minute") || !stricmp(str, "minutes") || !stricmp(str, "min") || !stricmp(str, "mins") || !stricmp(str, get_language_string(user, "TIME_MINUTE")) || !stricmp(str, get_language_string(user, "TIME_MINUTES")))
343                 unit_multiplikator = 60;
344             else
345                 unit_multiplikator = 1;
346         } else {
347             switch(*str) {
348                 case 'y':
349                     unit_multiplikator = 31536000; //60*60*24*365 = 31536000
350                     break;
351                 case 'M':
352                     unit_multiplikator = 2592000; //60*60*24*30 = 2592000
353                     break;
354                 case 'w':
355                     unit_multiplikator = 604800; //60*60*24*7 = 604800
356                     break;
357                 case 'd':
358                     unit_multiplikator = 86400; //60*60*24 = 86400
359                     break;
360                 case 'h':
361                     unit_multiplikator = 3600; //60*60 = 3600
362                     break;
363                 case 'm':
364                     unit_multiplikator = 60;
365                     break;
366                 default:
367                     unit_multiplikator = 1;
368                     break;
369             }
370         }
371         total_time += (cvalue * unit_multiplikator);
372         *p = tmpchar;
373         str = p;
374     }
375     return total_time;
376 }
377
378 int getCurrentSecondsOfDay() {
379     time_t now = time(0);
380     struct tm *timeofday = localtime(&now);
381     int seconds = 0;
382     seconds += timeofday->tm_hour * 3600;
383     seconds += timeofday->tm_min * 60;
384     seconds += timeofday->tm_sec;
385     return seconds;
386 }
387
388 struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *chan) {
389     struct ModeBuffer *modeBuf = malloc(sizeof(*modeBuf));
390     if(!modeBuf) {
391         perror("malloc() failed");
392         return NULL;
393     }
394     modeBuf->client = client;
395     modeBuf->chan = chan;
396     modeBuf->addCount = 0;
397     modeBuf->delCount = 0;
398     return modeBuf;
399 }
400
401 void modeBufferSet(struct ModeBuffer *modeBuf, int add, char mode, char *param) {
402     if(add) {
403         modeBuf->addModes[modeBuf->addCount] = mode;
404         modeBuf->addModesParams[modeBuf->addCount] = (param ? strdup(param) : NULL);
405         modeBuf->addCount++;
406         modeBuf->addModes[modeBuf->addCount] = '\0';
407     } else {
408         modeBuf->delModes[modeBuf->delCount] = mode;
409         modeBuf->delModesParams[modeBuf->delCount] = (param ? strdup(param) : NULL);
410         modeBuf->delCount++;
411         modeBuf->delModes[modeBuf->delCount] = '\0';
412     }
413     if(modeBuf->addCount + modeBuf->delCount == MAXMODES)
414         flushModeBuffer(modeBuf);
415 }
416
417 void flushModeBuffer(struct ModeBuffer *modeBuf) {
418     char modeStr[MAXMODES+3];
419     int modePos = 0;
420     char paramStr[MAXLEN];
421     *paramStr = '\0';
422     int paramPos = 0;
423     int i;
424     if(modeBuf->addCount) {
425         modeStr[modePos++] = '+';
426         for(i = 0; i < modeBuf->addCount; i++) {
427             modeStr[modePos++] = modeBuf->addModes[i];
428             if(modeBuf->addModesParams[i]) {
429                 paramPos += sprintf(paramStr + paramPos, " %s", modeBuf->addModesParams[i]);
430                 free(modeBuf->addModesParams[i]);
431                 modeBuf->addModesParams[i] = NULL;
432             }
433         }
434         modeBuf->addCount = 0;
435     }
436     if(modeBuf->delCount) {
437         modeStr[modePos++] = '-';
438         for(i = 0; i < modeBuf->delCount; i++) {
439             modeStr[modePos++] = modeBuf->delModes[i];
440             if(modeBuf->delModesParams[i]) {
441                 paramPos += sprintf(paramStr + paramPos, " %s", modeBuf->delModesParams[i]);
442                 free(modeBuf->delModesParams[i]);
443                 modeBuf->delModesParams[i] = NULL;
444             }
445         }
446         modeBuf->delCount = 0;
447     }
448     modeStr[modePos++] = '\0';
449     putsock(modeBuf->client, "MODE %s %s%s", modeBuf->chan->name, modeStr, paramStr);
450 }
451
452 void freeModeBuffer(struct ModeBuffer *modeBuf) {
453     if(modeBuf->addCount + modeBuf->delCount)
454         flushModeBuffer(modeBuf);
455     free(modeBuf);
456 }
457
458 int is_ircmask(const char *text) {
459     while (*text && (isalnum((char)*text) || strchr("-_[]|\\`^{}?*", *text)))
460         text++;
461     if (*text++ != '!')
462         return 0;
463     while (*text && *text != '@' && !isspace((char)*text))
464         text++;
465     if (*text++ != '@')
466         return 0;
467     while (*text && !isspace((char)*text))
468         text++;
469     return !*text;
470 }
471
472 char* generate_banmask(struct UserNode *user, char *buffer) {
473     char *userhost = user->host;
474     
475     if(isFakeHost(user->host)) {
476         sprintf(buffer, "*!*@%s", userhost);
477         return buffer;
478     }
479     
480     //check if the hostname has more than 4 connections (trusted host)
481     if(countUsersWithHost(userhost) > 4) {
482         sprintf(buffer, "*!%s@%s", user->ident, userhost);
483         return buffer;
484     } else {
485         sprintf(buffer, "*!*@%s", userhost);
486         return buffer;
487     }
488 }
489
490 char* make_banmask(char *input, char* buffer) {
491     char *nick = NULL, *ident = NULL, *host = NULL;
492     char tmp[HOSTLEN];
493     char *p;
494     if((p = strstr(input, "!"))) {
495         nick = input;
496         *p = '\0';
497         ident = p+1;
498         if((p = strstr(ident, "@"))) {
499             *p = '\0';
500             host = p+1;
501         }
502     } else if((p = strstr(input, "@"))) {
503         ident = input;
504         *p = '\0';
505         host = p+1;
506     } else if((p = strstr(input, ".")) || (p = strstr(input, ":"))) {
507         host = input;
508     } else if(*input == '*' && input[1] != '\0' && !strstr(input+1, "*")) {
509         //AUTH MASK
510         p = getAuthFakehost(input+1);
511         if(p)
512             host = p;
513         else {
514             sprintf(tmp, "%s.*", input+1);
515             host = tmp;
516         }
517     } else {
518         struct UserNode *user = searchUserByNick(input);
519         if(user)
520             return generate_banmask(user, buffer);
521         else
522             nick = input;
523     }
524     if(nick && *nick == '\0') nick = NULL;
525     if(ident && *ident == '\0') ident = NULL;
526     if(host && *host == '\0') host = NULL;
527     sprintf(buffer, "%s!%s@%s", (nick ? nick : "*"), (ident ? ident : "*"), (host ? host : "*"));
528     return buffer;
529 }
530
531 int isFakeHost(char *host) {
532     char *p1, *p2 = host;
533     
534     //find the last dot to identify if the hostmask is a fake host
535     while((p1 = strchr(p2, '.'))) {
536         p2 = p1 + 1;
537     }
538     //TLD database: http://www.iana.org/domains/root/db/
539     //the longest TLD i found was 6 chars long (ignoring the stange exotic ones :D)
540     //but we even ignore '.museum' and '.travel' so we can say that the TLD of our mask needs to be less than 4 chars to be a real domain
541     return (strlen(p2+1) > 4);
542 }
543
544 int mask_match(char *mask, struct UserNode *user) {
545     char usermask[NICKLEN+USERLEN+HOSTLEN+3];
546     char matchmask[strlen(mask)+3];
547     strcpy(matchmask, mask);
548     char *host = strchr(mask, '@');
549     if(host) {
550         struct IPNode *ip = createIPNode(host);
551         int bits = (ip->flags & IPNODE_IS_IPV6 ? 128 : 32);
552         if((host = strchr(host, '/'))) {
553             bits = atoi(host+1);
554         }
555         if(ip && user->ip&& !ipmatch(user->ip, ip, bits)) {
556             host[1] = '*';
557             host[2] = '\0';
558         }
559     }
560     sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host);
561     return match(matchmask, usermask);
562 }
563
564 static unsigned long crc_table[256];
565
566 static void crc32_init() {
567     unsigned long crc;
568     int i, j;
569     for(i = 0; i < 256; i++) {
570         crc = i;
571         for(j = 8; j > 0; j--) {
572             if(crc & 1)
573                                 crc = (crc >> 1) ^ 0xEDB88320L;
574             else
575                 crc >>= 1;
576         }
577         crc_table[i] = crc;
578     }
579 }
580
581 unsigned long crc32(const char *text) {
582     register unsigned long crc = 0xFFFFFFFF;
583     unsigned int c, i = 0;
584     while((c = (unsigned int)text[i++]) != 0)
585         crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_table[(crc^c) & 0xFF];
586     return (crc^0xFFFFFFFF);
587 }
588
589 int stricmp (const char *s1, const char *s2) {
590     return stricmplen(s1, s2, -1);
591 }
592
593 int stricmplen(const char *s1, const char *s2, int len) {
594     if (s1 == NULL) 
595         return (s2 == NULL ? 0 : -(*s2));
596     if (s2 == NULL) 
597         return *s1;
598     char c1, c2;
599     int i = 0;
600     while ((c1 = tolower(*s1)) == (c2 = tolower(*s2))) {
601         if (*s1 == '\0') 
602             break;
603         i++;
604         s1++; 
605         s2++;
606         if(len != -1 && i == len) break;
607     }
608     return c1 - c2;
609 }
610
611 void init_tools() {
612     register_default_language_table(msgtab);
613     crc32_init();
614 }