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