#include "config.h"
#include "cunit/cyrunit.h"
#include "imap/imap_err.h"
#include "prot.h"
#include "retry.h"
#include "xmalloc.h"
#include "lib/libconfig.h"
#include "lib/libcyr_cfg.h"
#include "imap/spool.h"
#define DBDIR "test-dbdir"
#define DELIVERED "Fri, 29 Oct 2010 13:07:07 +1100"
#define FIRST_RX "Fri, 29 Oct 2010 13:05:01 +1100"
#define SECOND_RX "Fri, 29 Oct 2010 13:03:03 +1100"
#define THIRD_RX "Fri, 29 Oct 2010 13:01:01 +1100"
#define SENT "Thu, 28 Oct 2010 18:37:26 +1100"
#define HFROM "Fred Bloggs <fbloggs@fastmail.fm>"
#define HFROM2 "Antoine Lavoisier <lavoisier@chemistry.fr>"
#define HTO "Sarah Jane Smith <sjsmith@gmail.com>"
#define HDATE SENT
#define HSUBJECT "Simple testing email"
#define HMESSAGEID "<fake1000@fastmail.fm>"
#define HRECEIVED1 "from mail.quux.com (mail.quux.com [10.0.0.1]) by mail.gmail.com (Software); " FIRST_RX
#define HRECEIVED2 "from mail.bar.com (mail.bar.com [10.0.0.1]) by mail.quux.com (Software); " SECOND_RX
#define HRECEIVED3 "from mail.fastmail.fm (mail.fastmail.fm [10.0.0.1]) by mail.bar.com (Software); " THIRD_RX
static int set_up(void)
{
/* need basic configuration for parseheader */
libcyrus_config_setstring(CYRUSOPT_CONFIG_DIR, DBDIR);
config_read_string(
"configdirectory: "DBDIR"/conf\n"
);
return 0;
}
static int tear_down(void)
{
int r;
config_reset();
r = system("rm -rf " DBDIR);
return r;
}
static void test_simple(void)
{
hdrcache_t cache;
const char **val;
cache = spool_new_hdrcache();
CU_ASSERT_PTR_NOT_NULL(cache);
val = spool_getheader(cache, "Nonesuch");
CU_ASSERT_PTR_NULL(val);
val = spool_getheader(cache, "From");
CU_ASSERT_PTR_NULL(val);
val = spool_getheader(cache, "fRoM");
CU_ASSERT_PTR_NULL(val);
val = spool_getheader(cache, "from");
CU_ASSERT_PTR_NULL(val);
spool_cache_header(xstrdup("From"), xstrdup(HFROM), cache);
val = spool_getheader(cache, "Nonesuch");
CU_ASSERT_PTR_NULL(val);
val = spool_getheader(cache, "From");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "fRoM");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "from");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
spool_cache_header(xstrdup("To"), xstrdup(HTO), cache);
spool_cache_header(xstrdup("Date"), xstrdup(HDATE), cache);
spool_cache_header(xstrdup("Subject"), xstrdup(HSUBJECT), cache);
spool_cache_header(xstrdup("Message-ID"), xstrdup(HMESSAGEID), cache);
spool_cache_header(xstrdup("Received"), xstrdup(HRECEIVED1), cache);
spool_cache_header(xstrdup("Received"), xstrdup(HRECEIVED2), cache);
spool_cache_header(xstrdup("Received"), xstrdup(HRECEIVED3), cache);
val = spool_getheader(cache, "Nonesuch");
CU_ASSERT_PTR_NULL(val);
val = spool_getheader(cache, "From");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "fRoM");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "from");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "To");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HTO);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "Subject");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HSUBJECT);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "message-id");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HMESSAGEID);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "received");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HRECEIVED1);
CU_ASSERT_STRING_EQUAL(val[1], HRECEIVED2);
CU_ASSERT_STRING_EQUAL(val[2], HRECEIVED3);
CU_ASSERT_PTR_NULL(val[3]);
spool_free_hdrcache(cache);
}
static void test_fill(void)
{
static const char MSG[] =
"From: " HFROM "\r\n"
"To: " HTO "\r\n"
"Date: " HDATE "\r\n"
"Subject: " HSUBJECT "\r\n"
"Message-ID: " HMESSAGEID "\r\n"
"Received: " HRECEIVED1 "\r\n"
"Received: " HRECEIVED2 "\r\n"
"Received: " HRECEIVED3 "\r\n"
"\r\n"
"Hello, World\r\n";
hdrcache_t cache;
const char **val;
int fd;
char tempfile[32];
int r;
struct protstream *pin;
FILE *fout;
/* Setup @pin to point to the start of a file open for (at least)
* reading containing the message. */
strcpy(tempfile, "/tmp/spooltestAXXXXXX");
fd = mkstemp(tempfile);
CU_ASSERT(fd >= 0);
r = retry_write(fd, MSG, sizeof(MSG)-1);
CU_ASSERT_EQUAL(r, sizeof(MSG)-1);
lseek(fd, SEEK_SET, 0);
pin = prot_new(fd, /*read*/0);
CU_ASSERT_PTR_NOT_NULL(pin);
/* Setup @fout to ignore data written to it */
fout = fopen("/dev/null", "w");
CU_ASSERT_PTR_NOT_NULL(fout);
cache = spool_new_hdrcache();
CU_ASSERT_PTR_NOT_NULL(cache);
/* TODO: test non-NULL skipheaders */
r = spool_fill_hdrcache(pin, fout, cache, NULL);
CU_ASSERT_EQUAL(r, 0);
val = spool_getheader(cache, "Nonesuch");
CU_ASSERT_PTR_NULL(val);
val = spool_getheader(cache, "From");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "fRoM");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "from");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "To");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HTO);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "Subject");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HSUBJECT);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "message-id");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HMESSAGEID);
CU_ASSERT_PTR_NULL(val[1]);
val = spool_getheader(cache, "received");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HRECEIVED1);
CU_ASSERT_STRING_EQUAL(val[1], HRECEIVED2);
CU_ASSERT_STRING_EQUAL(val[2], HRECEIVED3);
CU_ASSERT_PTR_NULL(val[3]);
spool_free_hdrcache(cache);
fclose(fout);
prot_free(pin);
unlink(tempfile);
}
/* BZ3640: headers with NULL bytes shall be rejected. */
static void test_fill_null(void)
{
static const char MSG[] =
"From: " HFROM "\r\n"
"To: " HTO "\r\n"
"Date: " HDATE "\r\n"
"Subject: " HSUBJECT "\r\n"
"Message-ID: " HMESSAGEID "\r\n"
"Received: " HRECEIVED1 "\r\n"
"Received:\0" HRECEIVED2 "\r\n"
"Received: " HRECEIVED3 "\r\n"
"\r\n"
"Hello, World\r\n";
hdrcache_t cache;
int fd;
char tempfile[32];
int r;
struct protstream *pin;
FILE *fout;
/* Setup @pin to point to the start of a file open for (at least)
* reading containing the message. */
strcpy(tempfile, "/tmp/spooltestAXXXXXX");
fd = mkstemp(tempfile);
CU_ASSERT(fd >= 0);
r = retry_write(fd, MSG, sizeof(MSG)-1);
CU_ASSERT_EQUAL(r, sizeof(MSG)-1);
lseek(fd, SEEK_SET, 0);
pin = prot_new(fd, /*read*/0);
CU_ASSERT_PTR_NOT_NULL(pin);
/* Setup @fout to ignore data written to it */
fout = fopen("/dev/null", "w");
CU_ASSERT_PTR_NOT_NULL(fout);
cache = spool_new_hdrcache();
CU_ASSERT_PTR_NOT_NULL(cache);
r = spool_fill_hdrcache(pin, fout, cache, NULL);
CU_ASSERT_EQUAL(r, IMAP_MESSAGE_CONTAINSNULL);
spool_free_hdrcache(cache);
fclose(fout);
prot_free(pin);
unlink(tempfile);
}
/* BZ3386: insert more unique headers than the internal limit of 4009
* headers, and see what happens. */
static void test_bz3386(void)
{
hdrcache_t cache;
#define N 5000
int i;
char name[32];
char body[128];
char body2[128]; /* use a different buffer Just In Case */
const char **val;
cache = spool_new_hdrcache();
CU_ASSERT_PTR_NOT_NULL(cache);
for (i = 0 ; i < N ; i++) {
snprintf(name, sizeof(name), "X-Foo-%d-%c", i, 'A'+(i%26));
snprintf(body, sizeof(body), "value %d %c", i, 'A'+(i%26));
spool_cache_header(xstrdup(name), xstrdup(body), cache);
}
strcpy(body, "Old Buffer");
for (i = 0 ; i < N ; i++) {
snprintf(name, sizeof(name), "X-Foo-%d-%c", i, 'A'+(i%26));
snprintf(body2, sizeof(body2), "value %d %c", i, 'A'+(i%26));
val = spool_getheader(cache, name);
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], body2);
CU_ASSERT_PTR_NULL(val[1]);
}
spool_free_hdrcache(cache);
#undef N
}
static void test_replace(void)
{
#define FOOBAR1 "If music be the foo of love"
#define FOOBAR2 "Foo glorious foo"
#define FOOBAR3 "Foo is an important part of a balanced diet"
/* apologies to Fran Liebowitz */
#define FOOBAR4 "Foo and Drug Administration"
hdrcache_t cache;
const char **val;
cache = spool_new_hdrcache();
CU_ASSERT_PTR_NOT_NULL(cache);
val = spool_getheader(cache, "From");
CU_ASSERT_PTR_NULL(val);
/* replace a single line */
spool_cache_header(xstrdup("From"), xstrdup(HFROM), cache);
val = spool_getheader(cache, "From");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM);
CU_ASSERT_PTR_NULL(val[1]);
spool_replace_header(xstrdup("From"), xstrdup(HFROM2), cache);
val = spool_getheader(cache, "From");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], HFROM2);
CU_ASSERT_PTR_NULL(val[1]);
/* replace multiple lines with one */
spool_cache_header(xstrdup("X-FooBar"), xstrdup(FOOBAR1), cache);
spool_cache_header(xstrdup("X-FooBar"), xstrdup(FOOBAR2), cache);
spool_cache_header(xstrdup("X-FooBar"), xstrdup(FOOBAR3), cache);
val = spool_getheader(cache, "X-FooBar");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], FOOBAR1);
CU_ASSERT_STRING_EQUAL(val[1], FOOBAR2);
CU_ASSERT_STRING_EQUAL(val[2], FOOBAR3);
CU_ASSERT_PTR_NULL(val[3]);
spool_replace_header(xstrdup("X-FooBar"), xstrdup(FOOBAR4), cache);
val = spool_getheader(cache, "X-FooBar");
CU_ASSERT_PTR_NOT_NULL(val);
CU_ASSERT_STRING_EQUAL(val[0], FOOBAR4);
CU_ASSERT_PTR_NULL(val[1]);
spool_free_hdrcache(cache);
#undef FOOBAR1
#undef FOOBAR2
#undef FOOBAR3
#undef FOOBAR4
}
/* vim: set ft=c: */