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