Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-common / core / fe-log.c
index a0967e1ab7f0165626428f6f1c7478d0d9c68fb2..3008d0a7741cf1d8bada6491c124a0b79bef9ae8 100644 (file)
@@ -13,9 +13,9 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 #include "module.h"
@@ -36,6 +36,7 @@
 #include "formats.h"
 #include "themes.h"
 #include "printtext.h"
+#include "fe-common-core.h"
 
 /* close autologs after 5 minutes of inactivity */
 #define AUTOLOG_INACTIVITY_CLOSE (60*5)
@@ -48,6 +49,10 @@ static THEME_REC *log_theme;
 static int skip_next_printtext;
 static const char *log_theme_name;
 
+static int log_dir_create_mode;
+
+static char **autolog_ignore_targets;
+
 static char *log_colorizer_strip(const char *str)
 {
         return strip_codes(str);
@@ -87,7 +92,7 @@ static void cmd_log_open(const char *data)
                return;
        if (*fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
 
-       level = level2bits(levels);
+       level = level2bits(levels, NULL);
        log = log_create_rec(fname, level != 0 ? level : MSGLEVEL_ALL);
 
        /* -<server tag> */
@@ -107,6 +112,8 @@ static void cmd_log_open(const char *data)
                targetarg = g_hash_table_lookup(optlist, "targets");
                if (targetarg != NULL && *targetarg != '\0')
                        log_add_targets(log, targetarg, servertag);
+               else if (servertag != NULL)
+                       log_add_targets(log, "*", servertag);
        }
 
        if (g_hash_table_lookup(optlist, "autoopen"))
@@ -187,17 +194,20 @@ static char *log_items_get_list(LOG_REC *log)
        GSList *tmp;
        GString *str;
        char *ret;
+       LOG_ITEM_REC *rec = NULL;
 
        g_return_val_if_fail(log != NULL, NULL);
        g_return_val_if_fail(log->items != NULL, NULL);
 
        str = g_string_new(NULL);
        for (tmp = log->items; tmp != NULL; tmp = tmp->next) {
-               LOG_ITEM_REC *rec = tmp->data;
+               rec = tmp->data;
 
-                g_string_sprintfa(str, "%s, ", rec->name);
+                g_string_append_printf(str, "%s, ", rec->name);
        }
        g_string_truncate(str, str->len-2);
+       if(rec->servertag != NULL)
+               g_string_append_printf(str, " (%s)", rec->servertag);
 
        ret = str->str;
        g_string_free(str, FALSE);
@@ -220,7 +230,8 @@ static void cmd_log_list(void)
 
                printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST,
                            index, rec->fname, items != NULL ? items : "",
-                           levelstr, rec->autoopen ? " -autoopen" : "");
+                           levelstr, rec->autoopen ? " -autoopen" : "",
+                           rec->handle != -1 ? " active" : "");
 
                g_free_not_null(items);
                g_free(levelstr);
@@ -245,6 +256,7 @@ static LOG_REC *logs_find_item(int type, const char *item,
        for (tmp = logs; tmp != NULL; tmp = tmp->next) {
                LOG_REC *log = tmp->data;
 
+               if (type == LOG_ITEM_TARGET && log->temp == 0) continue;
                logitem = log_item_find(log, type, item, servertag);
                if (logitem != NULL) {
                        if (ret_item != NULL) *ret_item = logitem;
@@ -270,15 +282,15 @@ static void cmd_window_log(const char *data)
        log = logs_find_item(LOG_ITEM_WINDOW_REFNUM, window, NULL, NULL);
 
         open_log = close_log = FALSE;
-       if (g_strcasecmp(set, "ON") == 0)
+       if (g_ascii_strcasecmp(set, "ON") == 0)
                open_log = TRUE;
-       else if (g_strcasecmp(set, "OFF") == 0) {
+       else if (g_ascii_strcasecmp(set, "OFF") == 0) {
                close_log = TRUE;
-       } else if (g_strcasecmp(set, "TOGGLE") == 0) {
+       } else if (g_ascii_strcasecmp(set, "TOGGLE") == 0) {
                 open_log = log == NULL;
                 close_log = log != NULL;
        } else {
-               printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_NOT_TOGGLE);
+               printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_NOT_TOGGLE);
                cmd_params_free(free_arg);
                return;
        }
@@ -381,14 +393,14 @@ static void autologs_close_all(void)
        }
 }
 
-/* '%' -> '%%', '/' -> '_' */
+/* '%' -> '%%', badness -> '_' */
 static char *escape_target(const char *target)
 {
        char *str, *p;
 
        p = str = g_malloc(strlen(target)*2+1);
        while (*target != '\0') {
-               if (*target == '/')
+               if (strchr("/\\|*?\"<>:", *target))
                        *p++ = '_';
                else {
                        if (*target == '%')
@@ -407,7 +419,7 @@ static void autolog_open(SERVER_REC *server, const char *server_tag,
                         const char *target)
 {
        LOG_REC *log;
-       char *fname, *dir, *fixed_target;
+       char *fname, *dir, *fixed_target, *params;
 
        log = logs_find_item(LOG_ITEM_TARGET, target, server_tag, NULL);
        if (log != NULL && !log->failed) {
@@ -417,24 +429,30 @@ static void autolog_open(SERVER_REC *server, const char *server_tag,
 
        /* '/' -> '_' - don't even accidentally try to log to
           #../../../file if you happen to join to such channel..
+          similar for some characters that are metacharacters
+          and/or illegal in Windows filenames.
 
           '%' -> '%%' - so strftime() won't mess with them */
        fixed_target = escape_target(target);
        if (CHAT_PROTOCOL(server)->case_insensitive)
-               g_strdown(fixed_target);
+               ascii_strdown(fixed_target);
 
-       fname = parse_special_string(autolog_path, server, NULL,
-                                    fixed_target, NULL, 0);
+        /* $0 = target, $1 = server tag */
+        params = g_strconcat(fixed_target, " ", server_tag, NULL);
        g_free(fixed_target);
 
+       fname = parse_special_string(autolog_path, server, NULL,
+                                    params, NULL, 0);
+       g_free(params);
+
        if (log_find(fname) == NULL) {
                log = log_create_rec(fname, autolog_level);
                 if (!settings_get_bool("autolog_colors"))
                        log->colorizer = log_colorizer_strip;
                log_item_add(log, LOG_ITEM_TARGET, target, server_tag);
 
-               dir = g_dirname(log->real_fname);
-               mkpath(dir, LOG_DIR_CREATE_MODE);
+               dir = g_path_get_dirname(log->real_fname);
+               mkpath(dir, log_dir_create_mode);
                g_free(dir);
 
                log->temp = TRUE;
@@ -444,10 +462,13 @@ static void autolog_open(SERVER_REC *server, const char *server_tag,
        g_free(fname);
 }
 
-static void autolog_open_check(SERVER_REC *server, const char *server_tag,
-                              const char *target, int level)
+static void autolog_open_check(TEXT_DEST_REC *dest)
 {
-       char **targets, **tmp;
+       const char *deftarget;
+       SERVER_REC *server = dest->server;
+       const char *server_tag = dest->server_tag;
+       const char *target = dest->target;
+       int level = dest->level;
 
        /* FIXME: kind of a kludge, but we don't want to reopen logs when
           we're parting the channel with /WINDOW CLOSE.. Maybe a small
@@ -457,37 +478,32 @@ static void autolog_open_check(SERVER_REC *server, const char *server_tag,
            (autolog_level & level) == 0 || target == NULL || *target == '\0')
                return;
 
-       /* there can be multiple targets separated with comma */
-       targets = g_strsplit(target, ",", -1);
-       for (tmp = targets; *tmp != NULL; tmp++)
-               autolog_open(server, server_tag, *tmp);
-       g_strfreev(targets);
+       deftarget = server ? server->nick : "unknown";
+
+       if (autolog_ignore_targets != NULL &&
+           strarray_find_dest(autolog_ignore_targets, dest))
+               return;
+
+       if (target != NULL)
+               autolog_open(server, server_tag, strcmp(target, "*") ? target : deftarget);
 }
 
 static void log_single_line(WINDOW_REC *window, const char *server_tag,
                            const char *target, int level, const char *text)
 {
        char windownum[MAX_INT_STRLEN];
-       char **targets, **tmp;
        LOG_REC *log;
 
-       /* save to log created with /WINDOW LOG */
-       ltoa(windownum, window->refnum);
-       log = logs_find_item(LOG_ITEM_WINDOW_REFNUM,
-                            windownum, NULL, NULL);
-       if (log != NULL) {
-               log_write_rec(log, text, level);
+       if (window != NULL) {
+               /* save to log created with /WINDOW LOG */
+               ltoa(windownum, window->refnum);
+               log = logs_find_item(LOG_ITEM_WINDOW_REFNUM,
+                                    windownum, NULL, NULL);
+               if (log != NULL)
+                       log_write_rec(log, text, level);
        }
 
-       if (target == NULL)
-               log_file_write(server_tag, NULL, level, text, FALSE);
-       else {
-               /* there can be multiple items separated with comma */
-               targets = g_strsplit(target, ",", -1);
-               for (tmp = targets; *tmp != NULL; tmp++)
-                       log_file_write(server_tag, *tmp, level, text, FALSE);
-               g_strfreev(targets);
-       }
+       log_file_write(server_tag, target, level, text, FALSE);
 }
 
 static void log_line(TEXT_DEST_REC *dest, const char *text)
@@ -498,8 +514,7 @@ static void log_line(TEXT_DEST_REC *dest, const char *text)
                return;
 
        /* let autolog open the log records */
-       autolog_open_check(dest->server, dest->server_tag,
-                          dest->target, dest->level);
+       autolog_open_check(dest);
 
        if (logs == NULL)
                return;
@@ -587,11 +602,11 @@ static int sig_autoremove(void)
        return 1;
 }
 
-static void sig_window_item_destroy(WINDOW_REC *window, WI_ITEM_REC *item)
+static void sig_window_item_remove(WINDOW_REC *window, WI_ITEM_REC *item)
 {
        LOG_REC *log;
 
-       log = logs_find_item(LOG_ITEM_TARGET, item->name,
+       log = logs_find_item(LOG_ITEM_TARGET, item->visible_name,
                             item->server == NULL ? NULL :
                             item->server->tag, NULL);
        if (log != NULL && log->temp)
@@ -600,13 +615,13 @@ static void sig_window_item_destroy(WINDOW_REC *window, WI_ITEM_REC *item)
 
 static void sig_log_locked(LOG_REC *log)
 {
-       printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+       printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
                    TXT_LOG_LOCKED, log->fname);
 }
 
 static void sig_log_create_failed(LOG_REC *log)
 {
-       printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+       printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
                    TXT_LOG_CREATE_FAILED,
                    log->real_fname, g_strerror(errno));
 }
@@ -660,10 +675,11 @@ static void sig_theme_destroyed(THEME_REC *theme)
 static void read_settings(void)
 {
        int old_autolog = autolog_level;
+        int log_file_create_mode;
 
        autolog_path = settings_get_str("autolog_path");
        autolog_level = !settings_get_bool("autolog") ? 0 :
-               level2bits(settings_get_str("autolog_level"));
+               settings_get_level("autolog_level");
 
        if (old_autolog && !autolog_level)
                autologs_close_all();
@@ -679,6 +695,17 @@ static void read_settings(void)
 
        log_theme = log_theme_name == NULL ? NULL :
                theme_load(log_theme_name);
+
+       log_file_create_mode = octal2dec(settings_get_int("log_create_mode"));
+        log_dir_create_mode = log_file_create_mode;
+        if (log_file_create_mode & 0400) log_dir_create_mode |= 0100;
+        if (log_file_create_mode & 0040) log_dir_create_mode |= 0010;
+        if (log_file_create_mode & 0004) log_dir_create_mode |= 0001;
+
+       if (autolog_ignore_targets != NULL)
+               g_strfreev(autolog_ignore_targets);
+
+       autolog_ignore_targets = g_strsplit(settings_get_str("autolog_ignore_targets"), " ", -1);
 }
 
 void fe_log_init(void)
@@ -690,8 +717,9 @@ void fe_log_init(void)
         settings_add_bool("log", "autolog", FALSE);
        settings_add_bool("log", "autolog_colors", FALSE);
         settings_add_str("log", "autolog_path", "~/irclogs/$tag/$0.log");
-       settings_add_str("log", "autolog_level", "all -crap -clientcrap -ctcps");
+       settings_add_level("log", "autolog_level", "all -crap -clientcrap -ctcps");
         settings_add_str("log", "log_theme", "");
+       settings_add_str("log", "autolog_ignore_targets", "");
 
        autolog_level = 0;
        log_theme_name = NULL;
@@ -705,7 +733,7 @@ void fe_log_init(void)
        command_bind("window log", NULL, (SIGNAL_FUNC) cmd_window_log);
        command_bind("window logfile", NULL, (SIGNAL_FUNC) cmd_window_logfile);
        signal_add_first("print text", (SIGNAL_FUNC) sig_printtext);
-       signal_add("window item destroy", (SIGNAL_FUNC) sig_window_item_destroy);
+       signal_add("window item remove", (SIGNAL_FUNC) sig_window_item_remove);
        signal_add("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed);
        signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
        signal_add("log locked", (SIGNAL_FUNC) sig_log_locked);
@@ -734,7 +762,7 @@ void fe_log_deinit(void)
        command_unbind("window log", (SIGNAL_FUNC) cmd_window_log);
        command_unbind("window logfile", (SIGNAL_FUNC) cmd_window_logfile);
        signal_remove("print text", (SIGNAL_FUNC) sig_printtext);
-       signal_remove("window item destroy", (SIGNAL_FUNC) sig_window_item_destroy);
+       signal_remove("window item remove", (SIGNAL_FUNC) sig_window_item_remove);
        signal_remove("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed);
        signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
        signal_remove("log locked", (SIGNAL_FUNC) sig_log_locked);
@@ -745,4 +773,7 @@ void fe_log_deinit(void)
        signal_remove("awaylog show", (SIGNAL_FUNC) sig_awaylog_show);
        signal_remove("theme destroyed", (SIGNAL_FUNC) sig_theme_destroyed);
        signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+
+       if (autolog_ignore_targets != NULL)
+               g_strfreev(autolog_ignore_targets);
 }