changed Makefile; build all commands as an own file
[NeonServV5.git] / tools.c
diff --git a/tools.c b/tools.c
index 3bc3374139748594d1a62848c34d0a4d5dfb9bb8..097684855d8230a66cb21819ceb9240dce68a5cb 100644 (file)
--- a/tools.c
+++ b/tools.c
@@ -1,20 +1,26 @@
 #include "tools.h"
 #include "UserNode.h"
+#include "ChanNode.h"
 #include "lang.h"
+#include "ClientSocket.h"
 
 static const struct default_language_entry msgtab[] = {
-    {"TIME_MASK_2_ITEMS", "%s and %s"},
-    {"TIME_MASK_3_ITEMS", "%s, %s and %s"},
-    {"TIME_YEAR", "%d year"},
-    {"TIME_YEARS", "%d years"},
-    {"TIME_DAY", "%d day"},
-    {"TIME_DAYS", "%d days"},
-    {"TIME_HOUR", "%d hour"},
-    {"TIME_HOURS", "%d hours"},
-    {"TIME_MINUTE", "%d minute"},
-    {"TIME_MINUTES", "%d minutes"},
-    {"TIME_SECOND", "%d second"},
-    {"TIME_SECONDS", "%d seconds"},
+    {"TIME_MASK_2_ITEMS", "%s and %s"}, /* {ARGS: "2 days", "1 hour"} */
+    {"TIME_MASK_3_ITEMS", "%s, %s and %s"}, /* {ARGS: "2 days", "1 hour", "20 minutes"} */
+    {"TIME_YEAR", "year"},
+    {"TIME_YEARS", "years"},
+    {"TIME_MONTH", "month"},
+    {"TIME_MONTHS", "months"},
+    {"TIME_WEEK", "week"},
+    {"TIME_WEEKS", "weeks"},
+    {"TIME_DAY", "day"},
+    {"TIME_DAYS", "days"},
+    {"TIME_HOUR", "hour"},
+    {"TIME_HOURS", "hours"},
+    {"TIME_MINUTE", "minute"},
+    {"TIME_MINUTES", "minutes"},
+    {"TIME_SECOND", "second"},
+    {"TIME_SECONDS", "seconds"},
     {NULL, NULL}
 };
 
@@ -111,14 +117,44 @@ int table_add(struct Table *table, char **entry) {
     int col;
     if(table->entrys == table->length) return 0;
     for(col = 0; col < table->width; col++) {
-        table->contents[table->entrys][col] = ((table->flags & TABLE_FLAG_USE_POINTER) ? entry[col] : strdup(entry[col]));
-        if(strlen(entry[col]) > table->maxwidth[col])
+        table->contents[table->entrys][col] = ((table->flags & TABLE_FLAG_USE_POINTER) || !entry[col] ? entry[col] : strdup(entry[col]));
+        if(table->contents[table->entrys][col])
+            table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
+        if(entry[col] && strlen(entry[col]) > table->maxwidth[col])
             table->maxwidth[col] = strlen(entry[col]);
     }
     table->entrys++;
     return 1;
 }
 
+int table_change(struct Table *table, int row, char **entry) {
+    int col;
+    if(row >= table->length) return 0;
+    for(col = 0; col < table->width; col++) {
+        if(table->contents[row][col] && !(table->flags & TABLE_FLAG_USE_POINTER))
+            free(table->contents[row][col]);
+        table->contents[row][col] = ((table->flags & TABLE_FLAG_USE_POINTER) || !entry[col] ? entry[col] : strdup(entry[col]));
+        if(table->contents[row][col])
+            table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
+        if(entry[col] && strlen(entry[col]) > table->maxwidth[col])
+            table->maxwidth[col] = strlen(entry[col]);
+    }
+    return 1;
+}
+
+int table_change_field(struct Table *table, int row, int col, char *entry) {
+    if(row >= table->length) return 0;
+    if(col >= table->width) return 0;
+    if(table->contents[row][col] && !(table->flags & TABLE_FLAG_USE_POINTER))
+        free(table->contents[row][col]);
+    table->contents[row][col] = (((table->flags & TABLE_FLAG_USE_POINTER) || !entry) ? entry : strdup(entry));
+    if(table->contents[row][col])
+        table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
+    if(entry && strlen(entry) > table->maxwidth[col])
+        table->maxwidth[col] = strlen(entry);
+    return 1;
+}
+
 int table_set_bold(struct Table *table, int collum, int bold) {
     if(bold)
         table->col_flags[collum] |= TABLE_FLAG_COL_BOLD;
@@ -140,20 +176,22 @@ char **table_end(struct Table *table) {
         table->table_lines[row] = malloc(tablewidth * sizeof(*table->table_lines[row]));
         pos = 0;
         for(col = 0; col < table->width; col++) {
+            if(!(table->col_flags[col] & TABLE_FLAG_COL_CONTENTS)) continue;
             if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
                 table->table_lines[row][pos++] = '\002';
             for(i = 0; i < strlen(table->contents[row][col]); i++) {
                 table->table_lines[row][pos++] = table->contents[row][col][i];
             }
-            for(;i < table->maxwidth[col]; i++) {
+            if(col < table->width-1) {
+                for(;i < table->maxwidth[col]; i++) {
+                    table->table_lines[row][pos++] = ' ';
+                }
                 table->table_lines[row][pos++] = ' ';
-            }
+            } else
+                table->table_lines[row][pos++] = '\0';
+            
             if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
                 table->table_lines[row][pos++] = '\002';
-            if(col < table->width-1)
-                table->table_lines[row][pos++] = ' ';
-            else
-                table->table_lines[row][pos++] = '\0';
         }
     }
     return table->table_lines;
@@ -164,7 +202,8 @@ void table_free(struct Table *table) {
     for(row = 0; row < table->length; row++) {
         if(!(table->flags & TABLE_FLAG_USE_POINTER) && table->entrys > row) {
             for(col = 0; col < table->width; col++) {
-                free(table->contents[row][col]);
+                if(table->contents[row][col])
+                    free(table->contents[row][col]);
             }
         }
         free(table->contents[row]);
@@ -181,52 +220,278 @@ void table_free(struct Table *table) {
     free(table);
 }
 
-int timeToStr(struct UserNode *user, int seconds, int items, char *buf) {
-    char *item[items];
+char* timeToStr(struct UserNode *user, int seconds, int items, char *buf) {
+    char item[items][MAXLEN];
     int tmp, citem = 0;
     if(citem != items && seconds >= 31536000) { //60*60*24*365 = 31536000
         
         tmp = seconds / 31536000;
-        item[citem++] = build_language_string(user, NULL, (tmp == 1 ? "TIME_YEAR" : "TIME_YEARS"), tmp);
+        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_YEAR" : "TIME_YEARS"));
         seconds -= tmp * 31536000;
     }
     if(citem != items && seconds >= 86400) { //60*60*24 = 86400
         tmp = seconds / 86400;
-        item[citem++] = build_language_string(user, NULL, (tmp == 1 ? "TIME_DAY" : "TIME_DAYS"), tmp);
+        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_DAY" : "TIME_DAYS"));
         seconds -= tmp * 86400;
     }
     if(citem != items && seconds >= 3600) { //60*60 = 3600
         tmp = seconds / 3600;
-        item[citem++] = build_language_string(user, NULL, (tmp == 1 ? "TIME_HOUR" : "TIME_HOURS"), tmp);
+        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_HOUR" : "TIME_HOURS"));
         seconds -= tmp * 3600;
     }
     if(citem != items && seconds >= 60) {
         tmp = seconds / 60;
-        item[citem++] = build_language_string(user, NULL, (tmp == 1 ? "TIME_MINUTE" : "TIME_MINUTES"), tmp);
+        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_MINUTE" : "TIME_MINUTES"));
         seconds -= tmp * 60;
     }
     if(citem != items && seconds >= 1) {
-        item[citem++] = build_language_string(user, NULL, (seconds == 1 ? "TIME_SECOND" : "TIME_SECONDS"), seconds);
+        sprintf(item[citem++], "%d %s", seconds, get_language_string(user, seconds == 1 ? "TIME_SECOND" : "TIME_SECONDS"));
     }
-    if(items == 2) {
+    if(citem == 2) {
         build_language_string(user, buf, "TIME_MASK_2_ITEMS", item[0], item[1]);
-    } else if(items == 3) {
+    } else if(citem == 3) {
         build_language_string(user, buf, "TIME_MASK_3_ITEMS", item[0], item[1], item[2]);
     } else {
         int i, ii, p = 0;
-        for(i = 0; i < items; i++) {
+        for(i = 0; i < citem; i++) {
             for(ii = 0; ii < strlen(item[i]); ii++) {
                 buf[p++] = item[i][ii];
             }
             buf[p++] = ' ';
         }
-        buf[p-1] = '\0';
+        buf[(p ? p-1 : 0)] = '\0';
     }
-    return 1;
+    return buf;
+}
+
+int strToTime(struct UserNode *user, char *str) {
+    /*
+    * y = year = 365 days
+    * M = month = 30 days
+    * w = week = 7 days
+    * d = day
+    * h = hour
+    * m = minute
+    * (s) = second
+    */
+    int total_time = 0, cvalue;
+    char *p, tmpchar;
+    int unit_multiplikator;
+    while(*str) {
+        p = str;
+        while(*p && !isdigit(*p)) //skip leading chars
+            p++;
+        str = p;
+        while(*p && isdigit(*p)) //get the value
+            p++;
+        tmpchar = *p;
+        *p = '\0';
+        cvalue = isdigit(*str) ? atoi(str) : 0;
+        *p = tmpchar;
+        while(*p == ' ') //skip spaces
+            p++;
+        str = p;
+        while(*p && !isdigit(*p)) //get the unit
+            p++;
+        tmpchar = *p;
+        *p = '\0';
+        if(p - str > 1) { //unit has more than one char
+            if(!stricmp(str, "year") || !stricmp(str, "year") || !stricmp(str, get_language_string(user, "TIME_YEAR")) || !stricmp(str, get_language_string(user, "TIME_YEARS")))
+                unit_multiplikator = 31536000; //60*60*24*365 = 31536000
+            else if(!stricmp(str, "month") || !stricmp(str, "months") || !stricmp(str, get_language_string(user, "TIME_MONTH")) || !stricmp(str, get_language_string(user, "TIME_MONTHS")))
+                unit_multiplikator = 2592000; //60*60*24*30 = 2592000
+            else if(!stricmp(str, "week") || !stricmp(str, "weeks") || !stricmp(str, get_language_string(user, "TIME_WEEK")) || !stricmp(str, get_language_string(user, "TIME_WEEKS")))
+                unit_multiplikator = 604800; //60*60*24*7 = 604800
+            else if(!stricmp(str, "day") || !stricmp(str, "days") || !stricmp(str, get_language_string(user, "TIME_DAY")) || !stricmp(str, get_language_string(user, "TIME_DAYS")))
+                unit_multiplikator = 86400; //60*60*24 = 86400
+            else if(!stricmp(str, "hour") || !stricmp(str, "hours") || !stricmp(str, get_language_string(user, "TIME_HOUR")) || !stricmp(str, get_language_string(user, "TIME_HOURS")))
+                unit_multiplikator = 3600; //60*60 = 3600
+            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")))
+                unit_multiplikator = 60;
+            else
+                unit_multiplikator = 1;
+        } else {
+            switch(*str) {
+                case 'y':
+                    unit_multiplikator = 31536000; //60*60*24*365 = 31536000
+                    break;
+                case 'M':
+                    unit_multiplikator = 2592000; //60*60*24*30 = 2592000
+                    break;
+                case 'w':
+                    unit_multiplikator = 604800; //60*60*24*7 = 604800
+                    break;
+                case 'd':
+                    unit_multiplikator = 86400; //60*60*24 = 86400
+                    break;
+                case 'h':
+                    unit_multiplikator = 3600; //60*60 = 3600
+                    break;
+                case 'm':
+                    unit_multiplikator = 60;
+                    break;
+                default:
+                    unit_multiplikator = 1;
+                    break;
+            }
+        }
+        total_time += (cvalue * unit_multiplikator);
+        *p = tmpchar;
+        str = p;
+    }
+    return total_time;
+}
+
+struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *chan) {
+    struct ModeBuffer *modeBuf = malloc(sizeof(*modeBuf));
+    if(!modeBuf) {
+        perror("malloc() failed");
+        return NULL;
+    }
+    modeBuf->client = client;
+    modeBuf->chan = chan;
+    modeBuf->addCount = 0;
+    modeBuf->delCount = 0;
+    return modeBuf;
+}
+
+void modeBufferSet(struct ModeBuffer *modeBuf, int add, char mode, char *param) {
+    if(add) {
+        modeBuf->addModes[modeBuf->addCount] = mode;
+        modeBuf->addModesParams[modeBuf->addCount] = (param ? strdup(param) : NULL);
+        modeBuf->addCount++;
+        modeBuf->addModes[modeBuf->addCount] = '\0';
+    } else {
+        modeBuf->delModes[modeBuf->delCount] = mode;
+        modeBuf->delModesParams[modeBuf->delCount] = (param ? strdup(param) : NULL);
+        modeBuf->delCount++;
+        modeBuf->delModes[modeBuf->delCount] = '\0';
+    }
+    if(modeBuf->addCount + modeBuf->delCount == MAXMODES)
+        flushModeBuffer(modeBuf);
+}
+
+void flushModeBuffer(struct ModeBuffer *modeBuf) {
+    char modeStr[MAXMODES+3];
+    int modePos = 0;
+    char paramStr[MAXLEN];
+    int paramPos = 0;
+    int i;
+    if(modeBuf->addCount) {
+        modeStr[modePos++] = '+';
+        for(i = 0; i < modeBuf->addCount; i++) {
+            modeStr[modePos++] = modeBuf->addModes[i];
+            if(modeBuf->addModesParams[i]) {
+                paramPos += sprintf(paramStr + paramPos, " %s", modeBuf->addModesParams[i]);
+            }
+        }
+        modeBuf->addCount = 0;
+    }
+    if(modeBuf->delCount) {
+        modeStr[modePos++] = '-';
+        for(i = 0; i < modeBuf->delCount; i++) {
+            modeStr[modePos++] = modeBuf->delModes[i];
+            if(modeBuf->delModesParams[i]) {
+                paramPos += sprintf(paramStr + paramPos, " %s", modeBuf->delModesParams[i]);
+            }
+        }
+        modeBuf->delCount = 0;
+    }
+    modeStr[modePos++] = '\0';
+    putsock(modeBuf->client, "MODE %s %s%s", modeBuf->chan->name, modeStr, paramStr);
 }
 
+void freeModeBuffer(struct ModeBuffer *modeBuf) {
+    if(modeBuf->addCount + modeBuf->delCount)
+        flushModeBuffer(modeBuf);
+    free(modeBuf);
+}
 
+int is_ircmask(const char *text) {
+    while (*text && (isalnum((char)*text) || strchr("-_[]|\\`^{}?*", *text)))
+        text++;
+    if (*text++ != '!')
+        return 0;
+    while (*text && *text != '@' && !isspace((char)*text))
+        text++;
+    if (*text++ != '@')
+        return 0;
+    while (*text && !isspace((char)*text))
+        text++;
+    return !*text;
+}
 
+char* generate_banmask(struct UserNode *user, char *buffer) {
+    char *userhost = user->host;
+    
+    if(isFakeHost(user->host)) {
+        sprintf(buffer, "*!*@%s", userhost);
+        return buffer;
+    }
+    
+    //check if the hostname has more than 4 connections (trusted host)
+    if(countUsersWithHost(userhost) > 4) {
+        sprintf(buffer, "*!%s@%s", user->ident, userhost);
+        return buffer;
+    } else {
+        sprintf(buffer, "*!*@%s", userhost);
+        return buffer;
+    }
+}
+
+char* make_banmask(char *input, char* buffer) {
+    char *nick = NULL, *ident = NULL, *host = NULL;
+    char tmp[HOSTLEN];
+    char *p;
+    if((p = strstr(input, "!"))) {
+        nick = input;
+        *p = '\0';
+        ident = p+1;
+        if((p = strstr(ident, "@"))) {
+            *p = '\0';
+            host = p+1;
+        }
+    } else if((p = strstr(input, "@"))) {
+        ident = input;
+        *p = '\0';
+        host = p+1;
+    } else if((p = strstr(input, "."))) {
+        host = input;
+    } else if(*input == '*' && input[1] != '\0' && !strstr(input+1, "*")) {
+        //AUTH MASK
+        p = getAuthFakehost(input+1);
+        if(p)
+            host = p;
+        else {
+            sprintf(tmp, "%s.*", input+1);
+            host = tmp;
+        }
+    } else {
+        struct UserNode *user = searchUserByNick(input);
+        if(user)
+            return generate_banmask(user, buffer);
+        else
+            nick = input;
+    }
+    if(nick && *nick == '\0') nick = NULL;
+    if(ident && *ident == '\0') ident = NULL;
+    if(host && *host == '\0') host = NULL;
+    sprintf(buffer, "%s!%s@%s", (nick ? nick : "*"), (ident ? ident : "*"), (host ? host : "*"));
+    return buffer;
+}
+
+int isFakeHost(char *host) {
+    char *p1, *p2 = host;
+    
+    //find the last dot to identify if the hostmask is a fake host
+    while((p1 = strstr(p2, "."))) {
+        p2 = p1 + 1;
+    }
+    //TLD database: http://www.iana.org/domains/root/db/
+    //the longest TLD i found was 6 chars long (ignoring the stange exotic ones :D)
+    //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
+    return (strlen(p2+1) > 4);
+}
 
 void init_tools() {
     register_default_language_table(msgtab);