Fixed the webcit preferences bug once and for all, using a proper
authorArt Cancro <ajc@citadel.org>
Tue, 22 Jan 2008 05:02:04 +0000 (05:02 +0000)
committerArt Cancro <ajc@citadel.org>
Tue, 22 Jan 2008 05:02:04 +0000 (05:02 +0000)
linked list instead of a clumsy hack with the string tokenizer.

webcit/context_loop.c
webcit/preferences.c
webcit/webcit.h

index 452edd2f0ba87bb87f1f55ad213a44bef7689c28..b7d556c50a4fdea202b6444ef7e162c1161d846e 100644 (file)
@@ -92,8 +92,13 @@ void do_housekeeping(void)
                pthread_mutex_lock(&sessions_to_kill->SessionMutex);
                close(sessions_to_kill->serv_sock);
                close(sessions_to_kill->chat_sock);
-               if (sessions_to_kill->preferences != NULL) {
-                       free(sessions_to_kill->preferences);
+               while (sessions_to_kill->first_pref != NULL) {
+                       struct wcpref *ptr;
+                       ptr = sessions_to_kill->first_pref->next;
+                       free(sessions_to_kill->first_pref->pref_key);
+                       free(sessions_to_kill->first_pref->pref_value);
+                       free(sessions_to_kill->first_pref);
+                       sessions_to_kill->first_pref = ptr;
                }
                if (sessions_to_kill->cache_fold != NULL) {
                        free(sessions_to_kill->cache_fold);
index 70068cb5d4800e223508d768c1a89e1416111571..8991c0c13f06e98d53f2f3e71b2a81590f2d9d36 100644 (file)
@@ -1,22 +1,52 @@
 /*
  * $Id$
- */
-/**
- * \defgroup ManagePrefs Manage user preferences with a little help from the Citadel server.
- * \ingroup CitadelConfig
+ *
+ * Manage user preferences with a little help from the Citadel server.
  *
  */
-/*@{*/
+
 #include "webcit.h"
 #include "webserver.h"
 #include "groupdav.h"
 
 
-/**
- * \brief display preferences dialog
+/* This function is for private use -- callers should use set_preference() instead
+ */
+void store_preference(char *key, char *value) {
+
+       struct wcpref *ptr = NULL;
+
+       if (WC->first_pref == NULL) {
+               WC->first_pref = malloc(sizeof(struct wcpref));
+               WC->first_pref->next = NULL;
+               WC->first_pref->pref_key = strdup(key);
+               WC->first_pref->pref_value = strdup(value);
+               return;
+       }
+
+       for (ptr = WC->first_pref; ptr != NULL; ptr = ptr->next) {
+               if (!strcasecmp(ptr->pref_key, key)) {
+                       free(ptr->pref_value);
+                       ptr->pref_value = strdup(value);
+                       return;
+               }
+       }
+
+       ptr = malloc(sizeof(struct wcpref));
+       ptr->pref_key = strdup(key);
+       ptr->pref_value = strdup(value);
+       ptr->next = WC->first_pref;
+       WC->first_pref = ptr;
+}
+
+
+/*
+ * display preferences dialog
  */
 void load_preferences(void) {
        char buf[SIZ];
+       char key[SIZ];
+       char value[SIZ];
        long msgnum = 0L;
 
        serv_printf("GOTO %s", USERCONFIGROOM);
@@ -42,32 +72,22 @@ void load_preferences(void) {
                        }
                        if (!strcmp(buf, "text")) {
                                while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
-                                       if (WC->preferences == NULL) {
-                                               WC->preferences = malloc(SIZ);
-                                               strcpy(WC->preferences, "");
-                                       }
-                                       else {
-                                               WC->preferences = realloc(
-                                                       WC->preferences,
-                                                       strlen(WC->preferences)
-                                                       +SIZ
-                                               );
-                                       }
-                                       strcat(WC->preferences, buf);
-                                       strcat(WC->preferences, "\n");
+                                       extract_token(key, buf, 0, '|', sizeof key);
+                                       extract_token(value, buf, 1, '|', sizeof value);
+                                       store_preference(key, value);
                                }
                        }
                }
        }
 
-       /** Go back to the room we're supposed to be in */
+       /* Go back to the room we're supposed to be in */
        serv_printf("GOTO %s", WC->wc_roomname);
        serv_getln(buf, sizeof buf);
 }
 
-/**
- * \brief Goto the user's configuration room, creating it if necessary.
- * \return 0 on success or nonzero upon failure.
+/*
+ * Goto the user's configuration room, creating it if necessary.
+ * return 0 on success or nonzero upon failure.
  */
 int goto_config_room(void) {
        char buf[SIZ];
@@ -84,12 +104,13 @@ int goto_config_room(void) {
        return(0);
 }
 
-/**
- * \brief save the modifications
+/*
+ * save the modifications
  */
 void save_preferences(void) {
        char buf[SIZ];
        long msgnum = 0L;
+       struct wcpref *ptr;
 
        if (goto_config_room() != 0) return;    /* oh well. */
        serv_puts("MSGS ALL|0|1");
@@ -110,85 +131,55 @@ void save_preferences(void) {
        serv_printf("ENT0 1||0|1|__ WebCit Preferences __|");
        serv_getln(buf, sizeof buf);
        if (buf[0] == '4') {
-               serv_puts(WC->preferences);
+               for (ptr = WC->first_pref; ptr != NULL; ptr = ptr->next) {
+                       serv_printf("%s|%s", ptr->pref_key, ptr->pref_value);
+               }
                serv_puts("");
                serv_puts("000");
        }
 
-       /** Go back to the room we're supposed to be in */
+       /* Go back to the room we're supposed to be in */
        serv_printf("GOTO %s", WC->wc_roomname);
        serv_getln(buf, sizeof buf);
 }
 
-/**
- * \brief query the actual setting of key in the citadel database
- * \param key config key to query
- * \param value value to the key to get
- * \param value_len length of the value string
+/*
+ * query the actual setting of key in the citadel database
+ * key config  key to query
+ * value       value to the key to get
+ * value_len   length of the value string
  */
 void get_preference(char *key, char *value, size_t value_len) {
-       int num_prefs;
-       int i;
-       char buf[SIZ];
-       char thiskey[SIZ];
+       struct wcpref *ptr;
 
        strcpy(value, "");
 
-       num_prefs = num_tokens(WC->preferences, '\n');
-       for (i=0; i<num_prefs; ++i) {
-               extract_token(buf, WC->preferences, i, '\n', sizeof buf);
-               extract_token(thiskey, buf, 0, '|', sizeof thiskey);
-               if (!strcasecmp(thiskey, key)) {
-                       extract_token(value, buf, 1, '|', value_len);
+       for (ptr = WC->first_pref;  ptr != NULL; ptr = ptr->next) {
+               if (!strcasecmp(ptr->pref_key, key)) {
+                       safestrncpy(value, ptr->pref_value, value_len);
+                       return;
                }
        }
 }
 
-/**
- * \brief      Write a key into the webcit preferences database for this user
+/*
+ *Write a key into the webcit preferences database for this user
  *
- * \params     key             key whichs value is to be modified
- * \param      value           value to set
- * \param      save_to_server  1 = flush all data to the server, 0 = cache it for now
+ * key         key whichs value is to be modified
+ * value               value to set
+ * save_to_server      1 = flush all data to the server, 0 = cache it for now
  */
 void set_preference(char *key, char *value, int save_to_server) {
-       int num_prefs;
-       int i;
-       char buf[SIZ];
-       char thiskey[SIZ];
-       char *newprefs = NULL;
-       size_t newprefs_len = 0;
-
-       newprefs_len = strlen(key) + strlen(value) + 10;
-       if (WC->preferences != NULL) newprefs_len += strlen(WC->preferences);
-       newprefs = malloc(newprefs_len);
-       if (newprefs == NULL) return;
-       strcpy(newprefs, "");
-
-       num_prefs = num_tokens(WC->preferences, '\n');
-       for (i=0; i<num_prefs; ++i) {
-               extract_token(buf, WC->preferences, i, '\n', sizeof buf);
-               if (num_tokens(buf, '|') == 2) {
-                       extract_token(thiskey, buf, 0, '|', sizeof thiskey);
-                       if (strcasecmp(thiskey, key)) {
-                               strcat(newprefs, buf);
-                               strcat(newprefs, "\n");
-                       }
-               }
-       }
-
-       sprintf(&newprefs[strlen(newprefs)], "%s|%s\n", key, value);
-       free(WC->preferences);
-       WC->preferences = newprefs;
 
+       store_preference(key, value);
        if (save_to_server) save_preferences();
 }
 
 
 
 
-/*
- * \brief display form for changing your preferences and settings
+/*
+ * display form for changing your preferences and settings
  */
 void display_preferences(void)
 {
index d99b17e27511f94a22475d4dce44ff41f050e9a9..1c8397df9bf91796629f300b76bb2ca0b1692468 100644 (file)
@@ -326,6 +326,15 @@ struct folder {
        int num_rooms;  /**< If this is a floor, how many rooms does it have */
 };
 
+
+/* Linked list member for a list of webcit preferences for a user
+ */
+struct wcpref {
+       struct wcpref *next;
+       char *pref_key;
+       char *pref_value;
+};
+
 /**
  * \brief One of these is kept for each active Citadel session.
  * HTTP transactions are bound to on e at a time.
@@ -375,7 +384,6 @@ struct wcsession {
        struct wcsubst *vars;                   /**< HTTP variable substitutions for this page */
        char this_page[512];                    /**< URL of current page */
        char http_host[512];                    /**< HTTP Host: header */
-       char *preferences;                      /**< WebCit preferences for this user */
 #ifdef WEBCIT_WITH_CALENDAR_SERVICE            
        /** \brief ical???? */                          
        struct disp_cal {                                       
@@ -405,6 +413,7 @@ struct wcsession {
        time_t last_pager_check;                /**< last time we polled for instant msgs */
        int nonce;                              /**< session nonce (to prevent session riding) */
        int time_format_cache;                  /**< which timeformat does our user like? */
+       struct wcpref *first_pref;              /* linked list of preferences */
 };
 
 /** values for WC->current_iconbar */