summaryrefslogtreecommitdiffstats
path: root/maildir/maildirkeywords.c
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /maildir/maildirkeywords.c
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'maildir/maildirkeywords.c')
-rw-r--r--maildir/maildirkeywords.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/maildir/maildirkeywords.c b/maildir/maildirkeywords.c
new file mode 100644
index 0000000..456664d
--- /dev/null
+++ b/maildir/maildirkeywords.c
@@ -0,0 +1,343 @@
+/*
+** Copyright 2003 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "maildirkeywords.h"
+
+
+const char *libmail_kwVerbotten=NULL;
+int libmail_kwCaseSensitive=1;
+
+void libmail_kwhInit(struct libmail_kwHashtable *h)
+{
+ size_t i;
+
+ memset(h, 0, sizeof(*h));
+
+ for (i=0; i<sizeof(h->heads)/sizeof(h->heads[0]); i++)
+ {
+ h->heads[i].u.userPtr=h;
+ h->tails[i].u.userPtr=h;
+
+ h->heads[i].next=&h->tails[i];
+ h->tails[i].prev=&h->heads[i];
+ }
+}
+
+/* The hash table SHOULD be empty now */
+
+int libmail_kwhCheck(struct libmail_kwHashtable *h)
+{
+ size_t i;
+
+ for (i=0; i<sizeof(h->heads)/sizeof(h->heads[0]); i++)
+ if (h->heads[i].next->next)
+ {
+ errno=EIO;
+ return -1; /* Should not happen */
+ }
+
+ return 0;
+}
+
+struct libmail_keywordEntry *libmail_kweFind(struct libmail_kwHashtable *ht,
+ const char *name, int createIfNew)
+{
+ size_t hashBucket=0;
+ const char *p;
+ char *fixed_p=NULL;
+
+ struct libmail_keywordEntry *e, *eNew;
+
+ if (libmail_kwVerbotten)
+ {
+ for (p=name; *p; p++)
+ if (strchr( libmail_kwVerbotten, *p))
+ break;
+
+ if (*p) /* Verbotten char, fix it */
+ {
+ char *q;
+
+ fixed_p=strdup(name);
+
+ if (!fixed_p)
+ return NULL;
+
+ for (q=fixed_p; *q; q++)
+ if (strchr(libmail_kwVerbotten, *q))
+ *q='_';
+
+ name=fixed_p;
+ }
+ }
+
+ p=name;
+ while (*p)
+ {
+ hashBucket=(hashBucket << 1) ^ (hashBucket & 0x8000 ? 0x1301:0)
+
+ ^ (libmail_kwCaseSensitive ?
+ (unsigned char)*p:tolower((unsigned char)*p));
+ ++p;
+ }
+ hashBucket=hashBucket & 0xFFFF;
+ hashBucket %= sizeof(ht->heads)/sizeof(ht->heads[0]);
+
+ for (e= ht->heads[hashBucket].next; e->next; e=e->next)
+ {
+ const char *kn=keywordName(e);
+ int n=libmail_kwCaseSensitive ? strcmp(kn, name) :
+ strcasecmp(kn, name);
+
+ if (n == 0)
+ {
+ if (fixed_p)
+ free(fixed_p);
+ return e;
+ }
+
+ if (n > 0)
+ break;
+ }
+
+ if (!createIfNew)
+ {
+ if (fixed_p)
+ free(fixed_p);
+ return NULL;
+ }
+
+ if ((eNew=malloc(sizeof(*e)+1+strlen(name))) == NULL)
+ {
+ if (fixed_p)
+ free(fixed_p);
+ return NULL;
+ }
+
+ memset(eNew, 0, sizeof(*eNew));
+ strcpy(keywordName(eNew), name);
+ eNew->next=e;
+ eNew->prev=e->prev;
+ eNew->next->prev=eNew;
+ eNew->prev->next=eNew;
+ eNew->firstMsg=NULL;
+ eNew->lastMsg=NULL;
+ ht->keywordAddedRemoved=1;
+
+ if (fixed_p)
+ free(fixed_p);
+ return eNew;
+}
+
+struct libmail_kwMessage *libmail_kwmCreate()
+{
+ struct libmail_kwMessage *kw=malloc(sizeof(struct libmail_kwMessage));
+
+ if (kw == NULL)
+ return NULL;
+
+ memset(kw, 0, sizeof(*kw));
+
+ return kw;
+}
+
+void libmail_kwmDestroy(struct libmail_kwMessage *kw)
+{
+ while (kw->firstEntry)
+ libmail_kwmClearEntry(kw->firstEntry);
+
+ free(kw);
+}
+
+int libmail_kwmSetName(struct libmail_kwHashtable *h,
+ struct libmail_kwMessage *km, const char *n)
+{
+ struct libmail_keywordEntry *ke=libmail_kweFind(h, n, 1);
+
+ if (!ke)
+ return -1;
+
+ return libmail_kwmSet(km, ke);
+}
+
+int libmail_kwmSet(struct libmail_kwMessage *km, struct libmail_keywordEntry *ke)
+{
+ struct libmail_kwMessageEntry *keLast, *kePtr;
+
+ const char *name=keywordName(ke);
+
+ for (keLast=km->firstEntry; keLast; keLast=keLast->next)
+ {
+ int rc=strcmp(keywordName(keLast->libmail_keywordEntryPtr), name);
+
+ if (rc == 0)
+ return 1; /* Keyword already set */
+
+ if (rc > 0)
+ break;
+ }
+
+ kePtr=malloc(sizeof(*kePtr));
+
+ if (!kePtr)
+ return -1;
+
+ if (keLast)
+ {
+ kePtr->next=keLast;
+ kePtr->prev=keLast->prev;
+
+ keLast->prev=kePtr;
+
+ if (kePtr->prev)
+ kePtr->prev->next=kePtr;
+ else
+ km->firstEntry=kePtr;
+ }
+ else
+ {
+ kePtr->next=NULL;
+
+ if ((kePtr->prev=km->lastEntry) != NULL)
+ kePtr->prev->next=kePtr;
+ else
+ km->firstEntry=kePtr;
+ km->lastEntry=kePtr;
+ }
+ kePtr->libmail_kwMessagePtr=km;
+
+ kePtr->keywordNext=NULL;
+ if ((kePtr->keywordPrev=ke->lastMsg) != NULL)
+ kePtr->keywordPrev->keywordNext=kePtr;
+ else
+ ke->firstMsg=kePtr;
+
+ ke->lastMsg=kePtr;
+ kePtr->libmail_keywordEntryPtr=ke;
+ return 0;
+}
+
+/*
+** Because keywords are linked in a sorted order, comparing for equality
+** is trivial.
+*/
+
+int libmail_kwmCmp(struct libmail_kwMessage *km1,
+ struct libmail_kwMessage *km2)
+{
+ struct libmail_kwMessageEntry *e1, *e2;
+
+ for (e1=km1->firstEntry, e2=km2->firstEntry; e1 && e2;
+ e1=e1->next, e2=e2->next)
+ if (strcmp(keywordName(e1->libmail_keywordEntryPtr),
+ keywordName(e2->libmail_keywordEntryPtr)))
+ break;
+
+ return e1 || e2 ? -1:0;
+}
+
+
+int libmail_kwmClear(struct libmail_kwMessage *km,
+ struct libmail_keywordEntry *ke)
+{
+ return libmail_kwmClearName(km, keywordName(ke));
+}
+
+int libmail_kwmClearName(struct libmail_kwMessage *km, const char *n)
+{
+ struct libmail_kwMessageEntry *kEntry;
+
+ for (kEntry=km->firstEntry; kEntry; kEntry=kEntry->next)
+ if (strcmp(keywordName(kEntry->libmail_keywordEntryPtr), n) == 0)
+ {
+ return libmail_kwmClearEntry(kEntry);
+ }
+
+ return 1;
+}
+
+int libmail_kwmClearEntry(struct libmail_kwMessageEntry *e)
+{
+ struct libmail_keywordEntry *kw=e->libmail_keywordEntryPtr;
+
+ if (e->next)
+ e->next->prev=e->prev;
+ else e->libmail_kwMessagePtr->lastEntry=e->prev;
+
+ if (e->prev)
+ e->prev->next=e->next;
+ else e->libmail_kwMessagePtr->firstEntry=e->next;
+
+ if (e->keywordNext)
+ e->keywordNext->keywordPrev=e->keywordPrev;
+ else
+ kw->lastMsg=e->keywordPrev;
+
+ if (e->keywordPrev)
+ e->keywordPrev->keywordNext=e->keywordNext;
+ else
+ kw->firstMsg=e->keywordNext;
+
+ libmail_kweClear(kw);
+ free(e);
+ return 0;
+}
+
+
+void libmail_kweClear(struct libmail_keywordEntry *kw)
+{
+ if (kw->firstMsg == NULL && kw->lastMsg == NULL)
+ {
+ struct libmail_keywordEntry *k;
+
+ for (k=kw; k->next; k=k->next)
+ ;
+
+ ((struct libmail_kwHashtable *)k->u.userPtr)
+ ->keywordAddedRemoved=1;
+
+ kw->prev->next=kw->next;
+ kw->next->prev=kw->prev; /* There are always dummy head/tail */
+
+ free(kw);
+ }
+}
+
+int libmail_kwEnumerate(struct libmail_kwHashtable *h,
+ int (*callback_func)(struct libmail_keywordEntry *,
+ void *),
+ void *callback_arg)
+{
+ size_t i;
+
+ for (i=0; i<sizeof(h->heads)/sizeof(h->heads[0]); i++)
+ {
+ struct libmail_keywordEntry *ke=h->heads[i].next;
+
+ while (ke->next)
+ {
+ struct libmail_keywordEntry *ke2=ke;
+ int rc;
+
+ ke=ke->next;
+
+ if ((rc=(*callback_func)(ke2, callback_arg)) != 0)
+ return rc;
+ }
+ }
+ return 0;
+}