a8c1ce56c9462f1ce11f4c30e484256a0e49d67e
[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 long get_ROOM_PREFS_LONG(const char *key, size_t keylen, long *value, long Default)
628 {
629         Preference *Pref;
630         int Ret;
631
632         Ret = get_room_prefs_backend(key, keylen, &Pref);
633
634         if (Ret == 0) {
635                 *value = Default;
636                 return 0;
637         }
638
639         if (Pref->decoded)
640                 *value = Pref->lval;
641         else {
642                 *value = Pref->lval = atol(ChrPtr(Pref->Val));
643                 Pref->decoded = 1;
644         }
645         return Ret;
646 }
647
648
649 StrBuf *get_ROOM_PREFS(const char *key, size_t keylen)
650 {
651         Preference *Pref;
652         int Ret;
653
654         Ret = get_room_prefs_backend(key, keylen, &Pref);
655
656         if (Ret == 0) {
657                 return NULL;
658         }
659         else 
660                 return Pref->Val;
661 }
662
663 void set_ROOM_PREFS(const char *key, size_t keylen, StrBuf *value, int save_to_server)
664 {
665         StrBuf *pref_name;
666         
667         pref_name = NewStrBufPlain (HKEY("ROOM:"));
668         StrBufAppendBuf(pref_name, WC->wc_roomname, 0);
669         StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
670         StrBufAppendBufPlain(pref_name, key, keylen, 0);
671         set_preference_backend(SKEY(pref_name), 0, value, PRF_STRING, save_to_server, NULL);
672         FreeStrBuf(&pref_name);
673 }
674
675
676 void GetPreferences(HashList *Setting)
677 {
678         wcsession *WCC = WC;
679         HashPos *It;
680         long len;
681         const char *Key;
682         void *vSetting;
683         PrefDef *PrefType;
684         StrBuf *Buf;
685         long lval;
686         HashList *Tmp;
687
688         Tmp = WCC->hash_prefs;
689         WCC->hash_prefs = Setting;
690
691         It = GetNewHashPos(PreferenceHooks, 0);
692         while (GetNextHashPos(PreferenceHooks, It, &len, &Key, &vSetting)) {
693                 PrefType = (PrefDef*) vSetting;
694
695                 if (!HaveBstr(SKEY(PrefType->Setting)))
696                         continue;
697                 switch (PrefType->Type) {
698                 case PRF_STRING:
699                         Buf = NewStrBufDup(SBstr(SKEY(PrefType->Setting)));
700                         set_preference_backend(SKEY(PrefType->Setting),
701                                                0, 
702                                                Buf, 
703                                                PRF_STRING,
704                                                1, 
705                                                PrefType);
706                         break;
707                 case PRF_INT:
708                         lval = LBstr(SKEY(PrefType->Setting));
709                         set_preference_backend(SKEY(PrefType->Setting),
710                                                lval, 
711                                                NULL, 
712                                                PRF_INT,
713                                                1, 
714                                                PrefType);
715                         break;
716                 case PRF_QP_STRING:
717                         Buf = NewStrBufDup(SBstr(SKEY(PrefType->Setting)));
718                         set_preference_backend(SKEY(PrefType->Setting),
719                                                0, 
720                                                Buf, 
721                                                PRF_QP_STRING,
722                                                1, 
723                                                PrefType);
724                         break;
725                 case PRF_YESNO:
726                         lval = YesBstr(SKEY(PrefType->Setting));
727                         set_preference_backend(SKEY(PrefType->Setting),
728                                                lval, 
729                                                NULL, 
730                                                PRF_YESNO,
731                                                1, 
732                                                PrefType);
733                         break;
734                 }
735         }
736         WCC->hash_prefs = Tmp;
737         DeleteHashPos(&It);
738 }
739
740
741 /**
742  * \brief Commit new preferences and settings
743  */
744 void set_preferences(void)
745 {       
746         if (!havebstr("change_button")) {
747                 safestrncpy(WC->ImportantMessage, 
748                             _("Cancelled.  No settings were changed."),
749                             sizeof WC->ImportantMessage);
750                 display_main_menu();
751                 return;
752         }
753         GetPreferences(WC->hash_prefs);
754         display_main_menu();
755 }
756
757
758 void tmplput_CFG_Value(StrBuf *Target, WCTemplputParams *TP)
759 {
760         Preference *Pref;
761         if (get_pref_backend(TKEY(0), &Pref))
762         {
763                 if (Pref->Type == NULL) {
764                         StrBufAppendTemplate(Target, TP, Pref->Val, 1);
765                 }
766                 switch (Pref->Type->Type)
767                 {
768                 case PRF_STRING:
769                         StrBufAppendTemplate(Target, TP, Pref->Val, 1);
770                         break;
771                 case PRF_INT:
772                         if (Pref->decoded != 1) {
773                                 if (Pref->Val == NULL)
774                                         Pref->Val = NewStrBufPlain(NULL, 64);
775                                 StrBufPrintf(Pref->Val, "%ld", Pref->lval);
776                                 Pref->decoded = 1;
777                         }
778                         StrBufAppendTemplate(Target, TP, Pref->Val, 1);
779                         break;
780                 case PRF_QP_STRING:
781                         if (Pref->decoded != 1) {
782                                 if (Pref->DeQPed == NULL)
783                                         Pref->DeQPed = NewStrBufPlain(NULL, StrLength(Pref->Val));
784                                         
785                                 StrBufEUid_unescapize(Pref->DeQPed, Pref->Val);
786                                 Pref->decoded = 1;
787                         }
788                         StrBufAppendTemplate(Target, TP, Pref->DeQPed, 1);
789                         break;
790                 case PRF_YESNO:
791                         if (Pref->decoded != 1) {
792                                 Pref->lval = strcmp(ChrPtr(Pref->Val), "yes") == 0;
793                                 Pref->decoded = 1;
794                         }
795                         StrBufAppendTemplate(Target, TP, Pref->Val, 1);
796                         break;
797                 }
798         }
799 }
800
801 void tmplput_CFG_Descr(StrBuf *Target, WCTemplputParams *TP)
802 {
803         const char *SettingStr;
804         SettingStr = PrefGetLocalStr(TKEY(0));
805         if (SettingStr != NULL) 
806                 StrBufAppendBufPlain(Target, SettingStr, -1, 0);
807 }
808 void tmplput_CFG_RoomValueLong(StrBuf *Target, WCTemplputParams *TP)
809 {
810         long lvalue;
811         long defval;
812
813         defval = GetTemplateTokenNumber(Target, TP, 1, 0);
814         get_ROOM_PREFS_LONG(TKEY(0), &lvalue, defval);
815         StrBufAppendPrintf(Target, "%ld", lvalue);
816 }
817 void tmplput_CFG_RoomValue(StrBuf *Target, WCTemplputParams *TP)
818 {
819         StrBuf *pref = get_ROOM_PREFS(TKEY(0));
820         if (pref != NULL) 
821                 StrBufAppendBuf(Target, pref, 0);
822 }
823 int ConditionalHasRoomPreference(StrBuf *Target, WCTemplputParams *TP) 
824 {
825         if (get_ROOM_PREFS(TP->Tokens->Params[0]->Start, 
826                            TP->Tokens->Params[0]->len) != NULL) 
827                 return 1;
828   
829         return 0;
830 }
831
832 int ConditionalPreference(StrBuf *Target, WCTemplputParams *TP)
833 {
834         StrBuf *Pref;
835
836         if (!get_PREFERENCE(TKEY(2), &Pref)) 
837                 return 0;
838         
839         if (TP->Tokens->nParameters == 3) {
840                 return 1;
841         }
842         else if (TP->Tokens->Params[3]->Type == TYPE_STR)
843                 return ((TP->Tokens->Params[3]->len == StrLength(Pref)) &&
844                         (strcmp(TP->Tokens->Params[3]->Start, ChrPtr(Pref)) == 0));
845         else 
846                 return (StrTol(Pref) == TP->Tokens->Params[3]->lvalue);
847 }
848
849 int ConditionalHasPreference(StrBuf *Target, WCTemplputParams *TP)
850 {
851         StrBuf *Pref;
852
853         if (!get_PREFERENCE(TKEY(2), &Pref) || 
854             (Pref == NULL)) 
855                 return 0;
856         else 
857                 return 1;
858 }
859
860
861 /********************************************************************************
862  *                 preferences stored discrete in citserver
863  ********************************************************************************/
864 HashList *GetGVEAHash(StrBuf *Target, WCTemplputParams *TP)
865 {
866         StrBuf *Rcp;
867         HashList *List = NULL;
868         int Done = 0;
869         int i, n = 1;
870         char N[64];
871
872         Rcp = NewStrBuf();
873         serv_puts("GVEA");
874         StrBuf_ServGetln(Rcp);
875         if (GetServerStatus(Rcp, NULL) == 1) {
876                 FlushStrBuf(Rcp);
877                 List = NewHash(1, NULL);
878                 while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
879                         if ( (StrLength(Rcp)==3) && 
880                              !strcmp(ChrPtr(Rcp), "000")) 
881                         {
882                                 Done = 1;
883                         }
884                         else {
885                                 i = snprintf(N, sizeof(N), "%d", n);
886                                 StrBufTrim(Rcp);
887                                 Put(List, N, i, Rcp, HFreeStrBuf);
888                                 Rcp = NewStrBuf();
889                         }
890                         n++;
891                 }
892         }
893         FreeStrBuf(&Rcp);
894         return List;
895 }
896 void DeleteGVEAHash(HashList **KillMe)
897 {
898         DeleteHash(KillMe);
899 }
900
901 HashList *GetGVSNHash(StrBuf *Target, WCTemplputParams *TP)
902 {
903         StrBuf *Rcp;
904         HashList *List = NULL;
905         int Done = 0;
906         int i, n = 1;
907         char N[64];
908
909         Rcp = NewStrBuf();
910         serv_puts("GVSN");
911         StrBuf_ServGetln(Rcp);
912         if (GetServerStatus(Rcp, NULL) == 1) {
913                 FlushStrBuf(Rcp);
914                 List = NewHash(1, NULL);
915                 while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
916                         if ( (StrLength(Rcp)==3) && 
917                              !strcmp(ChrPtr(Rcp), "000")) 
918                         {
919                                 Done = 1;
920                         }
921                         else {
922                                 i = snprintf(N, sizeof(N), "%d", n);
923                                 StrBufTrim(Rcp);
924                                 Put(List, N, i, Rcp, HFreeStrBuf);
925                                 Rcp = NewStrBuf();
926                         }
927                         n++;
928                 }
929         }
930         FreeStrBuf(&Rcp);
931         return List;
932 }
933 void DeleteGVSNHash(HashList **KillMe)
934 {
935         DeleteHash(KillMe);
936 }
937
938
939
940
941 /*
942  * Offer to make any page the user's "start page."
943  */
944 void offer_start_page(StrBuf *Target, WCTemplputParams *TP)
945 {
946         wprintf("<a href=\"change_start_page?startpage=");
947         urlescputs(ChrPtr(WC->Hdr->this_page));
948         wprintf("\">");
949         wprintf(_("Make this my start page"));
950         wprintf("</a>");
951 }
952
953
954 /*
955  * Change the user's start page
956  */
957 void change_start_page(void) 
958 {
959         if (!havebstr("startpage")) {
960                 set_preference_backend(HKEY("startpage"), 
961                                        0, 
962                                        NewStrBufPlain(HKEY("")),
963                                        PRF_STRING,
964                                        1, 
965                                        NULL);
966                 safestrncpy(WC->ImportantMessage,
967                             _("You no longer have a start page selected."),
968                             sizeof( WC->ImportantMessage));
969                 display_main_menu();
970                 return;
971         }
972
973         set_preference_backend(HKEY("startpage"), 
974                                0, 
975                                NewStrBufDup(sbstr("startpage")),
976                                PRF_STRING,
977                                1, 
978                                NULL);
979
980         output_headers(1, 1, 0, 0, 0, 0);
981         do_template("newstartpage", NULL);
982         wDumpContent(1);
983 }
984
985
986 void LoadStartpage(StrBuf *URL, long lvalue)
987 {
988         const char *pch;
989         pch = strchr(ChrPtr(URL), '?');
990         if (pch == NULL) {
991                 /* purge the sins of the past... */
992                 pch = strchr(ChrPtr(URL), '&');
993                 if (pch != NULL) {
994                         StrBufPeek(URL, pch, -1, '?');
995                         WC->SavePrefsToServer = 1;
996                 }
997         }
998 }
999
1000
1001 void 
1002 InitModule_PREFERENCES
1003 (void)
1004 {
1005         WebcitAddUrlHandler(HKEY("set_preferences"), set_preferences, 0);
1006         WebcitAddUrlHandler(HKEY("change_start_page"), change_start_page, 0);
1007
1008         RegisterPreference("startpage", _("Prefered startpage"), PRF_STRING, LoadStartpage);
1009
1010         RegisterNamespace("OFFERSTARTPAGE", 0, 0, offer_start_page, NULL, CTX_NONE);
1011         RegisterNamespace("PREF:ROOM:VALUE", 1, 2, tmplput_CFG_RoomValue,  NULL, CTX_NONE);
1012         RegisterNamespace("PREF:ROOM:VALUE:INT", 1, 2, tmplput_CFG_RoomValueLong,  NULL, CTX_NONE);
1013         RegisterNamespace("PREF:VALUE", 1, 2, tmplput_CFG_Value, NULL, CTX_NONE);
1014         
1015         RegisterNamespace("PREF:DESCR", 1, 1, tmplput_CFG_Descr, NULL, CTX_NONE);
1016
1017         RegisterConditional(HKEY("COND:PREF"), 4, ConditionalPreference, CTX_NONE);
1018         RegisterConditional(HKEY("COND:PREF:SET"), 4, ConditionalHasPreference, CTX_NONE);
1019         RegisterConditional(HKEY("COND:ROOM:SET"), 4, ConditionalHasRoomPreference, CTX_NONE);
1020         
1021         RegisterIterator("PREF:VALID:EMAIL:ADDR", 0, NULL, 
1022                          GetGVEAHash, NULL, DeleteGVEAHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
1023         RegisterIterator("PREF:VALID:EMAIL:NAME", 0, NULL, 
1024                          GetGVSNHash, NULL, DeleteGVSNHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
1025
1026 }
1027
1028
1029 void 
1030 ServerStartModule_PREFERENCES
1031 (void)
1032 {
1033         PreferenceHooks = NewHash(1, NULL);
1034 }
1035
1036
1037
1038 void 
1039 ServerShutdownModule_PREFERENCES
1040 (void)
1041 {
1042         DeleteHash(&PreferenceHooks);
1043 }
1044
1045 void
1046 SessionDetachModule__PREFERENCES
1047 (wcsession *sess)
1048 {
1049         if (sess->SavePrefsToServer) {
1050                 save_preferences();
1051                 sess->SavePrefsToServer = 0;
1052         }
1053 }
1054
1055 void
1056 SessionNewModule_PREFERENCES
1057 (wcsession *sess)
1058 {
1059         sess->hash_prefs = NewHash(1,NULL);
1060 }
1061
1062 void 
1063 SessionDestroyModule_PREFERENCES
1064 (wcsession *sess)
1065 {
1066         DeleteHash(&sess->hash_prefs);
1067 }
1068
1069
1070
1071 /*@}*/