+long compare_preference(const Preference *PrefA, const Preference *PrefB)
+{
+ ePrefType TypeA, TypeB;
+
+ if (PrefA->Type != NULL) {
+ TypeA = PrefA->Type->eType;
+ }
+ else {
+ TypeA = PrefA->eFlatPrefType;
+ }
+
+ if (PrefB->Type != NULL) {
+ TypeB = PrefB->Type->eType;
+ }
+ else {
+ TypeB = PrefB->eFlatPrefType;
+ }
+
+ if ( (TypeA != PRF_UNSET)
+ && (TypeB != PRF_UNSET)
+ && (TypeA != TypeB)
+ ) {
+ if (TypeA > TypeB) {
+ return 1;
+ }
+ else { /* (PrefA->Type < PrefB->Type) */
+ return -1;
+ }
+ }
+
+ if (TypeB == PRF_UNSET) {
+ TypeA = PRF_UNSET;
+ }
+
+ switch (TypeA)
+ {
+ default:
+ case PRF_UNSET:
+ case PRF_STRING:
+ return strcmp(ChrPtr(PrefA->Val), ChrPtr(PrefB->Val));
+ case PRF_YESNO:
+ case PRF_INT:
+ if (PrefA->lval == PrefB->lval)
+ return 0;
+ else if (PrefA->lval > PrefB->lval)
+ return 1;
+ else
+ return -1;
+ case PRF_QP_STRING:
+ return strcmp(ChrPtr(PrefA->DeQPed),
+ ChrPtr(PrefB->DeQPed));
+ }
+}
+
+
+/*
+ * Write a key into the webcit preferences database for this user
+ *
+ * key key which value is to be modified
+ * keylen length of the key string
+ * value value to set
+ * save_to_server 1 = flush all data to the server, 0 = cache it for now
+ */
+void set_preference_backend(const char *key, size_t keylen,
+ long lvalue,
+ StrBuf *value,
+ long lPrefType,
+ int save_to_server,
+ PrefDef *PrefType)
+{
+ wcsession *WCC = WC;
+ void *vPrefDef;
+ void *vPrefB;
+ Preference *Pref;
+
+ Pref = (Preference*) malloc(sizeof(Preference));
+ memset(Pref, 0, sizeof(Preference));
+ Pref->Key = NewStrBufPlain(key, keylen);
+
+ if ((PrefType == NULL) &&
+ GetHash(PreferenceHooks, SKEY(Pref->Key), &vPrefDef) &&
+ (vPrefDef != NULL))
+ PrefType = (PrefDef*) vPrefDef;
+
+ if (PrefType != NULL)
+ {
+ Pref->Type = PrefType;
+ Pref->eFlatPrefType = PrefType->eType;
+ if (Pref->Type->eType != lPrefType)
+ syslog(LOG_WARNING, "warning: saving preference with wrong type [%s] %d != %ld \n",
+ key, Pref->Type->eType, lPrefType);
+ switch (Pref->Type->eType)
+ {
+ case PRF_UNSET: /* default to string... */
+ case PRF_STRING:
+ Pref->Val = value;
+ Pref->decoded = 1;
+ break;
+ case PRF_INT:
+ Pref->lval = lvalue;
+ Pref->Val = value;
+ if (Pref->Val == NULL)
+ Pref->Val = NewStrBufPlain(NULL, 64);
+ StrBufPrintf(Pref->Val, "%ld", lvalue);
+ Pref->decoded = 1;
+ break;
+ case PRF_QP_STRING:
+ Pref->DeQPed = value;
+ Pref->Val = NewStrBufPlain(NULL, StrLength(Pref->DeQPed) * 3);
+ StrBufEUid_escapize(Pref->Val, Pref->DeQPed);
+ Pref->decoded = 1;
+ break;
+ case PRF_YESNO:
+ Pref->lval = lvalue;
+ if (lvalue)
+ Pref->Val = NewStrBufPlain(HKEY("yes"));
+ else
+ Pref->Val = NewStrBufPlain(HKEY("no"));
+ Pref->decoded = 1;
+ break;
+ }
+ if (Pref->Type->OnLoad != NULL)
+ Pref->Type->OnLoad(Pref->Val, Pref->lval);
+ }
+ else {
+ Pref->eFlatPrefType = lPrefType;
+ switch (lPrefType)
+ {
+ case PRF_STRING:
+ Pref->Val = value;
+ Pref->decoded = 1;
+ break;
+ case PRF_INT:
+ Pref->lval = lvalue;
+ Pref->Val = value;
+ if (Pref->Val == NULL)
+ Pref->Val = NewStrBufPlain(NULL, 64);
+ StrBufPrintf(Pref->Val, "%ld", lvalue);
+ Pref->decoded = 1;
+ break;
+ case PRF_QP_STRING:
+ Pref->DeQPed = value;
+ Pref->Val = NewStrBufPlain(NULL, StrLength(Pref->DeQPed) * 3);
+ StrBufEUid_escapize(Pref->Val, Pref->DeQPed);
+ Pref->decoded = 1;
+ break;
+ case PRF_YESNO:
+ Pref->lval = lvalue;
+ if (lvalue)
+ Pref->Val = NewStrBufPlain(HKEY("yes"));
+ else
+ Pref->Val = NewStrBufPlain(HKEY("no"));
+ Pref->decoded = 1;
+ break;
+ }
+ }
+
+ if ((save_to_server != 0) &&
+ GetHash(WCC->hash_prefs, key, keylen, &vPrefB) &&
+ (vPrefB != NULL) &&
+ (compare_preference (Pref, vPrefB) == 0))
+ save_to_server = 0;
+
+ Put(WCC->hash_prefs, key, keylen, Pref, DestroyPreference);
+
+ if (save_to_server) WCC->SavePrefsToServer = 1;
+}
+
+void set_PREFERENCE(const char *key, size_t keylen, StrBuf *value, int save_to_server)
+{
+ set_preference_backend(key, keylen, 0, value, PRF_STRING, save_to_server, NULL);
+}
+
+int get_PREF_LONG(const char *key, size_t keylen, long *value, long Default)
+{
+ Preference *Pref;
+ int Ret;
+
+ Ret = get_pref_backend(key, keylen, &Pref);
+ if (Ret == 0) {
+ *value = Default;
+ return 0;
+ }
+
+ if (Pref->decoded)
+ *value = Pref->lval;
+ else {
+ *value = Pref->lval = atol(ChrPtr(Pref->Val));
+ Pref->decoded = 1;
+ }
+ return Ret;
+}
+
+
+void set_PREF_LONG(const char *key, size_t keylen, long value, int save_to_server)
+{
+ set_preference_backend(key, keylen, value, NULL, PRF_INT, save_to_server, NULL);
+}
+
+int get_PREF_YESNO(const char *key, size_t keylen, int *value, int Default)
+{
+ Preference *Pref;
+ int Ret;
+
+ Ret = get_pref_backend(key, keylen, &Pref);
+ if (Ret == 0) {
+ *value = Default;
+ return 0;
+ }
+
+ if (Pref->decoded)
+ *value = Pref->lval;
+ else {
+ *value = Pref->lval = strcmp(ChrPtr(Pref->Val), "yes") == 0;
+ Pref->decoded = 1;
+ }
+ return Ret;
+}
+
+void set_PREF_YESNO(const char *key, size_t keylen, long value, int save_to_server)
+{
+ set_preference_backend(key, keylen, value, NULL, PRF_YESNO, save_to_server, NULL);
+}
+
+int get_room_prefs_backend(const char *key, size_t keylen,
+ Preference **Pref)
+{
+ StrBuf *pref_name;
+ int Ret;
+
+ pref_name = NewStrBufPlain (HKEY("ROOM:"));
+ StrBufAppendBuf(pref_name, WC->CurRoom.name, 0);
+ StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
+ StrBufAppendBufPlain(pref_name, key, keylen, 0);
+ Ret = get_pref_backend(SKEY(pref_name), Pref);
+ FreeStrBuf(&pref_name);
+
+ return Ret;
+}
+
+const StrBuf *get_X_PREFS(const char *key, size_t keylen,
+ const char *xkey, size_t xkeylen)
+{
+ int ret;
+ StrBuf *pref_name;
+ Preference *Prf;