/* ** Copyright 2003-2004 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" 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; for (n=0; nfilename); 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); }