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