]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/helpfile.c
Finally fixed all those pesky warnings
[irc/evilnet/x3.git] / src / helpfile.c
index a5d5bdd2aa41be95c47da261906036c4e19b20c4..caee9765ee4d0d4ead8b4b784da4d9d6c300e50a 100644 (file)
@@ -3,9 +3,9 @@
  *
  * This file is part of x3.
  *
- * srvx is free software; you can redistribute it and/or modify
+ * x3 is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -23,6 +23,7 @@
 #include "log.h"
 #include "modcmd.h"
 #include "nickserv.h"
+#include "spamserv.h"
 
 #if defined(HAVE_DIRENT_H)
 #include <dirent.h>
@@ -41,13 +42,13 @@ static const struct message_entry msgtab[] = {
 #define DEFAULT_LINE_SIZE      MAX_LINE_SIZE
 #define DEFAULT_TABLE_SIZE      80
 
-extern struct userNode *global, *chanserv, *opserv, *nickserv;
+extern struct userNode *global, *chanserv, *opserv, *nickserv, *spamserv;
 struct userNode *message_dest;
 struct userNode *message_source;
 struct language *lang_C;
 struct dict *languages;
 
-static void language_cleanup(void)
+static void language_cleanup(UNUSED_ARG(void *extra))
 {
     dict_delete(languages);
 }
@@ -171,8 +172,10 @@ static struct language *language_read(const char *name)
 
     /* Open the directory stream; if we can't, fail. */
     snprintf(filename, sizeof(filename), "languages/%s", name);
-    if (!(dir = opendir(filename)))
+    if (!(dir = opendir(filename))) {
+        log_module(MAIN_LOG, LOG_ERROR, "Unable to open language directory languages/%s: %s", name, strerror(errno));
         return NULL;
+    }
     if (!(lang = dict_find(languages, name, NULL)))
         lang = language_alloc(name);
 
@@ -203,7 +206,7 @@ static struct language *language_read(const char *name)
     /* Read all the translations from the directory. */
     while ((dirent = readdir(dir))) {
         snprintf(filename, sizeof(filename), "languages/%s/%s", name, dirent->d_name);
-        if (!strcmp(dirent->d_name,"parent")) {
+        if (!strcmp(dirent->d_name, "parent")) {
             continue;
         } else if (!strcmp(dirent->d_name, "strings.db")) {
             dict = parse_database(filename);
@@ -222,29 +225,30 @@ static struct language *language_read(const char *name)
 
 static void language_read_list(void)
 {
+    struct stat sbuf;
     struct dirent *dirent;
     DIR *dir;
+    char namebuf[MAXLEN];
 
     if (!(dir = opendir("languages")))
         return;
     while ((dirent = readdir(dir))) {
         if (dirent->d_name[0] == '.')
             continue;
-#ifdef HAVE_DIRENT_D_TYPE
-        if (dirent->d_type != DT_DIR)
+        snprintf(namebuf, sizeof(namebuf), "languages/%s", dirent->d_name);
+        if (!strcmp(dirent->d_name, "strings.db")) {
             continue;
-#else
-        {
-            char namebuf[MAXLEN];
-            struct stat sbuf;
-            snprintf(namebuf, sizeof(namebuf), "languages/%s", dirent->d_name);
-            if (stat(namebuf, &sbuf) < 0)
-                continue;
-            if (!S_ISDIR(sbuf.st_mode))
-                continue;
         }
-#endif
-        language_alloc(dirent->d_name);
+        if (stat(namebuf, &sbuf) < 0) {
+            log_module(MAIN_LOG, LOG_INFO, "Skipping language entry '%s' (unable to stat).", dirent->d_name);
+            continue;
+        }
+        if (!S_ISDIR(sbuf.st_mode)) {
+            log_module(MAIN_LOG, LOG_INFO, "Skipping language entry '%s' (not directory).", dirent->d_name);
+            continue;
+        }
+        if (!dict_find(languages, dirent->d_name, NULL))
+            language_alloc(dirent->d_name);
     }
     closedir(dir);
 }
@@ -276,7 +280,7 @@ table_send(struct userNode *from, const char *to, unsigned int size, irc_send_fu
     char line[MAX_LINE_SIZE+1];
     struct handle_info *hi;
     char *sepstr = NULL;
-    int sepsize = 0;
+    unsigned int sepsize = 0;
 
     if (IsChannelName(to) || *to == '$') {
         message_dest = NULL;
@@ -308,10 +312,18 @@ table_send(struct userNode *from, const char *to, unsigned int size, irc_send_fu
 
     if (irc_send)
         {} /* use that function */
-    else if (hi)
+    else if(IsChannelName(to)) {
+        irc_send = irc_privmsg;
+    }
+    else if (message_dest->no_notice) {
+        irc_send = irc_privmsg;
+    }
+    else if (hi) {
         irc_send = HANDLE_FLAGGED(hi, USE_PRIVMSG) ? irc_privmsg : irc_notice;
-    else
-        irc_send = IsChannelName(to) ? irc_privmsg : irc_notice;
+    }
+    else {
+        irc_send = irc_notice;
+    }
 
     /* Limit size to how much we can show at once */
     if (size > sizeof(line))
@@ -345,14 +357,14 @@ table_send(struct userNode *from, const char *to, unsigned int size, irc_send_fu
         for (pos=ii=0; ii<((table.flags & TABLE_REPEAT_HEADERS)?nreps:1); ii++) {
             for (jj=0; 1; ) {
                 len = strlen(table.contents[0][jj]);
-                line[pos++] = '\02'; /* bold header */
+                //line[pos++] = '\02'; /* bold header */
                 spaces = max_width[jj] - len;
                 if (table.flags & TABLE_PAD_LEFT)
                     while (spaces--)
                         line[pos++] = ' ';
                 memcpy(line+pos, table.contents[0][jj], len);
                 pos += len;
-                line[pos++] = '\02'; /* end bold header */
+                //line[pos++] = '\02'; /* end bold header */
                 if (++jj == table.width)
                     break;
                 if (!(table.flags & TABLE_PAD_LEFT))
@@ -360,22 +372,34 @@ table_send(struct userNode *from, const char *to, unsigned int size, irc_send_fu
                         line[pos++] = ' ';
                 line[pos++] = ' ';
             }
+            line[pos++] = ' ';
         }
         line[pos] = 0;
-        irc_send(from, to, line);
-        sepsize = strlen_vis(line);
-        sepstr = malloc(sepsize + 1);
-        memset(sepstr, '-', sepsize);
-        sepstr[sepsize] = 0;
-        irc_send(from, to, sepstr);
+
+        /* Dont show ---- bars in 'clean' style. */
+        if(!(hi && hi->userlist_style == HI_STYLE_CLEAN)) {
+            //sepsize = strlen_vis(line);
+            sepsize = tot_width * nreps;
+            sepstr = malloc(sepsize + 1);
+            memset(sepstr, '-', sepsize);
+            sepstr[sepsize] = 0;
+            irc_send(from, to, sepstr); /* ----------------- */
+        }
+        irc_send(from, to, line);       /* alpha  beta   roe */
+        if(!(hi && hi->userlist_style == HI_STYLE_CLEAN)) 
+            irc_send(from, to, sepstr); /* ----------------- */
         ii = 1;
     }
     /* Send the table. */
     for (jj=0, pos=0, reps=0; ii<table.length; ) {
         while (1) {
+            int PAD_COL_LEFT = false;
+            if(table.flags & TABLE_PAD_LEFT || str_is_number(table.contents[ii][jj]))
+                PAD_COL_LEFT = true;
             len = strlen(table.contents[ii][jj]);
             spaces = max_width[jj] - len;
-            if (table.flags & TABLE_PAD_LEFT)
+            //if (table.flags & TABLE_PAD_LEFT)
+            if(PAD_COL_LEFT)
                 while (spaces--) line[pos++] = ' ';
             memcpy(line+pos, table.contents[ii][jj], len);
             pos += len;
@@ -388,24 +412,34 @@ table_send(struct userNode *from, const char *to, unsigned int size, irc_send_fu
                     break;
                 }
             }
-            if (!(table.flags & TABLE_PAD_LEFT))
+            //if (!(table.flags & TABLE_PAD_LEFT))
+            if(!PAD_COL_LEFT)
                 while (spaces--)
                     line[pos++] = ' ';
             line[pos++] = ' ';
         }
     }
-    if (!(table.flags & TABLE_NO_HEADERS)) {
-        /* Send end bar & free its memory */
-        if(sepsize > 5)
+    /* Send end bar */
+    if (!(table.flags & TABLE_NO_HEADERS) && 
+        !(table.flags & TABLE_NO_FOOTER) && 
+        !(hi && hi->userlist_style == HI_STYLE_CLEAN)) {
+        char endstr[MAX_LINE_SIZE+1];
+        sprintf(endstr, "End (%d rows)", table.length-1);
+
+        /* Copy above into the sepstr, centered */
+        if(sepsize > strlen(endstr)+2)
         {
-           sepstr[sepsize/2-1] = 'E';
-           sepstr[sepsize/2] = 'n';
-           sepstr[sepsize/2+1]= 'd';
+           char* eptr = endstr;
+           char* sptr = sepstr+(sepsize/2) - (strlen(endstr)+2)/2;
+           while(*eptr)
+               *sptr++ = *eptr++;
         }
         irc_send(from, to, sepstr);
-        free(sepstr);
     }
 
+    if(!(hi && hi->userlist_style == HI_STYLE_CLEAN))
+      free(sepstr);
+
     if (!(table.flags & TABLE_NO_FREE)) {
         /* Deallocate table memory (but not the string memory). */
         for (ii=0; ii<table.length; ii++)
@@ -420,8 +454,10 @@ vsend_message(const char *dest, struct userNode *src, struct handle_info *handle
     void (*irc_send)(struct userNode *from, const char *to, const char *msg);
     static struct string_buffer input;
     unsigned int size, ipos, pos, length, chars_sent, use_color;
-    unsigned int expand_pos, expand_ipos, newline_ipos;
+    unsigned int expand_ipos, newline_ipos;
     char line[MAX_LINE_SIZE];
+    struct service *service;
+    static char* trigger = NULL;
 
     if (IsChannelName(dest) || *dest == '$') {
         message_dest = NULL;
@@ -459,7 +495,10 @@ vsend_message(const char *dest, struct userNode *src, struct handle_info *handle
         size = DEFAULT_LINE_SIZE;
     switch (msg_type & 3) {
         case 0:
-            irc_send = irc_notice;
+            if(message_dest && message_dest->no_notice)
+               irc_send = irc_privmsg;
+            else
+               irc_send = irc_notice;
             break;
         case 2:
             irc_send = irc_wallchops;
@@ -474,10 +513,10 @@ vsend_message(const char *dest, struct userNode *src, struct handle_info *handle
      * that requires a very big intermediate buffer.
      */
     expand_ipos = newline_ipos = ipos = 0;
-    expand_pos = pos = 0;
+    pos = 0;
     chars_sent = 0;
     while (input.list[ipos]) {
-       char ch, *value, *free_value;
+       char ch, *value = NULL, *free_value;
 
         while ((ch = input.list[ipos]) && (ch != '$') && (ch != '\n') && (pos < size)) {
            line[pos++] = ch;
@@ -531,6 +570,9 @@ vsend_message(const char *dest, struct userNode *src, struct handle_info *handle
        case 'b':
            value = use_color ? "\002" : "";
            break;
+       case 'k':
+           value = use_color ? "\003" : "";
+           break;
        case 'o':
            value = use_color ? "\017" : "";
            break;
@@ -556,12 +598,29 @@ vsend_message(const char *dest, struct userNode *src, struct handle_info *handle
        case 'N':
             value = nickserv ? nickserv->nick : "NickServ";
             break;
+        case 'X':
+            value = spamserv ? spamserv->nick : "SpamServ";
+            break;
         case 's':
             value = self->name;
             break;
+#ifdef HAVE_HELPSERV
+        case 'i':
+            value = strdup(get_helpserv_id(dest, src));
+            break;
+#endif
        case 'H':
            value = handle ? handle->handle : "Account";
            break;
+        case '!':  /* Command Char for chanserv */
+            if(!trigger)
+               trigger = calloc(sizeof(*trigger), 2);
+            if(chanserv && (service = service_find(chanserv->nick)))
+                trigger[0] = service->trigger;
+            else
+                trigger[0] = '!';
+            value = trigger;
+            break;
 #define SEND_LINE(TRUNCED) do { \
     line[pos] = 0; \
     if (pos > 0) { \
@@ -616,7 +675,7 @@ vsend_message(const char *dest, struct userNode *src, struct handle_info *handle
                 break;
             default:
                 value = "";
-                log_module(MAIN_LOG, LOG_ERROR, "Invalid exp.type %d from expansion function %p.", exp.type, expand_f);
+                log_module(MAIN_LOG, LOG_ERROR, "Invalid exp.type %d from expansion function %p.", exp.type, (void*)expand_f);
                 break;
             }
             ipos = name_end - input.list;
@@ -671,12 +730,10 @@ vsend_message(const char *dest, struct userNode *src, struct handle_info *handle
             free(free_value);
        pos += length;
         if ((pos < size-1) && input.list[ipos]) {
-            expand_pos = pos;
             expand_ipos = ipos;
             continue;
         }
       send_line:
-        expand_pos = pos;
         expand_ipos = ipos;
         SEND_LINE(0);
 #undef SEND_LINE
@@ -690,7 +747,7 @@ send_message(struct userNode *dest, struct userNode *src, const char *format, ..
     int res;
     va_list ap;
 
-    if (IsLocal(dest)) return 0;
+    if (IsLocal(dest) && !IsDummy(dest)) return 0;
     va_start(ap, format);
     res = vsend_message(dest->nick, src, dest->handle_info, 0, NULL, format, ap);
     va_end(ap);
@@ -702,7 +759,7 @@ send_message_type(int msg_type, struct userNode *dest, struct userNode *src, con
     int res;
     va_list ap;
 
-    if (IsLocal(dest)) return 0;
+    if (IsLocal(dest) && !IsDummy(dest)) return 0;
     va_start(ap, format);
     res = vsend_message(dest->nick, src, dest->handle_info, msg_type, NULL, format, ap);
     va_end(ap);
@@ -744,7 +801,7 @@ send_help(struct userNode *dest, struct userNode *src, struct helpfile *hf, cons
         topic = "<index>";
     if (!hf) {
         _send_help(dest, src, NULL, "HFMSG_MISSING_HELPFILE");
-        return 0;
+        return false;
     }
     for (curr = (dest->handle_info ? dest->handle_info->language : lang_C);
          curr;
@@ -753,15 +810,20 @@ send_help(struct userNode *dest, struct userNode *src, struct helpfile *hf, cons
         if (!lang_hf)
             continue;
         rec = dict_find(lang_hf->db, topic, NULL);
-        if (rec && rec->type == RECDB_QSTRING)
-            return _send_help(dest, src, hf->expand, rec->d.qstring);
+        if (rec && rec->type == RECDB_QSTRING) {
+            _send_help(dest, src, hf->expand, rec->d.qstring);
+            return true;
+        }
     }
     rec = dict_find(hf->db, "<missing>", NULL);
     if (!rec)
-        return send_message(dest, src, "MSG_TOPIC_UNKNOWN");
-    if (rec->type != RECDB_QSTRING)
-       return send_message(dest, src, "HFMSG_HELP_NOT_STRING");
-    return _send_help(dest, src, hf->expand, rec->d.qstring);
+        return false;
+    if (rec->type != RECDB_QSTRING) { 
+        send_message(dest, src, "HFMSG_HELP_NOT_STRING");
+       return false; 
+    }
+    _send_help(dest, src, hf->expand, rec->d.qstring);
+    return true;
 }
 
 int
@@ -800,9 +862,9 @@ send_help_brief(struct userNode *dest, struct userNode *src, struct helpfile *hf
     }
     rec = dict_find(hf->db, "<missing>", NULL);
     if (!rec)
-        return send_message(dest, src, "MSG_TOPIC_UNKNOWN");
+        return 0; /* send_message(dest, src, "MSG_TOPIC_UNKNOWN"); */
     if (rec->type != RECDB_QSTRING)
-       return send_message(dest, src, "HFMSG_HELP_NOT_STRING");
+       return 0; /* send_message(dest, src, "HFMSG_HELP_NOT_STRING"); */
     return _send_help(dest, src, hf->expand, rec->d.qstring);
 }
 
@@ -878,7 +940,7 @@ helpfile_eval_identifier(const char *start, const char **end)
         *end = start + 5;
         return 0;
     } else {
-        log_module(MAIN_LOG, LOG_FATAL, "Unexpected helpfile identifier '%.*s'.", *end-start, start);
+        log_module(MAIN_LOG, LOG_FATAL, "Unexpected helpfile identifier '%.*s'.", (int)(*end-start), start);
         return -1;
     }
 }
@@ -910,7 +972,7 @@ helpfile_eval_atomicexpr(const char *start, const char **end)
     while (isspace(*sep) && (sep < *end))
         sep++;
     if ((sep == *end) || (sep[0] != ')')) {
-        log_module(MAIN_LOG, LOG_FATAL, "Expected close parenthesis at '%.*s'.", *end-sep, sep);
+        log_module(MAIN_LOG, LOG_FATAL, "Expected close parenthesis at '%.*s'.", (int)(*end-sep), sep);
         return -1;
     }
 
@@ -947,7 +1009,7 @@ helpfile_eval_expr(const char *start, const char **end)
         sep += len;
     }
     if (op == OP_INVALID) {
-        log_module(MAIN_LOG, LOG_FATAL, "Unrecognized helpfile operator at '%.*s'.", *end-sep, sep);
+        log_module(MAIN_LOG, LOG_FATAL, "Unrecognized helpfile operator at '%.*s'.", (int)(*end-sep), sep);
         return -1;
     }
 
@@ -961,7 +1023,7 @@ helpfile_eval_expr(const char *start, const char **end)
     while (isspace(*sep2) && (sep2 < *end))
         sep2++;
     if (sep2 != *end) {
-        log_module(MAIN_LOG, LOG_FATAL, "Trailing garbage in helpfile expression: '%.*s'.", *end-sep2, sep2);
+        log_module(MAIN_LOG, LOG_FATAL, "Trailing garbage in helpfile expression: '%.*s'.", (int)(*end-sep2), sep2);
         return -1;
     }
 
@@ -988,7 +1050,7 @@ helpfile_eval_condition(const char *start, const char **end)
     for (term = start; isalnum(*term) && (term < *end); ++term) ;
     if (term != start) {
         if ((term + 2 >= *end) || (term[0] != ':') || (term[1] != ' ')) {
-            log_module(MAIN_LOG, LOG_FATAL, "In helpfile condition '%.*s' expected prefix to end with ': '.", *end-start, start);
+            log_module(MAIN_LOG, LOG_FATAL, "In helpfile condition '%.*s' expected prefix to end with ': '.",(int)(*end-start), start);
             return -1;
         }
         start = term + 2;
@@ -1106,10 +1168,27 @@ void helpfile_init(void)
     language_read_list();
 }
 
-void helpfile_finalize(void)
+static void helpfile_read_languages(void)
 {
     dict_iterator_t it;
+    dict_t dict;
+
+    language_read_list();
     for (it = dict_first(languages); it; it = iter_next(it))
         language_read(iter_key(it));
-    reg_exit_func(language_cleanup);
+
+    /* If the user has a strings.db in their languages directory,
+     * allow that to override C language strings.
+     */
+    dict = parse_database("languages/strings.db");
+    if (dict) {
+        language_set_messages(lang_C, dict);
+        free_database(dict);
+    }
+}
+
+void helpfile_finalize(void)
+{
+    conf_register_reload(helpfile_read_languages);
+    reg_exit_func(language_cleanup, NULL);
 }