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 * display preferences dialog
51 void load_preferences(void) {
56 serv_printf("GOTO %s", USERCONFIGROOM);
57 serv_getln(buf, sizeof buf);
58 if (buf[0] != '2') return;
60 serv_puts("MSGS ALL|0|1");
61 serv_getln(buf, sizeof buf);
63 serv_puts("subj|__ WebCit Preferences __");
66 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
71 serv_printf("MSG0 %ld", msgnum);
72 serv_getln(buf, sizeof buf);
74 ReadBuf = NewStrBuf();
75 while (StrBuf_ServGetln(ReadBuf),
76 (strcmp(ChrPtr(ReadBuf), "text") &&
77 strcmp(ChrPtr(ReadBuf), "000"))) {
79 if (!strcmp(ChrPtr(ReadBuf), "text")) {
82 StrBuf *LastData = NULL;
85 while (StrBuf_ServGetln(ReadBuf),
86 strcmp(ChrPtr(ReadBuf), "000"))
88 if ((ChrPtr(ReadBuf)[0] == ' ') &&
90 StrBufAppendBuf(Data, ReadBuf, 1);
93 LastData = Data = NewStrBuf();
94 StrBufExtract_token(Key, ReadBuf, 0, '|');
95 StrBufExtract_token(Data, ReadBuf, 1, '|');
96 if (!IsEmptyStr(ChrPtr(Key)))
99 ChrPtr(Key), StrLength(Key),
112 FreeStrBuf(&ReadBuf);
116 /* Go back to the room we're supposed to be in */
117 serv_printf("GOTO %s", WC->wc_roomname);
118 serv_getln(buf, sizeof buf);
122 * \brief Goto the user's configuration room, creating it if necessary.
123 * \return 0 on success or nonzero upon failure.
125 int goto_config_room(void) {
128 serv_printf("GOTO %s", USERCONFIGROOM);
129 serv_getln(buf, sizeof buf);
130 if (buf[0] != '2') { /* try to create the config room if not there */
131 serv_printf("CRE8 1|%s|4|0", USERCONFIGROOM);
132 serv_getln(buf, sizeof buf);
133 serv_printf("GOTO %s", USERCONFIGROOM);
134 serv_getln(buf, sizeof buf);
135 if (buf[0] != '2') return(1);
141 * \brief save the modifications
143 void save_preferences(void) {
147 if (goto_config_room() != 0) return; /* oh well. */
148 serv_puts("MSGS ALL|0|1");
149 serv_getln(buf, sizeof buf);
151 serv_puts("subj|__ WebCit Preferences __");
154 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
159 serv_printf("DELE %ld", msgnum);
160 serv_getln(buf, sizeof buf);
163 serv_printf("ENT0 1||0|1|__ WebCit Preferences __|");
164 serv_getln(buf, sizeof buf);
172 StrBuf *SubBuf = NULL;
174 Hash = WC->hash_prefs;
175 #ifdef DBG_PREFS_HASH
176 dbg_PrintHash(Hash, PrintPref, NULL);
178 HashPos = GetNewHashPos();
179 while (GetNextHashPos(Hash, HashPos, &len, &Key, &Value)!=0)
182 Buf = (StrBuf*) Value;
185 nchars = StrLength(Buf);
188 size_t offset, nchars;
190 SubBuf = NewStrBuf();
199 nchars = StrBufSub(SubBuf, Buf, offset, nchars);
202 serv_printf("%s|%s", Key, ChrPtr(SubBuf));
204 serv_printf(" %s", ChrPtr(SubBuf));
207 nchars = StrLength(Buf) - offset;
213 serv_printf("%s|%s", Key, ChrPtr(Buf));
220 DeleteHashPos(&HashPos);
223 /** Go back to the room we're supposed to be in */
224 serv_printf("GOTO %s", WC->wc_roomname);
225 serv_getln(buf, sizeof buf);
229 * \brief query the actual setting of key in the citadel database
230 * \param key config key to query
231 * \param keylen length of the key string
232 * \param value StrBuf-value to the key to get
235 int get_PREFERENCE(const char *key, size_t keylen, StrBuf **value)
237 void *hash_value = NULL;
238 #ifdef DBG_PREFS_HASH
239 dbg_PrintHash(WC->hash_prefs, PrintPref, NULL);
241 if (GetHash(WC->hash_prefs, key, keylen, &hash_value) == 0) {
247 *value = (StrBuf*) hash_value;
253 * \brief Write a key into the webcit preferences database for this user
255 * \params key key whichs value is to be modified
256 * \param keylen length of the key string
257 * \param value value to set
258 * \param save_to_server 1 = flush all data to the server, 0 = cache it for now
260 void set_PREFERENCE(const char *key, size_t keylen, StrBuf *value, int save_to_server) {
262 Put(WC->hash_prefs, key, keylen, value, HFreeStrBuf);
264 if (save_to_server) save_preferences();
267 int get_PREF_LONG(const char *key, size_t keylen, long *value, long Default)
271 ret = get_PREFERENCE(key, keylen, &val);
273 *value = atol(ChrPtr(val));
283 void set_PREF_LONG(const char *key, size_t keylen, long value, int save_to_server)
286 if (get_PREFERENCE(key, keylen, &val)) {
287 StrBufPrintf(val, "%ld", value);
291 StrBufPrintf(val, "%ld", value);
292 set_PREFERENCE(key, keylen, val, save_to_server);
298 int get_PREF_YESNO(const char *key, size_t keylen, int *value, int Default)
302 ret = get_PREFERENCE(key, keylen, &val);
304 *value = strcmp(ChrPtr(val), "yes") == 0;
313 void set_PREF_YESNO(const char *key, size_t keylen, int value, int save_to_server)
316 if (get_PREFERENCE(key, keylen, &val)) {
317 StrBufPrintf(val, "%s", (value)?"yes":"no");
321 StrBufPrintf(val, "%s", (value)?"yes":"no");
322 set_PREFERENCE(key, keylen, val, save_to_server);
326 StrBuf *get_ROOM_PREFS(const char *key, size_t keylen)
328 StrBuf *pref_name, *pref_value;
330 pref_name = NewStrBuf ();
331 StrBufPrintf(pref_name, "%s %s", key, WC->wc_roomname);
332 get_pref(pref_name, &pref_value);
333 FreeStrBuf(&pref_name);
337 void set_ROOM_PREFS(const char *key, size_t keylen, StrBuf *value, int save_to_server)
341 pref_name = NewStrBuf ();
342 StrBufPrintf(pref_name, "%s %s", key, WC->wc_roomname);
343 set_PREFERENCE(ChrPtr(pref_name), StrLength(pref_name), value, save_to_server);
344 FreeStrBuf(&pref_name);
348 * \brief display form for changing your preferences and settings
350 void display_preferences(void)
352 output_headers(1, 1, 1, 0, 0, 0);
355 long DayEnd, DayStart, WeekStart;
356 int UseSig, ShowEmptyFloors;
364 time_format = get_time_format_cached ();
366 wprintf("<div class=\"box\">\n");
367 wprintf("<div class=\"boxlabel\">");
368 wprintf(_("Preferences and settings"));
371 wprintf("<div class=\"boxcontent\">");
374 wprintf("<form name=\"prefform\" action=\"set_preferences\" "
375 "method=\"post\">\n");
376 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
379 wprintf("<table class=\"altern\">\n");
384 get_preference("roomlistview", &Buf);
385 wprintf("<tr class=\"even\"><td>");
386 wprintf(PrefGetLocalStr(HKEY("roomlistview")));
387 wprintf("</td><td>");
389 wprintf("<input type=\"radio\" name=\"roomlistview\" VALUE=\"folders\"");
390 if (!strcasecmp(ChrPtr(Buf), "folders")) wprintf(" checked");
392 wprintf(_("Tree (folders) view"));
393 wprintf("</input> ");
395 wprintf("<input type=\"radio\" name=\"roomlistview\" VALUE=\"rooms\"");
396 if (IsEmptyStr(ChrPtr(Buf)) || !strcasecmp(ChrPtr(Buf), "rooms")) wprintf(" checked");
398 wprintf(_("Table (rooms) view"));
399 wprintf("</input>\n");
401 wprintf("</td></tr>\n");
407 wprintf("<tr class=\"odd\"><td>");
408 wprintf(PrefGetLocalStr(HKEY("calhourformat")));
409 wprintf("</td><td>");
411 wprintf("<input type=\"radio\" name=\"calhourformat\" VALUE=\"12\"");
412 if (time_format == WC_TIMEFORMAT_AMPM)
415 wprintf(_("12 hour (am/pm)"));
416 wprintf("</input> ");
418 wprintf("<input type=\"radio\" name=\"calhourformat\" VALUE=\"24\"");
419 if (time_format == WC_TIMEFORMAT_24)
422 wprintf(_("24 hour"));
423 wprintf("</input>\n");
425 wprintf("</td></tr>\n");
428 * Calendar day view -- day start time
430 get_pref_long("daystart", &DayStart, 8);
432 wprintf("<tr class=\"even\"><td>");
433 wprintf(PrefGetLocalStr(HKEY("daystart")));
434 wprintf("</td><td>");
436 wprintf("<select name=\"daystart\" size=\"1\">\n");
437 for (i=0; i<=23; ++i) {
439 if (time_format == WC_TIMEFORMAT_24) {
440 wprintf("<option %s value=\"%d\">%d:00</option>\n",
441 ((DayStart == i) ? "selected" : ""),
446 wprintf("<option %s value=\"%d\">%s</option>\n",
447 ((DayStart == i) ? "selected" : ""),
453 wprintf("</select>\n");
454 wprintf("</td></tr>\n");
457 * Calendar day view -- day end time
459 get_pref_long("dayend", &DayEnd, 17);
461 wprintf("<tr class=\"odd\"><td>");
462 wprintf(PrefGetLocalStr(HKEY("dayend")));
463 wprintf("</td><td>");
465 wprintf("<select name=\"dayend\" size=\"1\">\n");
466 for (i=0; i<=23; ++i) {
468 if (time_format == WC_TIMEFORMAT_24) {
469 wprintf("<option %s value=\"%d\">%d:00</option>\n",
470 ((DayEnd == i) ? "selected" : ""),
475 wprintf("<option %s value=\"%d\">%s</option>\n",
476 ((DayEnd == i) ? "selected" : ""),
482 wprintf("</select>\n");
483 wprintf("</td></tr>\n");
486 * Day of week to begin calendar month view
488 get_pref_long("weekstart", &WeekStart, 17);
489 wprintf("<tr class=\"even\"><td>");
490 wprintf(PrefGetLocalStr(HKEY("weekstart")));
491 wprintf("</td><td>");
493 wprintf("<select name=\"weekstart\" size=\"1\">\n");
495 for (i=0; i<=1; ++i) {
497 localtime_r(&tt, &tm);
499 wc_strftime(daylabel, sizeof daylabel, "%A", &tm);
501 wprintf("<option %s value=\"%d\">%s</option>\n",
502 ((WeekStart == i) ? "selected" : ""),
507 wprintf("</select>\n");
508 wprintf("</td></tr>\n");
513 get_pref_yesno("use_sig", &UseSig, 0);
514 wprintf("<tr class=\"odd\"><td>");
515 wprintf(_("Attach signature to email messages?"));
516 wprintf("</td><td>");
518 wprintf(" <script type=\"text/javascript\"> "
519 " function show_or_hide_sigbox() { "
520 " if ( $F('yes_sig') ) { "
521 " $('signature_box').style.display = 'inline'; "
524 " $('signature_box').style.display = 'none'; "
530 wprintf(PrefGetLocalStr(HKEY("use_sig")));
532 wprintf("<input type=\"radio\" id=\"no_sig\" name=\"use_sig\" VALUE=\"no\"");
533 if (!UseSig) wprintf(" checked");
534 wprintf(" onChange=\"show_or_hide_sigbox();\" >");
535 wprintf(_("No signature"));
536 wprintf("</input> , \n");
538 wprintf("<input type=\"radio\" id=\"yes_sig\" name=\"use_sig\" VALUE=\"yes\"");
539 if (UseSig) wprintf(" checked");
540 wprintf(" onChange=\"show_or_hide_sigbox();\" >");
541 wprintf(PrefGetLocalStr(HKEY("signature")));
542 wprintf("<div id=\"signature_box\">"
543 "<br><textarea name=\"signature\" cols=\"40\" rows=\"5\">"
546 get_preference("signature", &Signature);
548 StrBufEUid_unescapize(ebuf, Signature);
551 wprintf("</textarea>"
555 wprintf("</input>\n");
557 wprintf("</td></tr>\n");
559 wprintf(" <script type=\"text/javascript\"> "
560 " show_or_hide_sigbox(); "
564 /** Character set to assume is in use for improperly encoded headers */
565 if (!get_preference("default_header_charset", &Buf)) {
567 StrBufPrintf(Buf, "%s", "UTF-8");
568 set_preference("default_header_charset", Buf, 0);
570 wprintf("<tr class=\"even\"><td>");
571 wprintf(PrefGetLocalStr(HKEY("default_header_charset")));
572 wprintf("</td><td>");
573 wprintf("<input type=\"text\" NAME=\"default_header_charset\" MAXLENGTH=\"32\" VALUE=\"");
574 StrEscPuts(Buf); // here shouldn't be bad chars, so...
576 wprintf("</td></tr>");
582 get_pref_yesno("emptyfloors", &ShowEmptyFloors, 0);
583 wprintf("<tr class=\"odd\"><td>");
584 wprintf(PrefGetLocalStr(HKEY("emptyfloors")));
585 wprintf("</td><td>");
587 wprintf("<input type=\"radio\" name=\"emptyfloors\" VALUE=\"yes\"");
588 if (ShowEmptyFloors) wprintf(" checked");
591 wprintf("</input> ");
593 wprintf("<input type=\"radio\" name=\"emptyfloors\" VALUE=\"no\"");
594 if (!ShowEmptyFloors) wprintf(" checked");
597 wprintf("</input>\n");
599 wprintf("</td></tr>\n");
602 wprintf("</table>\n");
604 /** submit buttons */
605 wprintf("<div class=\"buttons\"> ");
606 wprintf("<input type=\"submit\" name=\"change_button\" value=\"%s\">"
608 "<INPUT type=\"submit\" name=\"cancel_button\" value=\"%s\">\n",
615 wprintf("</form>\n");
621 * \brief Commit new preferences and settings
623 void set_preferences(void)
626 StrBuf *buf, *encBuf;
627 int *time_format_cache;
629 time_format_cache = &(WC->time_format_cache);
631 if (!havebstr("change_button")) {
632 safestrncpy(WC->ImportantMessage,
633 _("Cancelled. No settings were changed."),
634 sizeof WC->ImportantMessage);
640 * Set the last argument to 1 only for the final setting, so
641 * we don't send the prefs file to the server repeatedly
643 set_preference("roomlistview", NewStrBufPlain(bstr("roomlistview"), -1), 0);
644 fmt = lbstr("calhourformat");
645 set_pref_long("calhourformat", fmt, 0);
647 *time_format_cache = WC_TIMEFORMAT_24;
649 *time_format_cache = WC_TIMEFORMAT_AMPM;
651 set_pref_long("weekstart", lbstr("weekstart"), 0);
652 set_pref_yesno("use_sig", yesbstr("use_sig"), 0);
653 set_pref_long("daystart", lbstr("daystart"), 0);
654 set_pref_long("dayend", lbstr("dayend"), 0);
655 set_preference("default_header_charset", NewStrBufPlain(bstr("default_header_charset"), -1), 0);
656 set_preference("emptyfloors", NewStrBufPlain(bstr("emptyfloors"), -1), 0);
658 buf = NewStrBufPlain(bstr("signature"), -1);
659 encBuf = NewStrBuf();
660 StrBufEUid_escapize(encBuf, buf);
661 set_preference("signature", encBuf, 1);
670 #define PRF_QP_STRING 3
674 void tmplput_CFG_Value(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context)
677 if (get_PREFERENCE(Token->Params[0]->Start,
678 Token->Params[0]->len,
680 StrBufAppendBuf(Target, Setting, 0);
683 void tmplput_CFG_Descr(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context)
685 const char *SettingStr;
686 SettingStr = PrefGetLocalStr(Token->Params[0]->Start,
687 Token->Params[0]->len);
688 if (SettingStr != NULL)
689 StrBufAppendBufPlain(Target, SettingStr, -1, 0);
693 void CfgZoneTempl(StrBuf *TemplBuffer, void *vContext, WCTemplateToken *Token)
695 StrBuf *Zone = (StrBuf*) vContext;
697 SVPutBuf("ZONENAME", Zone, 1);
700 int ConditionalPreference(WCTemplateToken *Token, void *Context)
704 if (!get_PREFERENCE(Token->Params[2]->Start,
705 Token->Params[2]->len,
709 if (Token->nParameters == 3) {
712 else if (Token->Params[3]->Type == TYPE_STR)
713 return ((Token->Params[3]->len == StrLength(Pref)) &&
714 (strcmp(Token->Params[3]->Start, ChrPtr(Pref)) == 0));
716 return (StrTol(Pref) == Token->Params[3]->lvalue);
721 InitModule_PREFERENCES
724 WebcitAddUrlHandler(HKEY("display_preferences"), display_preferences, 0);
725 WebcitAddUrlHandler(HKEY("set_preferences"), set_preferences, 0);
727 RegisterPreference("roomlistview",_("Room list view"),PRF_STRING);
728 RegisterPreference("calhourformat",_("Time format"), PRF_INT);
729 RegisterPreference("daystart", _("Calendar day view begins at:"), PRF_INT);
730 RegisterPreference("dayend", _("Calendar day view ends at:"), PRF_INT);
731 RegisterPreference("weekstart",_("Week starts on:"), PRF_INT);
733 RegisterPreference("use_sig",_("Attach signature to email messages?"), PRF_YESNO);
734 RegisterPreference("signature",_("Use this signature:"),PRF_QP_STRING);
735 RegisterPreference("default_header_charset", _("Default character set for email headers:") ,PRF_STRING);
736 RegisterPreference("emptyfloors", _("Show empty floors"), PRF_YESNO);
738 RegisterNamespace("PREF:VALUE", 1, 1, tmplput_CFG_Value);
739 RegisterNamespace("PREF:DESCR", 1, 1, tmplput_CFG_Descr);
740 RegisterIterator("PREF:ZONE", 0, ZoneHash, NULL, CfgZoneTempl, NULL);
742 RegisterConditional(HKEY("COND:PREF"), 4, ConditionalPreference);