summaryrefslogtreecommitdiffstats
path: root/maildir/maildirmake.c
diff options
context:
space:
mode:
Diffstat (limited to 'maildir/maildirmake.c')
-rw-r--r--maildir/maildirmake.c434
1 files changed, 433 insertions, 1 deletions
diff --git a/maildir/maildirmake.c b/maildir/maildirmake.c
index 9e14eb4..6d35899 100644
--- a/maildir/maildirmake.c
+++ b/maildir/maildirmake.c
@@ -1,5 +1,5 @@
/*
-** Copyright 1998 - 2006Double Precision, Inc.
+** Copyright 1998 - 2018 Double Precision, Inc.
** See COPYING for distribution information.
*/
@@ -25,8 +25,10 @@
#include "maildircreate.h"
#include "maildirmisc.h"
+#include "maildirinfo.h"
#include "maildirsharedrc.h"
#include "maildirquota.h"
+#include "maildirfilter.h"
#include <courier-unicode.h>
static void usage()
@@ -194,6 +196,421 @@ int found;
exit(0);
}
+/*****************************************************************************
+
+Convert modified-UTF7 folder names to UTF-8 (sort-of).
+
+*****************************************************************************/
+
+struct convertutf8_list {
+ struct convertutf8_list *next;
+ char *rename_from;
+ char *rename_to;
+};
+
+struct convertutf8_status {
+ struct convertutf8_list *list;
+ int status;
+};
+
+/* Find folders that need to change */
+
+static void convertutf8_build_list(const char *inbox_name,
+ void *arg)
+{
+ struct convertutf8_status *status=
+ (struct convertutf8_status *)arg;
+ struct convertutf8_list *list;
+
+ char *converted=imap_foldername_to_filename(0, inbox_name);
+
+ if (!converted)
+ {
+ fprintf(stderr,
+ "Error: %s: does not appear to be valid"
+ " modified-UTF7\n",
+ inbox_name);
+ status->status=1;
+ return;
+ }
+
+ if (strcmp(converted, inbox_name) == 0)
+ {
+ free(converted);
+ return;
+ }
+ list=(struct convertutf8_list *)malloc(sizeof(struct convertutf8_list));
+
+ if (!list || !(list->rename_from=strdup(inbox_name)))
+ {
+ perror("malloc");
+ exit(1);
+ }
+
+ list->rename_to=converted;
+ list->next=status->list;
+ status->list=list;
+}
+
+void convertutf8(const char *maildir, const char *mailfilter, int doit)
+{
+ struct convertutf8_status status;
+ struct convertutf8_list *list;
+ char *courierimapsubscribed;
+ char *courierimapsubscribed_new;
+ FILE *courierimapsubscribed_fp;
+ struct maildirfilter mf;
+ int mf_status;
+ char *mailfilter_newname=0;
+
+ memset(&status, 0, sizeof(status));
+ memset(&mf, 0, sizeof(mf));
+
+ printf("Checking %s:\n", maildir);
+
+ maildir_list(maildir, convertutf8_build_list, &status);
+
+ if (status.status)
+ exit(status.status);
+
+ if (mailfilter)
+ {
+ struct maildirfilterrule *r;
+
+ /*
+ ** Try to convert folder references from mailfilter
+ */
+
+ mailfilter_newname=malloc(strlen(mailfilter)+10);
+
+ strcat(strcpy(mailfilter_newname, mailfilter), ".new");
+ mf_status=maildir_filter_loadrules(&mf, mailfilter);
+
+ if (mf_status != MF_LOADOK && mf_status != MF_LOADNOTFOUND)
+ {
+ fprintf(stderr, "Error: cannot load %s\n",
+ mailfilter);
+ }
+
+ for (r=mf.first; r; r=r->next)
+ {
+ char *converted;
+
+ /* Look for deliveries to a folder */
+
+ if (strncmp(r->tofolder, "INBOX.", 6))
+ continue;
+
+ converted=imap_foldername_to_filename(0, r->tofolder);
+
+ if (!converted)
+ {
+ fprintf(stderr, "Error: %s: "
+ "%s: does not appear to be valid "
+ "modified-UTF7\n",
+ mailfilter,
+ r->tofolder);
+ status.status=1;
+ }
+
+ if (strcmp(converted, r->tofolder) == 0)
+ {
+ free(converted);
+ continue;
+ }
+
+ printf("Mail filter to %s updated to %s\n",
+ r->tofolder, converted);
+
+ free(r->tofolder);
+ r->tofolder=converted;
+ }
+
+ if (mf_status == MF_LOADOK)
+ {
+ FILE *fp=fopen(mailfilter, "r");
+ char detected_from[1024];
+ char detected_tomaildir[1024];
+ char buffer[1024];
+ struct stat st_buf;
+
+ /*
+ ** We need to know the FROM address and the MAILDIR
+ ** reference. Attempt to ham-fistedly parse the
+ ** current filter file.
+ */
+
+ detected_from[0]=0;
+ detected_tomaildir[0]=0;
+
+ if (!fp)
+ {
+ perror(mailfilter);
+ exit(1);
+ }
+
+ while (fgets(buffer, sizeof(buffer), fp))
+ {
+ char *p, *q;
+
+ if (strncmp(buffer, "FROM='", 6) == 0)
+ {
+ char *p=strchr(buffer+6, '\'');
+
+ if (!p)
+ {
+ fprintf(stderr,
+ "Cannot parse %s\n",
+ mailfilter);
+ status.status=1;
+ }
+ else
+ {
+ *p=0;
+ strcpy(detected_from, buffer+6);
+
+ /*
+ Unescape, because saverules()
+ escapes it.
+ */
+
+ for (q=p=detected_from; *p; p++)
+ {
+ if (*p == '\\' && p[1])
+ ++p;
+ *q=*p;
+ ++q;
+ }
+ *q=0;
+ }
+ }
+
+ if (strncmp(buffer, "to \"", 4) == 0)
+ {
+ p=strstr(buffer+4, "/.\"");
+
+ if (!p)
+ {
+ fprintf(stderr,
+ "Cannot parse %s\n",
+ mailfilter);
+ status.status=1;
+ }
+ else
+ {
+ *p=0;
+ }
+ strcpy(detected_tomaildir, buffer+4);
+ }
+ }
+ fclose(fp);
+ if (detected_from[0] == 0 ||
+ detected_tomaildir[0] == 0)
+ {
+ fprintf(stderr,
+ "Failed to parse %s\n",
+ mailfilter);
+ status.status=1;
+ }
+ maildir_filter_saverules(&mf, mailfilter_newname,
+ detected_tomaildir,
+ detected_from);
+
+ if (stat(mailfilter, &st_buf) ||
+ chmod(mailfilter_newname, st_buf.st_mode))
+ {
+ perror(mailfilter);
+ exit(1);
+ }
+ /*
+ ** If we're root, preserve the ownership and permission
+ */
+ if (geteuid() == 0)
+ {
+ if (chown(mailfilter_newname, st_buf.st_uid,
+ st_buf.st_gid))
+ {
+ perror(mailfilter_newname);
+ exit(1);
+ }
+ }
+ }
+ }
+ else
+ {
+ mf_status=MF_LOADNOTFOUND;
+ }
+
+ courierimapsubscribed=malloc(strlen(maildir)+100);
+ courierimapsubscribed_new=malloc(strlen(maildir)+100);
+
+ strcat(strcpy(courierimapsubscribed, maildir),
+ "/courierimapsubscribed");
+ strcat(strcpy(courierimapsubscribed_new, maildir),
+ "/courierimapsubscribed.new");
+
+ /*
+ ** Update folder references in the IMAP subscription file.
+ */
+
+ if ((courierimapsubscribed_fp=fopen(courierimapsubscribed, "r"))
+ != NULL)
+ {
+ char buffer[2048];
+ FILE *new_fp=fopen(courierimapsubscribed_new, "w");
+ char *converted;
+ struct stat st_buf;
+
+ while (fgets(buffer, sizeof(buffer), courierimapsubscribed_fp))
+ {
+ char *p=strchr(buffer, '\n');
+
+ if (!p)
+ {
+ fprintf(stderr, "Error: courierimapsubscribed: "
+ "folder name too long\n");
+ status.status=1;
+ continue;
+ }
+
+ *p=0;
+
+ converted=imap_foldername_to_filename(0, buffer);
+
+ if (!converted)
+ {
+ fprintf(stderr, "Error: courierimapsubscribed: "
+ "%s: does not appear to be valid "
+ "modified-UTF7\n",
+ buffer);
+ status.status=1;
+ continue;
+ }
+ fprintf(new_fp, "%s\n", converted);
+
+ if (strcmp(buffer, converted))
+ {
+ printf("Subscription to %s changed to %s\n",
+ buffer, converted);
+ }
+ free(converted);
+ }
+ if (fflush(new_fp) || fclose(new_fp))
+ {
+ exit(1);
+ }
+ fclose(courierimapsubscribed_fp);
+
+ /*
+ ** If we're root, preserve the ownership and permission
+ */
+ if (stat(courierimapsubscribed, &st_buf) ||
+ chmod(courierimapsubscribed_new, st_buf.st_mode))
+ {
+ perror(courierimapsubscribed);
+ exit(1);
+ }
+
+ if (geteuid() == 0)
+ {
+ if (chown(courierimapsubscribed_new, st_buf.st_uid,
+ st_buf.st_gid))
+ {
+ perror(courierimapsubscribed_new);
+ exit(1);
+ }
+ }
+ }
+
+ if (status.status)
+ {
+ unlink(courierimapsubscribed_new);
+ if (mf_status == MF_LOADOK)
+ unlink(mailfilter_newname);
+ exit(status.status);
+ }
+ for (list=status.list; list; list=list->next)
+ {
+ char *frompath, *topath;
+
+ printf("Rename %s to %s\n", list->rename_from, list->rename_to);
+
+ frompath=malloc(strlen(maildir)+strlen(list->rename_from));
+ topath=malloc(strlen(maildir)+strlen(list->rename_to));
+
+ if (!frompath || !topath)
+ {
+ perror("malloc");
+ exit(1);
+ }
+
+ strcat(strcpy(frompath, maildir), "/");
+ strcat(strcpy(topath, maildir), "/");
+
+ /* They all have the INBOX. prefix, strip it off */
+ strcat(frompath, strchr(list->rename_from, '.'));
+ strcat(topath, strchr(list->rename_to, '.'));
+
+ if (doit)
+ {
+ if (rename(frompath, topath))
+ {
+ fprintf(stderr,
+ "FATAL ERROR RENAMING %s to %s: %s\n",
+ frompath, topath, strerror(errno));
+ status.status=1;
+ }
+ }
+ free(frompath);
+ free(topath);
+ }
+
+ if (doit)
+ {
+ if (courierimapsubscribed_fp)
+ {
+ printf("Updating %s\n", courierimapsubscribed);
+
+ if (rename(courierimapsubscribed_new,
+ courierimapsubscribed))
+ {
+ fprintf(stderr,
+ "FATAL ERROR RENAMING %s to %s: %s\n",
+ courierimapsubscribed_new,
+ courierimapsubscribed, strerror(errno));
+ status.status=1;
+ }
+ }
+
+ if (mf_status == MF_LOADOK)
+ {
+ printf("Updating %s\n", mailfilter);
+
+ if (rename(mailfilter_newname, mailfilter))
+ {
+ fprintf(stderr,
+ "FATAL ERROR RENAMING %s to %s: %s\n",
+ mailfilter_newname, mailfilter,
+ strerror(errno));
+ status.status=1;
+ }
+ }
+ }
+ else
+ {
+ if (courierimapsubscribed_fp)
+ {
+ printf("Verified %s\n", courierimapsubscribed);
+ }
+
+ if (mf_status == MF_LOADOK)
+ {
+ printf("Verified %s\n", mailfilter);
+ }
+ }
+ exit(status.status);
+}
+
int main(int argc, char *argv[])
{
const char *maildir, *folder=0;
@@ -297,6 +714,21 @@ char *tmp=0;
continue;
}
+ if (strcmp(argv[argn], "--convutf8") == 0 && argc-argn > 1)
+ {
+ char *maildir=argv[++argn];
+ char *mailfilter=argn < argc ? argv[++argn]:0;
+ convertutf8(maildir, mailfilter, 1);
+ exit(0);
+ }
+
+ if (strcmp(argv[argn], "--checkutf8") == 0 && argc-argn > 1)
+ {
+ char *maildir=argv[++argn];
+ char *mailfilter=argn < argc ? argv[++argn]:0;
+ convertutf8(maildir, mailfilter, 0);
+ exit(0);
+ }
usage();
}