mirror of
https://github.com/moparisthebest/imapfilter
synced 2024-08-13 16:53:51 -04:00
Add support for non-ASCII mailbox names
International mailbox names are specified with the IMAP4rev1 modified UTF-7 encoding, and the conversion is done automatically.
This commit is contained in:
parent
dae82ff5af
commit
ca818203f0
@ -21,7 +21,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
extern buffer ibuf, obuf, nbuf;
|
||||
extern buffer ibuf, obuf, nbuf, cbuf;
|
||||
extern regexp responses[];
|
||||
|
||||
options opts; /* Program options. */
|
||||
@ -98,6 +98,7 @@ main(int argc, char *argv[])
|
||||
buffer_init(&ibuf, INPUT_BUF);
|
||||
buffer_init(&obuf, OUTPUT_BUF);
|
||||
buffer_init(&nbuf, NAMESPACE_BUF);
|
||||
buffer_init(&cbuf, CONVERSION_BUF);
|
||||
|
||||
if (opts.config == NULL)
|
||||
opts.config = get_filepath("config.lua");
|
||||
@ -137,6 +138,7 @@ main(int argc, char *argv[])
|
||||
buffer_free(&ibuf);
|
||||
buffer_free(&obuf);
|
||||
buffer_free(&nbuf);
|
||||
buffer_free(&cbuf);
|
||||
|
||||
xfree(env.home);
|
||||
|
||||
|
@ -53,7 +53,8 @@
|
||||
/* Initial buffer size for input, output and namespace buffers. */
|
||||
#define INPUT_BUF 4096
|
||||
#define OUTPUT_BUF 1024
|
||||
#define NAMESPACE_BUF 128
|
||||
#define NAMESPACE_BUF 512
|
||||
#define CONVERSION_BUF 512
|
||||
|
||||
/* Maximum length, in bytes, of a utility's input line. */
|
||||
#ifndef LINE_MAX
|
||||
|
194
src/namespace.c
194
src/namespace.c
@ -1,11 +1,18 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <iconv.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "imapfilter.h"
|
||||
#include "buffer.h"
|
||||
|
||||
|
||||
buffer nbuf; /* Namespace buffer. */
|
||||
buffer cbuf; /* Conversion buffer. */
|
||||
|
||||
|
||||
const char *apply_conversion(const char *mbox);
|
||||
const char *reverse_conversion(const char *mbox);
|
||||
|
||||
|
||||
/*
|
||||
@ -17,26 +24,29 @@ apply_namespace(const char *mbox, char *prefix, char delim)
|
||||
{
|
||||
int n;
|
||||
char *c;
|
||||
const char *m;
|
||||
|
||||
if (!strcasecmp(mbox, "INBOX"))
|
||||
return mbox;
|
||||
|
||||
m = apply_conversion(mbox);
|
||||
|
||||
if ((prefix == NULL && delim == '\0') ||
|
||||
(prefix == NULL && delim == '/') ||
|
||||
!strcasecmp(mbox, "INBOX"))
|
||||
return mbox;
|
||||
(prefix == NULL && delim == '/'))
|
||||
return m;
|
||||
|
||||
buffer_reset(&nbuf);
|
||||
|
||||
n = snprintf(nbuf.data, nbuf.size + 1, "%s%s", (prefix ? prefix : ""),
|
||||
mbox);
|
||||
m);
|
||||
if (n > (int)nbuf.size) {
|
||||
buffer_check(&nbuf, n);
|
||||
snprintf(nbuf.data, nbuf.size + 1, "%s%s",
|
||||
(prefix ? prefix : ""), mbox);
|
||||
snprintf(nbuf.data, nbuf.size + 0, "%s%s",
|
||||
(prefix ? prefix : ""), m);
|
||||
}
|
||||
c = nbuf.data;
|
||||
while ((c = strchr(c, '/')))
|
||||
*(c++) = delim;
|
||||
for (c = nbuf.data; (c = strchr(c, '/')) != NULL; *(c++) = delim);
|
||||
|
||||
debug("namespace: '%s' -> '%s'\n", mbox, nbuf.data);
|
||||
debug("namespace: '%s' -> '%s'\n", m, nbuf.data);
|
||||
|
||||
return nbuf.data;
|
||||
}
|
||||
@ -52,11 +62,13 @@ reverse_namespace(const char *mbox, char *prefix, char delim)
|
||||
int n, o;
|
||||
char *c;
|
||||
|
||||
if ((prefix == NULL && delim == '\0') ||
|
||||
(prefix == NULL && delim == '/') ||
|
||||
!strcasecmp(mbox, "INBOX"))
|
||||
if (!strcasecmp(mbox, "INBOX"))
|
||||
return mbox;
|
||||
|
||||
if ((prefix == NULL && delim == '\0') ||
|
||||
(prefix == NULL && delim == '/'))
|
||||
return reverse_conversion(mbox);
|
||||
|
||||
buffer_reset(&nbuf);
|
||||
|
||||
o = strlen(prefix ? prefix : "");
|
||||
@ -68,11 +80,161 @@ reverse_namespace(const char *mbox, char *prefix, char delim)
|
||||
buffer_check(&nbuf, n);
|
||||
snprintf(nbuf.data, nbuf.size + 1, "%s", mbox + o);
|
||||
}
|
||||
c = nbuf.data;
|
||||
while ((c = strchr(c, delim)))
|
||||
*(c++) = '/';
|
||||
for (c = nbuf.data; (c = strchr(c, delim)) != NULL; *(c++) = '/');
|
||||
|
||||
debug("namespace: '%s' <- '%s'\n", mbox, nbuf.data);
|
||||
|
||||
return reverse_conversion(nbuf.data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a mailbox name to the modified UTF-7 encoding, according to RFC 3501
|
||||
* Section 5.1.3.
|
||||
*/
|
||||
const char *
|
||||
apply_conversion(const char *mbox)
|
||||
{
|
||||
size_t n;
|
||||
iconv_t cd;
|
||||
char *inbuf, *outbuf;
|
||||
size_t inlen, outlen;
|
||||
char *c, *shift;
|
||||
|
||||
n = strlen(mbox);
|
||||
buffer_check(&nbuf, n);
|
||||
buffer_reset(&nbuf);
|
||||
xstrncpy(nbuf.data, mbox, *(mbox + n - 1) == '*' ||
|
||||
*(mbox + n - 1) == '%' ? n - 1 : n);
|
||||
for (c = nbuf.data; (c = strchr(c, '&')) != NULL; *c = '+');
|
||||
|
||||
do {
|
||||
inbuf = nbuf.data;
|
||||
inlen = strlen(nbuf.data);
|
||||
|
||||
buffer_check(&cbuf, inlen);
|
||||
buffer_reset(&cbuf);
|
||||
|
||||
outbuf = cbuf.data;
|
||||
outlen = cbuf.size;
|
||||
|
||||
cd = iconv_open("UTF-7", "");
|
||||
if (cd == (iconv_t)-1) {
|
||||
error("converting mailbox name; %s\n", strerror(errno));
|
||||
return mbox;
|
||||
}
|
||||
while (inlen > 0) {
|
||||
if (iconv(cd, &inbuf, &inlen, &outbuf, &outlen) == -1) {
|
||||
if (errno == E2BIG) {
|
||||
buffer_check(&cbuf, cbuf.size * 2);
|
||||
break;
|
||||
} else {
|
||||
error("converting mailbox name; %s\n",
|
||||
strerror(errno));
|
||||
return mbox;
|
||||
}
|
||||
} else {
|
||||
iconv(cd, NULL, NULL, &outbuf, &outlen);
|
||||
}
|
||||
}
|
||||
iconv_close(cd);
|
||||
} while (inlen > 0);
|
||||
|
||||
if (*outbuf != '\0')
|
||||
*outbuf = '\0';
|
||||
for (c = cbuf.data, shift = NULL; *c != '\0'; c++)
|
||||
switch (*c) {
|
||||
case '+':
|
||||
*c = '&';
|
||||
shift = c;
|
||||
break;
|
||||
case '-':
|
||||
shift = NULL;
|
||||
break;
|
||||
case '/':
|
||||
if (shift != NULL)
|
||||
*c = ',';
|
||||
break;
|
||||
}
|
||||
if (shift != NULL) {
|
||||
*outbuf++ = '-';
|
||||
*outbuf = '\0';
|
||||
}
|
||||
if (*(mbox + n - 1) == '*' || *(mbox + n - 1) == '%') {
|
||||
*outbuf++ = *(mbox + n - 1);
|
||||
*outbuf = '\0';
|
||||
}
|
||||
|
||||
debug("conversion: '%s' -> '%s'\n", mbox, cbuf.data);
|
||||
|
||||
return cbuf.data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a mailbox name from the modified UTF-7 encoding, according to RFC
|
||||
* 3501 Section 5.1.3.
|
||||
*/
|
||||
const char *reverse_conversion(const char *mbox)
|
||||
{
|
||||
iconv_t cd;
|
||||
char *inbuf, *outbuf;
|
||||
size_t inlen, outlen;
|
||||
char *c, *shift;
|
||||
|
||||
buffer_check(&cbuf, strlen(mbox));
|
||||
buffer_reset(&cbuf);
|
||||
xstrncpy(cbuf.data, mbox, cbuf.size);
|
||||
for (c = cbuf.data, shift = NULL; *c != '\0'; c++)
|
||||
switch (*c) {
|
||||
case '&':
|
||||
*c = '+';
|
||||
shift = c;
|
||||
break;
|
||||
case '-':
|
||||
shift = NULL;
|
||||
break;
|
||||
case ',':
|
||||
if (shift != NULL)
|
||||
*c = '/';
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
inbuf = cbuf.data;
|
||||
inlen = strlen(cbuf.data);
|
||||
|
||||
buffer_check(&nbuf, inlen);
|
||||
buffer_reset(&nbuf);
|
||||
|
||||
outbuf = nbuf.data;
|
||||
outlen = nbuf.size;
|
||||
|
||||
cd = iconv_open("", "UTF-7");
|
||||
if (cd == (iconv_t)-1) {
|
||||
error("converting mailbox name; %s\n", strerror(errno));
|
||||
return mbox;
|
||||
}
|
||||
while (inlen > 0) {
|
||||
if (iconv(cd, &inbuf, &inlen, &outbuf, &outlen) == -1) {
|
||||
if (errno == E2BIG) {
|
||||
buffer_check(&nbuf, nbuf.size * 2);
|
||||
break;
|
||||
} else {
|
||||
error("converting mailbox name; %s\n",
|
||||
strerror(errno));
|
||||
return mbox;
|
||||
}
|
||||
} else {
|
||||
iconv(cd, NULL, NULL, &outbuf, &outlen);
|
||||
}
|
||||
}
|
||||
iconv_close(cd);
|
||||
} while (inlen > 0);
|
||||
|
||||
*outbuf = '\0';
|
||||
for (c = nbuf.data; (c = strchr(c,'+')) != NULL; *c = '&');
|
||||
|
||||
debug("conversion: '%s' <- '%s'\n", mbox, nbuf.data);
|
||||
|
||||
return nbuf.data;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user