imapfilter/src/namespace.c

241 lines
4.9 KiB
C
Raw Normal View History

2011-03-06 06:58:58 -05:00
#include <stdio.h>
#include <string.h>
#include <iconv.h>
#include <errno.h>
2011-03-06 06:58:58 -05:00
#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);
2011-03-06 06:58:58 -05:00
/*
* Convert the names of personal mailboxes, using the namespace specified
* by the mail server, from internal to mail server format.
*/
const char *
apply_namespace(const char *mbox, char *prefix, char delim)
{
int n;
char *c;
const char *m;
2011-03-06 06:58:58 -05:00
if (!strcasecmp(mbox, "INBOX"))
2011-03-06 06:58:58 -05:00
return mbox;
m = apply_conversion(mbox);
if ((prefix == NULL && delim == '\0') ||
(prefix == NULL && delim == '/'))
return m;
2011-03-06 06:58:58 -05:00
buffer_reset(&nbuf);
n = snprintf(nbuf.data, nbuf.size + 1, "%s%s", (prefix ? prefix : ""),
m);
2011-03-06 06:58:58 -05:00
if (n > (int)nbuf.size) {
buffer_check(&nbuf, n);
snprintf(nbuf.data, nbuf.size + 0, "%s%s",
(prefix ? prefix : ""), m);
2011-03-06 06:58:58 -05:00
}
for (c = nbuf.data; (c = strchr(c, '/')) != NULL; *(c++) = delim);
2011-03-06 06:58:58 -05:00
debug("namespace: '%s' -> '%s'\n", m, nbuf.data);
2011-03-06 06:58:58 -05:00
return nbuf.data;
}
/*
* Convert the names of personal mailboxes, using the namespace specified by
* the mail server, from mail server format to internal format.
*/
const char *
reverse_namespace(const char *mbox, char *prefix, char delim)
{
int n, o;
char *c;
if (!strcasecmp(mbox, "INBOX"))
2011-03-06 06:58:58 -05:00
return mbox;
if ((prefix == NULL && delim == '\0') ||
(prefix == NULL && delim == '/'))
return reverse_conversion(mbox);
2011-03-06 06:58:58 -05:00
buffer_reset(&nbuf);
o = strlen(prefix ? prefix : "");
if (strncasecmp(mbox, (prefix ? prefix : ""), o))
o = 0;
n = snprintf(nbuf.data, nbuf.size + 1, "%s", mbox + o);
if (n > (int)nbuf.size) {
buffer_check(&nbuf, n);
snprintf(nbuf.data, nbuf.size + 1, "%s", mbox + o);
}
for (c = nbuf.data; (c = strchr(c, delim)) != NULL; *(c++) = '/');
2011-03-06 06:58:58 -05:00
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);
2011-03-06 06:58:58 -05:00
return nbuf.data;
}