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", 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", 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, 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, 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, int nArgs, WCTemplateToken *Token, void *Context, int ContextType) {
364 wprintf("<a href=\"change_start_page?startpage=");
365 urlescputs(WC->this_page);
367 wprintf(_("Make this my start page"));
370 wprintf("<br/><a href=\"rss?room=");
371 urlescputs(WC->wc_roomname);
372 wprintf("\" title=\"RSS 2.0 feed for ");
373 escputs(WC->wc_roomname);
374 wprintf("\"><img alt=\"RSS\" border=\"0\" src=\"static/xml_button.gif\"/></a>\n");
380 * Change the user's start page
382 void change_start_page(void) {
384 if (bstr("startpage") == NULL) {
385 safestrncpy(WC->ImportantMessage,
386 _("You no longer have a start page selected."),
387 sizeof WC->ImportantMessage);
392 set_preference("startpage", NewStrBufPlain(bstr("startpage"), -1), 1);
394 output_headers(1, 1, 0, 0, 0, 0);
395 do_template("newstartpage", NULL);
402 * \brief Commit new preferences and settings
404 void set_preferences(void)
407 StrBuf *buf, *encBuf;
408 int *time_format_cache;
410 time_format_cache = &(WC->time_format_cache);
412 if (!havebstr("change_button")) {
413 safestrncpy(WC->ImportantMessage,
414 _("Cancelled. No settings were changed."),
415 sizeof WC->ImportantMessage);
421 * Set the last argument to 1 only for the final setting, so
422 * we don't send the prefs file to the server repeatedly
424 set_preference("roomlistview", NewStrBufPlain(bstr("roomlistview"), -1), 0);
425 fmt = lbstr("calhourformat");
426 set_pref_long("calhourformat", fmt, 0);
428 *time_format_cache = WC_TIMEFORMAT_24;
430 *time_format_cache = WC_TIMEFORMAT_AMPM;
432 set_pref_long("weekstart", lbstr("weekstart"), 0);
433 set_pref_yesno("use_sig", yesbstr("use_sig"), 0);
434 set_pref_long("daystart", lbstr("daystart"), 0);
435 set_pref_long("dayend", lbstr("dayend"), 0);
436 set_preference("default_header_charset", NewStrBufPlain(bstr("default_header_charset"), -1), 0);
437 set_preference("emptyfloors", NewStrBufPlain(bstr("emptyfloors"), -1), 0);
438 set_preference("defaultfrom", NewStrBufDup(sbstr("defaultfrom")), 0);
439 set_preference("defaultname", NewStrBufDup(sbstr("defaultname")), 0);
440 set_preference("defaulthandle", NewStrBufDup(sbstr("defaulthandle")), 0);
443 buf = NewStrBufPlain(bstr("signature"), -1);
444 encBuf = NewStrBuf();
445 StrBufEUid_escapize(encBuf, buf);
446 set_preference("signature", encBuf, 1);
455 #define PRF_QP_STRING 3
459 void tmplput_CFG_Value(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
462 if (get_PREFERENCE(TKEY(0), &Setting))
463 StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Setting, 1);
466 void tmplput_CFG_Descr(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
468 const char *SettingStr;
469 SettingStr = PrefGetLocalStr(TKEY(0));
470 if (SettingStr != NULL)
471 StrBufAppendBufPlain(Target, SettingStr, -1, 0);
475 void CfgZoneTempl(StrBuf *TemplBuffer, void *vContext, WCTemplateToken *Token)
477 StrBuf *Zone = (StrBuf*) vContext;
479 SVPutBuf("ZONENAME", Zone, 1);
482 int ConditionalPreference(WCTemplateToken *Tokens, void *Context, int ContextType)
486 if (!get_PREFERENCE(TKEY(2), &Pref))
489 if (Tokens->nParameters == 3) {
492 else if (Tokens->Params[3]->Type == TYPE_STR)
493 return ((Tokens->Params[3]->len == StrLength(Pref)) &&
494 (strcmp(Tokens->Params[3]->Start, ChrPtr(Pref)) == 0));
496 return (StrTol(Pref) == Tokens->Params[3]->lvalue);
499 int ConditionalHazePreference(WCTemplateToken *Tokens, void *Context, int ContextType)
503 if (!get_PREFERENCE(TKEY(2), &Pref) ||
510 HashList *GetGVEAHash(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
513 HashList *List = NULL;
520 StrBuf_ServGetln(Rcp);
521 if (ChrPtr(Rcp)[0] == '1') {
523 List = NewHash(1, NULL);
524 while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
525 if ( (StrLength(Rcp)==3) &&
526 !strcmp(ChrPtr(Rcp), "000"))
531 i = snprintf(N, sizeof(N), "%d", n);
533 Put(List, N, i, Rcp, HFreeStrBuf);
542 void DeleteGVEAHash(HashList **KillMe)
547 HashList *GetGVSNHash(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
550 HashList *List = NULL;
557 StrBuf_ServGetln(Rcp);
558 if (ChrPtr(Rcp)[0] == '1') {
560 List = NewHash(1, NULL);
561 while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
562 if ( (StrLength(Rcp)==3) &&
563 !strcmp(ChrPtr(Rcp), "000"))
568 i = snprintf(N, sizeof(N), "%d", n);
570 Put(List, N, i, Rcp, HFreeStrBuf);
579 void DeleteGVSNHash(HashList **KillMe)
586 InitModule_PREFERENCES
589 WebcitAddUrlHandler(HKEY("set_preferences"), set_preferences, 0);
590 WebcitAddUrlHandler(HKEY("change_start_page"), change_start_page, 0);
592 RegisterPreference("roomlistview",_("Room list view"),PRF_STRING);
593 RegisterPreference("calhourformat",_("Time format"), PRF_INT);
594 RegisterPreference("daystart", _("Calendar day view begins at:"), PRF_INT);
595 RegisterPreference("dayend", _("Calendar day view ends at:"), PRF_INT);
596 RegisterPreference("weekstart",_("Week starts on:"), PRF_INT);
598 RegisterPreference("use_sig",_("Attach signature to email messages?"), PRF_YESNO);
599 RegisterPreference("signature",_("Use this signature:"),PRF_QP_STRING);
600 RegisterPreference("default_header_charset", _("Default character set for email headers:") ,PRF_STRING);
601 RegisterPreference("emptyfloors", _("Show empty floors"), PRF_YESNO);
602 RegisterPreference("defaultfrom", _("Prefered Email Address"), PRF_STRING);
603 RegisterPreference("defaultname", _("Prefered Email Sendername"), PRF_STRING);
604 RegisterPreference("defaulthandle", _("Prefered Name for posting messages"), PRF_STRING);
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);
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);
616 RegisterIterator("PREF:VALID:EMAIL:NAME", 0, NULL,
617 GetGVSNHash, NULL, DeleteGVSNHash, CTX_STRBUF, CTX_NONE);