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