Back to index

webcit  8.12-dfsg
preferences.c
Go to the documentation of this file.
00001 /*
00002  * Manage user preferences with a little help from the Citadel server.
00003  *
00004  * Copyright (c) 1996-2012 by the citadel.org team
00005  *
00006  * This program is open source software.  You can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License, version 3.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include "webcit.h"
00016 #include "webserver.h"
00017 #include "dav.h"
00018 
00019 HashList *PreferenceHooks;
00020 extern HashList *HandlerHash;
00021 
00022 typedef struct _PrefDef {
00023        ePrefType eType;
00024        StrBuf *Setting;
00025        const char *PrefStr;
00026        PrefEvalFunc OnLoad;
00027        StrBuf *OnLoadName;
00028 } PrefDef;
00029 
00030 typedef struct _Preference {
00031        PrefDef *Type;
00032        ePrefType eFlatPrefType;
00033 
00034        StrBuf *Key;
00035        StrBuf *Val;
00036 
00037        long lval;
00038        long decoded;
00039        StrBuf *DeQPed;
00040 } Preference;
00041 
00042 void DestroyPrefDef(void *vPrefDef)
00043 {
00044        PrefDef *Prefdef = (PrefDef*) vPrefDef;
00045        FreeStrBuf(&Prefdef->Setting);
00046        FreeStrBuf(&Prefdef->OnLoadName);
00047        free(Prefdef);
00048 }
00049 
00050 void DestroyPreference(void *vPref)
00051 {
00052        Preference *Pref = (Preference*) vPref;
00053        FreeStrBuf(&Pref->Key);
00054        FreeStrBuf(&Pref->Val);
00055        FreeStrBuf(&Pref->DeQPed);
00056        free(Pref);
00057 
00058 }
00059 
00060 void _RegisterPreference(const char *Setting, long SettingLen, 
00061                       const char *PrefStr, 
00062                       ePrefType Type, 
00063                       PrefEvalFunc OnLoad, 
00064                       const char *OnLoadName)
00065 {
00066        PrefDef *Newpref = (PrefDef*) malloc(sizeof(PrefDef));
00067        Newpref->Setting = NewStrBufPlain(Setting, SettingLen);
00068        Newpref->PrefStr = PrefStr;
00069        Newpref->eType = Type;
00070        Newpref->OnLoad = OnLoad;
00071        if (Newpref->OnLoad != NULL) {
00072               Newpref->OnLoadName = NewStrBufPlain(OnLoadName, -1);
00073        }
00074        else
00075               Newpref->OnLoadName = NULL;
00076        Put(PreferenceHooks, Setting, SettingLen, Newpref, DestroyPrefDef);
00077 }
00078 
00079 const char *PrefGetLocalStr(const char *Setting, long len)
00080 {
00081        void *hash_value;
00082        if (GetHash(PreferenceHooks, Setting, len, &hash_value) != 0) {
00083               PrefDef *Newpref = (PrefDef*) hash_value;
00084               return _(Newpref->PrefStr);
00085 
00086        }
00087        return "";
00088 }
00089 
00090 #ifdef DBG_PREFS_HASH
00091 inline const char *PrintPref(void *vPref)
00092 {
00093        Preference *Pref = (Preference*) vPref;
00094        if (Pref->DeQPed != NULL)
00095               return ChrPtr(Pref->DeQPed);
00096        else 
00097               return ChrPtr(Pref->Val);
00098 }
00099 #endif
00100 
00101 void GetPrefTypes(HashList *List)
00102 {
00103        HashPos *It;
00104        long len;
00105        const char *Key;
00106        void *vSetting;
00107        void *vPrefDef;
00108        Preference *Pref;
00109        PrefDef *PrefType;
00110 
00111        It = GetNewHashPos(List, 0);
00112        while (GetNextHashPos(List, It, &len, &Key, &vSetting)) 
00113        {
00114               Pref = (Preference*) vSetting;
00115               if (GetHash(PreferenceHooks, SKEY(Pref->Key), &vPrefDef) && 
00116                   (vPrefDef != NULL)) 
00117               {
00118                      PrefType = (PrefDef*) vPrefDef;
00119                      Pref->Type = PrefType;
00120                      Pref->eFlatPrefType = Pref->Type->eType;
00121 
00122                      syslog(1, "Loading [%s]with type [%d] [\"%s\"]\n",
00123                             ChrPtr(Pref->Key),
00124                             Pref->Type->eType,
00125                             ChrPtr(Pref->Val));
00126 
00127                      switch (Pref->Type->eType)
00128                      {
00129                      case PRF_UNSET: /* WHUT? */
00130                             break;
00131                      case PRF_STRING:
00132                             break;
00133                      case PRF_INT:
00134                             Pref->lval = StrTol(Pref->Val);
00135                             Pref->decoded = 1;
00136                             break;
00137                      case PRF_QP_STRING:
00138                             Pref->DeQPed = NewStrBufPlain(NULL, StrLength(Pref->Val));
00139                             StrBufEUid_unescapize(Pref->DeQPed, Pref->Val);
00140                             Pref->decoded = 1;
00141                             break;
00142                      case PRF_YESNO:
00143                             Pref->lval = strcmp(ChrPtr(Pref->Val), "yes") == 0;
00144                             Pref->decoded = 1;
00145                             break;
00146                      }
00147 
00148                      if (PrefType->OnLoad != NULL){
00149 
00150                             syslog(1, "Loading with: -> %s(\"%s\", %ld)\n",
00151                                    ChrPtr(PrefType->OnLoadName),
00152                                    ChrPtr(Pref->Val),
00153                                    Pref->lval);
00154                             PrefType->OnLoad(Pref->Val, Pref->lval);
00155                      }
00156               }
00157        }
00158        DeleteHashPos(&It);
00159 }
00160 
00161 void ParsePref(HashList **List, StrBuf *ReadBuf)
00162 {
00163        int Done = 0;
00164        Preference *Data = NULL;
00165        Preference *LastData = NULL;
00166                             
00167        while (!Done) {
00168               if (StrBuf_ServGetln(ReadBuf) < 0)
00169                      break;
00170               if ( (StrLength(ReadBuf)==3) && 
00171                    !strcmp(ChrPtr(ReadBuf), "000")) {
00172                      Done = 1;
00173                      break;
00174               }
00175 
00176               if ((ChrPtr(ReadBuf)[0] == ' ') &&
00177                   (LastData != NULL)) {
00178                      StrBufAppendBuf(LastData->Val, ReadBuf, 1);
00179               }
00180               else {
00181                      LastData = Data = malloc(sizeof(Preference));
00182                      memset(Data, 0, sizeof(Preference));
00183                      Data->Key = NewStrBuf();
00184                      Data->Val = NewStrBuf();
00185                      StrBufExtract_token(Data->Key, ReadBuf, 0, '|');
00186                      StrBufExtract_token(Data->Val, ReadBuf, 1, '|');
00187 
00188                      /***************** BEGIN VILE SLEAZY HACK ************************/
00189 
00190                      /* some users might still have this start page configured, which now breaks */
00191 
00192                      if (   (!strcasecmp(ChrPtr(Data->Key), "startpage"))
00193                             && (!strcasecmp(ChrPtr(Data->Val), "/do_template?template=summary_page"))
00194                      ) {
00195                             FreeStrBuf(&Data->Val);
00196                             Data->Val = NewStrBufPlain(HKEY("/summary"));
00197                      }
00198 
00199                      /******************* END VILE SLEAZY HACK ************************/
00200 
00201                      if (!IsEmptyStr(ChrPtr(Data->Key)))
00202                      {
00203                             Put(*List, 
00204                                 SKEY(Data->Key),
00205                                 Data, 
00206                                 DestroyPreference);
00207                      }
00208                      else 
00209                      {
00210                             StrBufTrim(ReadBuf);
00211                             syslog(1, "ignoring spurious preference line: [%s]\n", 
00212                                    ChrPtr(ReadBuf));
00213                             DestroyPreference(Data);
00214                             LastData = NULL;
00215                      }
00216                      Data = NULL;
00217               }
00218        }
00219        GetPrefTypes(*List);
00220 }
00221 
00222 
00223 /*
00224  * display preferences dialog
00225  */
00226 void load_preferences(void) 
00227 {
00228        folder Room;
00229        wcsession *WCC = WC;
00230        int Done = 0;
00231        StrBuf *ReadBuf;
00232        long msgnum = 0L;
00233        
00234        memset(&Room, 0, sizeof(folder));
00235        ReadBuf = NewStrBufPlain(NULL, SIZ * 4);
00236        if (goto_config_room(ReadBuf, &Room) != 0) {
00237               FreeStrBuf(&ReadBuf);
00238               FlushFolder(&Room);
00239 
00240               return;       /* oh well. */
00241        }
00242 
00243        serv_puts("MSGS ALL|0|1");
00244        StrBuf_ServGetln(ReadBuf);
00245        if (GetServerStatus(ReadBuf, NULL) == 8) {
00246               serv_puts("subj|__ WebCit Preferences __");
00247               serv_puts("000");
00248        }
00249        while (!Done && (StrBuf_ServGetln(ReadBuf) >= 0)) {
00250               if ( (StrLength(ReadBuf)==3) && !strcmp(ChrPtr(ReadBuf), "000")) {
00251                      Done = 1;
00252                      break;
00253               }
00254               msgnum = StrTol(ReadBuf);
00255        }
00256 
00257        if (msgnum > 0L) {
00258               serv_printf("MSG0 %ld", msgnum);
00259               StrBuf_ServGetln(ReadBuf);
00260               if (GetServerStatus(ReadBuf, NULL) == 1) {
00261                      while (       (StrBuf_ServGetln(ReadBuf) >= 0)
00262                             && (strcmp(ChrPtr(ReadBuf), "text")
00263                             && strcmp(ChrPtr(ReadBuf), "000"))
00264                      ) {
00265                             /* flush */
00266                      }
00267                      if (!strcmp(ChrPtr(ReadBuf), "text")) {
00268                             ParsePref(&WCC->hash_prefs, ReadBuf);
00269                      }
00270               }
00271        }
00272 
00273        /* Go back to the room we're supposed to be in */
00274        if (StrLength(WCC->CurRoom.name) > 0) {
00275               serv_printf("GOTO %s", ChrPtr(WCC->CurRoom.name));
00276               StrBuf_ServGetln(ReadBuf);
00277               GetServerStatus(ReadBuf, NULL);
00278        }
00279        FreeStrBuf(&ReadBuf);
00280        FlushFolder(&Room);
00281 }
00282 
00283 
00284 /*
00285  * Go to the user's configuration room, creating it if necessary.
00286  * returns 0 on success or nonzero upon failure.
00287  */
00288 int goto_config_room(StrBuf *Buf, folder *Room) 
00289 {
00290        serv_printf("GOTO %s", USERCONFIGROOM);
00291        StrBuf_ServGetln(Buf);
00292        if (GetServerStatus(Buf, NULL) != 2) {    /* try to create the config room if not there */
00293               serv_printf("CRE8 1|%s|4|0", USERCONFIGROOM);
00294               StrBuf_ServGetln(Buf);
00295               GetServerStatus(Buf, NULL);
00296 
00297               serv_printf("GOTO %s", USERCONFIGROOM);
00298               StrBuf_ServGetln(Buf);
00299               if (GetServerStatus(Buf, NULL) != 2) {
00300                      return(1);
00301               }
00302        }
00303        ParseGoto(Room, Buf);
00304        return(0);
00305 }
00306 
00307 void WritePrefsToServer(HashList *Hash)
00308 {
00309        wcsession *WCC = WC;
00310        long len;
00311        HashPos *HashPos;
00312        void *vPref;
00313        const char *Key;
00314        Preference *Pref;
00315        StrBuf *SubBuf = NULL;
00316        
00317        Hash = WCC->hash_prefs;
00318 #ifdef DBG_PREFS_HASH
00319        dbg_PrintHash(Hash, PrintPref, NULL);
00320 #endif
00321        HashPos = GetNewHashPos(Hash, 0);
00322        while (GetNextHashPos(Hash, HashPos, &len, &Key, &vPref)!=0)
00323        {
00324               size_t nchars;
00325               if (vPref == NULL)
00326                      continue;
00327               Pref = (Preference*) vPref;
00328               nchars = StrLength(Pref->Val);
00329               if (nchars > 80){
00330                      int n = 0;
00331                      size_t offset, nchars;
00332                      if (SubBuf == NULL)
00333                             SubBuf = NewStrBufPlain(NULL, SIZ);
00334                      nchars = 1;
00335                      offset = 0;
00336                      while (nchars > 0) {
00337                             if (n == 0)
00338                                    nchars = 70;
00339                             else 
00340                                    nchars = 80;
00341                             
00342                             nchars = StrBufSub(SubBuf, Pref->Val, offset, nchars);
00343                             
00344                             if (n == 0) {
00345                                    serv_printf("%s|%s", ChrPtr(Pref->Key), ChrPtr(SubBuf));
00346                             }
00347                             else {
00348                                    serv_printf(" %s", ChrPtr(SubBuf));
00349                             }
00350                             
00351                             offset += nchars;
00352                             nchars = StrLength(Pref->Val) - offset;
00353                             n++;
00354                      }
00355                      
00356               }
00357               else {
00358                      serv_printf("%s|%s", ChrPtr(Pref->Key), ChrPtr(Pref->Val));
00359               }
00360               
00361        }
00362        FreeStrBuf(&SubBuf);
00363        DeleteHashPos(&HashPos);
00364 }
00365 
00366 /*
00367  * save the modifications
00368  */
00369 void save_preferences(void) 
00370 {
00371        folder Room;
00372        wcsession *WCC = WC;
00373        int Done = 0;
00374        StrBuf *ReadBuf;
00375        long msgnum = 0L;
00376        
00377        ReadBuf = NewStrBuf();
00378        memset(&Room, 0, sizeof(folder));
00379        if (goto_config_room(ReadBuf, &Room) != 0) {
00380               FreeStrBuf(&ReadBuf);
00381               FlushFolder(&Room);
00382 
00383               return;       /* oh well. */
00384        }
00385 
00386        /* make shure the config room has the right type, else it might reject our config */
00387        if (Room.view != VIEW_BBS) {
00388               serv_printf("VIEW %d", VIEW_BBS);
00389               StrBuf_ServGetln(ReadBuf);
00390               if (GetServerStatus(ReadBuf, NULL) != 2) {
00391                      /* UPS? */
00392               }
00393               else if (goto_config_room(ReadBuf, &Room) != 0) {
00394                      FreeStrBuf(&ReadBuf);
00395                      FlushFolder(&Room);
00396                      
00397                      return;       /* oh well. */
00398               }
00399        }
00400 
00401        serv_puts("MSGS ALL|0|1");
00402        StrBuf_ServGetln(ReadBuf);
00403        if (GetServerStatus(ReadBuf, NULL) == 8) {
00404               serv_puts("subj|__ WebCit Preferences __");
00405               serv_puts("000");
00406        }
00407        while (!Done && (StrBuf_ServGetln(ReadBuf) >= 0)) {
00408               if ( (StrLength(ReadBuf)==3) && !strcmp(ChrPtr(ReadBuf), "000")) {
00409                      Done = 1;
00410                      break;
00411               }
00412               msgnum = StrTol(ReadBuf);
00413        }
00414 
00415        if (msgnum > 0L) {
00416               serv_printf("DELE %ld", msgnum);
00417               StrBuf_ServGetln(ReadBuf);
00418               GetServerStatus(ReadBuf, NULL);
00419        }
00420 
00421        serv_printf("ENT0 1||0|1|__ WebCit Preferences __|");
00422        StrBuf_ServGetln(ReadBuf);
00423        if (GetServerStatus(ReadBuf, NULL) == 4) {
00424 
00425               WritePrefsToServer(WCC->hash_prefs);
00426               serv_puts("");
00427               serv_puts("000");
00428        }
00429 
00431        if (StrLength(WCC->CurRoom.name) > 0) {
00432               serv_printf("GOTO %s", ChrPtr(WCC->CurRoom.name));
00433               StrBuf_ServGetln(ReadBuf);
00434               GetServerStatus(ReadBuf, NULL);
00435        }
00436        FreeStrBuf(&ReadBuf);
00437        FlushFolder(&Room);
00438 }
00439 
00440 /*
00441  * query the actual setting of key in the citadel database
00442  *
00443  * key        config key to query
00444  * keylen     length of the key string
00445  * value      StrBuf-value to the key to get
00446  * returns:   found?
00447  */
00448 int get_pref_backend(const char *key, size_t keylen, Preference **Pref)
00449 {
00450        void *hash_value = NULL;
00451 #ifdef DBG_PREFS_HASH
00452        dbg_PrintHash(WC->hash_prefs, PrintPref, NULL);
00453 #endif
00454        if (GetHash(WC->hash_prefs, key, keylen, &hash_value) == 0) {
00455               *Pref = NULL;
00456               return 0;
00457        }
00458        else {
00459               *Pref = (Preference*) hash_value;
00460               return 1;
00461        }
00462 }
00463 
00464 int get_PREFERENCE(const char *key, size_t keylen, StrBuf **value)
00465 {
00466        Preference *Pref;
00467        int Ret;
00468 
00469        Ret = get_pref_backend(key, keylen, &Pref);
00470        if (Ret != 0)
00471               *value = Pref->Val;
00472        else
00473               *value = NULL;
00474        return Ret;
00475 }
00476 
00477 /*
00478  * Write a key into the webcit preferences database for this user
00479  *
00480  * key               key whichs value is to be modified
00481  * keylen            length of the key string
00482  * value             value to set
00483  * save_to_server    1 = flush all data to the server, 0 = cache it for now
00484  */
00485 long compare_preference(const Preference *PrefA, const Preference *PrefB)
00486 {
00487        ePrefType TypeA, TypeB;
00488 
00489        if (PrefA->Type != NULL) {
00490               TypeA = PrefA->Type->eType;
00491        }
00492        else {
00493               TypeA = PrefA->eFlatPrefType;
00494        }
00495 
00496        if (PrefB->Type != NULL) {
00497               TypeB = PrefB->Type->eType;
00498        }
00499        else {
00500               TypeB = PrefB->eFlatPrefType;
00501        }
00502 
00503        if (   (TypeA != PRF_UNSET)
00504               && (TypeB != PRF_UNSET)
00505               && (TypeA != TypeB)
00506        ) {
00507               if (TypeA > TypeB) {
00508                      return 1;
00509               }
00510               else { /* (PrefA->Type < PrefB->Type) */
00511                      return -1;
00512               }
00513        }
00514 
00515        if (TypeB == PRF_UNSET) {
00516               TypeA = PRF_UNSET;
00517        }
00518                   
00519        switch (TypeA)
00520        {
00521        default:
00522        case PRF_UNSET:
00523        case PRF_STRING:
00524               return strcmp(ChrPtr(PrefA->Val), ChrPtr(PrefB->Val));
00525        case PRF_YESNO:
00526        case PRF_INT:
00527               if (PrefA->lval == PrefB->lval)
00528                      return 0;
00529               else if (PrefA->lval > PrefB->lval)
00530                      return 1;
00531               else
00532                      return -1;
00533        case PRF_QP_STRING:
00534               return strcmp(ChrPtr(PrefA->DeQPed), 
00535                            ChrPtr(PrefB->DeQPed));
00536        }
00537 }
00538 
00539 
00540 /*
00541  * Write a key into the webcit preferences database for this user
00542  *
00543  * key               key which value is to be modified
00544  * keylen            length of the key string
00545  * value             value to set
00546  * save_to_server    1 = flush all data to the server, 0 = cache it for now
00547  */
00548 void set_preference_backend(const char *key, size_t keylen, 
00549                          long lvalue, 
00550                          StrBuf *value, 
00551                          long lPrefType,
00552                          int save_to_server, 
00553                          PrefDef *PrefType) 
00554 {
00555        wcsession *WCC = WC;
00556        void *vPrefDef;
00557        void *vPrefB;
00558        Preference *Pref;
00559 
00560        Pref = (Preference*) malloc(sizeof(Preference));
00561        memset(Pref, 0, sizeof(Preference));
00562        Pref->Key = NewStrBufPlain(key, keylen);
00563 
00564        if ((PrefType == NULL) &&
00565            GetHash(PreferenceHooks, SKEY(Pref->Key), &vPrefDef) && 
00566            (vPrefDef != NULL))
00567               PrefType = (PrefDef*) vPrefDef;
00568 
00569        if (PrefType != NULL)
00570        {
00571               Pref->Type = PrefType;
00572               Pref->eFlatPrefType = PrefType->eType;
00573               if (Pref->Type->eType != lPrefType)
00574                      syslog(1, "warning: saving preference with wrong type [%s] %d != %ld \n",
00575                             key, Pref->Type->eType, lPrefType);
00576               switch (Pref->Type->eType)
00577               {
00578               case PRF_UNSET: /* default to string... */
00579               case PRF_STRING:
00580                      Pref->Val = value;
00581                      Pref->decoded = 1;
00582                      break;
00583               case PRF_INT:
00584                      Pref->lval = lvalue;
00585                      Pref->Val = value;
00586                      if (Pref->Val == NULL)
00587                             Pref->Val = NewStrBufPlain(NULL, 64);
00588                      StrBufPrintf(Pref->Val, "%ld", lvalue);
00589                      Pref->decoded = 1;
00590                      break;
00591               case PRF_QP_STRING:
00592                      Pref->DeQPed = value;
00593                      Pref->Val = NewStrBufPlain(NULL, StrLength(Pref->DeQPed) * 3);
00594                      StrBufEUid_escapize(Pref->Val, Pref->DeQPed);
00595                      Pref->decoded = 1;
00596                      break;
00597               case PRF_YESNO:
00598                      Pref->lval = lvalue;
00599                      if (lvalue) 
00600                             Pref->Val = NewStrBufPlain(HKEY("yes"));
00601                      else
00602                             Pref->Val = NewStrBufPlain(HKEY("no"));
00603                      Pref->decoded = 1;
00604                      break;
00605               }
00606               if (Pref->Type->OnLoad != NULL)
00607                      Pref->Type->OnLoad(Pref->Val, Pref->lval);
00608        }
00609        else {
00610               Pref->eFlatPrefType = lPrefType;
00611               switch (lPrefType)
00612               {
00613               case PRF_STRING:
00614                      Pref->Val = value;
00615                      Pref->decoded = 1;
00616                      break;
00617               case PRF_INT:
00618                      Pref->lval = lvalue;
00619                      Pref->Val = value;
00620                      if (Pref->Val == NULL)
00621                             Pref->Val = NewStrBufPlain(NULL, 64);
00622                      StrBufPrintf(Pref->Val, "%ld", lvalue);
00623                      Pref->decoded = 1;
00624                      break;
00625               case PRF_QP_STRING:
00626                      Pref->DeQPed = value;
00627                      Pref->Val = NewStrBufPlain(NULL, StrLength(Pref->DeQPed) * 3);
00628                      StrBufEUid_escapize(Pref->Val, Pref->DeQPed);
00629                      Pref->decoded = 1;
00630                      break;
00631               case PRF_YESNO:
00632                      Pref->lval = lvalue;
00633                      if (lvalue) 
00634                             Pref->Val = NewStrBufPlain(HKEY("yes"));
00635                      else
00636                             Pref->Val = NewStrBufPlain(HKEY("no"));
00637                      Pref->decoded = 1;
00638                      break;
00639               }
00640        }
00641 
00642        if ((save_to_server != 0) && 
00643            GetHash(WCC->hash_prefs, key, keylen, &vPrefB) && 
00644            (vPrefB != NULL) && 
00645            (compare_preference (Pref, vPrefB) == 0))
00646               save_to_server = 0;
00647 
00648        Put(WCC->hash_prefs, key, keylen, Pref, DestroyPreference);
00649        
00650        if (save_to_server) WCC->SavePrefsToServer = 1;
00651 }
00652 
00653 void set_PREFERENCE(const char *key, size_t keylen, StrBuf *value, int save_to_server) 
00654 {
00655        set_preference_backend(key, keylen, 0, value, PRF_STRING, save_to_server, NULL);
00656 }
00657 
00658 int get_PREF_LONG(const char *key, size_t keylen, long *value, long Default)
00659 {
00660        Preference *Pref;
00661        int Ret;
00662 
00663        Ret = get_pref_backend(key, keylen, &Pref);
00664        if (Ret == 0) {
00665               *value = Default;
00666               return 0;
00667        }
00668 
00669        if (Pref->decoded)
00670               *value = Pref->lval;
00671        else {
00672               *value = Pref->lval = atol(ChrPtr(Pref->Val));
00673               Pref->decoded = 1;
00674        }
00675        return Ret;
00676 }
00677 
00678 
00679 void set_PREF_LONG(const char *key, size_t keylen, long value, int save_to_server)
00680 {
00681        set_preference_backend(key, keylen, value, NULL, PRF_INT, save_to_server, NULL);
00682 }
00683 
00684 int get_PREF_YESNO(const char *key, size_t keylen, int *value, int Default)
00685 {
00686        Preference *Pref;
00687        int Ret;
00688 
00689        Ret = get_pref_backend(key, keylen, &Pref);
00690        if (Ret == 0) {
00691               *value = Default;
00692               return 0;
00693        }
00694 
00695        if (Pref->decoded)
00696               *value = Pref->lval;
00697        else {
00698               *value = Pref->lval = strcmp(ChrPtr(Pref->Val), "yes") == 0;
00699               Pref->decoded = 1;
00700        }
00701        return Ret;
00702 }
00703 
00704 void set_PREF_YESNO(const char *key, size_t keylen, long value, int save_to_server)
00705 {
00706        set_preference_backend(key, keylen, value, NULL, PRF_YESNO, save_to_server, NULL);
00707 }
00708 
00709 int get_room_prefs_backend(const char *key, size_t keylen, 
00710                         Preference **Pref)
00711 {
00712        StrBuf *pref_name;
00713        int Ret;
00714 
00715        pref_name = NewStrBufPlain (HKEY("ROOM:"));
00716        StrBufAppendBuf(pref_name, WC->CurRoom.name, 0);
00717        StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
00718        StrBufAppendBufPlain(pref_name, key, keylen, 0);
00719        Ret = get_pref_backend(SKEY(pref_name), Pref);
00720        FreeStrBuf(&pref_name);
00721 
00722        return Ret;
00723 }
00724 
00725 const StrBuf *get_X_PREFS(const char *key, size_t keylen, 
00726                        const char *xkey, size_t xkeylen)
00727 {
00728        int ret;
00729        StrBuf *pref_name;
00730        Preference *Prf;
00731        
00732        pref_name = NewStrBufPlain (HKEY("XPREF:"));
00733        StrBufAppendBufPlain(pref_name, xkey, xkeylen, 0);
00734        StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
00735        StrBufAppendBufPlain(pref_name, key, keylen, 0);
00736 
00737        ret = get_pref_backend(SKEY(pref_name), &Prf);
00738        FreeStrBuf(&pref_name);
00739 
00740        if (ret)
00741               return Prf->Val;
00742        else return NULL;
00743 }
00744 
00745 void set_X_PREFS(const char *key, size_t keylen, const char *xkey, size_t xkeylen, StrBuf *value, int save_to_server)
00746 {
00747        StrBuf *pref_name;
00748        
00749        pref_name = NewStrBufPlain (HKEY("XPREF:"));
00750        StrBufAppendBufPlain(pref_name, xkey, xkeylen, 0);
00751        StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
00752        StrBufAppendBufPlain(pref_name, key, keylen, 0);
00753 
00754        set_preference_backend(SKEY(pref_name), 0, value, PRF_STRING, save_to_server, NULL);
00755        FreeStrBuf(&pref_name);
00756 }
00757 
00758 
00759 long get_ROOM_PREFS_LONG(const char *key, size_t keylen, long *value, long Default)
00760 {
00761        Preference *Pref;
00762        int Ret;
00763 
00764        Ret = get_room_prefs_backend(key, keylen, &Pref);
00765 
00766        if (Ret == 0) {
00767               *value = Default;
00768               return 0;
00769        }
00770 
00771        if (Pref->decoded)
00772               *value = Pref->lval;
00773        else {
00774               *value = Pref->lval = atol(ChrPtr(Pref->Val));
00775               Pref->decoded = 1;
00776        }
00777        return Ret;
00778 }
00779 
00780 
00781 StrBuf *get_ROOM_PREFS(const char *key, size_t keylen)
00782 {
00783        Preference *Pref;
00784        int Ret;
00785 
00786        Ret = get_room_prefs_backend(key, keylen, &Pref);
00787 
00788        if (Ret == 0) {
00789               return NULL;
00790        }
00791        else 
00792               return Pref->Val;
00793 }
00794 
00795 void set_ROOM_PREFS(const char *key, size_t keylen, StrBuf *value, int save_to_server)
00796 {
00797        StrBuf *pref_name;
00798        
00799        pref_name = NewStrBufPlain (HKEY("ROOM:"));
00800        StrBufAppendBuf(pref_name, WC->CurRoom.name, 0);
00801        StrBufAppendBufPlain(pref_name, HKEY(":"), 0);
00802        StrBufAppendBufPlain(pref_name, key, keylen, 0);
00803        set_preference_backend(SKEY(pref_name), 0, value, PRF_STRING, save_to_server, NULL);
00804        FreeStrBuf(&pref_name);
00805 }
00806 
00807 
00808 void GetPreferences(HashList *Setting)
00809 {
00810         wcsession *WCC = WC;
00811        HashPos *It;
00812        long len;
00813        const char *Key;
00814        void *vSetting;
00815        PrefDef *PrefType;
00816        StrBuf *Buf;
00817        long lval;
00818        HashList *Tmp;
00819 
00820        Tmp = WCC->hash_prefs;
00821        WCC->hash_prefs = Setting;
00822 
00823        It = GetNewHashPos(PreferenceHooks, 0);
00824        while (GetNextHashPos(PreferenceHooks, It, &len, &Key, &vSetting)) {
00825               PrefType = (PrefDef*) vSetting;
00826 
00827               if (!HaveBstr(SKEY(PrefType->Setting)))
00828                      continue;
00829               switch (PrefType->eType) {
00830               case PRF_UNSET:
00831               case PRF_STRING:
00832                      Buf = NewStrBufDup(SBstr(SKEY(PrefType->Setting)));
00833                      set_preference_backend(SKEY(PrefType->Setting),
00834                                           0, 
00835                                           Buf, 
00836                                           PRF_STRING,
00837                                           1, 
00838                                           PrefType);
00839                      break;
00840               case PRF_INT:
00841                      lval = LBstr(SKEY(PrefType->Setting));
00842                      set_preference_backend(SKEY(PrefType->Setting),
00843                                           lval, 
00844                                           NULL, 
00845                                           PRF_INT,
00846                                           1, 
00847                                           PrefType);
00848                      break;
00849               case PRF_QP_STRING:
00850                      Buf = NewStrBufDup(SBstr(SKEY(PrefType->Setting)));
00851                      set_preference_backend(SKEY(PrefType->Setting),
00852                                           0, 
00853                                           Buf, 
00854                                           PRF_QP_STRING,
00855                                           1, 
00856                                           PrefType);
00857                      break;
00858               case PRF_YESNO:
00859                      lval = YesBstr(SKEY(PrefType->Setting));
00860                      set_preference_backend(SKEY(PrefType->Setting),
00861                                           lval, 
00862                                           NULL, 
00863                                           PRF_YESNO,
00864                                           1, 
00865                                           PrefType);
00866                      break;
00867               }
00868        }
00869        WCC->hash_prefs = Tmp;
00870        DeleteHashPos(&It);
00871 }
00872 
00873 
00874 /*
00875  * Commit new preferences and settings
00876  */
00877 void set_preferences(void)
00878 {      
00879        if (!havebstr("change_button")) {
00880               AppendImportantMessage(_("Cancelled.  No settings were changed."), -1);
00881               display_main_menu();
00882               return;
00883        }
00884        GetPreferences(WC->hash_prefs);
00885        display_main_menu();
00886 }
00887 
00888 
00889 void tmplput_CFG_Value(StrBuf *Target, WCTemplputParams *TP)
00890 {
00891        Preference *Pref;
00892        if (get_pref_backend(TKEY(0), &Pref))
00893        {
00894               if (Pref->Type == NULL) {
00895                      StrBufAppendTemplate(Target, TP, Pref->Val, 1);
00896               }
00897               switch (Pref->Type->eType)
00898               {
00899               case PRF_UNSET: /* default to string... */
00900               case PRF_STRING:
00901                      StrBufAppendTemplate(Target, TP, Pref->Val, 1);
00902                      break;
00903               case PRF_INT:
00904                      if (Pref->decoded != 1) {
00905                             if (Pref->Val == NULL)
00906                                    Pref->Val = NewStrBufPlain(NULL, 64);
00907                             StrBufPrintf(Pref->Val, "%ld", Pref->lval);
00908                             Pref->decoded = 1;
00909                      }
00910                      StrBufAppendTemplate(Target, TP, Pref->Val, 1);
00911                      break;
00912               case PRF_QP_STRING:
00913                      if (Pref->decoded != 1) {
00914                             if (Pref->DeQPed == NULL)
00915                                    Pref->DeQPed = NewStrBufPlain(NULL, StrLength(Pref->Val));
00916                                    
00917                             StrBufEUid_unescapize(Pref->DeQPed, Pref->Val);
00918                             Pref->decoded = 1;
00919                      }
00920                      StrBufAppendTemplate(Target, TP, Pref->DeQPed, 1);
00921                      break;
00922               case PRF_YESNO:
00923                      if (Pref->decoded != 1) {
00924                             Pref->lval = strcmp(ChrPtr(Pref->Val), "yes") == 0;
00925                             Pref->decoded = 1;
00926                      }
00927                      StrBufAppendTemplate(Target, TP, Pref->Val, 1);
00928                      break;
00929               }
00930        }
00931 }
00932 
00933 void tmplput_CFG_Descr(StrBuf *Target, WCTemplputParams *TP)
00934 {
00935        const char *SettingStr;
00936        SettingStr = PrefGetLocalStr(TKEY(0));
00937        if (SettingStr != NULL) 
00938               StrBufAppendBufPlain(Target, SettingStr, -1, 0);
00939 }
00940 void tmplput_CFG_RoomValueLong(StrBuf *Target, WCTemplputParams *TP)
00941 {
00942        long lvalue;
00943        long defval = 0;
00944 
00945        if (HAVE_PARAM(1))
00946               defval = GetTemplateTokenNumber(Target, TP, 1, 0);
00947        get_ROOM_PREFS_LONG(TKEY(0), &lvalue, defval);
00948        StrBufAppendPrintf(Target, "%ld", lvalue);
00949 }
00950 void tmplput_CFG_RoomValue(StrBuf *Target, WCTemplputParams *TP)
00951 {
00952        StrBuf *pref = get_ROOM_PREFS(TKEY(0));
00953        if (pref != NULL) 
00954               StrBufAppendBuf(Target, pref, 0);
00955 }
00956 int ConditionalHasRoomPreference(StrBuf *Target, WCTemplputParams *TP) 
00957 {
00958        if (get_ROOM_PREFS(TP->Tokens->Params[0]->Start, 
00959                         TP->Tokens->Params[0]->len) != NULL) 
00960               return 1;
00961   
00962        return 0;
00963 }
00964 
00965 int ConditionalPreference(StrBuf *Target, WCTemplputParams *TP)
00966 {
00967        StrBuf *Pref;
00968 
00969        if (!get_PREFERENCE(TKEY(2), &Pref)) 
00970               return 0;
00971        
00972        if (!HAVE_PARAM(3)) {
00973               return 1;
00974        }
00975        else if (IS_NUMBER(TP->Tokens->Params[3]->Type))
00976        {
00977               return StrTol(Pref) == GetTemplateTokenNumber (Target, TP, 3, 0);
00978        }
00979        else 
00980        {
00981               const char *pch;
00982               long len;
00983               
00984               GetTemplateTokenString(Target, TP, 3, &pch, &len);
00985               
00986               return ((len == StrLength(Pref)) &&
00987                      (strcmp(pch, ChrPtr(Pref)) == 0));
00988        }
00989 }
00990 
00991 int ConditionalHasPreference(StrBuf *Target, WCTemplputParams *TP)
00992 {
00993        StrBuf *Pref;
00994 
00995        if (!get_PREFERENCE(TKEY(2), &Pref) || 
00996            (Pref == NULL)) 
00997               return 0;
00998        else 
00999               return 1;
01000 }
01001 
01002 
01003 /********************************************************************************
01004  *                 preferences stored discrete in citserver
01005  ********************************************************************************/
01006 HashList *GetGVEAHash(StrBuf *Target, WCTemplputParams *TP)
01007 {
01008        StrBuf *Rcp;
01009        HashList *List = NULL;
01010        int Done = 0;
01011        int i, n = 1;
01012        char N[64];
01013 
01014        Rcp = NewStrBuf();
01015        serv_puts("GVEA");
01016        StrBuf_ServGetln(Rcp);
01017        if (GetServerStatus(Rcp, NULL) == 1) {
01018               FlushStrBuf(Rcp);
01019               List = NewHash(1, NULL);
01020               while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
01021                      if ( (StrLength(Rcp)==3) && 
01022                           !strcmp(ChrPtr(Rcp), "000")) 
01023                      {
01024                             Done = 1;
01025                      }
01026                      else {
01027                             i = snprintf(N, sizeof(N), "%d", n);
01028                             StrBufTrim(Rcp);
01029                             Put(List, N, i, Rcp, HFreeStrBuf);
01030                             Rcp = NewStrBuf();
01031                      }
01032                      n++;
01033               }
01034        }
01035        FreeStrBuf(&Rcp);
01036        return List;
01037 }
01038 void DeleteGVEAHash(HashList **KillMe)
01039 {
01040        DeleteHash(KillMe);
01041 }
01042 
01043 HashList *GetGVSNHash(StrBuf *Target, WCTemplputParams *TP)
01044 {
01045        StrBuf *Rcp;
01046        HashList *List = NULL;
01047        int Done = 0;
01048        int i, n = 1;
01049        char N[64];
01050 
01051        Rcp = NewStrBuf();
01052        serv_puts("GVSN");
01053        StrBuf_ServGetln(Rcp);
01054        if (GetServerStatus(Rcp, NULL) == 1) {
01055               FlushStrBuf(Rcp);
01056               List = NewHash(1, NULL);
01057               while (!Done && (StrBuf_ServGetln(Rcp)>=0)) {
01058                      if ( (StrLength(Rcp)==3) && 
01059                           !strcmp(ChrPtr(Rcp), "000")) 
01060                      {
01061                             Done = 1;
01062                      }
01063                      else {
01064                             i = snprintf(N, sizeof(N), "%d", n);
01065                             StrBufTrim(Rcp);
01066                             Put(List, N, i, Rcp, HFreeStrBuf);
01067                             Rcp = NewStrBuf();
01068                      }
01069                      n++;
01070               }
01071        }
01072        FreeStrBuf(&Rcp);
01073        return List;
01074 }
01075 void DeleteGVSNHash(HashList **KillMe)
01076 {
01077        DeleteHash(KillMe);
01078 }
01079 
01080 
01081 
01082 
01083 /*
01084  * Offer to make any page the user's "start page" (only if logged in)
01085  */
01086 void offer_start_page(StrBuf *Target, WCTemplputParams *TP)
01087 {
01088        if (WC->logged_in) {
01089               wc_printf("<a href=\"change_start_page?startpage=");
01090               urlescputs(ChrPtr(WC->Hdr->this_page));
01091               wc_printf("\">");
01092               wc_printf(_("Make this my start page"));
01093               wc_printf("</a>");
01094        };
01095 }
01096 
01097 
01098 /*
01099  * Change the user's start page
01100  */
01101 void change_start_page(void) 
01102 {
01103        const char *pch;
01104        void *vHandler;
01105        int ProhibitSave = 0;
01106        const StrBuf *pStartPage = sbstr("startpage");
01107 
01108        if (pStartPage != NULL) {
01109               pch = strchr(ChrPtr(pStartPage), '?');
01110 
01111               if ((pch != NULL) && (
01112                          GetHash(HandlerHash, ChrPtr(pStartPage), pch - ChrPtr(pStartPage), &vHandler), 
01113                          (vHandler != NULL) &&
01114                          ((((WebcitHandler*)vHandler)->Flags & PROHIBIT_STARTPAGE) != 0)))
01115               { /* OK, This handler doesn't want to be set as start page, prune it. */
01116                      ProhibitSave = 1;
01117               }
01118        }
01119 
01120        if ((pStartPage == NULL) || 
01121            (ProhibitSave == 1))
01122        {
01123               set_preference_backend(HKEY("startpage"), 
01124                                    0, 
01125                                    NewStrBufPlain(HKEY("")),
01126                                    PRF_STRING,
01127                                    1, 
01128                                    NULL);
01129               if (ProhibitSave == 1)
01130                      AppendImportantMessage(_("This isn't allowed to become the start page."), -1);
01131               else
01132                      AppendImportantMessage(_("You no longer have a start page selected."), -1);
01133               display_main_menu();
01134               return;
01135        }
01136 
01137 
01138 
01139        set_preference_backend(HKEY("startpage"), 
01140                             0, 
01141                             NewStrBufDup(pStartPage),
01142                             PRF_STRING,
01143                             1, 
01144                             NULL);
01145 
01146        output_headers(1, 1, 0, 0, 0, 0);
01147        do_template("newstartpage");
01148        wDumpContent(1);
01149 }
01150 
01151 
01152 void LoadStartpage(StrBuf *URL, long lvalue)
01153 {
01154        const char *pch;
01155        void *vHandler;
01156        pch = strchr(ChrPtr(URL), '?');
01157        if (pch == NULL) {
01158               /* purge the sins of the past... */
01159               pch = strchr(ChrPtr(URL), '&');
01160               if (pch != NULL) {
01161                      StrBufPeek(URL, pch, -1, '?');
01162                      WC->SavePrefsToServer = 1;
01163               }
01164        }
01165        else if (GetHash(HandlerHash, ChrPtr(URL), pch - ChrPtr(URL), &vHandler), 
01166                (vHandler != NULL) &&
01167                ((((WebcitHandler*)vHandler)->Flags & PROHIBIT_STARTPAGE) != 0))
01168        { /* OK, This handler doesn't want to be set as start page, prune it. */
01169               FlushStrBuf(URL);
01170               WC->SavePrefsToServer = 1;
01171        }
01172 }
01173 
01174 
01175 void 
01176 InitModule_PREFERENCES
01177 (void)
01178 {
01179        WebcitAddUrlHandler(HKEY("set_preferences"), "", 0, set_preferences, 0);
01180        WebcitAddUrlHandler(HKEY("change_start_page"), "", 0, change_start_page, 0);
01181 
01182        RegisterPreference("startpage", _("Prefered startpage"), PRF_STRING, LoadStartpage);
01183 
01184        RegisterNamespace("OFFERSTARTPAGE", 0, 0, offer_start_page, NULL, CTX_NONE);
01185        RegisterNamespace("PREF:ROOM:VALUE", 1, 2, tmplput_CFG_RoomValue,  NULL, CTX_NONE);
01186        RegisterNamespace("PREF:ROOM:VALUE:INT", 1, 2, tmplput_CFG_RoomValueLong,  NULL, CTX_NONE);
01187        RegisterNamespace("PREF:VALUE", 1, 2, tmplput_CFG_Value, NULL, CTX_NONE);
01188        
01189        RegisterNamespace("PREF:DESCR", 1, 1, tmplput_CFG_Descr, NULL, CTX_NONE);
01190 
01191        RegisterConditional(HKEY("COND:PREF"), 4, ConditionalPreference, CTX_NONE);
01192        RegisterConditional(HKEY("COND:PREF:SET"), 4, ConditionalHasPreference, CTX_NONE);
01193        RegisterConditional(HKEY("COND:ROOM:SET"), 4, ConditionalHasRoomPreference, CTX_NONE);
01194        
01195        RegisterIterator("PREF:VALID:EMAIL:ADDR", 0, NULL, 
01196                       GetGVEAHash, NULL, DeleteGVEAHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
01197        RegisterIterator("PREF:VALID:EMAIL:NAME", 0, NULL, 
01198                       GetGVSNHash, NULL, DeleteGVSNHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
01199 
01200 }
01201 
01202 
01203 void 
01204 ServerStartModule_PREFERENCES
01205 (void)
01206 {
01207        PreferenceHooks = NewHash(1, NULL);
01208 }
01209 
01210 
01211 
01212 void 
01213 ServerShutdownModule_PREFERENCES
01214 (void)
01215 {
01216        DeleteHash(&PreferenceHooks);
01217 }
01218 
01219 void
01220 SessionDetachModule__PREFERENCES
01221 (wcsession *sess)
01222 {
01223        if (sess->SavePrefsToServer) {
01224               save_preferences();
01225               sess->SavePrefsToServer = 0;
01226        }
01227 }
01228 
01229 void
01230 SessionNewModule_PREFERENCES
01231 (wcsession *sess)
01232 {
01233        sess->hash_prefs = NewHash(1,NULL);
01234 }
01235 
01236 void 
01237 SessionDestroyModule_PREFERENCES
01238 (wcsession *sess)
01239 {
01240        DeleteHash(&sess->hash_prefs);
01241 }