c134355aefaead9bcffe5e8067c4c0ad0ab738bc
[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 HashList *PreferenceHooks;
13
14 typedef struct _PrefDef {
15         long Type;
16         StrBuf *Setting;
17         const char *PrefStr;
18         PrefEvalFunc OnLoad;
19         StrBuf *OnLoadName;
20 } PrefDef;
21
22 typedef struct _Preference {
23         StrBuf *Key;
24         StrBuf *Val;
25         PrefDef *Type;
26
27         long lval;
28         long decoded;
29         StrBuf *DeQPed;
30 }Preference;
31
32 void DestroyPrefDef(void *vPrefDef)
33 {
34         PrefDef *Prefdef = (PrefDef*) vPrefDef;
35         FreeStrBuf(&Prefdef->Setting);
36         FreeStrBuf(&Prefdef->OnLoadName);
37         free(Prefdef);
38 }
39
40 void DestroyPreference(void *vPref)
41 {
42         Preference *Pref = (Preference*) vPref;
43         FreeStrBuf(&Pref->Key);
44         FreeStrBuf(&Pref->Val);
45         FreeStrBuf(&Pref->DeQPed);
46         free(Pref);
47
48 }
49 void _RegisterPreference(const char *Setting, long SettingLen, 
50                          const char *PrefStr, 
51                          long Type, 
52                          PrefEvalFunc OnLoad, 
53                          const char *OnLoadName)
54 {
55         PrefDef *Newpref = (PrefDef*) malloc(sizeof(PrefDef));
56         Newpref->Setting = NewStrBufPlain(Setting, SettingLen);
57         Newpref->PrefStr = PrefStr;
58         Newpref->Type = Type;
59         Newpref->OnLoad = OnLoad;
60         if (Newpref->OnLoad != NULL) {
61                 Newpref->OnLoadName = NewStrBufPlain(OnLoadName, -1);
62         }
63         else
64                 Newpref->OnLoadName = NULL;
65         Put(PreferenceHooks, Setting, SettingLen, Newpref, DestroyPrefDef);
66 }
67
68 const char *PrefGetLocalStr(const char *Setting, long len)
69 {
70         void *hash_value;
71         if (GetHash(PreferenceHooks, Setting, len, &hash_value) != 0) {
72                 PrefDef *Newpref = (PrefDef*) hash_value;
73                 return _(Newpref->PrefStr);
74
75         }
76         return "";
77 }
78
79 #ifdef DBG_PREFS_HASH
80 inline const char *PrintPref(void *vPref)
81 {
82         Preference *Pref = (Preference*) vPref;
83         if (Pref->DeQPed != NULL)
84                 return ChrPtr(Pref->DeQPed);
85         else 
86                 return ChrPtr(Pref->Val);
87 }
88 #endif
89
90 void GetPrefTypes(HashList *List)
91 {
92         HashPos *It;
93         long len;
94         const char *Key;
95         void *vSetting;
96         void *vPrefDef;
97         Preference *Pref;
98         PrefDef *PrefType;
99
100         It = GetNewHashPos(List, 0);
101         while (GetNextHashPos(List, It, &len, &Key, &vSetting)) 
102         {
103                 Pref = (Preference*) vSetting;
104                 if (GetHash(PreferenceHooks, SKEY(Pref->Key), &vPrefDef) && 
105                     (vPrefDef != NULL)) 
106                 {
107                         PrefType = (PrefDef*) vPrefDef;
108                         Pref->Type = PrefType;
109
110                         lprintf(1, "Loading [%s]with type [%ld] [\"%s\"]\n",
111                                 ChrPtr(Pref->Key),
112                                 Pref->Type->Type,
113                                 ChrPtr(Pref->Val));
114
115                         switch (Pref->Type->Type)
116                         {
117
118                         case PRF_STRING:
119                                 break;
120                         case PRF_INT:
121                                 Pref->lval = StrTol(Pref->Val);
122                                 Pref->decoded = 1;
123                                 break;
124                         case PRF_QP_STRING:
125                                 Pref->DeQPed = NewStrBufPlain(NULL, StrLength(Pref->Val));
126                                 StrBufEUid_unescapize(Pref->DeQPed, Pref->Val);
127                                 Pref->decoded = 1;
128                                 break;
129                         case PRF_YESNO:
130                                 Pref->lval = strcmp(ChrPtr(Pref->Val), "yes") == 0;
131                                 Pref->decoded = 1;
132                                 break;
133                         }
134
135                         if (PrefType->OnLoad != NULL){
136
137                                 lprintf(1, "Loading with: -> %s(\"%s\", %ld)\n",
138                                         ChrPtr(PrefType->OnLoadName),
139                                         ChrPtr(Pref->Val),
140                                         Pref->lval);
141                                 PrefType->OnLoad(Pref->Val, Pref->lval);
142                         }
143                 }
144         }
145         DeleteHashPos(&It);
146 }
147
148 void ParsePref(HashList **List, StrBuf *ReadBuf)
149 {
150         Preference *Data = NULL;
151         Preference *LastData = NULL;
152                                 
153         while (StrBuf_ServGetln(ReadBuf), 
154                strcmp(ChrPtr(ReadBuf), "000")) 
155         {
156                 if ((ChrPtr(ReadBuf)[0] == ' ') &&
157                     (Data != NULL)) {
158                         StrBufAppendBuf(Data->Val, ReadBuf, 1);
159                 }
160                 else {
161                         LastData = Data = malloc(sizeof(Preference));
162                         memset(Data, 0, sizeof(Preference));
163                         Data->Key = NewStrBuf();
164                         Data->Val = NewStrBuf();
165                         StrBufExtract_token(Data->Key, ReadBuf, 0, '|');
166                         StrBufExtract_token(Data->Val, ReadBuf, 1, '|');
167                         if (!IsEmptyStr(ChrPtr(Data->Key)))
168                         {
169                                 Put(*List, 
170                                     SKEY(Data->Key),
171                                     Data, 
172                                     DestroyPreference);
173                         }
174                         else 
175                         {
176                                 StrBufTrim(ReadBuf);
177                                 lprintf(1, "ignoring spurious preference line: [%s]\n", 
178                                         ChrPtr(ReadBuf));
179                                 DestroyPreference(Data);
180                                 LastData = NULL;
181                         }
182                 }
183         }
184         GetPrefTypes(*List);
185 }
186
187
188 /*
189  * display preferences dialog
190  */
191 void load_preferences(void) 
192 {
193         StrBuf *ReadBuf;
194         char buf[SIZ];
195         long msgnum = 0L;
196         
197         if (goto_config_room() != 0) return;    /* oh well. */
198
199         ReadBuf = NewStrBuf();
200         serv_puts("MSGS ALL|0|1");
201         StrBuf_ServGetln(ReadBuf);
202         if (GetServerStatus(ReadBuf, NULL) == 8) {
203                 serv_puts("subj|__ WebCit Preferences __");
204                 serv_puts("000");
205         }
206         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
207                 msgnum = atol(buf);
208         }
209
210         if (msgnum > 0L) {
211                 serv_printf("MSG0 %ld", msgnum);
212                 StrBuf_ServGetln(ReadBuf);
213                 if (GetServerStatus(ReadBuf, NULL) == 1) {
214                         while (StrBuf_ServGetln(ReadBuf),
215                                (strcmp(ChrPtr(ReadBuf), "text") && 
216                                 strcmp(ChrPtr(ReadBuf), "000"))) {
217                         }
218                         if (!strcmp(ChrPtr(ReadBuf), "text")) {
219                                 ParsePref(&WC->hash_prefs, ReadBuf);
220                         }
221                 }
222         }
223
224         /* Go back to the room we're supposed to be in */
225         serv_printf("GOTO %s", ChrPtr(WC->wc_roomname));
226         StrBuf_ServGetln(ReadBuf);
227         GetServerStatus(ReadBuf, NULL);
228         FreeStrBuf(&ReadBuf);
229 }
230
231 /**
232  * \brief Goto the user's configuration room, creating it if necessary.
233  * \return 0 on success or nonzero upon failure.
234  */
235 int goto_config_room(void) {
236         char buf[SIZ];
237
238         serv_printf("GOTO %s", USERCONFIGROOM);
239         serv_getln(buf, sizeof buf);
240         if (buf[0] != '2') { /* try to create the config room if not there */
241                 serv_printf("CRE8 1|%s|4|0", USERCONFIGROOM);
242                 serv_getln(buf, sizeof buf);
243                 serv_printf("GOTO %s", USERCONFIGROOM);
244                 serv_getln(buf, sizeof buf);
245                 if (buf[0] != '2') return(1);
246         }
247         return(0);
248 }
249
250 void WritePrefsToServer(HashList *Hash)
251 {
252         long len;
253         HashPos *HashPos;
254         void *vPref;
255         const char *Key;
256         Preference *Pref;
257         StrBuf *SubBuf = NULL;
258         
259         Hash = WC->hash_prefs;
260 #ifdef DBG_PREFS_HASH
261         dbg_PrintHash(Hash, PrintPref, NULL);
262 #endif
263         HashPos = GetNewHashPos(Hash, 0);
264         while (GetNextHashPos(Hash, HashPos, &len, &Key, &vPref)!=0)
265         {
266                 size_t nchars;
267                 if (vPref == NULL)
268                         continue;
269                 Pref = (Preference*) vPref;
270                 nchars = StrLength(Pref->Val);
271                 if (nchars > 80){
272                         int n = 0;
273                         size_t offset, nchars;
274                         if (SubBuf == NULL)
275                                 SubBuf = NewStrBuf();
276                         nchars = 1;
277                         offset = 0;
278                         while (nchars > 0) {
279                                 if (n == 0)
280                                         nchars = 70;
281                                 else 
282                                         nchars = 80;
283                                 
284                                 nchars = StrBufSub(SubBuf, Pref->Val, offset, nchars);
285                                 
286                                 if (n == 0)
287                                         serv_printf("%s|%s", ChrPtr(Pref->Key), ChrPtr(SubBuf));
288                                 else
289                                         serv_printf(" %s", ChrPtr(SubBuf));
290                                 
291                                 offset += nchars;
292                                 nchars = StrLength(Pref->Val) - offset;
293                                 n++;
294                         }
295                         
296                 }
297                 else
298                         serv_printf("%s|%s", ChrPtr(Pref->Key), ChrPtr(Pref->Val));
299                 
300         }
301         FreeStrBuf(&SubBuf);
302         DeleteHashPos(&HashPos);
303 }
304
305 /**
306  * \brief save the modifications
307  */
308 void save_preferences(void) 
309 {
310         char buf[SIZ];
311         long msgnum = 0L;
312         
313         if (goto_config_room() != 0) return;    /* oh well. */
314         serv_puts("MSGS ALL|0|1");
315         serv_getln(buf, sizeof buf);
316         if (buf[0] == '8') {
317                 serv_puts("subj|__ WebCit Preferences __");
318                 serv_puts("000");
319         }
320         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
321                 msgnum = atol(buf);
322         }
323
324         if (msgnum > 0L) {
325                 serv_printf("DELE %ld", msgnum);
326                 serv_getln(buf, sizeof buf);
327         }
328
329         serv_printf("ENT0 1||0|1|__ WebCit Preferences __|");
330         serv_getln(buf, sizeof buf);
331         if (buf[0] == '4') {
332
333                 WritePrefsToServer(WC->hash_prefs);
334                 serv_puts("");
335                 serv_puts("000");
336         }
337
338         /** Go back to the room we're supposed to be in */
339         serv_printf("GOTO %s", ChrPtr(WC->wc_roomname));
340         serv_getln(buf, sizeof buf);
341 }
342
343 /**
344  * \brief query the actual setting of key in the citadel database
345  * \param key config key to query
346  * \param keylen length of the key string
347  * \param value StrBuf-value to the key to get
348  * \returns found?
349  */
350 int get_pref_backend(const char *key, size_t keylen, Preference **Pref)
351 {
352         void *hash_value = NULL;
353 #ifdef DBG_PREFS_HASH
354         dbg_PrintHash(WC->hash_prefs, PrintPref, NULL);
355 #endif
356         if (GetHash(WC->hash_prefs, key, keylen, &hash_value) == 0) {
357                 *Pref = NULL;
358                 return 0;
359         }
360         else {
361                 *Pref = (Preference*) hash_value;
362                 return 1;
363         }
364 }
365
366 int get_PREFERENCE(const char *key, size_t keylen, StrBuf **value)
367 {
368         Preference *Pref;
369         int Ret;
370
371         Ret = get_pref_backend(key, keylen, &Pref);
372         if (Ret != 0)
373                 *value = Pref->Val;
374         else
375                 *value = NULL;
376         return Ret;
377 }
378
379 /**
380  * \brief       Write a key into the webcit preferences database for this user
381  *
382  * \params      key             key whichs value is to be modified
383  * \param keylen length of the key string
384  * \param       value           value to set
385  * \param       save_to_server  1 = flush all data to the server, 0 = cache it for now
386  */
387 void set_preference_backend(const char *key, size_t keylen, 
388                             long lvalue, 
389                             StrBuf *value, 
390                             long lPrefType,
391                             int save_to_server, 
392                             PrefDef *PrefType) 
393 {
394         void *vPrefDef;
395         Preference *Pref;
396
397         Pref = (Preference*) malloc(sizeof(Preference));
398         memset(Pref, 0, sizeof(Preference));
399         Pref->Key = NewStrBufPlain(key, keylen);
400
401         if ((PrefType == NULL) &&
402             GetHash(PreferenceHooks, SKEY(Pref->Key), &vPrefDef) && 
403             (vPrefDef != NULL))
404                 PrefType = (PrefDef*) vPrefDef;
405
406         if (PrefType != NULL)
407         {
408                 Pref->Type = PrefType;
409                 if (Pref->Type->Type != lPrefType)
410                         lprintf(1, "warning: saving preference with wrong type [%s] %ld != %ld \n",
411                                 key, Pref->Type->Type, lPrefType);
412                 switch (Pref->Type->Type)
413                 {
414                 case PRF_STRING:
415                         Pref->Val = value;
416                         Pref->decoded = 1;
417                         break;
418                 case PRF_INT:
419                         Pref->lval = lvalue;
420                         Pref->Val = value;
421                         if (Pref->Val == NULL)
422                                 Pref->Val = NewStrBufPlain(NULL, 64);
423                         StrBufPrintf(Pref->Val, "%ld", lvalue);
424                         Pref->decoded = 1;
425                         break;
426                 case PRF_QP_STRING:
427                         Pref->DeQPed = value;
428                         Pref->Val = NewStrBufPlain(NULL, StrLength(Pref->DeQPed) * 3);
429                         StrBufEUid_escapize(Pref->Val, Pref->DeQPed);
430                         Pref->decoded = 1;
431                         break;
432                 case PRF_YESNO:
433                         Pref->lval = lvalue;
434                         if (lvalue) 
435                                 Pref->Val = NewStrBufPlain(HKEY("yes"));
436                         else
437                                 Pref->Val = NewStrBufPlain(HKEY("no"));
438                         Pref->decoded = 1;
439                         break;
440                 }
441                 if (Pref->Type->OnLoad != NULL)
442                         Pref->Type->OnLoad(Pref->Val, Pref->lval);
443         }
444         else {
445                 switch (lPrefType)
446                 {
447                 case PRF_STRING:
448                         Pref->Val = value;
449                         Pref->decoded = 1;
450                         break;
451                 case PRF_INT:
452                         Pref->lval = lvalue;
453                         Pref->Val = value;
454                         if (Pref->Val == NULL)
455                                 Pref->Val = NewStrBufPlain(NULL, 64);
456                         StrBufPrintf(Pref->Val, "%ld", lvalue);
457                         Pref->decoded = 1;
458                         break;
459                 case PRF_QP_STRING:
460                         Pref->DeQPed = value;
461                         Pref->Val = NewStrBufPlain(NULL, StrLength(Pref->DeQPed) * 3);
462                         StrBufEUid_escapize(Pref->Val, Pref->DeQPed);
463                         Pref->decoded = 1;
464                         break;
465                 case PRF_YESNO:
466                         Pref->lval = lvalue;
467                         if (lvalue) 
468                                 Pref->Val = NewStrBufPlain(HKEY("yes"));
469                         else
470                                 Pref->Val = NewStrBufPlain(HKEY("no"));
471                         Pref->decoded = 1;
472                         break;
473                 }
474         }
475         Put(WC->hash_prefs, key, keylen, Pref, DestroyPreference);
476         
477         if (save_to_server) WC->SavePrefsToServer = 1;
478 }
479
480 void set_PREFERENCE(const char *key, size_t keylen, StrBuf *value, int save_to_server) 
481 {
482         set_preference_backend(key, keylen, 0, value, PRF_STRING, save_to_server, NULL);
483 }
484
485 int get_PREF_LONG(const char *key, size_t keylen, long *value, long Default)
486 {
487         Preference *Pref;
488         int Ret;
489
490         Ret = get_pref_backend(key, keylen, &Pref);
491         if (Ret == 0) {
492                 *value = Default;
493                 return 0;
494         }
495
496         if (Pref->decoded)
497                 *value = Pref->lval;
498         else {
499                 *value = Pref->lval = atol(ChrPtr(Pref->Val));
500                 Pref->decoded = 1;
501         }
502         return Ret;
503 }
504
505
506 void set_PREF_LONG(const char *key, size_t keylen, long value, int save_to_server)
507 {
508         set_preference_backend(key, keylen, value, NULL, PRF_INT, save_to_server, NULL);
509 }
510
511 int get_PREF_YESNO(const char *key, size_t keylen, int *value, int Default)
512 {
513         Preference *Pref;
514         int Ret;
515
516         Ret = get_pref_backend(key, keylen, &Pref);
517         if (Ret == 0) {
518                 *value = Default;
519                 return 0;
520         }
521
522         if (Pref->decoded)
523                 *value = Pref->lval;
524         else {
525                 *value = Pref->lval = strcmp(ChrPtr(Pref->Val), "yes") == 0;
526                 Pref->decoded = 1;
527         }
528         return Ret;
529 }
530
531 void set_PREF_YESNO(const char *key, size_t keylen, long value, int save_to_server)
532 {
533         set_preference_backend(key, keylen, value, NULL, PRF_YESNO, save_to_server, NULL);
534 }
535
536 int get_room_prefs_backend(const char *key, size_t keylen, 
537                            Preference **Pref)
538 {
539         StrBuf *pref_name;
540         int Ret;
541
542         pref_name = NewStrBufPlain (HKEY("ROOM:"));
543         StrBufAppendBuf(pref_name, WC->wc_roomname, 0);
544         StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
545         StrBufAppendBufPlain(pref_name, key, keylen, 0);
546         Ret = get_pref_backend(SKEY(pref_name), Pref);
547         FreeStrBuf(&pref_name);
548
549         return Ret;
550 }
551
552 const StrBuf *get_X_PREFS(const char *key, size_t keylen, 
553                           const char *xkey, size_t xkeylen)
554 {
555         int ret;
556         StrBuf *pref_name;
557         Preference *Prf;
558         
559         pref_name = NewStrBufPlain (HKEY("XPREF:"));
560         StrBufAppendBufPlain(pref_name, xkey, xkeylen, 0);
561         StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
562         StrBufAppendBufPlain(pref_name, key, keylen, 0);
563
564         ret = get_pref_backend(SKEY(pref_name), &Prf);
565         FreeStrBuf(&pref_name);
566
567         if (ret)
568                 return Prf->Val;
569         else return NULL;
570 }
571
572 void set_X_PREFS(const char *key, size_t keylen, const char *xkey, size_t xkeylen, StrBuf *value, int save_to_server)
573 {
574         StrBuf *pref_name;
575         
576         pref_name = NewStrBufPlain (HKEY("XPREF:"));
577         StrBufAppendBufPlain(pref_name, xkey, xkeylen, 0);
578         StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
579         StrBufAppendBufPlain(pref_name, key, keylen, 0);
580
581         set_preference_backend(SKEY(pref_name), 0, value, PRF_STRING, save_to_server, NULL);
582         FreeStrBuf(&pref_name);
583 }
584
585
586 StrBuf *get_ROOM_PREFS(const char *key, size_t keylen)
587 {
588         Preference *Pref;
589         int Ret;
590
591         Ret = get_room_prefs_backend(key, keylen, &Pref);
592
593         if (Ret == 0) {
594                 return NULL;
595         }
596         else 
597                 return Pref->Val;
598 }
599
600 void set_ROOM_PREFS(const char *key, size_t keylen, StrBuf *value, int save_to_server)
601 {
602         StrBuf *pref_name;
603         
604         pref_name = NewStrBufPlain (HKEY("ROOM:"));
605         StrBufAppendBuf(pref_name, WC->wc_roomname, 0);
606         StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
607         StrBufAppendBufPlain(pref_name, key, keylen, 0);
608         set_preference_backend(SKEY(pref_name), 0, value, PRF_STRING, save_to_server, NULL);
609         FreeStrBuf(&pref_name);
610 }
611
612
613 void GetPreferences(HashList *Setting)
614 {
615         wcsession *WCC = WC;
616         HashPos *It;
617         long len;
618         const char *Key;
619         void *vSetting;
620         PrefDef *PrefType;
621         StrBuf *Buf;
622         long lval;
623         HashList *Tmp;
624
625         Tmp = WCC->hash_prefs;
626         WCC->hash_prefs = Setting;
627
628         It = GetNewHashPos(PreferenceHooks, 0);
629         while (GetNextHashPos(PreferenceHooks, It, &len, &Key, &vSetting)) {
630                 PrefType = (PrefDef*) vSetting;
631
632                 if (!HaveBstr(SKEY(PrefType->Setting)))
633                         continue;
634                 switch (PrefType->Type) {
635                 case PRF_STRING:
636                         Buf = NewStrBufDup(SBstr(SKEY(PrefType->Setting)));
637                         set_preference_backend(SKEY(PrefType->Setting),
638                                                0, 
639                                                Buf, 
640                                                PRF_STRING,
641                                                1, 
642                                                PrefType);
643                         break;
644                 case PRF_INT:
645                         lval = LBstr(SKEY(PrefType->Setting));
646                         set_preference_backend(SKEY(PrefType->Setting),
647                                                lval, 
648                                                NULL, 
649                                                PRF_INT,
650                                                1, 
651                                                PrefType);
652                         break;
653                 case PRF_QP_STRING:
654                         Buf = NewStrBufDup(SBstr(SKEY(PrefType->Setting)));
655                         set_preference_backend(SKEY(PrefType->Setting),
656                                                0, 
657                                                Buf, 
658                                                PRF_QP_STRING,
659                                                1, 
660                                                PrefType);
661                         break;
662                 case PRF_YESNO:
663                         lval = YesBstr(SKEY(PrefType->Setting));
664                         set_preference_backend(SKEY(PrefType->Setting),
665                                                lval, 
666                                                NULL, 
667                                                PRF_YESNO,
668                                                1, 
669                                                PrefType);
670                         break;
671                 }
672         }
673         WCC->hash_prefs = Tmp;
674         DeleteHashPos(&It);
675 }
676
677
678 /**
679  * \brief Commit new preferences and settings
680  */
681 void set_preferences(void)
682 {       
683         if (!havebstr("change_button")) {
684                 safestrncpy(WC->ImportantMessage, 
685                             _("Cancelled.  No settings were changed."),
686                             sizeof WC->ImportantMessage);
687                 display_main_menu();
688                 return;
689         }
690         GetPreferences(WC->hash_prefs);
691         display_main_menu();
692 }
693
694
695 void tmplput_CFG_Value(StrBuf *Target, WCTemplputParams *TP)
696 {
697         Preference *Pref;
698         if (get_pref_backend(TKEY(0), &Pref))
699         {
700                 if (Pref->Type == NULL) {
701                         StrBufAppendTemplate(Target, TP, Pref->Val, 1);
702                 }
703                 switch (Pref->Type->Type)
704                 {
705                 case PRF_STRING:
706                         StrBufAppendTemplate(Target, TP, Pref->Val, 1);
707                         break;
708                 case PRF_INT:
709                         if (Pref->decoded != 1) {
710                                 if (Pref->Val == NULL)
711                                         Pref->Val = NewStrBufPlain(NULL, 64);
712                                 StrBufPrintf(Pref->Val, "%ld", Pref->lval);
713                                 Pref->decoded = 1;
714                         }
715                         StrBufAppendTemplate(Target, TP, Pref->Val, 1);
716                         break;
717                 case PRF_QP_STRING:
718                         if (Pref->decoded != 1) {
719                                 if (Pref->DeQPed == NULL)
720                                         Pref->DeQPed = NewStrBufPlain(NULL, StrLength(Pref->Val));
721                                         
722                                 StrBufEUid_unescapize(Pref->DeQPed, Pref->Val);
723                                 Pref->decoded = 1;
724                         }
725                         StrBufAppendTemplate(Target, TP, Pref->DeQPed, 1);
726                         break;
727                 case PRF_YESNO:
728                         if (Pref->decoded != 1) {
729                                 Pref->lval = strcmp(ChrPtr(Pref->Val), "yes") == 0;
730                                 Pref->decoded = 1;
731                         }
732                         StrBufAppendTemplate(Target, TP, Pref->Val, 1);
733                         break;
734                 }
735         }
736 }
737
738 void tmplput_CFG_Descr(StrBuf *Target, WCTemplputParams *TP)
739 {
740         const char *SettingStr;
741         SettingStr = PrefGetLocalStr(TKEY(0));
742         if (SettingStr != NULL) 
743                 StrBufAppendBufPlain(Target, SettingStr, -1, 0);
744 }
745 void tmplput_CFG_RoomValue(StrBuf *Target, WCTemplputParams *TP)
746 {
747         StrBuf *pref = get_ROOM_PREFS(TKEY(0));
748         if (pref != NULL) 
749                 StrBufAppendBuf(Target, pref, 0);
750 }
751 int ConditionalHasRoomPreference(StrBuf *Target, WCTemplputParams *TP) 
752 {
753         if (get_ROOM_PREFS(TP->Tokens->Params[0]->Start, 
754                            TP->Tokens->Params[0]->len) != NULL) 
755                 return 1;
756   
757         return 0;
758 }
759 void CfgZoneTempl(StrBuf *TemplBuffer, WCTemplputParams *TP)
760 {
761         StrBuf *Zone = (StrBuf*) CTX;
762
763         SVPutBuf("ZONENAME", Zone, 1);
764 }
765
766 int ConditionalPreference(StrBuf *Target, WCTemplputParams *TP)
767 {
768         StrBuf *Pref;
769
770         if (!get_PREFERENCE(TKEY(2), &Pref)) 
771                 return 0;
772         
773         if (TP->Tokens->nParameters == 3) {
774                 return 1;
775         }
776         else if (TP->Tokens->Params[3]->Type == TYPE_STR)
777                 return ((TP->Tokens->Params[3]->len == StrLength(Pref)) &&
778                         (strcmp(TP->Tokens->Params[3]->Start, ChrPtr(Pref)) == 0));
779         else 
780                 return (StrTol(Pref) == TP->Tokens->Params[3]->lvalue);
781 }
782
783 int ConditionalHasPreference(StrBuf *Target, WCTemplputParams *TP)
784 {
785         StrBuf *Pref;
786
787         if (!get_PREFERENCE(TKEY(2), &Pref) || 
788             (Pref == NULL)) 
789                 return 0;
790         else 
791                 return 1;
792 }
793
794
795 /********************************************************************************
796  *                 preferences stored discrete in citserver
797  ********************************************************************************/
798 HashList *GetGVEAHash(StrBuf *Target, WCTemplputParams *TP)
799 {
800         StrBuf *Rcp;
801         HashList *List = NULL;
802         int Done = 0;
803         int i, n = 1;
804         char N[64];
805
806         Rcp = NewStrBuf();
807         serv_puts("GVEA");
808         StrBuf_ServGetln(Rcp);
809         if (GetServerStatus(Rcp, NULL) == 1) {
810                 FlushStrBuf(Rcp);
811                 List = NewHash(1, NULL);
812                 while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
813                         if ( (StrLength(Rcp)==3) && 
814                              !strcmp(ChrPtr(Rcp), "000")) 
815                         {
816                                 Done = 1;
817                         }
818                         else {
819                                 i = snprintf(N, sizeof(N), "%d", n);
820                                 StrBufTrim(Rcp);
821                                 Put(List, N, i, Rcp, HFreeStrBuf);
822                                 Rcp = NewStrBuf();
823                         }
824                         n++;
825                 }
826         }
827         FreeStrBuf(&Rcp);
828         return List;
829 }
830 void DeleteGVEAHash(HashList **KillMe)
831 {
832         DeleteHash(KillMe);
833 }
834
835 HashList *GetGVSNHash(StrBuf *Target, WCTemplputParams *TP)
836 {
837         StrBuf *Rcp;
838         HashList *List = NULL;
839         int Done = 0;
840         int i, n = 1;
841         char N[64];
842
843         Rcp = NewStrBuf();
844         serv_puts("GVSN");
845         StrBuf_ServGetln(Rcp);
846         if (GetServerStatus(Rcp, NULL) == 1) {
847                 FlushStrBuf(Rcp);
848                 List = NewHash(1, NULL);
849                 while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
850                         if ( (StrLength(Rcp)==3) && 
851                              !strcmp(ChrPtr(Rcp), "000")) 
852                         {
853                                 Done = 1;
854                         }
855                         else {
856                                 i = snprintf(N, sizeof(N), "%d", n);
857                                 StrBufTrim(Rcp);
858                                 Put(List, N, i, Rcp, HFreeStrBuf);
859                                 Rcp = NewStrBuf();
860                         }
861                         n++;
862                 }
863         }
864         FreeStrBuf(&Rcp);
865         return List;
866 }
867 void DeleteGVSNHash(HashList **KillMe)
868 {
869         DeleteHash(KillMe);
870 }
871
872
873
874
875 /*
876  * Offer to make any page the user's "start page."
877  */
878 void offer_start_page(StrBuf *Target, WCTemplputParams *TP)
879 {
880         wprintf("<a href=\"change_start_page?startpage=");
881         urlescputs(ChrPtr(WC->this_page));
882         wprintf("\">");
883         wprintf(_("Make this my start page"));
884         wprintf("</a>");
885 #ifdef TECH_PREVIEW
886         wprintf("<br/><a href=\"rss?room=");
887         urlescputs(ChrPtr(WC->wc_roomname));
888         wprintf("\" title=\"RSS 2.0 feed for ");
889         escputs(ChrPtr(WC->wc_roomname));
890         wprintf("\"><img alt=\"RSS\" border=\"0\" src=\"static/xml_button.gif\"/></a>\n");
891 #endif
892 }
893
894
895 /*
896  * Change the user's start page
897  */
898 void change_start_page(void) 
899 {
900         if (!havebstr("startpage")) {
901                 set_preference_backend(HKEY("startpage"), 
902                                        0, 
903                                        NewStrBufPlain(HKEY("")),
904                                        PRF_STRING,
905                                        1, 
906                                        NULL);
907                 safestrncpy(WC->ImportantMessage,
908                             _("You no longer have a start page selected."),
909                             sizeof( WC->ImportantMessage));
910                 display_main_menu();
911                 return;
912         }
913
914         set_preference_backend(HKEY("startpage"), 
915                                0, 
916                                NewStrBufDup(sbstr("startpage")),
917                                PRF_STRING,
918                                1, 
919                                NULL);
920
921         output_headers(1, 1, 0, 0, 0, 0);
922         do_template("newstartpage", NULL);
923         wDumpContent(1);
924 }
925
926
927 void 
928 InitModule_PREFERENCES
929 (void)
930 {
931         WebcitAddUrlHandler(HKEY("set_preferences"), set_preferences, 0);
932         WebcitAddUrlHandler(HKEY("change_start_page"), change_start_page, 0);
933
934
935         RegisterNamespace("OFFERSTARTPAGE", 0, 0, offer_start_page, CTX_NONE);
936         RegisterNamespace("PREF:ROOM:VALUE", 1, 2, tmplput_CFG_RoomValue,  CTX_NONE);
937         RegisterNamespace("PREF:VALUE", 1, 2, tmplput_CFG_Value, CTX_NONE);
938         RegisterNamespace("PREF:DESCR", 1, 1, tmplput_CFG_Descr, CTX_NONE);
939         RegisterIterator("PREF:ZONE", 0, ZoneHash, NULL, CfgZoneTempl, NULL, CTX_PREF, CTX_NONE, IT_NOFLAG);
940
941         RegisterConditional(HKEY("COND:PREF"), 4, ConditionalPreference, CTX_NONE);
942         RegisterConditional(HKEY("COND:PREF:SET"), 4, ConditionalHasPreference, CTX_NONE);
943         RegisterConditional(HKEY("COND:ROOM:SET"), 4, ConditionalHasRoomPreference, CTX_NONE);
944         
945         RegisterIterator("PREF:VALID:EMAIL:ADDR", 0, NULL, 
946                          GetGVEAHash, NULL, DeleteGVEAHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
947         RegisterIterator("PREF:VALID:EMAIL:NAME", 0, NULL, 
948                          GetGVSNHash, NULL, DeleteGVSNHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
949
950 }
951 /*@}*/