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