2006-11-12 [paul] 2.6.0cvs34
[claws.git] / src / prefs_gtk.c
index 849c1a266f2d2bf263a15d570b3e269e6224724b..e582e3207e628698c21579771fe7f4e2c80ecd59 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
+ * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #  include "config.h"
 #endif
 
+#define _GNU_SOURCE
+#include <stdio.h>
+
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 
+#include "defs.h"
 #include "main.h"
 #include "prefs.h"
 #include "prefs_gtk.h"
         (CL(c.green) << (gulong)  8) | \
         (CL(c.blue)))
 
+#ifdef HAVE_FGETS_UNLOCKED
+#define SC_FGETS fgets_unlocked
+#else
+#define SC_FGETS fgets
+#endif
+
 typedef enum
 {
        DUMMY_PARAM
 } DummyEnum;
 
+static GHashTable *whole_cache = NULL;
+
+static gboolean prefs_read_config_from_cache(PrefParam *param, const gchar *label,
+                              const gchar *rcfile);
+
 void prefs_read_config(PrefParam *param, const gchar *label,
                       const gchar *rcfile, const gchar *encoding)
 {
@@ -62,10 +76,18 @@ void prefs_read_config(PrefParam *param, const gchar *label,
        g_return_if_fail(label != NULL);
        g_return_if_fail(rcfile != NULL);
 
+       if (encoding != NULL)
+               g_warning("Encoding is ignored\n");
+
        debug_print("Reading configuration...\n");
 
        prefs_set_default(param);
 
+       if (whole_cache != NULL) {
+               if (prefs_read_config_from_cache(param, label, rcfile) == TRUE)
+                       return;
+       }
+
        if ((fp = g_fopen(rcfile, "rb")) == NULL) {
                if (ENOENT != errno) FILE_OP_ERROR(rcfile, "fopen");
                return;
@@ -73,8 +95,12 @@ void prefs_read_config(PrefParam *param, const gchar *label,
 
        block_label = g_strdup_printf("[%s]", label);
 
+#ifdef HAVE_FGETS_UNLOCKED
+       flockfile(fp);
+#endif
+
        /* search aiming block */
-       while (fgets(buf, sizeof(buf), fp) != NULL) {
+       while (SC_FGETS(buf, sizeof(buf), fp) != NULL) {
                gint val;
 
                if (encoding) {
@@ -96,10 +122,11 @@ void prefs_read_config(PrefParam *param, const gchar *label,
        }
        g_free(block_label);
 
-       while (fgets(buf, sizeof(buf), fp) != NULL) {
+       while (SC_FGETS(buf, sizeof(buf), fp) != NULL) {
                strretchomp(buf);
                /* reached next block */
                if (buf[0] == '[') break;
+               if (buf[0] == '#') continue;
 
                if (encoding) {
                        gchar *conv_str;
@@ -115,6 +142,9 @@ void prefs_read_config(PrefParam *param, const gchar *label,
        }
 
        debug_print("Finished reading configuration.\n");
+#ifdef HAVE_FGETS_UNLOCKED
+       funlockfile(fp);
+#endif
        fclose(fp);
 }
 
@@ -137,13 +167,19 @@ void prefs_config_parse_one_line(PrefParam *param, const gchar *buf)
                switch (param[i].type) {
                case P_STRING:
                {
-                       gchar *tmp;
+                       gchar *tmp = NULL;
 
-                       tmp = *value ?
-                               conv_codeset_strdup(value,
-                                                   conv_get_locale_charset_str(),
-                                                   CS_UTF_8)
-                               : g_strdup("");
+                       if (*value) {
+                               if (g_utf8_validate(value, -1, NULL))
+                                       tmp = g_strdup(value);
+                               else {
+                                       tmp = conv_codeset_strdup(value,
+                                                   conv_get_locale_charset_str_no_utf8(),
+                                                   CS_INTERNAL);
+                               }
+                       } else {
+                               tmp = g_strdup("");
+                       }
                        if (!tmp) {
                                g_warning("failed to convert character set.");
                                tmp = g_strdup(value);
@@ -253,13 +289,12 @@ void prefs_write_config(PrefParam *param, const gchar *label,
        }
 
        TRY(fprintf(pfile->fp, "%s\n", block_label) > 0);
-       g_free(block_label);
-       block_label = NULL;
 
        /* write all param data to file */
        TRY(prefs_write_param(param, pfile->fp) == 0);
 
        if (block_matched) {
+               gboolean in_dup_block = FALSE;
                while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
                        /* next block */
                        if (buf[0] == '[') {
@@ -268,10 +303,22 @@ void prefs_write_config(PrefParam *param, const gchar *label,
                                break;
                        }
                }
-               while (fgets(buf, sizeof(buf), orig_fp) != NULL)
-                       TRY(fputs(buf, pfile->fp) != EOF);
+               while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
+                       if (buf[0] == '[') {
+                               if (!strncmp(buf, block_label,
+                                               strlen(block_label)))
+                                       in_dup_block = TRUE;
+                               else
+                                       in_dup_block = FALSE;
+                       }
+                       if (!in_dup_block)
+                               TRY(fputs(buf, pfile->fp) != EOF);
+               }
        }
 
+       g_free(block_label);
+       block_label = NULL;
+
        if (orig_fp) fclose(orig_fp);
        if (prefs_file_close(pfile) < 0)
                g_warning("failed to write configuration to file\n");
@@ -292,11 +339,15 @@ gint prefs_write_param(PrefParam *param, FILE *fp)
                        gchar *tmp = NULL;
 
                        if (*((gchar **)param[i].data)) {
-                               tmp = conv_codeset_strdup(*((gchar **)param[i].data),
-                                                         CS_UTF_8,
-                                                         conv_get_locale_charset_str());
-                               if (!tmp)
+                               if (g_utf8_validate(*((gchar **)param[i].data), -1, NULL))
                                        tmp = g_strdup(*((gchar **)param[i].data));
+                               else {
+                                       tmp = conv_codeset_strdup(*((gchar **)param[i].data),
+                                               conv_get_locale_charset_str_no_utf8(),
+                                               CS_INTERNAL);
+                                       if (!tmp)
+                                               tmp = g_strdup(*((gchar **)param[i].data));
+                               }
                        }
 
                        g_snprintf(buf, sizeof(buf), "%s=%s\n", param[i].name,
@@ -385,7 +436,7 @@ void prefs_set_default(PrefParam *param)
                                        tmp = envstr && *envstr ?
                                                conv_codeset_strdup(envstr,
                                                                    conv_get_locale_charset_str(),
-                                                                   CS_UTF_8)
+                                                                   CS_INTERNAL)
                                                : g_strdup("");
                                        if (!tmp) {
                                                g_warning("faild to convert character set.");
@@ -537,6 +588,14 @@ void prefs_button_toggled(GtkToggleButton *toggle_btn, GtkWidget *widget)
        gtk_widget_set_sensitive(widget, is_active);
 }
 
+void prefs_button_toggled_reverse(GtkToggleButton *toggle_btn, GtkWidget *widget)
+{
+       gboolean is_active;
+
+       is_active = gtk_toggle_button_get_active(toggle_btn);
+       gtk_widget_set_sensitive(widget, !is_active);
+}
+
 void prefs_set_dialog(PrefParam *param)
 {
        gint i;
@@ -859,3 +918,158 @@ void prefs_gtk_unregister_page(PrefsPage *page)
 {
        prefs_pages = g_slist_remove(prefs_pages, page);
 }
+
+static void prefs_destroy_whole_cache(gpointer to_free)
+{      
+       GHashTable *table = (GHashTable *)to_free;
+       g_hash_table_destroy(table);
+}
+
+static void prefs_destroy_file_cache(gpointer to_free)
+{      
+       GHashTable *table = (GHashTable *)to_free;
+       g_hash_table_destroy(table);
+}
+
+static int prefs_cache_sections(GHashTable *file_cache, const gchar *rcfile)
+{
+       FILE *fp = g_fopen(rcfile, "rb");
+       gchar buf[PREFSBUFSIZE];
+       GHashTable *section_cache = NULL;
+
+       if (!fp) {
+               debug_print("cache: %s: %s", rcfile, strerror(errno));
+               return -1;
+       }
+       
+#ifdef HAVE_FGETS_UNLOCKED
+       flockfile(fp);
+#endif
+       
+       while (SC_FGETS(buf, sizeof(buf), fp) != NULL) {
+               strretchomp(buf);
+               if (buf[0] == '\0')
+                       continue;
+               if (buf[0] == '#')
+                       continue; /* comment */
+               if (buf[0] == '[') { /* new section */
+                       gchar *blockname = g_strdup(buf+1);
+
+                       if (strrchr(blockname, ']'))
+                               *strrchr(blockname, ']') = '\0';
+
+                       if ((section_cache = g_hash_table_lookup(file_cache, blockname)) == NULL) {
+                               debug_print("new section '%s'\n", blockname);
+                               section_cache = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                               g_free, NULL);
+                               g_hash_table_insert(file_cache, 
+                                       blockname, section_cache);
+                       } else {
+                               debug_print("section '%s' already done\n", blockname);
+                               g_free(blockname);
+                               section_cache = NULL;
+                               continue;
+                       }
+               } else {
+                       if (!section_cache) {
+                               debug_print("skipping stuff %s with no section\n", buf);
+                               continue;
+                       } else {
+                               gchar *pref;
+                               
+                               if (!strchr(buf, '=')) {
+                                       /* plugins do differently */
+                                       continue;
+                               }
+                               pref = g_strdup(buf);
+                               
+                               //debug_print("new pref '%s'\n", pref);
+                               g_hash_table_insert(section_cache, pref, GINT_TO_POINTER(1));
+                       }
+               }
+       }
+#ifdef HAVE_FGETS_UNLOCKED
+       funlockfile(fp);
+#endif
+       fclose(fp);
+       return 0;
+}
+
+static int prefs_cache(const gchar *rcfile)
+{
+       GHashTable *file_cache = g_hash_table_new_full(g_str_hash, g_str_equal, 
+                                       g_free, prefs_destroy_file_cache);
+       
+       debug_print("new file '%s'\n", rcfile);
+       g_hash_table_insert(whole_cache, g_strdup(rcfile), file_cache);
+       
+       return prefs_cache_sections(file_cache, rcfile);
+}
+
+void prefs_prepare_cache(void)
+{
+       gchar *clawsrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
+       gchar *folderitemrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FOLDERITEM_RC, NULL);
+       gchar *accountrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL);
+       
+       if (whole_cache == NULL) {
+               whole_cache = g_hash_table_new_full(g_str_hash, g_str_equal,
+                               g_free, prefs_destroy_whole_cache);
+       } else {
+               debug_print("already cached\n");
+               g_free(clawsrc);
+               g_free(folderitemrc);
+               g_free(accountrc);
+               return;
+       }
+       if (prefs_cache(clawsrc) < 0 ||
+           prefs_cache(folderitemrc) < 0 ||
+           prefs_cache(accountrc) < 0)
+               prefs_destroy_cache();
+
+       g_free(clawsrc);
+       g_free(folderitemrc);
+       g_free(accountrc);
+}
+
+void prefs_destroy_cache(void)
+{
+       if (!whole_cache) {
+               debug_print("no cache\n");
+               return;
+       }
+       debug_print("destroying cache\n");
+       g_hash_table_destroy(whole_cache);
+       whole_cache = NULL;
+       return;
+}
+
+static void prefs_parse_cache(gpointer key, gpointer value, gpointer user_data)
+{
+       gchar *pref = (gchar *)key;
+
+       PrefParam *param = (PrefParam *)user_data;
+       
+       prefs_config_parse_one_line(param, pref);
+}
+
+static gboolean prefs_read_config_from_cache(PrefParam *param, const gchar *label,
+                              const gchar *rcfile) 
+{
+       GHashTable *sections_table = NULL;
+       GHashTable *values_table = NULL;
+       sections_table = g_hash_table_lookup(whole_cache, rcfile);
+       
+       if (sections_table == NULL) {
+               g_warning("can't find %s in the whole cache\n", rcfile);
+               return FALSE;
+       }
+       values_table = g_hash_table_lookup(sections_table, label);
+       
+       if (values_table == NULL) {
+               debug_print("no '%s' section in '%s' cache\n", label, rcfile);
+               return TRUE;
+       }
+       g_hash_table_foreach(values_table, prefs_parse_cache, param);
+       return TRUE;
+}