From 7ccf3c9341de9dc5319e7269793c4fcc7ece4eab Mon Sep 17 00:00:00 2001 From: Sam Varshavchik Date: Thu, 3 Feb 2022 23:38:02 -0500 Subject: Add additional tests. Test keyword handling. Fix memory corruption in the maildirkw utilty. --- maildir/maildirkw.C | 375 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 maildir/maildirkw.C (limited to 'maildir/maildirkw.C') diff --git a/maildir/maildirkw.C b/maildir/maildirkw.C new file mode 100644 index 0000000..1c17959 --- /dev/null +++ b/maildir/maildirkw.C @@ -0,0 +1,375 @@ +/* +** Copyright 2003-2022 Double Precision, Inc. +** See COPYING for distribution information. +*/ + + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#endif +#include +#include "maildirkeywords.h" +#include "maildirwatch.h" + +#include +#include + +static void usage() +{ + printf("Usage: maildirkw [ options ] maildir [+/-]flag [+/-]flag...\n"); + exit(1); +} + +static int doit_locked(const char *maildir, + const char *filename, + int lockflag, int plusminus, + char **argv, + int optind, int argc) +{ + char *tmpname, *newname; + + if (!plusminus) + { + struct libmail_kwHashtable kwh; + struct libmail_kwMessage *kwm; + + struct libmail_kwGeneric g; + int rc; + + libmail_kwgInit(&g); + + /* Make sure courierimapkeywords directory exists */ + + libmail_kwEnabled=0; + rc=libmail_kwgReadMaildir(&g, maildir); + libmail_kwEnabled=1; + libmail_kwgDestroy(&g); + + if (rc) + return -1; + + + libmail_kwhInit(&kwh); + + if (!(kwm=libmail_kwmCreate())) + { + perror("libmail_kwmCreate"); + return -1; + } + + while (optind < argc) + if (libmail_kwmSetName(&kwh, kwm, + argv[optind++]) < 0) + { + libmail_kwmDestroy(kwm); + perror("libmail_kwmSetName"); + return -1; + } + + if (maildir_kwSave(maildir, filename, kwm, + &tmpname, &newname, 0) < 0) + { + perror(maildir); + libmail_kwmDestroy(kwm); + return -1; + } + libmail_kwmDestroy(kwm); + + if (rename(tmpname, newname) < 0) + { + perror(newname); + free(tmpname); + free(newname); + return -1; + } + free(tmpname); + free(newname); + return 0; + } + else + { + struct libmail_kwGeneric g; + int rc; + struct libmail_kwGenericEntry *e; + struct libmail_kwMessage *kwm, *kwm_alloced; + + libmail_kwgInit(&g); + + rc=libmail_kwgReadMaildir(&g, maildir); + + if (rc != 0) + return rc; + + e=libmail_kwgFindByName(&g, filename); + + kwm_alloced=NULL; + + if (e && e->keywords) + kwm=e->keywords; + else + { + if ((kwm=kwm_alloced=libmail_kwmCreate()) == NULL) + { + perror("libmail_kwmCreate"); + libmail_kwgDestroy(&g); + return -1; + } + } + + while (optind < argc) + { + const char *f=argv[optind++]; + + if ( plusminus == '+') + { + if (libmail_kwmSetName(&g.kwHashTable, + kwm, f) < 0) + { + perror("libmail_kwmSetName"); + if (kwm_alloced) + libmail_kwmDestroy(kwm_alloced + ); + libmail_kwgDestroy(&g); + return -1; + } + } else + { + struct libmail_keywordEntry *kwe= + libmail_kweFind(&g.kwHashTable, + f, 0); + + if (kwe) + libmail_kwmClear(kwm, kwe); + } + } + + rc=maildir_kwSave(maildir, filename, kwm, + &tmpname, &newname, 1); + + if (rc == 0) + { + if (link(tmpname, newname) == 0) + { + struct stat stat_buf; + + if (stat(tmpname, &stat_buf) == 0 && + stat_buf.st_nlink == 2) + unlink(tmpname); + else + rc=1; /* What's up? */ + } + else + { + if (errno == EEXIST) + rc=1; + else + rc= -1; + unlink(tmpname); + } + free(tmpname); + free(newname); + } + + if (kwm_alloced) + libmail_kwmDestroy(kwm_alloced); + libmail_kwgDestroy(&g); + + return rc; + } +} + +static int list_locked(const char *maildir) +{ + struct libmail_kwGeneric g; + int rc; + size_t n; + + libmail_kwgInit(&g); + + rc=libmail_kwgReadMaildir(&g, maildir); + + if (rc) + return rc; + + std::map messages; + + for (n=0; nfilename]=n; + } + + for (auto b=messages.begin(), ee=messages.end(); b != ee; ++b) + { + struct libmail_kwGenericEntry *e= + libmail_kwgFindByIndex(&g, b->second); + struct libmail_kwMessageEntry *k; + + if (!e) + continue; + + printf("%s", e->filename); + + for (k=e->keywords ? e->keywords->firstEntry:NULL; k; + k=k->next) + printf(" %s", keywordName(k->libmail_keywordEntryPtr)); + printf("\n"); + } + libmail_kwgDestroy(&g); + return 0; +} + +static int doit(const char *maildir, const char *filename, int lockflag, + int plusminus, + char **argv, int optind, int argc) +{ + if (lockflag) + { + struct maildirwatch *w=maildirwatch_alloc(maildir); + int tryAnyway; + char *lockname; + int rc; + + if (!w) + { + perror(maildir); + return -1; + } + + lockname=maildir_lock(maildir, w, &tryAnyway); + + if (!lockname) + { + perror(maildir); + if (!tryAnyway) + { + maildirwatch_free(w); + maildirwatch_cleanup(); + return -1; + } + } + + rc=doit_locked(maildir, filename, 1, plusminus, + argv, optind, argc); + if (lockname) + { + unlink(lockname); + free(lockname); + } + maildirwatch_free(w); + maildirwatch_cleanup(); + return rc; + } + + return doit_locked(maildir, filename, 0, plusminus, + argv, optind, argc); +} + +static int dolist(const char *maildir, int lockflag) +{ + if (lockflag) + { + struct maildirwatch *w=maildirwatch_alloc(maildir); + int tryAnyway; + char *lockname; + int rc; + + if (!w) + { + perror(maildir); + return -1; + } + + lockname=maildir_lock(maildir, w, &tryAnyway); + + if (!lockname) + { + perror(maildir); + if (!tryAnyway) + { + maildirwatch_free(w); + maildirwatch_cleanup(); + return -1; + } + } + + rc=list_locked(maildir); + if (lockname) + { + unlink(lockname); + free(lockname); + } + maildirwatch_free(w); + maildirwatch_cleanup(); + return rc; + } + + return list_locked(maildir); +} + +int main(int argc, char *argv[]) +{ + int lockflag=0; + int optc; + const char *maildir; + const char *filename; + int list=0; + int plusminus=0; + int n; + + libmail_kwCaseSensitive=0; + + while ((optc=getopt(argc, argv, "arLlhc")) != -1) + switch (optc) { + case 'c': + libmail_kwCaseSensitive=1; + break; + case 'l': + lockflag=1; + break; + case 'L': + list=1; + break; + case 'a': + plusminus='+'; + break; + case 'r': + plusminus='-'; + break; + default: + usage(); + } + + if (optind >= argc) + usage(); + + maildir=argv[optind++]; + + if (list) + { + exit (dolist(maildir, lockflag)); + } + + if (optind >= argc) + usage(); + + filename=argv[optind++]; + + while ((n=doit(maildir, filename, lockflag, plusminus, + argv, optind, argc)) > 0) + ; + + exit(-n); + return (0); +} -- cgit v1.2.3