4 * Manage user preferences with a little help from the Citadel server.
12 HashList
*PreferenceHooks
;
14 typedef struct _PrefDef
{
21 typedef struct _Preference
{
31 void DestroyPrefDef(void *vPrefDef
)
33 PrefDef
*Prefdef
= (PrefDef
*) vPrefDef
;
34 FreeStrBuf(&Prefdef
->Setting
);
38 void DestroyPreference(void *vPref
)
40 Preference
*Pref
= (Preference
*) vPref
;
41 FreeStrBuf(&Pref
->Key
);
42 FreeStrBuf(&Pref
->Val
);
43 FreeStrBuf(&Pref
->DeQPed
);
47 void RegisterPreference(const char *Setting
, long SettingLen
,
52 PrefDef
*Newpref
= (PrefDef
*) malloc(sizeof(PrefDef
));
53 Newpref
->Setting
= NewStrBufPlain(Setting
, SettingLen
);
54 Newpref
->PrefStr
= PrefStr
;
56 Newpref
->OnLoad
= OnLoad
;
57 Put(PreferenceHooks
, Setting
, SettingLen
, Newpref
, DestroyPrefDef
);
60 const char *PrefGetLocalStr(const char *Setting
, long len
)
63 if (GetHash(PreferenceHooks
, Setting
, len
, &hash_value
) != 0) {
64 PrefDef
*Newpref
= (PrefDef
*) hash_value
;
65 return _(Newpref
->PrefStr
);
72 inline const char *PrintPref(void *vPref
)
74 Preference
*Pref
= (Preference
*) vPref
;
75 if (Pref
->DeQPed
!= NULL
)
76 return ChrPtr(Pref
->DeQPed
);
78 return ChrPtr(Pref
->Val
);
82 void GetPrefTypes(HashList
*List
)
92 It
= GetNewHashPos(List
, 0);
93 while (GetNextHashPos(List
, It
, &len
, &Key
, &vSetting
))
95 Setting
= (Preference
*) vSetting
;
96 if (GetHash(PreferenceHooks
, SKEY(Setting
->Key
), &vPrefDef
) &&
99 PrefType
= (PrefDef
*) vPrefDef
;
100 Setting
->Type
= PrefType
;
101 if (PrefType
->OnLoad
!= NULL
)
102 PrefType
->OnLoad(Setting
->Val
, Setting
->lval
);
108 void ParsePref(HashList
**List
, StrBuf
*ReadBuf
)
111 Preference
*Data
= NULL
;
112 Preference
*LastData
= NULL
;
115 while (StrBuf_ServGetln(ReadBuf
),
116 strcmp(ChrPtr(ReadBuf
), "000"))
118 if ((ChrPtr(ReadBuf
)[0] == ' ') &&
120 StrBufAppendBuf(Data
->Val
, ReadBuf
, 1);
123 LastData
= Data
= malloc(sizeof(Preference
));
124 memset(Data
, 0, sizeof(Preference
));
125 Data
->Key
= NewStrBuf();
126 Data
->Val
= NewStrBuf();
127 StrBufExtract_token(Data
->Key
, ReadBuf
, 0, '|');
128 StrBufExtract_token(Data
->Val
, ReadBuf
, 1, '|');
129 if (!IsEmptyStr(ChrPtr(Data
->Key
)))
139 lprintf(1, "ignoring spurious preference line: [%s]\n",
141 DestroyPreference(Data
);
151 * display preferences dialog
153 void load_preferences(void)
159 if (goto_config_room() != 0) return; /* oh well. */
161 ReadBuf
= NewStrBuf();
162 serv_puts("MSGS ALL|0|1");
163 StrBuf_ServGetln(ReadBuf
);
164 if (GetServerStatus(ReadBuf
, NULL
) == 8) {
165 serv_puts("subj|__ WebCit Preferences __");
168 while (serv_getln(buf
, sizeof buf
), strcmp(buf
, "000")) {
173 serv_printf("MSG0 %ld", msgnum
);
174 StrBuf_ServGetln(ReadBuf
);
175 if (GetServerStatus(ReadBuf
, NULL
) == 1) {
176 while (StrBuf_ServGetln(ReadBuf
),
177 (strcmp(ChrPtr(ReadBuf
), "text") &&
178 strcmp(ChrPtr(ReadBuf
), "000"))) {
180 if (!strcmp(ChrPtr(ReadBuf
), "text")) {
181 ParsePref(&WC
->hash_prefs
, ReadBuf
);
186 /* Go back to the room we're supposed to be in */
187 serv_printf("GOTO %s", ChrPtr(WC
->wc_roomname
));
188 StrBuf_ServGetln(ReadBuf
);
189 GetServerStatus(ReadBuf
, NULL
);
190 FreeStrBuf(&ReadBuf
);
194 * \brief Goto the user's configuration room, creating it if necessary.
195 * \return 0 on success or nonzero upon failure.
197 int goto_config_room(void) {
200 serv_printf("GOTO %s", USERCONFIGROOM
);
201 serv_getln(buf
, sizeof buf
);
202 if (buf
[0] != '2') { /* try to create the config room if not there */
203 serv_printf("CRE8 1|%s|4|0", USERCONFIGROOM
);
204 serv_getln(buf
, sizeof buf
);
205 serv_printf("GOTO %s", USERCONFIGROOM
);
206 serv_getln(buf
, sizeof buf
);
207 if (buf
[0] != '2') return(1);
212 void WritePrefsToServer(HashList
*Hash
)
219 StrBuf
*SubBuf
= NULL
;
221 Hash
= WC
->hash_prefs
;
222 #ifdef DBG_PREFS_HASH
223 dbg_PrintHash(Hash
, PrintPref
, NULL
);
225 HashPos
= GetNewHashPos(Hash
, 0);
226 while (GetNextHashPos(Hash
, HashPos
, &len
, &Key
, &vPref
)!=0)
231 Pref
= (Preference
*) vPref
;
232 nchars
= StrLength(Pref
->Val
);
235 size_t offset
, nchars
;
237 SubBuf
= NewStrBuf();
246 nchars
= StrBufSub(SubBuf
, Pref
->Val
, offset
, nchars
);
249 serv_printf("%s|%s", ChrPtr(Pref
->Key
), ChrPtr(SubBuf
));
251 serv_printf(" %s", ChrPtr(SubBuf
));
254 nchars
= StrLength(Pref
->Val
) - offset
;
260 serv_printf("%s|%s", ChrPtr(Pref
->Key
), ChrPtr(Pref
->Val
));
264 DeleteHashPos(&HashPos
);
268 * \brief save the modifications
270 void save_preferences(void)
275 if (goto_config_room() != 0) return; /* oh well. */
276 serv_puts("MSGS ALL|0|1");
277 serv_getln(buf
, sizeof buf
);
279 serv_puts("subj|__ WebCit Preferences __");
282 while (serv_getln(buf
, sizeof buf
), strcmp(buf
, "000")) {
287 serv_printf("DELE %ld", msgnum
);
288 serv_getln(buf
, sizeof buf
);
291 serv_printf("ENT0 1||0|1|__ WebCit Preferences __|");
292 serv_getln(buf
, sizeof buf
);
295 WritePrefsToServer(WC
->hash_prefs
);
300 /** Go back to the room we're supposed to be in */
301 serv_printf("GOTO %s", ChrPtr(WC
->wc_roomname
));
302 serv_getln(buf
, sizeof buf
);
306 * \brief query the actual setting of key in the citadel database
307 * \param key config key to query
308 * \param keylen length of the key string
309 * \param value StrBuf-value to the key to get
312 int get_pref_backend(const char *key
, size_t keylen
, Preference
**Pref
)
314 void *hash_value
= NULL
;
315 #ifdef DBG_PREFS_HASH
316 dbg_PrintHash(WC
->hash_prefs
, PrintPref
, NULL
);
318 if (GetHash(WC
->hash_prefs
, key
, keylen
, &hash_value
) == 0) {
323 *Pref
= (Preference
*) hash_value
;
328 int get_PREFERENCE(const char *key
, size_t keylen
, StrBuf
**value
)
333 Ret
= get_pref_backend(key
, keylen
, &Pref
);
342 * \brief Write a key into the webcit preferences database for this user
344 * \params key key whichs value is to be modified
345 * \param keylen length of the key string
346 * \param value value to set
347 * \param save_to_server 1 = flush all data to the server, 0 = cache it for now
349 void set_preference_backend(const char *key
, size_t keylen
,
359 Pref
= (Preference
*) malloc(sizeof(Preference
));
360 memset(Pref
, 0, sizeof(Preference
));
361 Pref
->Key
= NewStrBufPlain(key
, keylen
);
363 if ((PrefType
== NULL
) &&
364 GetHash(PreferenceHooks
, SKEY(Pref
->Key
), &vPrefDef
) &&
366 PrefType
= (PrefDef
*) vPrefDef
;
368 if (PrefType
!= NULL
)
370 Pref
->Type
= PrefType
;
371 if (Pref
->Type
->Type
!= lPrefType
)
372 lprintf(1, "warning: saving preference with wrong type [%s] %ld != %ld \n",
373 key
, Pref
->Type
->Type
, lPrefType
);
374 switch (Pref
->Type
->Type
)
383 if (Pref
->Val
== NULL
)
384 Pref
->Val
= NewStrBufPlain(NULL
, 64);
385 StrBufPrintf(Pref
->Val
, "%ld", lvalue
);
389 Pref
->DeQPed
= value
;
390 Pref
->Val
= NewStrBufPlain(NULL
, StrLength(Pref
->DeQPed
) * 3);
391 StrBufEUid_escapize(Pref
->Val
, Pref
->DeQPed
);
397 Pref
->Val
= NewStrBufPlain(HKEY("yes"));
399 Pref
->Val
= NewStrBufPlain(HKEY("no"));
403 if (Pref
->Type
->OnLoad
!= NULL
)
404 Pref
->Type
->OnLoad(Pref
->Val
, Pref
->lval
);
416 if (Pref
->Val
== NULL
)
417 Pref
->Val
= NewStrBufPlain(NULL
, 64);
418 StrBufPrintf(Pref
->Val
, "%ld", lvalue
);
422 Pref
->DeQPed
= value
;
423 Pref
->Val
= NewStrBufPlain(NULL
, StrLength(Pref
->DeQPed
) * 3);
424 StrBufEUid_escapize(Pref
->Val
, Pref
->DeQPed
);
430 Pref
->Val
= NewStrBufPlain(HKEY("yes"));
432 Pref
->Val
= NewStrBufPlain(HKEY("no"));
437 Put(WC
->hash_prefs
, key
, keylen
, Pref
, DestroyPreference
);
439 if (save_to_server
) WC
->SavePrefsToServer
= 1;
442 void set_PREFERENCE(const char *key
, size_t keylen
, StrBuf
*value
, int save_to_server
)
444 set_preference_backend(key
, keylen
, 0, value
, PRF_STRING
, save_to_server
, NULL
);
447 int get_PREF_LONG(const char *key
, size_t keylen
, long *value
, long Default
)
452 Ret
= get_pref_backend(key
, keylen
, &Pref
);
461 *value
= Pref
->lval
= atol(ChrPtr(Pref
->Val
));
468 void set_PREF_LONG(const char *key
, size_t keylen
, long value
, int save_to_server
)
470 set_preference_backend(key
, keylen
, value
, NULL
, PRF_INT
, save_to_server
, NULL
);
473 int get_PREF_YESNO(const char *key
, size_t keylen
, int *value
, int Default
)
478 Ret
= get_pref_backend(key
, keylen
, &Pref
);
487 *value
= Pref
->lval
= strcmp(ChrPtr(Pref
->Val
), "yes") == 0;
493 void set_PREF_YESNO(const char *key
, size_t keylen
, long value
, int save_to_server
)
495 set_preference_backend(key
, keylen
, value
, NULL
, PRF_YESNO
, save_to_server
, NULL
);
498 int get_room_prefs_backend(const char *key
, size_t keylen
,
504 pref_name
= NewStrBufPlain (HKEY("ROOM:"));
505 StrBufAppendBuf(pref_name
, WC
->wc_roomname
, 0);
506 StrBufAppendBufPlain(pref_name
, HKEY(":"), 0);
507 StrBufAppendBufPlain(pref_name
, key
, keylen
, 0);
508 Ret
= get_pref_backend(SKEY(pref_name
), Pref
);
509 FreeStrBuf(&pref_name
);
514 const StrBuf
*get_X_PREFS(const char *key
, size_t keylen
,
515 const char *xkey
, size_t xkeylen
)
521 pref_name
= NewStrBufPlain (HKEY("XPREF:"));
522 StrBufAppendBufPlain(pref_name
, xkey
, xkeylen
, 0);
523 StrBufAppendBufPlain(pref_name
, HKEY(":"), 0);
524 StrBufAppendBufPlain(pref_name
, key
, keylen
, 0);
526 ret
= get_pref_backend(SKEY(pref_name
), &Prf
);
527 FreeStrBuf(&pref_name
);
534 void set_X_PREFS(const char *key
, size_t keylen
, const char *xkey
, size_t xkeylen
, StrBuf
*value
, int save_to_server
)
538 pref_name
= NewStrBufPlain (HKEY("XPREF:"));
539 StrBufAppendBufPlain(pref_name
, xkey
, xkeylen
, 0);
540 StrBufAppendBufPlain(pref_name
, HKEY(":"), 0);
541 StrBufAppendBufPlain(pref_name
, key
, keylen
, 0);
543 set_preference_backend(SKEY(pref_name
), 0, value
, PRF_STRING
, save_to_server
, NULL
);
544 FreeStrBuf(&pref_name
);
548 StrBuf
*get_ROOM_PREFS(const char *key
, size_t keylen
)
553 Ret
= get_room_prefs_backend(key
, keylen
, &Pref
);
562 void set_ROOM_PREFS(const char *key
, size_t keylen
, StrBuf
*value
, int save_to_server
)
566 pref_name
= NewStrBufPlain (HKEY("ROOM:"));
567 StrBufAppendBuf(pref_name
, WC
->wc_roomname
, 0);
568 StrBufAppendBufPlain(pref_name
, HKEY(":"), 0);
569 StrBufAppendBufPlain(pref_name
, key
, keylen
, 0);
570 set_preference_backend(SKEY(pref_name
), 0, value
, PRF_STRING
, save_to_server
, NULL
);
571 FreeStrBuf(&pref_name
);
575 void GetPreferences(HashList
*Setting
)
587 Tmp
= WCC
->hash_prefs
;
588 WCC
->hash_prefs
= Setting
;
590 It
= GetNewHashPos(PreferenceHooks
, 0);
591 while (GetNextHashPos(PreferenceHooks
, It
, &len
, &Key
, &vSetting
)) {
592 PrefType
= (PrefDef
*) vSetting
;
594 if (!HaveBstr(SKEY(PrefType
->Setting
)))
596 switch (PrefType
->Type
) {
598 Buf
= NewStrBufDup(SBstr(SKEY(PrefType
->Setting
)));
599 set_preference_backend(SKEY(PrefType
->Setting
),
607 lval
= LBstr(SKEY(PrefType
->Setting
));
608 set_preference_backend(SKEY(PrefType
->Setting
),
616 Buf
= NewStrBufDup(SBstr(SKEY(PrefType
->Setting
)));
617 set_preference_backend(SKEY(PrefType
->Setting
),
625 lval
= YesBstr(SKEY(PrefType
->Setting
));
626 set_preference_backend(SKEY(PrefType
->Setting
),
635 WCC
->hash_prefs
= Tmp
;
640 * \brief Commit new preferences and settings
642 void set_preferences(void)
644 if (!havebstr("change_button")) {
645 safestrncpy(WC
->ImportantMessage
,
646 _("Cancelled. No settings were changed."),
647 sizeof WC
->ImportantMessage
);
651 GetPreferences(WC
->hash_prefs
);
656 void tmplput_CFG_Value(StrBuf
*Target
, WCTemplputParams
*TP
)
659 if (get_pref_backend(TKEY(0), &Pref
))
661 if (Pref
->Type
== NULL
) {
662 StrBufAppendTemplate(Target
, TP
, Pref
->Val
, 1);
664 switch (Pref
->Type
->Type
)
667 StrBufAppendTemplate(Target
, TP
, Pref
->Val
, 1);
670 if (Pref
->decoded
!= 1) {
671 if (Pref
->Val
== NULL
)
672 Pref
->Val
= NewStrBufPlain(NULL
, 64);
673 StrBufPrintf(Pref
->Val
, "%ld", Pref
->lval
);
676 StrBufAppendTemplate(Target
, TP
, Pref
->Val
, 1);
679 if (Pref
->decoded
!= 1) {
680 if (Pref
->DeQPed
== NULL
)
681 Pref
->DeQPed
= NewStrBufPlain(NULL
, StrLength(Pref
->Val
));
683 StrBufEUid_unescapize(Pref
->DeQPed
, Pref
->Val
);
686 StrBufAppendTemplate(Target
, TP
, Pref
->DeQPed
, 1);
689 if (Pref
->decoded
!= 1) {
690 Pref
->lval
= strcmp(ChrPtr(Pref
->Val
), "yes") == 0;
693 StrBufAppendTemplate(Target
, TP
, Pref
->Val
, 1);
699 void tmplput_CFG_Descr(StrBuf
*Target
, WCTemplputParams
*TP
)
701 const char *SettingStr
;
702 SettingStr
= PrefGetLocalStr(TKEY(0));
703 if (SettingStr
!= NULL
)
704 StrBufAppendBufPlain(Target
, SettingStr
, -1, 0);
706 void tmplput_CFG_RoomValue(StrBuf
*Target
, WCTemplputParams
*TP
)
708 StrBuf
*pref
= get_ROOM_PREFS(TKEY(0));
710 StrBufAppendBuf(Target
, pref
, 0);
712 int ConditionalHasRoomPreference(StrBuf
*Target
, WCTemplputParams
*TP
)
714 if (get_ROOM_PREFS(TP
->Tokens
->Params
[0]->Start
,
715 TP
->Tokens
->Params
[0]->len
) != NULL
)
720 void CfgZoneTempl(StrBuf
*TemplBuffer
, WCTemplputParams
*TP
)
722 StrBuf
*Zone
= (StrBuf
*) CTX
;
724 SVPutBuf("ZONENAME", Zone
, 1);
727 int ConditionalPreference(StrBuf
*Target
, WCTemplputParams
*TP
)
731 if (!get_PREFERENCE(TKEY(2), &Pref
))
734 if (TP
->Tokens
->nParameters
== 3) {
737 else if (TP
->Tokens
->Params
[3]->Type
== TYPE_STR
)
738 return ((TP
->Tokens
->Params
[3]->len
== StrLength(Pref
)) &&
739 (strcmp(TP
->Tokens
->Params
[3]->Start
, ChrPtr(Pref
)) == 0));
741 return (StrTol(Pref
) == TP
->Tokens
->Params
[3]->lvalue
);
744 int ConditionalHasPreference(StrBuf
*Target
, WCTemplputParams
*TP
)
748 if (!get_PREFERENCE(TKEY(2), &Pref
) ||
756 /********************************************************************************
757 * preferences stored discrete in citserver
758 ********************************************************************************/
759 HashList
*GetGVEAHash(StrBuf
*Target
, WCTemplputParams
*TP
)
762 HashList
*List
= NULL
;
769 StrBuf_ServGetln(Rcp
);
770 if (GetServerStatus(Rcp
, NULL
) == 1) {
772 List
= NewHash(1, NULL
);
773 while (!Done
&& (StrBuf_ServGetln(Rcp
)>=0)) {
774 if ( (StrLength(Rcp
)==3) &&
775 !strcmp(ChrPtr(Rcp
), "000"))
780 i
= snprintf(N
, sizeof(N
), "%d", n
);
782 Put(List
, N
, i
, Rcp
, HFreeStrBuf
);
791 void DeleteGVEAHash(HashList
**KillMe
)
796 HashList
*GetGVSNHash(StrBuf
*Target
, WCTemplputParams
*TP
)
799 HashList
*List
= NULL
;
806 StrBuf_ServGetln(Rcp
);
807 if (GetServerStatus(Rcp
, NULL
) == 1) {
809 List
= NewHash(1, NULL
);
810 while (!Done
&& (StrBuf_ServGetln(Rcp
)>=0)) {
811 if ( (StrLength(Rcp
)==3) &&
812 !strcmp(ChrPtr(Rcp
), "000"))
817 i
= snprintf(N
, sizeof(N
), "%d", n
);
819 Put(List
, N
, i
, Rcp
, HFreeStrBuf
);
828 void DeleteGVSNHash(HashList
**KillMe
)
837 * Offer to make any page the user's "start page."
839 void offer_start_page(StrBuf
*Target
, WCTemplputParams
*TP
)
841 wprintf("<a href=\"change_start_page?startpage=");
842 urlescputs(ChrPtr(WC
->this_page
));
844 wprintf(_("Make this my start page"));
847 wprintf("<br/><a href=\"rss?room=");
848 urlescputs(ChrPtr(WC
->wc_roomname
));
849 wprintf("\" title=\"RSS 2.0 feed for ");
850 escputs(ChrPtr(WC
->wc_roomname
));
851 wprintf("\"><img alt=\"RSS\" border=\"0\" src=\"static/xml_button.gif\"/></a>\n");
857 * Change the user's start page
859 void change_start_page(void)
861 if (!havebstr("startpage")) {
862 set_preference_backend(HKEY("startpage"),
864 NewStrBufPlain(HKEY("")),
868 safestrncpy(WC
->ImportantMessage
,
869 _("You no longer have a start page selected."),
870 sizeof( WC
->ImportantMessage
));
875 set_preference_backend(HKEY("startpage"),
877 NewStrBufDup(sbstr("startpage")),
882 output_headers(1, 1, 0, 0, 0, 0);
883 do_template("newstartpage", NULL
);
889 InitModule_PREFERENCES
892 WebcitAddUrlHandler(HKEY("set_preferences"), set_preferences
, 0);
893 WebcitAddUrlHandler(HKEY("change_start_page"), change_start_page
, 0);
896 RegisterNamespace("OFFERSTARTPAGE", 0, 0, offer_start_page
, CTX_NONE
);
897 RegisterNamespace("PREF:ROOM:VALUE", 1, 2, tmplput_CFG_RoomValue
, CTX_NONE
);
898 RegisterNamespace("PREF:VALUE", 1, 2, tmplput_CFG_Value
, CTX_NONE
);
899 RegisterNamespace("PREF:DESCR", 1, 1, tmplput_CFG_Descr
, CTX_NONE
);
900 RegisterIterator("PREF:ZONE", 0, ZoneHash
, NULL
, CfgZoneTempl
, NULL
, CTX_PREF
, CTX_NONE
, IT_NOFLAG
);
902 RegisterConditional(HKEY("COND:PREF"), 4, ConditionalPreference
, CTX_NONE
);
903 RegisterConditional(HKEY("COND:PREF:SET"), 4, ConditionalHasPreference
, CTX_NONE
);
904 RegisterConditional(HKEY("COND:ROOM:SET"), 4, ConditionalHasRoomPreference
, CTX_NONE
);
906 RegisterIterator("PREF:VALID:EMAIL:ADDR", 0, NULL
,
907 GetGVEAHash
, NULL
, DeleteGVEAHash
, CTX_STRBUF
, CTX_NONE
, IT_NOFLAG
);
908 RegisterIterator("PREF:VALID:EMAIL:NAME", 0, NULL
,
909 GetGVSNHash
, NULL
, DeleteGVSNHash
, CTX_STRBUF
, CTX_NONE
, IT_NOFLAG
);