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