* abstract setting per room preferences
[citadel.git] / webcit / preferences.c
1 /*
2  * $Id$
3  *
4  * Manage user preferences with a little help from the Citadel server.
5  *
6  */
7
8 #include "webcit.h"
9 #include "webserver.h"
10 #include "groupdav.h"
11
12 #ifdef DBG_PREFS_HASH
13 inline const char *PrintPref(void *Prefstr)
14 {
15         return ChrPtr(Prefstr);
16 }
17 #endif
18
19 /*
20  * display preferences dialog
21  */
22 void load_preferences(void) {
23         char buf[SIZ];
24         long msgnum = 0L;
25         StrBuf *ReadBuf;
26         
27         serv_printf("GOTO %s", USERCONFIGROOM);
28         serv_getln(buf, sizeof buf);
29         if (buf[0] != '2') return;
30         
31         serv_puts("MSGS ALL|0|1");
32         serv_getln(buf, sizeof buf);
33         if (buf[0] == '8') {
34                 serv_puts("subj|__ WebCit Preferences __");
35                 serv_puts("000");
36         }
37         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
38                 msgnum = atol(buf);
39         }
40
41         if (msgnum > 0L) {
42                 serv_printf("MSG0 %ld", msgnum);
43                 serv_getln(buf, sizeof buf);
44                 if (buf[0] == '1') {
45                         ReadBuf = NewStrBuf();
46                         while (StrBuf_ServGetln(ReadBuf),
47                                (strcmp(ChrPtr(ReadBuf), "text") && 
48                                 strcmp(ChrPtr(ReadBuf), "000"))) {
49                         }
50                         if (!strcmp(ChrPtr(ReadBuf), "text")) {
51                                 StrBuf *Key;
52                                 StrBuf *Data = NULL;
53                                 StrBuf *LastData = NULL;
54                                 
55                                 Key = NewStrBuf();
56                                 while (StrBuf_ServGetln(ReadBuf), 
57                                        strcmp(ChrPtr(ReadBuf), "000")) 
58                                 {
59                                         if ((ChrPtr(ReadBuf)[0] == ' ') &&
60                                             (Data != NULL)) {
61                                                 StrBufAppendBuf(Data, ReadBuf, 1);
62                                         }
63                                         else {
64                                                 LastData = Data = NewStrBuf();
65                                                 StrBufExtract_token(Key, ReadBuf, 0, '|');
66                                                 StrBufExtract_token(Data, ReadBuf, 1, '|');
67                                                 if (!IsEmptyStr(ChrPtr(Key)))
68                                                 {
69                                                         Put(WC->hash_prefs, 
70                                                             ChrPtr(Key), StrLength(Key), 
71                                                             Data, 
72                                                             HFreeStrBuf);
73                                                 }
74                                                 else 
75                                                 {
76                                                         FreeStrBuf(&Data);
77                                                         LastData = NULL;
78                                                 }
79                                         }
80                                 }
81                                 FreeStrBuf(&Key);
82                         }
83                         FreeStrBuf(&ReadBuf);
84                 }
85         }
86
87         /* Go back to the room we're supposed to be in */
88         serv_printf("GOTO %s", WC->wc_roomname);
89         serv_getln(buf, sizeof buf);
90 }
91
92 /**
93  * \brief Goto the user's configuration room, creating it if necessary.
94  * \return 0 on success or nonzero upon failure.
95  */
96 int goto_config_room(void) {
97         char buf[SIZ];
98
99         serv_printf("GOTO %s", USERCONFIGROOM);
100         serv_getln(buf, sizeof buf);
101         if (buf[0] != '2') { /* try to create the config room if not there */
102                 serv_printf("CRE8 1|%s|4|0", USERCONFIGROOM);
103                 serv_getln(buf, sizeof buf);
104                 serv_printf("GOTO %s", USERCONFIGROOM);
105                 serv_getln(buf, sizeof buf);
106                 if (buf[0] != '2') return(1);
107         }
108         return(0);
109 }
110
111 /**
112  * \brief save the modifications
113  */
114 void save_preferences(void) {
115         char buf[SIZ];
116         long msgnum = 0L;
117         
118         if (goto_config_room() != 0) return;    /* oh well. */
119         serv_puts("MSGS ALL|0|1");
120         serv_getln(buf, sizeof buf);
121         if (buf[0] == '8') {
122                 serv_puts("subj|__ WebCit Preferences __");
123                 serv_puts("000");
124         }
125         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
126                 msgnum = atol(buf);
127         }
128
129         if (msgnum > 0L) {
130                 serv_printf("DELE %ld", msgnum);
131                 serv_getln(buf, sizeof buf);
132         }
133
134         serv_printf("ENT0 1||0|1|__ WebCit Preferences __|");
135         serv_getln(buf, sizeof buf);
136         if (buf[0] == '4') {
137                 long len;
138                 HashPos *HashPos;
139                 HashList *Hash;
140                 void *Value;
141                 char *Key;
142                 StrBuf *Buf;
143                 StrBuf *SubBuf = NULL;
144                 
145                 Hash = WC->hash_prefs;
146 #ifdef DBG_PREFS_HASH
147                 dbg_PrintHash(Hash, PrintPref, NULL);
148 #endif
149                 HashPos = GetNewHashPos();
150                 while (GetNextHashPos(Hash, HashPos, &len, &Key, &Value)!=0)
151                 {
152                         size_t nchars;
153                         Buf = (StrBuf*) Value;
154                         if (Buf == NULL)
155                                 continue;
156                         nchars = StrLength(Buf);
157                         if (nchars > 80){
158                                 int n = 0;
159                                 size_t offset, nchars;
160                                 if (SubBuf == NULL)
161                                         SubBuf = NewStrBuf();
162                                 nchars = 1;
163                                 offset = 0;
164                                 while (nchars > 0) {
165                                         if (n == 0)
166                                                 nchars = 70;
167                                         else 
168                                                 nchars = 80;
169
170                                         nchars = StrBufSub(SubBuf, Buf, offset, nchars);
171                                         
172                                         if (n == 0)
173                                                 serv_printf("%s|%s", Key, ChrPtr(SubBuf));
174                                         else
175                                                 serv_printf(" %s", ChrPtr(SubBuf));
176
177                                         offset += nchars;
178                                         nchars = StrLength(Buf) - offset;
179                                         n++;
180                                 }
181                                 
182                         }
183                         else
184                                 serv_printf("%s|%s", Key, ChrPtr(Buf));
185                         
186                 }
187                 if (SubBuf != NULL)
188                         FreeStrBuf(&SubBuf);
189                 serv_puts("");
190                 serv_puts("000");
191                 DeleteHashPos(&HashPos);
192         }
193
194         /** Go back to the room we're supposed to be in */
195         serv_printf("GOTO %s", WC->wc_roomname);
196         serv_getln(buf, sizeof buf);
197 }
198
199 /**
200  * \brief query the actual setting of key in the citadel database
201  * \param key config key to query
202  * \param keylen length of the key string
203  * \param value StrBuf-value to the key to get
204  * \returns found?
205  */
206 int get_PREFERENCE(const char *key, size_t keylen, StrBuf **value)
207 {
208         void *hash_value = NULL;
209 #ifdef DBG_PREFS_HASH
210         dbg_PrintHash(WC->hash_prefs, PrintPref, NULL);
211 #endif
212         if (GetHash(WC->hash_prefs, key, keylen, &hash_value) == 0) {
213                 *value = NULL;
214                 return 0;
215         }
216         else {
217                 *value = NULL;
218                 *value = (StrBuf*) hash_value;
219                 return 1;
220         }
221 }
222
223 /**
224  * \brief       Write a key into the webcit preferences database for this user
225  *
226  * \params      key             key whichs value is to be modified
227  * \param keylen length of the key string
228  * \param       value           value to set
229  * \param       save_to_server  1 = flush all data to the server, 0 = cache it for now
230  */
231 void set_PREFERENCE(const char *key, size_t keylen, StrBuf *value, int save_to_server) {
232         
233         Put(WC->hash_prefs, key, keylen, value, HFreeStrBuf);
234         
235         if (save_to_server) save_preferences();
236 }
237
238 int get_PREF_LONG(const char *key, size_t keylen, long *value, long Default)
239 {
240         int ret;
241         StrBuf *val;
242         ret = get_PREFERENCE(key, keylen, &val);
243         if (ret) {
244                 *value = atol(ChrPtr(val));
245         }
246         else {
247                 *value = Default;
248         }
249
250         return ret;
251 }
252
253
254 void set_PREF_LONG(const char *key, size_t keylen, long value, int save_to_server)
255 {
256         StrBuf *val;
257         if (get_PREFERENCE(key, keylen, &val)) {
258                 StrBufPrintf(val, "%ld", value);
259         }
260         else {
261                 val = NewStrBuf();
262                 StrBufPrintf(val, "%ld", value);
263                 set_PREFERENCE(key, keylen, val, save_to_server);
264         }
265 }
266
267
268
269 int get_PREF_YESNO(const char *key, size_t keylen, int *value, int Default)
270 {
271         int ret;
272         StrBuf *val;
273         ret = get_PREFERENCE(key, keylen, &val);
274         if (ret) {
275                 *value = strcmp(ChrPtr(val), "yes") == 0;
276         }
277         else {
278                 *value = Default;
279         }
280
281         return ret;
282 }
283
284 void set_PREF_YESNO(const char *key, size_t keylen, int value, int save_to_server)
285 {
286         StrBuf *val;
287         if (get_PREFERENCE(key, keylen, &val)) {
288                 StrBufPrintf(val, "%s", (value)?"yes":"no");
289         }
290         else {
291                 val = NewStrBuf();
292                 StrBufPrintf(val, "%s", (value)?"yes":"no");
293                 set_PREFERENCE(key, keylen, val, save_to_server);
294         }
295 }
296
297 StrBuf *get_ROOM_PREFS(const char *key, size_t keylen)
298 {
299         StrBuf *pref_name, *pref_value;
300         
301         pref_name = NewStrBuf ();
302         StrBufPrintf(pref_name, "%s %s", key, WC->wc_roomname);
303         get_pref(pref_name, &pref_value);
304         FreeStrBuf(&pref_name);
305         return pref_value;
306 }
307
308 void set_ROOM_PREFS(const char *key, size_t keylen, StrBuf *value, int save_to_server)
309 {
310         StrBuf *pref_name;
311         
312         pref_name = NewStrBuf ();
313         StrBufPrintf(pref_name, "%s %s", key, WC->wc_roomname);
314         set_PREFERENCE(ChrPtr(pref_name), StrLength(pref_name), value, save_to_server);
315         FreeStrBuf(&pref_name);
316 }
317
318 /** 
319  * \brief display form for changing your preferences and settings
320  */
321 void display_preferences(void)
322 {
323         output_headers(1, 1, 1, 0, 0, 0);
324         StrBuf *ebuf = NULL;
325         int i;
326         long DayEnd, DayStart, WeekStart;
327         int UseSig, ShowEmptyFloors;
328         int time_format;
329         time_t tt;
330         struct tm tm;
331         char daylabel[32];
332         StrBuf *Buf;
333         StrBuf *Signature;
334
335         time_format = get_time_format_cached ();
336
337         wprintf("<div class=\"box\">\n");
338         wprintf("<div class=\"boxlabel\">");
339         wprintf(_("Preferences and settings"));
340         wprintf("</div>");
341
342         wprintf("<div class=\"boxcontent\">");
343
344         /** begin form */
345         wprintf("<form name=\"prefform\" action=\"set_preferences\" "
346                 "method=\"post\">\n");
347         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
348
349         /** begin table */
350         wprintf("<table class=\"altern\">\n");
351
352         /**
353          * Room list view
354          */
355         get_preference("roomlistview", &Buf);
356         wprintf("<tr class=\"even\"><td>");
357         wprintf(_("Room list view"));
358         wprintf("</td><td>");
359
360         wprintf("<input type=\"radio\" name=\"roomlistview\" VALUE=\"folders\"");
361         if (!strcasecmp(ChrPtr(Buf), "folders")) wprintf(" checked");
362         wprintf(">");
363         wprintf(_("Tree (folders) view"));
364         wprintf("</input>&nbsp;&nbsp;&nbsp;");
365
366         wprintf("<input type=\"radio\" name=\"roomlistview\" VALUE=\"rooms\"");
367         if (IsEmptyStr(ChrPtr(Buf)) || !strcasecmp(ChrPtr(Buf), "rooms")) wprintf(" checked");
368         wprintf(">");
369         wprintf(_("Table (rooms) view"));
370         wprintf("</input>\n");
371
372         wprintf("</td></tr>\n");
373
374         /**
375          * Time hour format
376          */
377
378         wprintf("<tr class=\"odd\"><td>");
379         wprintf(_("Time format"));
380         wprintf("</td><td>");
381
382         wprintf("<input type=\"radio\" name=\"calhourformat\" VALUE=\"12\"");
383         if (time_format == WC_TIMEFORMAT_AMPM) 
384                 wprintf(" checked");
385         wprintf(">");
386         wprintf(_("12 hour (am/pm)"));
387         wprintf("</input>&nbsp;&nbsp;&nbsp;");
388
389         wprintf("<input type=\"radio\" name=\"calhourformat\" VALUE=\"24\"");
390         if (time_format == WC_TIMEFORMAT_24)
391                 wprintf(" checked");
392         wprintf(">");
393         wprintf(_("24 hour"));
394         wprintf("</input>\n");
395
396         wprintf("</td></tr>\n");
397
398         /**
399          * Calendar day view -- day start time
400          */
401         get_pref_long("daystart", &DayStart, 8);
402
403         wprintf("<tr class=\"even\"><td>");
404         wprintf(_("Calendar day view begins at:"));
405         wprintf("</td><td>");
406
407         wprintf("<select name=\"daystart\" size=\"1\">\n");
408         for (i=0; i<=23; ++i) {
409
410                 if (time_format == WC_TIMEFORMAT_24) {
411                         wprintf("<option %s value=\"%d\">%d:00</option>\n",
412                                 ((DayStart == i) ? "selected" : ""),
413                                 i, i
414                         );
415                 }
416                 else {
417                         wprintf("<option %s value=\"%d\">%s</option>\n",
418                                 ((DayStart == i) ? "selected" : ""),
419                                 i, hourname[i]
420                         );
421                 }
422
423         }
424         wprintf("</select>\n");
425         wprintf("</td></tr>\n");
426
427         /**
428          * Calendar day view -- day end time
429          */
430         get_pref_long("dayend", &DayEnd, 17);
431
432         wprintf("<tr class=\"odd\"><td>");
433         wprintf(_("Calendar day view ends at:"));
434         wprintf("</td><td>");
435
436         wprintf("<select name=\"dayend\" size=\"1\">\n");
437         for (i=0; i<=23; ++i) {
438
439                 if (time_format == WC_TIMEFORMAT_24) {
440                         wprintf("<option %s value=\"%d\">%d:00</option>\n",
441                                 ((DayEnd == i) ? "selected" : ""),
442                                 i, i
443                         );
444                 }
445                 else {
446                         wprintf("<option %s value=\"%d\">%s</option>\n",
447                                 ((DayEnd == i) ? "selected" : ""),
448                                 i, hourname[i]
449                         );
450                 }
451
452         }
453         wprintf("</select>\n");
454         wprintf("</td></tr>\n");
455
456         /**
457          * Day of week to begin calendar month view
458          */
459         get_pref_long("weekstart", &WeekStart, 17);
460         wprintf("<tr class=\"even\"><td>");
461         wprintf(_("Week starts on:"));
462         wprintf("</td><td>");
463
464         wprintf("<select name=\"weekstart\" size=\"1\">\n");
465
466         for (i=0; i<=1; ++i) {
467                 tt = time(NULL);
468                 localtime_r(&tt, &tm);
469                 tm.tm_wday = i;
470                 wc_strftime(daylabel, sizeof daylabel, "%A", &tm);
471
472                 wprintf("<option %s value=\"%d\">%s</option>\n",
473                         ((WeekStart == i) ? "selected" : ""),
474                         i, daylabel
475                 );
476         }
477
478         wprintf("</select>\n");
479         wprintf("</td></tr>\n");
480
481         /**
482          * Signature
483          */
484         get_pref_yesno("use_sig", &UseSig, 0);
485         wprintf("<tr class=\"odd\"><td>");
486         wprintf(_("Attach signature to email messages?"));
487         wprintf("</td><td>");
488
489         wprintf("       <script type=\"text/javascript\">                                       "
490                 "       function show_or_hide_sigbox() {                                        "
491                 "               if ( $F('yes_sig') ) {                                          "
492                 "                       $('signature_box').style.display = 'inline';            "
493                 "               }                                                               "
494                 "               else {                                                          "
495                 "                       $('signature_box').style.display = 'none';              "
496                 "               }                                                               "
497                 "       }                                                                       "
498                 "       </script>                                                               "
499         );
500
501         wprintf("<input type=\"radio\" id=\"no_sig\" name=\"use_sig\" VALUE=\"no\"");
502         if (!UseSig) wprintf(" checked");
503         wprintf(" onChange=\"show_or_hide_sigbox();\" >");
504         wprintf(_("No signature"));
505         wprintf("</input>&nbsp,&nbsp;&nbsp;\n");
506
507         wprintf("<input type=\"radio\" id=\"yes_sig\" name=\"use_sig\" VALUE=\"yes\"");
508         if (UseSig) wprintf(" checked");
509         wprintf(" onChange=\"show_or_hide_sigbox();\" >");
510         wprintf(_("Use this signature:"));
511         wprintf("<div id=\"signature_box\">"
512                 "<br><textarea name=\"signature\" cols=\"40\" rows=\"5\">"
513         );
514
515         get_preference("signature", &Signature);
516         ebuf = NewStrBuf();
517         StrBufEUid_unescapize(ebuf, Signature);
518         escputs((char*)ChrPtr(ebuf));///TODO
519         FreeStrBuf(&ebuf);
520         wprintf("</textarea>"
521                 "</div>"
522         );
523
524         wprintf("</input>\n");
525
526         wprintf("</td></tr>\n");
527
528         wprintf("       <script type=\"text/javascript\">       "
529                 "       show_or_hide_sigbox();                  "
530                 "       </script>                               "
531         );
532
533         /** Character set to assume is in use for improperly encoded headers */
534         if (!get_preference("default_header_charset", &Buf)) {
535                 Buf = NewStrBuf();////TODO: freeme!
536                 StrBufPrintf(Buf, "%s", "UTF-8");
537         }
538         wprintf("<tr class=\"even\"><td>");
539         wprintf(_("Default character set for email headers:"));
540         wprintf("</td><td>");
541         wprintf("<input type=\"text\" NAME=\"default_header_charset\" MAXLENGTH=\"32\" VALUE=\"");
542         escputs((char*)ChrPtr(Buf)); // here shouldn't be bad chars, so...
543         wprintf("\">");
544         wprintf("</td></tr>");
545
546         /**
547          * Show empty floors?
548          */
549
550         get_pref_yesno("emptyfloors", &ShowEmptyFloors, 0);
551         wprintf("<tr class=\"odd\"><td>");
552         wprintf(_("Show empty floors"));
553         wprintf("</td><td>");
554
555         wprintf("<input type=\"radio\" name=\"emptyfloors\" VALUE=\"yes\"");
556         if (ShowEmptyFloors) wprintf(" checked");
557         wprintf(">");
558         wprintf(_("Yes"));
559         wprintf("</input>&nbsp;&nbsp;&nbsp;");
560
561         wprintf("<input type=\"radio\" name=\"emptyfloors\" VALUE=\"no\"");
562         if (!ShowEmptyFloors) wprintf(" checked");
563         wprintf(">");
564         wprintf(_("No"));
565         wprintf("</input>\n");
566
567         wprintf("</td></tr>\n");
568
569         /** end table */
570         wprintf("</table>\n");
571
572         /** submit buttons */
573         wprintf("<div class=\"buttons\"> ");
574         wprintf("<input type=\"submit\" name=\"change_button\" value=\"%s\">"
575                 "&nbsp;"
576                 "<INPUT type=\"submit\" name=\"cancel_button\" value=\"%s\">\n",
577                 _("Change"),
578                 _("Cancel")
579         );
580         wprintf("</div>\n");
581
582         /** end form */
583         wprintf("</form>\n");
584         wprintf("</div>\n");
585         wDumpContent(1);
586 }
587
588 /**
589  * \brief Commit new preferences and settings
590  */
591 void set_preferences(void)
592 {
593         long fmt;
594         StrBuf *buf, *encBuf;
595         int *time_format_cache;
596         
597         time_format_cache = &(WC->time_format_cache);
598
599         if (!havebstr("change_button")) {
600                 safestrncpy(WC->ImportantMessage, 
601                         _("Cancelled.  No settings were changed."),
602                         sizeof WC->ImportantMessage);
603                 display_main_menu();
604                 return;
605         }
606
607         /**
608          * Set the last argument to 1 only for the final setting, so
609          * we don't send the prefs file to the server repeatedly
610          */
611         set_preference("roomlistview", NewStrBufPlain(bstr("roomlistview"), -1), 0);
612         fmt = lbstr("calhourformat");
613         set_pref_long("calhourformat", fmt, 0);
614         if (fmt == 24) 
615                 *time_format_cache = WC_TIMEFORMAT_24;
616         else
617                 *time_format_cache = WC_TIMEFORMAT_AMPM;
618
619         set_pref_long("weekstart", lbstr("weekstart"), 0);
620         set_pref_yesno("use_sig", yesbstr("use_sig"), 0);
621         set_pref_long("daystart", lbstr("daystart"), 0);
622         set_pref_long("dayend", lbstr("dayend"), 0);
623         set_preference("default_header_charset", NewStrBufPlain(bstr("default_header_charset"), -1), 0);
624         set_preference("emptyfloors", NewStrBufPlain(bstr("emptyfloors"), -1), 0);
625
626         buf = NewStrBufPlain(bstr("signature"), -1);
627         encBuf = NewStrBuf();
628         StrBufEUid_escapize(encBuf, buf);
629         set_preference("signature", encBuf, 1);
630
631         display_main_menu();
632 }
633
634
635 void 
636 InitModule_PREFERENCES
637 (void)
638 {
639         WebcitAddUrlHandler(HKEY("display_preferences"), display_preferences, 0);
640         WebcitAddUrlHandler(HKEY("set_preferences"), set_preferences, 0);
641 }
642 /*@}*/