diff options
| -rw-r--r-- | maildir/Makefile.am | 4 | ||||
| -rw-r--r-- | maildir/maildirfilter.c | 5 | ||||
| -rw-r--r-- | maildir/maildirfilter.h | 1 | ||||
| -rw-r--r-- | maildir/maildirfilter2.c | 2 | ||||
| -rw-r--r-- | maildir/maildirinfo.h | 4 | ||||
| -rw-r--r-- | maildir/maildirinfo2.c | 148 | ||||
| -rw-r--r-- | maildir/maildirmake.c | 434 | ||||
| -rw-r--r-- | maildir/maildirmake.sgml | 319 | ||||
| -rw-r--r-- | maildir/testmaildirfilter.c | 2 | 
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&AOk-sum&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&AOk-sum&AOk- updated to INBOX.Résumé +Subscription to INBOX.R&AOk-sum&AOk- changed to INBOX.Résumé +Rename INBOX.R&AOk-sum&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&AOk-sum&AOk- updated to INBOX.Résumé +Subscription to INBOX.R&AOk-sum&AOk- changed to INBOX.Résumé +Rename INBOX.R&AOk-sum&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); | 
