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