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