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