* added gcc printf format checking to wprintf
[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                         nchars = StrLength(Buf);
150                         if (nchars > 80){
151                                 int n = 0;
152                                 size_t offset, nchars;
153                                 if (SubBuf == NULL)
154                                         SubBuf = NewStrBuf();
155                                 nchars = 1;
156                                 offset = 0;
157                                 while (nchars > 0) {
158                                         if (n == 0)
159                                                 nchars = 70;
160                                         else 
161                                                 nchars = 80;
162
163                                         nchars = StrBufSub(SubBuf, Buf, offset, nchars);
164                                         
165                                         if (n == 0)
166                                                 serv_printf("%s|%s", Key, ChrPtr(SubBuf));
167                                         else
168                                                 serv_printf(" %s", Key, ChrPtr(SubBuf));
169
170                                         offset += nchars;
171                                         n++;
172                                 }
173                                 
174                         }
175                         else
176                                 serv_printf("%s|%s", Key, ChrPtr(Buf));
177                         
178                 }
179                 if (SubBuf != NULL)
180                         FreeStrBuf(&SubBuf);
181                 serv_puts("");
182                 serv_puts("000");
183                 DeleteHashPos(&HashPos);
184         }
185
186         /** Go back to the room we're supposed to be in */
187         serv_printf("GOTO %s", WC->wc_roomname);
188         serv_getln(buf, sizeof buf);
189 }
190
191 /**
192  * \brief query the actual setting of key in the citadel database
193  * \param key config key to query
194  * \param keylen length of the key string
195  * \param value StrBuf-value to the key to get
196  * \returns found?
197  */
198 int get_PREFERENCE(const char *key, size_t keylen, StrBuf **value)
199 {
200         void *hash_value = NULL;
201         
202         dbg_PrintHash(WC->hash_prefs, PrintPref, NULL);
203         if (GetHash(WC->hash_prefs, key, keylen, &hash_value) == 0) {
204                 *value = NULL;
205                 return 0;
206         }
207         else {
208                 *value = NULL;
209                 *value = (StrBuf*) hash_value;
210                 return 1;
211         }
212 }
213
214 /**
215  * \brief       Write a key into the webcit preferences database for this user
216  *
217  * \params      key             key whichs value is to be modified
218  * \param keylen length of the key string
219  * \param       value           value to set
220  * \param       save_to_server  1 = flush all data to the server, 0 = cache it for now
221  */
222 void set_PREFERENCE(const char *key, size_t keylen, StrBuf *value, int save_to_server) {
223         
224         Put(WC->hash_prefs, key, keylen, value, HFreeStrBuf);
225         
226         if (save_to_server) save_preferences();
227 }
228
229 int get_PREF_LONG(const char *key, size_t keylen, long *value, long Default)
230 {
231         int ret;
232         StrBuf *val;
233         ret = get_PREFERENCE(key, keylen, &val);
234         if (ret) {
235                 *value = atol(ChrPtr(val));
236         }
237         else {
238                 *value = Default;
239         }
240
241         return ret;
242 }
243
244
245 void set_PREF_LONG(const char *key, size_t keylen, long value, int save_to_server)
246 {
247         StrBuf *val;
248         if (get_PREFERENCE(key, keylen, &val)) {
249                 StrBufPrintf(val, "%ld", value);
250         }
251         else {
252                 val = NewStrBuf();
253                 StrBufPrintf(val, "%ld", value);
254                 set_PREFERENCE(key, keylen, val, save_to_server);
255         }
256 }
257
258
259
260 int get_PREF_YESNO(const char *key, size_t keylen, int *value, int Default)
261 {
262         int ret;
263         StrBuf *val;
264         ret = get_PREFERENCE(key, keylen, &val);
265         if (ret) {
266                 *value = strcmp(ChrPtr(val), "yes") == 0;
267         }
268         else {
269                 *value = Default;
270         }
271
272         return ret;
273 }
274
275 void set_PREF_YESNO(const char *key, size_t keylen, int value, int save_to_server)
276 {
277         StrBuf *val;
278         if (get_PREFERENCE(key, keylen, &val)) {
279                 StrBufPrintf(val, "%s", (value)?"yes":"no");
280         }
281         else {
282                 val = NewStrBuf();
283                 StrBufPrintf(val, "%s", (value)?"yes":"no");
284                 set_PREFERENCE(key, keylen, val, save_to_server);
285         }
286 }
287
288 /** 
289  * \brief display form for changing your preferences and settings
290  */
291 void display_preferences(void)
292 {
293         output_headers(1, 1, 1, 0, 0, 0);
294         StrBuf *ebuf = NULL;
295         int i;
296         long DayEnd, DayStart, WeekStart;
297         int UseSig, ShowEmptyFloors;
298         int time_format;
299         time_t tt;
300         struct tm tm;
301         char daylabel[32];
302         StrBuf *Buf;
303         StrBuf *Signature;
304
305         time_format = get_time_format_cached ();
306
307         wprintf("<div class=\"box\">\n");
308         wprintf("<div class=\"boxlabel\">");
309         wprintf(_("Preferences and settings"));
310         wprintf("</div>");
311
312         wprintf("<div class=\"boxcontent\">");
313
314         /** begin form */
315         wprintf("<form name=\"prefform\" action=\"set_preferences\" "
316                 "method=\"post\">\n");
317         wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
318
319         /** begin table */
320         wprintf("<table class=\"altern\">\n");
321
322         /**
323          * Room list view
324          */
325         get_preference("roomlistview", &Buf);
326         wprintf("<tr class=\"even\"><td>");
327         wprintf(_("Room list view"));
328         wprintf("</td><td>");
329
330         wprintf("<input type=\"radio\" name=\"roomlistview\" VALUE=\"folders\"");
331         if (!strcasecmp(ChrPtr(Buf), "folders")) wprintf(" checked");
332         wprintf(">");
333         wprintf(_("Tree (folders) view"));
334         wprintf("</input>&nbsp;&nbsp;&nbsp;");
335
336         wprintf("<input type=\"radio\" name=\"roomlistview\" VALUE=\"rooms\"");
337         if (IsEmptyStr(ChrPtr(Buf)) || !strcasecmp(ChrPtr(Buf), "rooms")) wprintf(" checked");
338         wprintf(">");
339         wprintf(_("Table (rooms) view"));
340         wprintf("</input>\n");
341
342         wprintf("</td></tr>\n");
343
344         /**
345          * Time hour format
346          */
347
348         wprintf("<tr class=\"odd\"><td>");
349         wprintf(_("Time format"));
350         wprintf("</td><td>");
351
352         wprintf("<input type=\"radio\" name=\"calhourformat\" VALUE=\"12\"");
353         if (time_format == WC_TIMEFORMAT_AMPM) 
354                 wprintf(" checked");
355         wprintf(">");
356         wprintf(_("12 hour (am/pm)"));
357         wprintf("</input>&nbsp;&nbsp;&nbsp;");
358
359         wprintf("<input type=\"radio\" name=\"calhourformat\" VALUE=\"24\"");
360         if (time_format == WC_TIMEFORMAT_24)
361                 wprintf(" checked");
362         wprintf(">");
363         wprintf(_("24 hour"));
364         wprintf("</input>\n");
365
366         wprintf("</td></tr>\n");
367
368         /**
369          * Calendar day view -- day start time
370          */
371         get_pref_long("daystart", &DayStart, 8);
372
373         wprintf("<tr class=\"even\"><td>");
374         wprintf(_("Calendar day view begins at:"));
375         wprintf("</td><td>");
376
377         wprintf("<select name=\"daystart\" size=\"1\">\n");
378         for (i=0; i<=23; ++i) {
379
380                 if (time_format == WC_TIMEFORMAT_24) {
381                         wprintf("<option %s value=\"%d\">%d:00</option>\n",
382                                 ((DayStart == i) ? "selected" : ""),
383                                 i, i
384                         );
385                 }
386                 else {
387                         wprintf("<option %s value=\"%d\">%s</option>\n",
388                                 ((DayStart == i) ? "selected" : ""),
389                                 i, hourname[i]
390                         );
391                 }
392
393         }
394         wprintf("</select>\n");
395         wprintf("</td></tr>\n");
396
397         /**
398          * Calendar day view -- day end time
399          */
400         get_pref_long("dayend", &DayEnd, 17);
401
402         wprintf("<tr class=\"odd\"><td>");
403         wprintf(_("Calendar day view ends at:"));
404         wprintf("</td><td>");
405
406         wprintf("<select name=\"dayend\" size=\"1\">\n");
407         for (i=0; i<=23; ++i) {
408
409                 if (time_format == WC_TIMEFORMAT_24) {
410                         wprintf("<option %s value=\"%d\">%d:00</option>\n",
411                                 ((DayEnd == i) ? "selected" : ""),
412                                 i, i
413                         );
414                 }
415                 else {
416                         wprintf("<option %s value=\"%d\">%s</option>\n",
417                                 ((DayEnd == i) ? "selected" : ""),
418                                 i, hourname[i]
419                         );
420                 }
421
422         }
423         wprintf("</select>\n");
424         wprintf("</td></tr>\n");
425
426         /**
427          * Day of week to begin calendar month view
428          */
429         get_pref_long("weekstart", &WeekStart, 17);
430         wprintf("<tr class=\"even\"><td>");
431         wprintf(_("Week starts on:"));
432         wprintf("</td><td>");
433
434         wprintf("<select name=\"weekstart\" size=\"1\">\n");
435
436         for (i=0; i<=1; ++i) {
437                 tt = time(NULL);
438                 localtime_r(&tt, &tm);
439                 tm.tm_wday = i;
440                 wc_strftime(daylabel, sizeof daylabel, "%A", &tm);
441
442                 wprintf("<option %s value=\"%d\">%s</option>\n",
443                         ((WeekStart == i) ? "selected" : ""),
444                         i, daylabel
445                 );
446         }
447
448         wprintf("</select>\n");
449         wprintf("</td></tr>\n");
450
451         /**
452          * Signature
453          */
454         get_pref_yesno("use_sig", &UseSig, 0);
455         wprintf("<tr class=\"odd\"><td>");
456         wprintf(_("Attach signature to email messages?"));
457         wprintf("</td><td>");
458
459         wprintf("       <script type=\"text/javascript\">                                       "
460                 "       function show_or_hide_sigbox() {                                        "
461                 "               if ( $F('yes_sig') ) {                                          "
462                 "                       $('signature_box').style.display = 'inline';            "
463                 "               }                                                               "
464                 "               else {                                                          "
465                 "                       $('signature_box').style.display = 'none';              "
466                 "               }                                                               "
467                 "       }                                                                       "
468                 "       </script>                                                               "
469         );
470
471         wprintf("<input type=\"radio\" id=\"no_sig\" name=\"use_sig\" VALUE=\"no\"");
472         if (!UseSig) wprintf(" checked");
473         wprintf(" onChange=\"show_or_hide_sigbox();\" >");
474         wprintf(_("No signature"));
475         wprintf("</input>&nbsp,&nbsp;&nbsp;\n");
476
477         wprintf("<input type=\"radio\" id=\"yes_sig\" name=\"use_sig\" VALUE=\"yes\"");
478         if (UseSig) wprintf(" checked");
479         wprintf(" onChange=\"show_or_hide_sigbox();\" >");
480         wprintf(_("Use this signature:"));
481         wprintf("<div id=\"signature_box\">"
482                 "<br><textarea name=\"signature\" cols=\"40\" rows=\"5\">"
483         );
484
485         get_preference("signature", &Signature);
486         ebuf = NewStrBuf();
487         StrBufEUid_unescapize(ebuf, Signature);
488         escputs(ChrPtr(ebuf));
489         FreeStrBuf(&ebuf);
490         wprintf("</textarea>"
491                 "</div>"
492         );
493
494         wprintf("</input>\n");
495
496         wprintf("</td></tr>\n");
497
498         wprintf("       <script type=\"text/javascript\">       "
499                 "       show_or_hide_sigbox();                  "
500                 "       </script>                               "
501         );
502
503         /** Character set to assume is in use for improperly encoded headers */
504         if (!get_preference("default_header_charset", &Buf)) {
505                 Buf = NewStrBuf();////TODO: freeme!
506                 StrBufPrintf(Buf, "%s", "UTF-8");
507         }
508         wprintf("<tr class=\"even\"><td>");
509         wprintf(_("Default character set for email headers:"));
510         wprintf("</td><td>");
511         wprintf("<input type=\"text\" NAME=\"default_header_charset\" MAXLENGTH=\"32\" VALUE=\"");
512         escputs(ChrPtr(Buf));
513         wprintf("\">");
514         wprintf("</td></tr>");
515
516         /**
517          * Show empty floors?
518          */
519
520         get_pref_yesno("emptyfloors", &ShowEmptyFloors, 0);
521         wprintf("<tr class=\"odd\"><td>");
522         wprintf(_("Show empty floors"));
523         wprintf("</td><td>");
524
525         wprintf("<input type=\"radio\" name=\"emptyfloors\" VALUE=\"yes\"");
526         if (ShowEmptyFloors) wprintf(" checked");
527         wprintf(">");
528         wprintf(_("Yes"));
529         wprintf("</input>&nbsp;&nbsp;&nbsp;");
530
531         wprintf("<input type=\"radio\" name=\"emptyfloors\" VALUE=\"no\"");
532         if (!ShowEmptyFloors) wprintf(" checked");
533         wprintf(">");
534         wprintf(_("No"));
535         wprintf("</input>\n");
536
537         wprintf("</td></tr>\n");
538
539         /** end table */
540         wprintf("</table>\n");
541
542         /** submit buttons */
543         wprintf("<div class=\"buttons\"> ");
544         wprintf("<input type=\"submit\" name=\"change_button\" value=\"%s\">"
545                 "&nbsp;"
546                 "<INPUT type=\"submit\" name=\"cancel_button\" value=\"%s\">\n",
547                 _("Change"),
548                 _("Cancel")
549         );
550         wprintf("</div>\n");
551
552         /** end form */
553         wprintf("</form>\n");
554         wprintf("</div>\n");
555         wDumpContent(1);
556 }
557
558 /**
559  * \brief Commit new preferences and settings
560  */
561 void set_preferences(void)
562 {
563         long fmt;
564         StrBuf *ebuf;
565         int *time_format_cache;
566         
567         time_format_cache = &(WC->time_format_cache);
568
569         if (!havebstr("change_button")) {
570                 safestrncpy(WC->ImportantMessage, 
571                         _("Cancelled.  No settings were changed."),
572                         sizeof WC->ImportantMessage);
573                 display_main_menu();
574                 return;
575         }
576
577         /**
578          * Set the last argument to 1 only for the final setting, so
579          * we don't send the prefs file to the server repeatedly
580          */
581         set_preference("roomlistview", NewStrBufPlain(bstr("roomlistview"), -1), 0);
582         fmt = lbstr("calhourformat");
583         set_pref_long("calhourformat", fmt, 0);
584         if (fmt == 24) 
585                 *time_format_cache = WC_TIMEFORMAT_24;
586         else
587                 *time_format_cache = WC_TIMEFORMAT_AMPM;
588
589         set_pref_long("weekstart", lbstr("weekstart"), 0);
590         set_pref_yesno("use_sig", yesbstr("use_sig"), 0);
591         set_pref_long("daystart", lbstr("daystart"), 0);
592         set_pref_long("dayend", lbstr("dayend"), 0);
593         set_preference("default_header_charset", NewStrBufPlain(bstr("default_header_charset"), -1), 0);
594         set_preference("emptyfloors", NewStrBufPlain(bstr("emptyfloors"), -1), 0);
595
596         ebuf = NewStrBufPlain(bstr("signature"), -1);
597         /////TODOeuid_escapize(ebuf);
598         set_preference("signature", ebuf, 1);
599
600         display_main_menu();
601 }
602
603
604 /*@}*/