4 * Manage user preferences with a little help from the Citadel server.
13 HashList *PreferenceHooks;
15 typedef struct _Prefs {
21 void RegisterPreference(const char *Setting, const char *PrefStr, long Type)
23 Prefs *Newpref = (Prefs*) malloc(sizeof(Prefs));
24 Newpref->Setting = Setting;
25 Newpref->PrefStr = PrefStr;
27 Put(PreferenceHooks, Setting, strlen(Setting), Newpref, NULL);
30 const char *PrefGetLocalStr(const char *Setting, long len)
33 if (GetHash(PreferenceHooks, Setting, len, &hash_value) != 0) {
34 Prefs *Newpref = (Prefs*) hash_value;
35 return _(Newpref->PrefStr);
42 inline const char *PrintPref(void *Prefstr)
44 return ChrPtr(Prefstr);
49 void ParsePref(HashList **List, StrBuf *ReadBuf)
53 StrBuf *LastData = NULL;
56 while (StrBuf_ServGetln(ReadBuf),
57 strcmp(ChrPtr(ReadBuf), "000"))
59 if ((ChrPtr(ReadBuf)[0] == ' ') &&
61 StrBufAppendBuf(Data, ReadBuf, 1);
64 LastData = Data = NewStrBuf();
65 StrBufExtract_token(Key, ReadBuf, 0, '|');
66 StrBufExtract_token(Data, ReadBuf, 1, '|');
67 if (!IsEmptyStr(ChrPtr(Key)))
70 ChrPtr(Key), StrLength(Key),
86 * display preferences dialog
88 void load_preferences(void)
94 serv_printf("GOTO %s", USERCONFIGROOM);
95 serv_getln(buf, sizeof buf);
96 if (buf[0] != '2') return;
98 serv_puts("MSGS ALL|0|1");
99 serv_getln(buf, sizeof buf);
101 serv_puts("subj|__ WebCit Preferences __");
104 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
109 serv_printf("MSG0 %ld", msgnum);
110 serv_getln(buf, sizeof buf);
112 ReadBuf = NewStrBuf();
113 while (StrBuf_ServGetln(ReadBuf),
114 (strcmp(ChrPtr(ReadBuf), "text") &&
115 strcmp(ChrPtr(ReadBuf), "000"))) {
117 if (!strcmp(ChrPtr(ReadBuf), "text")) {
118 ParsePref(&WC->hash_prefs, ReadBuf);
121 FreeStrBuf(&ReadBuf);
124 /* Go back to the room we're supposed to be in */
125 serv_printf("GOTO %s", ChrPtr(WC->wc_roomname));
126 serv_getln(buf, sizeof buf);
130 * \brief Goto the user's configuration room, creating it if necessary.
131 * \return 0 on success or nonzero upon failure.
133 int goto_config_room(void) {
136 serv_printf("GOTO %s", USERCONFIGROOM);
137 serv_getln(buf, sizeof buf);
138 if (buf[0] != '2') { /* try to create the config room if not there */
139 serv_printf("CRE8 1|%s|4|0", USERCONFIGROOM);
140 serv_getln(buf, sizeof buf);
141 serv_printf("GOTO %s", USERCONFIGROOM);
142 serv_getln(buf, sizeof buf);
143 if (buf[0] != '2') return(1);
148 void WritePrefsToServer(HashList *Hash)
155 StrBuf *SubBuf = NULL;
157 Hash = WC->hash_prefs;
158 #ifdef DBG_PREFS_HASH
159 dbg_PrintHash(Hash, PrintPref, NULL);
161 HashPos = GetNewHashPos(Hash, 0);
162 while (GetNextHashPos(Hash, HashPos, &len, &Key, &Value)!=0)
165 Buf = (StrBuf*) Value;
168 nchars = StrLength(Buf);
171 size_t offset, nchars;
173 SubBuf = NewStrBuf();
182 nchars = StrBufSub(SubBuf, Buf, offset, nchars);
185 serv_printf("%s|%s", Key, ChrPtr(SubBuf));
187 serv_printf(" %s", ChrPtr(SubBuf));
190 nchars = StrLength(Buf) - offset;
196 serv_printf("%s|%s", Key, ChrPtr(Buf));
201 DeleteHashPos(&HashPos);
205 * \brief save the modifications
207 void save_preferences(void) {
211 if (goto_config_room() != 0) return; /* oh well. */
212 serv_puts("MSGS ALL|0|1");
213 serv_getln(buf, sizeof buf);
215 serv_puts("subj|__ WebCit Preferences __");
218 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
223 serv_printf("DELE %ld", msgnum);
224 serv_getln(buf, sizeof buf);
227 serv_printf("ENT0 1||0|1|__ WebCit Preferences __|");
228 serv_getln(buf, sizeof buf);
231 WritePrefsToServer(WC->hash_prefs);
236 /** Go back to the room we're supposed to be in */
237 serv_printf("GOTO %s", ChrPtr(WC->wc_roomname));
238 serv_getln(buf, sizeof buf);
242 * \brief query the actual setting of key in the citadel database
243 * \param key config key to query
244 * \param keylen length of the key string
245 * \param value StrBuf-value to the key to get
248 int get_PREFERENCE(const char *key, size_t keylen, StrBuf **value)
250 void *hash_value = NULL;
251 #ifdef DBG_PREFS_HASH
252 dbg_PrintHash(WC->hash_prefs, PrintPref, NULL);
254 if (GetHash(WC->hash_prefs, key, keylen, &hash_value) == 0) {
260 *value = (StrBuf*) hash_value;
266 * \brief Write a key into the webcit preferences database for this user
268 * \params key key whichs value is to be modified
269 * \param keylen length of the key string
270 * \param value value to set
271 * \param save_to_server 1 = flush all data to the server, 0 = cache it for now
273 void set_PREFERENCE(const char *key, size_t keylen, StrBuf *value, int save_to_server) {
275 Put(WC->hash_prefs, key, keylen, value, HFreeStrBuf);
277 if (save_to_server) save_preferences();
280 int get_PREF_LONG(const char *key, size_t keylen, long *value, long Default)
284 ret = get_PREFERENCE(key, keylen, &val);
286 *value = atol(ChrPtr(val));
296 void set_PREF_LONG(const char *key, size_t keylen, long value, int save_to_server)
299 if (get_PREFERENCE(key, keylen, &val)) {
300 StrBufPrintf(val, "%ld", value);
304 StrBufPrintf(val, "%ld", value);
305 set_PREFERENCE(key, keylen, val, save_to_server);
311 int get_PREF_YESNO(const char *key, size_t keylen, int *value, int Default)
315 ret = get_PREFERENCE(key, keylen, &val);
317 *value = strcmp(ChrPtr(val), "yes") == 0;
326 void set_PREF_YESNO(const char *key, size_t keylen, int value, int save_to_server)
329 if (get_PREFERENCE(key, keylen, &val)) {
330 StrBufPrintf(val, "%s", (value)?"yes":"no");
334 StrBufPrintf(val, "%s", (value)?"yes":"no");
335 set_PREFERENCE(key, keylen, val, save_to_server);
339 StrBuf *get_ROOM_PREFS(const char *key, size_t keylen)
341 StrBuf *pref_name, *pref_value;
343 pref_name = NewStrBuf ();
344 StrBufPrintf(pref_name, "%s %s", key, ChrPtr(WC->wc_roomname));
345 get_pref(pref_name, &pref_value);
346 FreeStrBuf(&pref_name);
350 void set_ROOM_PREFS(const char *key, size_t keylen, StrBuf *value, int save_to_server)
354 pref_name = NewStrBuf ();
355 StrBufPrintf(pref_name, "%s %s", key, ChrPtr(WC->wc_roomname));
356 set_PREFERENCE(ChrPtr(pref_name), StrLength(pref_name), value, save_to_server);
357 FreeStrBuf(&pref_name);
361 * Offer to make any page the user's "start page."
363 void offer_start_page(StrBuf *Target, WCTemplputParams *TP)
365 wprintf("<a href=\"change_start_page?startpage=");
366 urlescputs(WC->this_page);
368 wprintf(_("Make this my start page"));
371 wprintf("<br/><a href=\"rss?room=");
372 urlescputs(ChrPtr(WC->wc_roomname));
373 wprintf("\" title=\"RSS 2.0 feed for ");
374 escputs(ChrPtr(WC->wc_roomname));
375 wprintf("\"><img alt=\"RSS\" border=\"0\" src=\"static/xml_button.gif\"/></a>\n");
381 * Change the user's start page
383 void change_start_page(void) {
385 if (bstr("startpage") == NULL) {
386 safestrncpy(WC->ImportantMessage,
387 _("You no longer have a start page selected."),
388 sizeof WC->ImportantMessage);
393 set_preference("startpage", NewStrBufPlain(bstr("startpage"), -1), 1);
395 output_headers(1, 1, 0, 0, 0, 0);
396 do_template("newstartpage", NULL);
403 * \brief Commit new preferences and settings
405 void set_preferences(void)
408 StrBuf *buf, *encBuf;
409 int *time_format_cache;
411 time_format_cache = &(WC->time_format_cache);
413 if (!havebstr("change_button")) {
414 safestrncpy(WC->ImportantMessage,
415 _("Cancelled. No settings were changed."),
416 sizeof WC->ImportantMessage);
422 * Set the last argument to 1 only for the final setting, so
423 * we don't send the prefs file to the server repeatedly
425 set_preference("roomlistview", NewStrBufPlain(bstr("roomlistview"), -1), 0);
426 fmt = lbstr("calhourformat");
427 set_pref_long("calhourformat", fmt, 0);
429 *time_format_cache = WC_TIMEFORMAT_24;
431 *time_format_cache = WC_TIMEFORMAT_AMPM;
433 set_pref_long("weekstart", lbstr("weekstart"), 0);
434 set_pref_yesno("use_sig", yesbstr("use_sig"), 0);
435 set_pref_long("daystart", lbstr("daystart"), 0);
436 set_pref_long("dayend", lbstr("dayend"), 0);
437 set_preference("default_header_charset", NewStrBufPlain(bstr("default_header_charset"), -1), 0);
438 set_preference("emptyfloors", NewStrBufPlain(bstr("emptyfloors"), -1), 0);
439 set_preference("defaultfrom", NewStrBufDup(sbstr("defaultfrom")), 0);
440 set_preference("defaultname", NewStrBufDup(sbstr("defaultname")), 0);
441 set_preference("defaulthandle", NewStrBufDup(sbstr("defaulthandle")), 0);
444 buf = NewStrBufPlain(bstr("signature"), -1);
445 encBuf = NewStrBuf();
446 StrBufEUid_escapize(encBuf, buf);
447 set_preference("signature", encBuf, 1);
456 #define PRF_QP_STRING 3
460 void tmplput_CFG_Value(StrBuf *Target, WCTemplputParams *TP)
463 if (get_PREFERENCE(TKEY(0), &Setting))
464 StrBufAppendTemplate(Target, TP, Setting, 1);
467 void tmplput_CFG_Descr(StrBuf *Target, WCTemplputParams *TP)
469 const char *SettingStr;
470 SettingStr = PrefGetLocalStr(TKEY(0));
471 if (SettingStr != NULL)
472 StrBufAppendBufPlain(Target, SettingStr, -1, 0);
476 void CfgZoneTempl(StrBuf *TemplBuffer, WCTemplputParams *TP)
478 StrBuf *Zone = (StrBuf*) CTX;
480 SVPutBuf("ZONENAME", Zone, 1);
483 int ConditionalPreference(StrBuf *Target, WCTemplputParams *TP)
487 if (!get_PREFERENCE(TKEY(2), &Pref))
490 if (TP->Tokens->nParameters == 3) {
493 else if (TP->Tokens->Params[3]->Type == TYPE_STR)
494 return ((TP->Tokens->Params[3]->len == StrLength(Pref)) &&
495 (strcmp(TP->Tokens->Params[3]->Start, ChrPtr(Pref)) == 0));
497 return (StrTol(Pref) == TP->Tokens->Params[3]->lvalue);
500 int ConditionalHazePreference(StrBuf *Target, WCTemplputParams *TP)
504 if (!get_PREFERENCE(TKEY(2), &Pref) ||
511 HashList *GetGVEAHash(StrBuf *Target, WCTemplputParams *TP)
514 HashList *List = NULL;
521 StrBuf_ServGetln(Rcp);
522 if (GetServerStatus(Rcp, NULL) == 1) {
524 List = NewHash(1, NULL);
525 while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
526 if ( (StrLength(Rcp)==3) &&
527 !strcmp(ChrPtr(Rcp), "000"))
532 i = snprintf(N, sizeof(N), "%d", n);
534 Put(List, N, i, Rcp, HFreeStrBuf);
543 void DeleteGVEAHash(HashList **KillMe)
548 HashList *GetGVSNHash(StrBuf *Target, WCTemplputParams *TP)
551 HashList *List = NULL;
558 StrBuf_ServGetln(Rcp);
559 if (GetServerStatus(Rcp, NULL) == 1) {
561 List = NewHash(1, NULL);
562 while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
563 if ( (StrLength(Rcp)==3) &&
564 !strcmp(ChrPtr(Rcp), "000"))
569 i = snprintf(N, sizeof(N), "%d", n);
571 Put(List, N, i, Rcp, HFreeStrBuf);
580 void DeleteGVSNHash(HashList **KillMe)
587 InitModule_PREFERENCES
590 WebcitAddUrlHandler(HKEY("set_preferences"), set_preferences, 0);
591 WebcitAddUrlHandler(HKEY("change_start_page"), change_start_page, 0);
593 RegisterPreference("roomlistview",_("Room list view"),PRF_STRING);
594 RegisterPreference("calhourformat",_("Time format"), PRF_INT);
595 RegisterPreference("daystart", _("Calendar day view begins at:"), PRF_INT);
596 RegisterPreference("dayend", _("Calendar day view ends at:"), PRF_INT);
597 RegisterPreference("weekstart",_("Week starts on:"), PRF_INT);
599 RegisterPreference("use_sig",_("Attach signature to email messages?"), PRF_YESNO);
600 RegisterPreference("signature",_("Use this signature:"),PRF_QP_STRING);
601 RegisterPreference("default_header_charset", _("Default character set for email headers:") ,PRF_STRING);
602 RegisterPreference("emptyfloors", _("Show empty floors"), PRF_YESNO);
603 RegisterPreference("defaultfrom", _("Preferred email address"), PRF_STRING);
604 RegisterPreference("defaultname", _("Preferred display name for email messages"), PRF_STRING);
605 RegisterPreference("defaulthandle", _("Preferred display name for bulletin board posts"), PRF_STRING);
606 RegisterNamespace("OFFERSTARTPAGE", 0, 0, offer_start_page, CTX_NONE);
607 RegisterNamespace("PREF:VALUE", 1, 2, tmplput_CFG_Value, CTX_NONE);
608 RegisterNamespace("PREF:DESCR", 1, 1, tmplput_CFG_Descr, CTX_NONE);
609 RegisterIterator("PREF:ZONE", 0, ZoneHash, NULL, CfgZoneTempl, NULL, CTX_PREF, CTX_NONE, IT_NOFLAG);
611 RegisterConditional(HKEY("COND:PREF"), 4, ConditionalPreference, CTX_NONE);
612 RegisterConditional(HKEY("COND:PREF:SET"), 4, ConditionalHazePreference, CTX_NONE);
614 RegisterIterator("PREF:VALID:EMAIL:ADDR", 0, NULL,
615 GetGVEAHash, NULL, DeleteGVEAHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
616 RegisterIterator("PREF:VALID:EMAIL:NAME", 0, NULL,
617 GetGVSNHash, NULL, DeleteGVSNHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);