summaryrefslogtreecommitdiffstats
path: root/maildir
diff options
context:
space:
mode:
authorSam Varshavchik2018-07-14 15:51:42 -0400
committerSam Varshavchik2018-07-16 21:20:25 -0400
commit9643d3d5adcbc6357833a818e2928eb8e76717ed (patch)
tree367ec86c8ccfb3aa2ab40b2440ebabfea382e0ce /maildir
parent3359e8155147662382d2fd982bcf75a1644901a0 (diff)
downloadcourier-libs-9643d3d5adcbc6357833a818e2928eb8e76717ed.tar.bz2
Add maidirmake options to convert pre-unicode mailboxes to unicode mailboxes.
Diffstat (limited to 'maildir')
-rw-r--r--maildir/Makefile.am4
-rw-r--r--maildir/maildirfilter.c5
-rw-r--r--maildir/maildirfilter.h1
-rw-r--r--maildir/maildirfilter2.c2
-rw-r--r--maildir/maildirinfo.h4
-rw-r--r--maildir/maildirinfo2.c148
-rw-r--r--maildir/maildirmake.c434
-rw-r--r--maildir/maildirmake.sgml319
-rw-r--r--maildir/testmaildirfilter.c2
9 files changed, 898 insertions, 21 deletions
diff --git a/maildir/Makefile.am b/maildir/Makefile.am
index 148c75c..60f0681 100644
--- a/maildir/Makefile.am
+++ b/maildir/Makefile.am
@@ -34,7 +34,7 @@ libmaildir_la_SOURCES=autoresponse.c autoresponse.h \
maildirfilter.h maildirfiltertypelist.h\
maildirflags.c maildirmkdir.c \
maildirgetquota.c maildirgetquota.h \
- maildirinfo.c maildirinfo.h \
+ maildirinfo.c maildirinfo.h maildirinfo2.c \
maildirkeywords.c maildirkeywords2.c maildirkeywords3.c \
maildirkeywords4.cpp \
maildirkeywords.h maildirlist.c maildirlock.c \
@@ -63,7 +63,7 @@ maildirmake_DEPENDENCIES=libmaildir.la \
../rfc822/librfc822.la
maildirmake_LDADD=libmaildir.la \
../numlib/libnumlib.la \
- ../rfc822/librfc822.la -lcourier-unicode
+ ../rfc822/librfc822.la -lcourier-unicode @LIBPCRE@
maildirmake_LDFLAGS=-static
testmaildirfilter_SOURCES=maildirfiltertypelist.h testmaildirfilter.c
diff --git a/maildir/maildirfilter.c b/maildir/maildirfilter.c
index a04ba0d..82702a1 100644
--- a/maildir/maildirfilter.c
+++ b/maildir/maildirfilter.c
@@ -175,7 +175,7 @@ static int maildir_filter_ruleupdate_utf8(struct maildirfilter *r,
/* rule name: may not already exist */
*errcode=MF_ERR_EXISTS;
-
+
for (pom=r->first; pom->next; pom=pom->next) {
if (p!=pom && !strcmp(name, pom->rulename_utf8))
return (-1);
@@ -508,8 +508,7 @@ static void print_pattern(FILE *f, int flags, const char *v)
}
int maildir_filter_saverules(struct maildirfilter *r, const char *filename,
- const char *maildir,
- const char *maildirpath, const char *fromaddr)
+ const char *maildirpath, const char *fromaddr)
{
FILE *f=fopen(filename, "w");
struct maildirfilterrule *p;
diff --git a/maildir/maildirfilter.h b/maildir/maildirfilter.h
index 3d4bfdf..44a32de 100644
--- a/maildir/maildirfilter.h
+++ b/maildir/maildirfilter.h
@@ -113,7 +113,6 @@ int maildir_filter_ruleupdate(struct maildirfilter *, struct maildirfilterrule *
int maildir_filter_saverules(struct maildirfilter *,
const char *, /* Filename */
- const char *, /* Maildir */
const char *, /* Path to maildir from mailfilter */
const char *); /* The return address */
diff --git a/maildir/maildirfilter2.c b/maildir/maildirfilter2.c
index 3a541d3..922ad13 100644
--- a/maildir/maildirfilter2.c
+++ b/maildir/maildirfilter2.c
@@ -213,7 +213,7 @@ int maildir_filter_savemaildirfilter(struct maildirfilter *mf, const char *maild
strcat(strcpy(createInfo.newname, maildir), "/maildirfilter.tmp");
rc=maildir_filter_saverules(mf, createInfo.tmpname,
- maildir, maildirpath, from);
+ maildirpath, from);
if (rc == 0 && rename(createInfo.tmpname, createInfo.newname))
rc= -1;
maildir_tmpcreate_free(&createInfo);
diff --git a/maildir/maildirinfo.h b/maildir/maildirinfo.h
index 85eca68..418b81c 100644
--- a/maildir/maildirinfo.h
+++ b/maildir/maildirinfo.h
@@ -20,6 +20,10 @@ struct maildir_info {
char *owner;
};
+char *imap_foldername_to_filename(int utf8_format, const char *foldername);
+
+char *imap_filename_to_foldername(int utf8_format, const char *filename);
+
void maildir_info_destroy(struct maildir_info *); /* Deallocate memory */
int maildir_info_imap_find(struct maildir_info *info, const char *path,
diff --git a/maildir/maildirinfo2.c b/maildir/maildirinfo2.c
new file mode 100644
index 0000000..fcae14c
--- /dev/null
+++ b/maildir/maildirinfo2.c
@@ -0,0 +1,148 @@
+/*
+** Copyright 2018 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 "maildirinfo.h"
+#include <courier-unicode.h>
+
+
+/* Count the size of the converted filename or foldername string */
+static void count_utf8(const char *str, size_t n, void *arg)
+{
+ *(size_t *)arg += n;
+}
+
+/* Save the converted filename or foldername string */
+static void save_utf8(const char *str, size_t n, void *arg)
+{
+ char **p=(char **)arg;
+
+ memcpy( (*p), str, n);
+ *p += n;
+}
+
+/*
+** Split a string at periods, convert each split range between charsets.
+*/
+static int foldername_filename_convert(const char *src_chset,
+ const char *dst_chset,
+ const char *foldername,
+ void (*closure)(const char *, size_t,
+ void *),
+ void *arg)
+{
+ unicode_convert_handle_t h;
+ char *cbufptr;
+ size_t cbufsize;
+ size_t l;
+ int conversion_error;
+
+ while (*foldername)
+ {
+ if (*foldername == '.')
+ {
+ (*closure)(foldername, 1, arg);
+ ++foldername;
+ continue;
+ }
+
+ h=unicode_convert_tocbuf_init(src_chset,
+ dst_chset,
+ &cbufptr,
+ &cbufsize,
+ 0);
+ if (!h)
+ {
+ errno=EINVAL;
+ return -1;
+ }
+
+ for (l=0; foldername[l] && foldername[l] != '.'; ++l)
+ ;
+
+ unicode_convert(h, foldername, l);
+
+ if (unicode_convert_deinit(h, &conversion_error) == 0)
+ {
+ closure(cbufptr, cbufsize, arg);
+ free(cbufptr);
+ if (conversion_error)
+ {
+ errno=EILSEQ;
+ return -1;
+ }
+ }
+ else
+ return -1;
+ foldername += l;
+ }
+ return 0;
+}
+
+/* Convert either a foldername or a filename to the other */
+
+static char *foldername_filename_convert_tobuf(const char *src_chset,
+ const char *dst_chset,
+ const char *foldername)
+{
+ char *utf8, *p;
+ size_t l=1;
+
+ if (foldername_filename_convert(src_chset,
+ dst_chset,
+ foldername, count_utf8, &l))
+ return NULL;
+
+ utf8=malloc(l+1);
+
+ if (!utf8)
+ return NULL;
+
+ p=utf8;
+ if (foldername_filename_convert(src_chset,
+ dst_chset,
+ foldername, save_utf8, &p))
+ {
+ free(utf8);
+ return NULL;
+ }
+
+ *p=0;
+
+ return utf8;
+}
+
+char *imap_foldername_to_filename(int utf8_format, const char *foldername)
+{
+ if (utf8_format)
+ return strdup(foldername);
+
+ return foldername_filename_convert_tobuf
+ (unicode_x_imap_modutf7,
+ "utf-8",
+ foldername);
+}
+
+char *imap_filename_to_foldername(int utf8_format, const char *filename)
+{
+ if (utf8_format)
+ return strdup(filename);
+
+ return foldername_filename_convert_tobuf
+ ("utf-8",
+ unicode_x_imap_modutf7,
+ filename);
+}
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();
}
diff --git a/maildir/maildirmake.sgml b/maildir/maildirmake.sgml
index b1a7d6d..e60ef61 100644
--- a/maildir/maildirmake.sgml
+++ b/maildir/maildirmake.sgml
@@ -1,5 +1,5 @@
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
-<!-- Copyright 1998 - 2009 Double Precision, Inc. See COPYING for -->
+<!-- Copyright 1998 - 2018 Double Precision, Inc. See COPYING for -->
<!-- distribution information. -->
<refentry>
<info><author><firstname>Sam</firstname><surname>Varshavchik</surname><contrib>Author</contrib></author><productname>Courier Mail Server</productname></info>
@@ -28,7 +28,7 @@
<para>
The <command>maildirmake</command> command creates maildirs, and
-maildir folders.
+maildir folders and performs some routine maintenance on them.
This documentation
describes the <command>maildirmake</command> command from the
<application>Courier</application> mail server,
@@ -46,9 +46,7 @@ slightly different permissions which allows creation of publicly-shared
folders.</simpara>
</listitem>
</varlistentry>
- </variablelist>
- <variablelist>
<varlistentry><term><literal>-q</literal> <replaceable>quota</replaceable></term>
<listitem><simpara>install a quota on the maildir.
See
@@ -59,17 +57,13 @@ folders.</simpara>
</simpara>
</listitem>
</varlistentry>
- </variablelist>
- <variablelist>
<varlistentry><term><literal>-f</literal> <replaceable>folder</replaceable></term>
<listitem><simpara>do not create a maildir, but create a folder in an
existing maildir.</simpara>
</listitem>
</varlistentry>
- </variablelist>
- <variablelist>
<varlistentry><term><literal>-F</literal> <replaceable>folder</replaceable></term>
<listitem><simpara>Like the <literal>-f</literal> option, except
that the folder's name is given using the system locale's
@@ -80,9 +74,7 @@ existing maildir.</simpara>
set..</simpara>
</listitem>
</varlistentry>
- </variablelist>
- <variablelist>
<varlistentry><term><literal>-s</literal> <replaceable>mode</replaceable></term>
<listitem><simpara>create a publicly accessible folder in an
existing sharable maildir. First, use the <option>-S</option> option to
@@ -100,9 +92,7 @@ your own system group to access messages in this folder (instead of
everyone).</simpara>
</listitem>
</varlistentry>
- </variablelist>
- <variablelist>
<varlistentry><term><literal>--add</literal> <replaceable>name</replaceable>=<replaceable>pathname</replaceable>,
<literal>--del</literal> <replaceable>name</replaceable></term>
<listitem><simpara>
@@ -110,6 +100,29 @@ create or delete the directories and links needed to
access shared folders. See below for more information.</simpara>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>--checkutf8</literal> <replaceable>maildir</replaceable> <replaceable>maildirfilter</replaceable></term>
+ <listitem>
+ <simpara>
+ Perform a sanity check to verify that a pre-unicode format
+ maildir can be converted to a unicode-format maildir.
+ See <quote>Converting pre-unicode format maildirs</quote>, below,
+ for more information.
+ </simpara>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>--convutf8</literal> <replaceable>maildir</replaceable> <replaceable>maildirfilter</replaceable></term>
+ <listitem>
+ <simpara>
+ Convert a pre-unicode format
+ maildir can be converted to a unicode-format maildir.
+ See <quote>Converting pre-unicode format maildirs</quote>, below,
+ for more information.
+ </simpara>
+ </listitem>
+ </varlistentry>
</variablelist>
<refsect2>
@@ -270,6 +283,288 @@ own.</para>
</refsect2>
</refsect1>
+
+ <refsect1>
+ <title>Converting pre-unicode format maildirs</title>
+
+ <para>
+ This section is relevant to:
+
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Updating <application>Courier-IMAP</application> to version 5.0, and
+ later, from prior versions of <application>Courier-IMAP</application>, or:
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Updating <application>SqWebmail</application> to version 6.0, and
+ later, from prior versions of <application>SqWebmail</application>, or:
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Updating Courier to version 1.0, and
+ later, from prior versions of Courier.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ These versions have been updated to implement native Unicode
+ support in several E-mail-related protocols. It is already expected
+ that updating Internet standards to use native Unicode-formatted
+ E-mail messages will not be 100% backwards-compatible, in terms of
+ E-mail client support.
+ Given that, this major update to Unicode will also introduce some
+ backwards-incompatible changes to the internal structure of maildirs,
+ as a long term major to simplify Unicode support going forward.
+ Might as well go through the pain of a major upgrade once.
+ </para>
+
+ <para>
+ <command>maildirmake</command>'s <option>--checkutf8</option> and
+ <option>--convutf8</option> options are tools to aid in conversion of
+ existing mailbox to the new Unicode-based naming standard.
+ </para>
+
+ <refsect2>
+ <title>Background</title>
+
+ <para>
+ Mail folders in a maildir are hidden subdirectories. For example:
+ a folder name <quote>Mailing list</quote> is a maildir subdirectory
+ named <filename>$HOME/Maildir/.Mailing list</filename> (with
+ <filename>$HOME/Maildir</filename> being the main mailbox).
+ </para>
+
+ <para>
+ Prior to the unicode update, non-English characters in folder names
+ were implemented using a convention that was derived from the
+ non-standard <quote>modified-UTF7</quote> encoding used by IMAP.
+ A folder named <quote>Résumé</quote> was in a maildir subdirectory
+ named <filename>$HOME/Maildir/.R&amp;AOk-sum&amp;AOk-</filename>.
+ The current versions of Courier, <application>Courier-IMAP</application>, and SqWebmail,
+ will simply create <filename>$HOME/Maildir/.Résumé</filename>
+ using the <acronym>UTF8</acronym> encoding, which will appear simply
+ as a <quote>.Résumé</quote> (hidden) subdirectory on modern
+ UTF8-based systems.
+ </para>
+
+ <para>
+ Consequently, any existing maildirs that have non-English folders
+ must be converted as part of updating to the current version of
+ Courier, <application>Courier-IMAP</application>, and SqWebmail from pre-unicode versions.
+ At this time
+ this does not occur as part of automatically updating to the current
+ version, and must be done manually given the wide variety of individual
+ mail server configurations that are possible.
+ </para>
+ </refsect2>
+
+ <refsect2>
+ <title>Unicode conversion overview</title>
+
+ <para>
+ Updating from pre-unicode versions involves:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Renaming the actual maildir folders,
+ <filename>$HOME/Maildir/.<replaceable>names</replaceable></filename>
+ into unicode names (using <acronym>UTF8</acronym>).
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Updating the
+ <filename>$HOME/Maildir/courierimapsubscribed</filename>,
+ which is a list of subscribed IMAP folders, if it exists.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Updating any
+ <application>maildrop</application>
+ mail filtering recipe,
+ <filename>$HOME/.mailfilter</filename>, if it exists, to reference
+ the unicode maildir folders; or updating any custom site mail
+ filtering engine that delivers to maildir folders, to reference
+ the correct subdirectory names.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </refsect2>
+ <refsect2>
+ <title>Unicode conversion steps</title>
+
+ <para>
+ The <option>--checkutf8</option> and
+ <option>--convutf8</option> options to
+ <command>maildirmake</command> convert a single maildir to the new
+ unicode format:
+ </para>
+
+ <blockquote>
+ <informalexample>
+ <programlisting>
+$ ./maildirmake --checkutf8 ~/Maildir ~/.mailfilter
+Checking /home/mrsam/Maildir:
+Mail filter to INBOX.R&amp;AOk-sum&amp;AOk- updated to INBOX.Résumé
+Subscription to INBOX.R&amp;AOk-sum&amp;AOk- changed to INBOX.Résumé
+Rename INBOX.R&amp;AOk-sum&amp;AOk- to INBOX.Résumé
+Verified /home/mrsam/Maildir/courierimapsubscribed
+Verified /home/mrsam/.mailfilter
+$ ./maildirmake --convutf8 ~/Maildir ~/.mailfilter
+Checking /home/mrsam/Maildir:
+Mail filter to INBOX.R&amp;AOk-sum&amp;AOk- updated to INBOX.Résumé
+Subscription to INBOX.R&amp;AOk-sum&amp;AOk- changed to INBOX.Résumé
+Rename INBOX.R&amp;AOk-sum&amp;AOk- to INBOX.Résumé
+Updating /home/mrsam/Maildir/courierimapsubscribed
+Updating /home/mrsam/.mailfilter</programlisting>
+ </informalexample>
+ </blockquote>
+
+ <para>
+ <option>--checkutf8</option> goes through the motions of converting
+ a single maildir to Unicode, but without making any actual changes.
+ <option>--convutf8</option> does the conversion for real.
+ The first required parameter is the maildir to convert. The
+ second parameter is optional, and specifies the corresponding
+ <command>maildrop</command> filtering recipe,
+ <emphasis>but only if <application>SqWebMail</application></emphasis>
+ generates the mail filtering recipes.
+ <application>SqWebMail</application>'s mail filtering recipes are
+ parsable, and can be automatically-converted.
+ Non-<application>SqWebMail</application>-generated
+ <filename>.mailfilter</filename>s cannot be converted automatically.
+ The second parameter must be omitted, and the mail filtering recipe
+ must be converted by hand.
+ </para>
+
+ <note>
+ <para>
+ Any manual work is only needed if maildirs have folders with
+ non-English names. Ignore everything you've just read if all
+ folder names are English-only.
+ <option>--checkutf8</option> and
+ <option>--convutf8</option> will not do anything, and nothing
+ needs to be done.
+ </para>
+ </note>
+
+ <para>
+ To convert all mailboxes to Unicode all at once:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Write a shell script to run <option>--checkutf8</option> on
+ all your mailboxes. It's ok to explicitly specify each mailbox's
+ <filename>.mailfilter</filename>, when using
+ <application>SqWebMail</application> even if a particular
+ mailbox does not use it. It will be ignored.
+ </para>
+
+ <para>
+ It is safe to run <option>--checkutf8</option> without shutting
+ down your mail server. A non-zero exit from
+ <option>--checkutf8</option> indicates a problem (see below)
+ for a particular maildir.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Once <option>--checkutf8</option> does not find any problems
+ with any mailbox, shut down the mail server, run
+ <option>--checkutf8</option> one more time for all mailboxes,
+ then if everything goes well, upgrade
+ <application>Courier</application>,
+ <application>Courier-IMAP</application>, or
+ <application>SqWebMail</application> and
+ run
+ <option>--convutf8</option> on every mailbox before restarting
+ the server.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <note>
+ <para>
+ <option>--convutf8</option> is a one-shot deal. Do not run
+ <option>--convutf8</option> a second time after it successfully
+ converted a maildir. In nearly all cases nothing will happen,
+ but there are rare edge cases where some folder names may
+ get garbled, or it fails completely.
+ </para>
+ </note>
+ </refsect2>
+
+ <refsect2>
+ <title>Resolving unicode conversion problems</title>
+
+ <para>
+ The only likely problems that might be encountered is the fall-out
+ from buggy IMAP clients that did not follow the pre-Unicode naming
+ convention for non-Latin folder names. The customized IMAP
+ <quote>modified-UTF7</quote> encoding convention for non-Latin
+ folder names is mostly an IMAP client convention, and the
+ pre-Unicode version of <application>Courier-IMAP</application> did
+ not enforce it. The server just uses the name from the IMAP client,
+ as is.
+ </para>
+
+ <para>
+ Unicode conversion (<option>--checkutf8</option> or
+ <option>--convutf8</option>) fails if it finds a folder name that
+ does not correctly use IMAP's
+ <quote>modified-UTF7</quote> encoding. This can only be resolved
+ manually, by renaming the folder. This may also involve manually
+ editing <filename>courierimapsubscribed</filename> and
+ <filename>.mailfilter</filename> if they exist. The bad folder name
+ should be removed from
+ <filename>courierimapsubscribed</filename>. For
+ <filename>.mailfilter</filename> it is sufficient to remove only
+ the comments that precede the actual <command>maildrop</command> rule,
+ and <option>--convutf8</option> will remove the entire rule, by itself.
+ <option>--convutf8</option> actually reads only the machine-parsable
+ comments in <command>SqWebMail</command>-generated
+ <filename>.mailfilter</filename> (plus a few other things in the
+ file), and replaces the
+ <filename>.mailfilter</filename> with the Unicode version based
+ solely on the parsed data.
+ </para>
+ </refsect2>
+
+ <refsect2>
+ <title>After the Unicode conversion</title>
+
+ <para>
+ The current, Unicode version of <application>Courier-IMAP</application>
+ supports both Unicode and non-Unicode
+ IMAP clients; however unlike the pre-Unicode version,
+ <application>Courier-IMAP</application> rejects requests from
+ non-Unicode IMAP clients to use or create folders that are not
+ properly encoded.
+ </para>
+
+ <para>
+ Encountering a bad folder during conversion strongly suggests the
+ usage of an IMAP client that does not correctly encode non-English
+ folder names. Such an IMAP client will likely have problems after
+ the conversion.
+ </para>
+ </refsect2>
+ </refsect1>
<refsect1>
<title>SEE ALSO</title>
diff --git a/maildir/testmaildirfilter.c b/maildir/testmaildirfilter.c
index c50d358..a8804d5 100644
--- a/maildir/testmaildirfilter.c
+++ b/maildir/testmaildirfilter.c
@@ -79,7 +79,7 @@ const char *charset=getenv("CHARSET");
}
unlink("maildirsize");
- errcode=maildir_filter_saverules(&mf, "testrules2", ".", "Maildir", "nobody@example.com");
+ errcode=maildir_filter_saverules(&mf, "testrules2", "Maildir", "nobody@example.com");
if (errcode)
{
fprintf(stderr, "Error saving testrules2: %d\n", errcode);