Back to index

courier  0.68.2
maildirkeywords.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2003 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 #include      <stdio.h>
00010 #include      <stdlib.h>
00011 #include      <string.h>
00012 #include      <errno.h>
00013 #include      <ctype.h>
00014 
00015 #if    HAVE_UNISTD_H
00016 #include      <unistd.h>
00017 #endif
00018 #include      "maildirkeywords.h"
00019 
00020 
00021 const char *libmail_kwVerbotten=NULL;
00022 int libmail_kwCaseSensitive=1;
00023 
00024 void libmail_kwhInit(struct libmail_kwHashtable *h)
00025 {
00026        size_t i;
00027 
00028        memset(h, 0, sizeof(*h));
00029 
00030        for (i=0; i<sizeof(h->heads)/sizeof(h->heads[0]); i++)
00031        {
00032               h->heads[i].u.userPtr=h;
00033               h->tails[i].u.userPtr=h;
00034 
00035               h->heads[i].next=&h->tails[i];
00036               h->tails[i].prev=&h->heads[i];
00037        }
00038 }
00039 
00040 /* The hash table SHOULD be empty now */
00041 
00042 int libmail_kwhCheck(struct libmail_kwHashtable *h)
00043 {
00044        size_t i;
00045 
00046        for (i=0; i<sizeof(h->heads)/sizeof(h->heads[0]); i++)
00047               if (h->heads[i].next->next)
00048               {
00049                      errno=EIO;
00050                      return -1; /* Should not happen */
00051               }
00052 
00053        return 0;
00054 }
00055 
00056 struct libmail_keywordEntry *libmail_kweFind(struct libmail_kwHashtable *ht,
00057                                   const char *name, int createIfNew)
00058 {
00059        size_t hashBucket=0;
00060        const char *p;
00061        char *fixed_p=NULL;
00062 
00063        struct libmail_keywordEntry *e, *eNew;
00064 
00065        if (libmail_kwVerbotten)
00066        {
00067               for (p=name; *p; p++)
00068                      if (strchr( libmail_kwVerbotten, *p))
00069                             break;
00070 
00071               if (*p) /* Verbotten char, fix it */
00072               {
00073                      char *q;
00074 
00075                      fixed_p=strdup(name);
00076 
00077                      if (!fixed_p)
00078                             return NULL;
00079 
00080                      for (q=fixed_p; *q; q++)
00081                             if (strchr(libmail_kwVerbotten, *q))
00082                                    *q='_';
00083 
00084                      name=fixed_p;
00085               }
00086        }
00087 
00088        p=name;
00089        while (*p)
00090        {
00091               hashBucket=(hashBucket << 1) ^ (hashBucket & 0x8000 ? 0x1301:0)
00092 
00093                      ^ (libmail_kwCaseSensitive ?
00094                         (unsigned char)*p:tolower((unsigned char)*p));
00095               ++p;
00096        }
00097        hashBucket=hashBucket & 0xFFFF;
00098        hashBucket %= sizeof(ht->heads)/sizeof(ht->heads[0]);
00099 
00100        for (e= ht->heads[hashBucket].next; e->next; e=e->next)
00101        {
00102               const char *kn=keywordName(e);
00103               int n=libmail_kwCaseSensitive ? strcmp(kn, name) :
00104                      strcasecmp(kn, name);
00105 
00106               if (n == 0)
00107               {
00108                      if (fixed_p)
00109                             free(fixed_p);
00110                      return e;
00111               }
00112 
00113               if (n > 0)
00114                      break;
00115        }
00116 
00117        if (!createIfNew)
00118        {
00119               if (fixed_p)
00120                      free(fixed_p);
00121               return NULL;
00122        }
00123 
00124        if ((eNew=malloc(sizeof(*e)+1+strlen(name))) == NULL)
00125        {
00126               if (fixed_p)
00127                      free(fixed_p);
00128               return NULL;
00129        }
00130 
00131        memset(eNew, 0, sizeof(*eNew));
00132        strcpy(keywordName(eNew), name);
00133        eNew->next=e;
00134        eNew->prev=e->prev;
00135        eNew->next->prev=eNew;
00136        eNew->prev->next=eNew;
00137        eNew->firstMsg=NULL;
00138        eNew->lastMsg=NULL;
00139        ht->keywordAddedRemoved=1;
00140 
00141        if (fixed_p)
00142               free(fixed_p);
00143        return eNew;
00144 }
00145 
00146 struct libmail_kwMessage *libmail_kwmCreate()
00147 {
00148        struct libmail_kwMessage *kw=malloc(sizeof(struct libmail_kwMessage));
00149 
00150        if (kw == NULL)
00151               return NULL;
00152 
00153        memset(kw, 0, sizeof(*kw));
00154 
00155        return kw;
00156 }
00157 
00158 void libmail_kwmDestroy(struct libmail_kwMessage *kw)
00159 {
00160        while (kw->firstEntry)
00161               libmail_kwmClearEntry(kw->firstEntry);
00162 
00163        free(kw);
00164 }
00165 
00166 int libmail_kwmSetName(struct libmail_kwHashtable *h,
00167                  struct libmail_kwMessage *km, const char *n)
00168 {
00169        struct libmail_keywordEntry *ke=libmail_kweFind(h, n, 1);
00170 
00171        if (!ke)
00172               return -1;
00173 
00174        return libmail_kwmSet(km, ke);
00175 }
00176 
00177 int libmail_kwmSet(struct libmail_kwMessage *km, struct libmail_keywordEntry *ke)
00178 {
00179        struct libmail_kwMessageEntry *keLast, *kePtr;
00180 
00181        const char *name=keywordName(ke);
00182 
00183        for (keLast=km->firstEntry; keLast; keLast=keLast->next)
00184        {
00185               int rc=strcmp(keywordName(keLast->libmail_keywordEntryPtr), name);
00186 
00187               if (rc == 0)
00188                      return 1; /* Keyword already set */
00189 
00190               if (rc > 0)
00191                      break;
00192        }
00193 
00194        kePtr=malloc(sizeof(*kePtr));
00195 
00196        if (!kePtr)
00197               return -1;
00198 
00199        if (keLast)
00200        {
00201               kePtr->next=keLast;
00202               kePtr->prev=keLast->prev;
00203 
00204               keLast->prev=kePtr;
00205 
00206               if (kePtr->prev)
00207                      kePtr->prev->next=kePtr;
00208               else
00209                      km->firstEntry=kePtr;
00210        }
00211        else
00212        {
00213               kePtr->next=NULL;
00214 
00215               if ((kePtr->prev=km->lastEntry) != NULL)
00216                      kePtr->prev->next=kePtr;
00217               else
00218                      km->firstEntry=kePtr;
00219               km->lastEntry=kePtr;
00220        }
00221        kePtr->libmail_kwMessagePtr=km;
00222 
00223        kePtr->keywordNext=NULL;
00224        if ((kePtr->keywordPrev=ke->lastMsg) != NULL)
00225               kePtr->keywordPrev->keywordNext=kePtr;
00226        else
00227               ke->firstMsg=kePtr;
00228 
00229        ke->lastMsg=kePtr;
00230        kePtr->libmail_keywordEntryPtr=ke;
00231        return 0;
00232 }
00233 
00234 /*
00235 ** Because keywords are linked in a sorted order, comparing for equality
00236 ** is trivial.
00237 */
00238 
00239 int libmail_kwmCmp(struct libmail_kwMessage *km1,
00240               struct libmail_kwMessage *km2)
00241 {
00242        struct libmail_kwMessageEntry *e1, *e2;
00243 
00244        for (e1=km1->firstEntry, e2=km2->firstEntry; e1 && e2;
00245             e1=e1->next, e2=e2->next)
00246               if (strcmp(keywordName(e1->libmail_keywordEntryPtr),
00247                         keywordName(e2->libmail_keywordEntryPtr)))
00248                      break;
00249 
00250        return e1 || e2 ? -1:0;
00251 }
00252 
00253 
00254 int libmail_kwmClear(struct libmail_kwMessage *km,
00255                    struct libmail_keywordEntry *ke)
00256 {
00257        return libmail_kwmClearName(km, keywordName(ke));
00258 }
00259 
00260 int libmail_kwmClearName(struct libmail_kwMessage *km, const char *n)
00261 {
00262        struct libmail_kwMessageEntry *kEntry;
00263 
00264        for (kEntry=km->firstEntry; kEntry; kEntry=kEntry->next)
00265               if (strcmp(keywordName(kEntry->libmail_keywordEntryPtr), n) == 0)
00266               {
00267                      return libmail_kwmClearEntry(kEntry);
00268               }
00269 
00270        return 1;
00271 }
00272 
00273 int libmail_kwmClearEntry(struct libmail_kwMessageEntry *e)
00274 {
00275        struct libmail_keywordEntry *kw=e->libmail_keywordEntryPtr;
00276 
00277        if (e->next)
00278               e->next->prev=e->prev;
00279        else e->libmail_kwMessagePtr->lastEntry=e->prev;
00280 
00281        if (e->prev)
00282               e->prev->next=e->next;
00283        else e->libmail_kwMessagePtr->firstEntry=e->next;
00284 
00285        if (e->keywordNext)
00286               e->keywordNext->keywordPrev=e->keywordPrev;
00287        else
00288               kw->lastMsg=e->keywordPrev;
00289 
00290        if (e->keywordPrev)
00291               e->keywordPrev->keywordNext=e->keywordNext;
00292        else
00293               kw->firstMsg=e->keywordNext;
00294 
00295        libmail_kweClear(kw);
00296        free(e);
00297        return 0;
00298 }
00299 
00300 
00301 void libmail_kweClear(struct libmail_keywordEntry *kw)
00302 {
00303        if (kw->firstMsg == NULL && kw->lastMsg == NULL)
00304        {
00305               struct libmail_keywordEntry *k;
00306 
00307               for (k=kw; k->next; k=k->next)
00308                      ;
00309 
00310               ((struct libmail_kwHashtable *)k->u.userPtr)
00311                      ->keywordAddedRemoved=1;
00312 
00313               kw->prev->next=kw->next;
00314               kw->next->prev=kw->prev; /* There are always dummy head/tail */
00315 
00316               free(kw);
00317        }
00318 }
00319 
00320 int libmail_kwEnumerate(struct libmail_kwHashtable *h,
00321                    int (*callback_func)(struct libmail_keywordEntry *,
00322                                      void *),
00323                    void *callback_arg)
00324 {
00325        size_t i;
00326 
00327        for (i=0; i<sizeof(h->heads)/sizeof(h->heads[0]); i++)
00328        {
00329               struct libmail_keywordEntry *ke=h->heads[i].next;
00330 
00331               while (ke->next)
00332               {
00333                      struct libmail_keywordEntry *ke2=ke;
00334                      int rc;
00335 
00336                      ke=ke->next;
00337 
00338                      if ((rc=(*callback_func)(ke2, callback_arg)) != 0)
00339                             return rc;
00340               }
00341        }
00342        return 0;
00343 }