END_TEST START_TEST(test_dbmail_message_cache_headers) { DbmailMessage *m = dbmail_message_new(); char *s = g_new0(char,20); GString *j = g_string_new(multipart_message); m = dbmail_message_init_with_string(m,j); dbmail_message_set_header(m, "References", "<*****@*****.**> <*****@*****.**> <*****@*****.**> "); dbmail_message_store(m); dbmail_message_free(m); g_string_free(j,TRUE); sprintf(s,"%.*s",10,"abcdefghijklmnopqrstuvwxyz"); fail_unless(MATCH(s,"abcdefghij"),"string truncate failed"); g_free(s); m = dbmail_message_new(); j = g_string_new(multipart_message); m = dbmail_message_init_with_string(m,j); dbmail_message_set_header(m, "Subject", "=?utf-8?Q?[xxxxxxxxxxxxxxxxxx.xx_0000747]:_=C3=84nderungen_an_der_Artikel?= =?utf-8?Q?-Detailseite?=" ); dbmail_message_store(m); dbmail_message_free(m); g_string_free(j,TRUE); }
END_TEST START_TEST(test_imap_get_envelope_8bit_id) { DbmailMessage *message; char *result, *expect; const char *msgid = "<000001c1f64e$c4a34180$0100007f@z=F0=B5=D241>"; expect = g_new0(char, 1024); /* text/plain */ message = dbmail_message_new(NULL); message = dbmail_message_init_with_string(message, rfc822); dbmail_message_set_header(message,"Message-ID",msgid); result = imap_get_envelope(GMIME_MESSAGE(message->content)); strncpy(expect,"(\"Thu, 01 Jan 1970 00:00:00 +0000\" \"dbmail test message\" ((NIL NIL \"somewher\" \"foo.org\")) ((NIL NIL \"somewher\" \"foo.org\")) ((NIL NIL \"somewher\" \"foo.org\")) ((NIL NIL \"testuser\" \"foo.org\")) NIL NIL NIL NIL)",1024); fail_unless(strncasecmp(result,expect,1024)==0, "imap_get_envelope failed"); g_free(result); dbmail_message_set_header(message,"Message-ID","<*****@*****.**>"); result = imap_get_envelope(GMIME_MESSAGE(message->content)); strncpy(expect,"(\"Thu, 01 Jan 1970 00:00:00 +0000\" \"dbmail test message\" ((NIL NIL \"somewher\" \"foo.org\")) ((NIL NIL \"somewher\" \"foo.org\")) ((NIL NIL \"somewher\" \"foo.org\")) ((NIL NIL \"testuser\" \"foo.org\")) NIL NIL NIL \"<*****@*****.**>\")",1024); fail_unless(strncasecmp(result,expect,1024)==0, "imap_get_envelope failed"); dbmail_message_free(message); g_free(result); g_free(expect); }
END_TEST //DbmailMessage * dbmail_message_retrieve(DbmailMessage *self, u64_t physid, int filter); START_TEST(test_dbmail_message_retrieve) { DbmailMessage *m, *n; GString *s; u64_t physid; s = g_string_new(multipart_message); m = dbmail_message_new(); m = dbmail_message_init_with_string(m, s); fail_unless(m != NULL, "dbmail_message_init_with_string failed"); dbmail_message_set_header(m, "References", "<*****@*****.**> <*****@*****.**> <*****@*****.**> "); dbmail_message_store(m); physid = dbmail_message_get_physid(m); fail_unless(physid > 0, "dbmail_message_get_physid failed"); n = dbmail_message_new(); n = dbmail_message_retrieve(n,physid,DBMAIL_MESSAGE_FILTER_HEAD); fail_unless(n != NULL, "dbmail_message_retrieve failed"); fail_unless(n->content != NULL, "dbmail_message_retrieve failed"); dbmail_message_free(m); dbmail_message_free(n); g_string_free(s,TRUE); }
END_TEST START_TEST(test_dbmail_message_store2) { DbmailMessage *m, *n; u64_t physid; char *t; char *expect; m = message_init(broken_message2); dbmail_message_set_header(m, "Return-Path", dbmail_message_get_header(m, "From")); expect = dbmail_message_to_string(m); fail_unless(m != NULL, "dbmail_message_store2 failed"); dbmail_message_store(m); physid = dbmail_message_get_physid(m); dbmail_message_free(m); n = dbmail_message_new(); dbmail_message_set_physid(n, physid); n = dbmail_message_retrieve(n,physid,DBMAIL_MESSAGE_FILTER_FULL); fail_unless(n != NULL, "_mime_retrieve failed"); t = dbmail_message_to_string(n); COMPARE(expect,t); dbmail_message_free(n); g_free(expect); g_free(t); }
END_TEST START_TEST(test_dbmail_message_set_header) { DbmailMessage *m; GString *s; s = g_string_new(multipart_message); m = dbmail_message_new(); m = dbmail_message_init_with_string(m,s); dbmail_message_set_header(m, "X-Foobar","Foo Bar"); fail_unless(dbmail_message_get_header(m, "X-Foobar")!=NULL, "set_header failed"); dbmail_message_free(m); g_string_free(s,TRUE); }
/* * Send a vacation message. FIXME: this should provide * MIME support, to comply with the Sieve-Vacation spec. */ static int send_vacation(DbmailMessage *message, const char *to, const char *from, const char *subject, const char *body, const char *handle) { int result; const char *x_dbmail_vacation = dbmail_message_get_header(message, "X-Dbmail-Vacation"); if (x_dbmail_vacation) { TRACE(TRACE_NOTICE, "vacation loop detected [%s]", x_dbmail_vacation); return 0; } DbmailMessage *new_message = dbmail_message_new(); new_message = dbmail_message_construct(new_message, to, from, subject, body); dbmail_message_set_header(new_message, "X-DBMail-Vacation", handle); result = send_mail(new_message, to, from, NULL, SENDMESSAGE, SENDMAIL); dbmail_message_free(new_message); return result; }
int lmtp(ClientSession_T * session) { DbmailMessage *msg; ClientBase_T *ci = session->ci; int helpcmd; const char *class, *subject, *detail; size_t tmplen = 0, tmppos = 0; char *tmpaddr = NULL, *tmpbody = NULL, *arg; switch (session->command_type) { case LMTP_QUIT: ci_write(ci, "221 %s BYE\r\n", session->hostname); session->state = QUIT; return 1; case LMTP_NOOP: ci_write(ci, "250 OK\r\n"); return 1; case LMTP_RSET: ci_write(ci, "250 OK\r\n"); lmtp_rset(session,TRUE); return 1; case LMTP_LHLO: /* Reply wth our hostname and a list of features. * The RFC requires a couple of SMTP extensions * with a MUST statement, so just hardcode them. * */ ci_write(ci, "250-%s\r\n250-PIPELINING\r\n" "250-ENHANCEDSTATUSCODES\r\n250 SIZE\r\n", session->hostname); /* This is a SHOULD implement: * "250-8BITMIME\r\n" * Might as well do these, too: * "250-CHUNKING\r\n" * "250-BINARYMIME\r\n" * */ client_session_reset(session); session->state = AUTH; client_session_set_timeout(session, server_conf->timeout); return 1; case LMTP_HELP: session->args = g_list_first(session->args); if (session->args && session->args->data) arg = (char *)session->args->data; else arg = NULL; if (arg == NULL) helpcmd = LMTP_END; else for (helpcmd = LMTP_LHLO; helpcmd < LMTP_END; helpcmd++) if (strcasecmp (arg, commands[helpcmd]) == 0) break; TRACE(TRACE_DEBUG, "LMTP_HELP requested for commandtype %d", helpcmd); if ((helpcmd == LMTP_LHLO) || (helpcmd == LMTP_DATA) || (helpcmd == LMTP_RSET) || (helpcmd == LMTP_QUIT) || (helpcmd == LMTP_NOOP) || (helpcmd == LMTP_HELP)) { ci_write(ci, "%s", LMTP_HELP_TEXT[helpcmd]); } else ci_write(ci, "%s", LMTP_HELP_TEXT[LMTP_END]); return 1; case LMTP_VRFY: /* RFC 2821 says this SHOULD be implemented... * and the goal is to say if the given address * is a valid delivery address at this server. */ ci_write(ci, "502 Command not implemented\r\n"); return 1; case LMTP_EXPN: /* RFC 2821 says this SHOULD be implemented... * and the goal is to return the membership * of the specified mailing list. */ ci_write(ci, "502 Command not implemented\r\n"); return 1; case LMTP_MAIL: /* We need to LHLO first because the client * needs to know what extensions we support. * */ if (session->state != AUTH) { ci_write(ci, "550 Command out of sequence.\r\n"); return 1; } if (g_list_length(session->from) > 0) { ci_write(ci, "500 Sender already received. Use RSET to clear.\r\n"); return 1; } /* First look for an email address. * Don't bother verifying or whatever, * just find something between angle brackets! * */ session->args = g_list_first(session->args); if (! (session->args && session->args->data)) return 1; arg = (char *)session->args->data; if (find_bounded(arg, '<', '>', &tmpaddr, &tmplen, &tmppos) < 0) { ci_write(ci, "500 No address found. Missing <> boundries.\r\n"); return 1; } /* Second look for a BODY keyword. * See if it has an argument, and if we * support that feature. Don't give an OK * if we can't handle it yet, like 8BIT! * */ /* Find the '=' following the address * then advance one character past it * (but only if there's more string!) * */ if ((tmpbody = strstr(arg + tmppos, "=")) != NULL) if (strlen(tmpbody)) tmpbody++; /* This is all a bit nested now... */ if (tmpbody) { if (MATCH(tmpbody, "8BITMIME")) { // RFC1652 ci_write(ci, "500 Please use 7BIT MIME only.\r\n"); return 1; } if (MATCH(tmpbody, "BINARYMIME")) { // RFC3030 ci_write(ci, "500 Please use 7BIT MIME only.\r\n"); return 1; } } session->from = g_list_prepend(session->from, g_strdup(tmpaddr)); ci_write(ci, "250 Sender <%s> OK\r\n", (char *)(session->from->data)); g_free(tmpaddr); return 1; case LMTP_RCPT: if (session->state != AUTH) { ci_write(ci, "550 Command out of sequence.\r\n"); return 1; } session->args = g_list_first(session->args); if (! (session->args && session->args->data)) return 1; arg = (char *)session->args->data; if (find_bounded(arg, '<', '>', &tmpaddr, &tmplen, &tmppos) < 0 || tmplen < 1) { ci_write(ci, "500 No address found. Missing <> boundries or address is null.\r\n"); return 1; } Delivery_T *dsnuser = g_new0(Delivery_T,1); dsnuser_init(dsnuser); /* find_bounded() allocated tmpaddr for us, and that's ok * since dsnuser_free() will free it for us later on. */ dsnuser->address = tmpaddr; if (dsnuser_resolve(dsnuser) != 0) { TRACE(TRACE_ERR, "dsnuser_resolve_list failed"); ci_write(ci, "430 Temporary failure in recipient lookup\r\n"); dsnuser_free(dsnuser); g_free(dsnuser); return 1; } /* Class 2 means the address was deliverable in some way. */ switch (dsnuser->dsn.class) { case DSN_CLASS_OK: ci_write(ci, "250 Recipient <%s> OK\r\n", dsnuser->address); session->rcpt = g_list_prepend(session->rcpt, dsnuser); break; default: ci_write(ci, "550 Recipient <%s> FAIL\r\n", dsnuser->address); dsnuser_free(dsnuser); g_free(dsnuser); break; } return 1; /* Here's where it gets really exciting! */ case LMTP_DATA: msg = dbmail_message_new(); dbmail_message_init_with_string(msg, session->rbuff); dbmail_message_set_header(msg, "Return-Path", (char *)session->from->data); g_string_truncate(session->rbuff,0); g_string_maybe_shrink(session->rbuff); if (insert_messages(msg, session->rcpt) == -1) { ci_write(ci, "430 Message not received\r\n"); dbmail_message_free(msg); return 1; } /* The DATA command itself it not given a reply except * that of the status of each of the remaining recipients. */ /* The replies MUST be in the order received */ session->rcpt = g_list_reverse(session->rcpt); while (session->rcpt) { Delivery_T * dsnuser = (Delivery_T *)session->rcpt->data; dsn_tostring(dsnuser->dsn, &class, &subject, &detail); /* Give a simple OK, otherwise a detailed message. */ switch (dsnuser->dsn.class) { case DSN_CLASS_OK: ci_write(ci, "%d%d%d Recipient <%s> OK\r\n", dsnuser->dsn.class, dsnuser->dsn.subject, dsnuser->dsn.detail, dsnuser->address); break; default: ci_write(ci, "%d%d%d Recipient <%s> %s %s %s\r\n", dsnuser->dsn.class, dsnuser->dsn.subject, dsnuser->dsn.detail, dsnuser->address, class, subject, detail); } if (! g_list_next(session->rcpt)) break; session->rcpt = g_list_next(session->rcpt); } dbmail_message_free(msg); /* Reset the session after a successful delivery; * MTA's like Exim prefer to immediately begin the * next delivery without an RSET or a reconnect. */ lmtp_rset(session,TRUE); return 1; default: return lmtp_error(session, "500 What are you trying to say here?\r\n"); } return 1; }