/* * Test time_to_rfc822() */ static void test_gen_rfc822(void) { static const char DATETIME_MEL[] = "Fri, 26 Nov 2010 14:22:02 +1100"; static const char DATETIME_UTC[] = "Fri, 26 Nov 2010 03:22:02 +0000"; static const char DATETIME_NYC[] = "Thu, 25 Nov 2010 22:22:02 -0500"; static const time_t TIMET = 1290741722; int r; char buf[RFC822_DATETIME_MAX+1]; memset(buf, 0x45, sizeof(buf)); r = time_to_rfc822(TIMET, buf, sizeof(buf)); CU_ASSERT_EQUAL(r, 31); CU_ASSERT_STRING_EQUAL(buf, DATETIME_MEL); push_tz(TZ_UTC); memset(buf, 0x45, sizeof(buf)); r = time_to_rfc822(TIMET, buf, sizeof(buf)); CU_ASSERT_EQUAL(r, 31); CU_ASSERT_STRING_EQUAL(buf, DATETIME_UTC); pop_tz(); push_tz(TZ_NEWYORK); memset(buf, 0x45, sizeof(buf)); r = time_to_rfc822(TIMET, buf, sizeof(buf)); CU_ASSERT_EQUAL(r, 31); CU_ASSERT_STRING_EQUAL(buf, DATETIME_NYC); pop_tz(); }
/* * mboxlist_findall() callback function to examine a mailbox */ static int do_timestamp(char *name) { unsigned recno; int r = 0; char ext_name_buf[MAX_MAILBOX_PATH+1]; struct mailbox *mailbox = NULL; struct index_record record; char olddate[RFC822_DATETIME_MAX+1]; char newdate[RFC822_DATETIME_MAX+1]; signals_poll(); /* Convert internal name to external */ (*recon_namespace.mboxname_toexternal)(&recon_namespace, name, "cyrus", ext_name_buf); printf("Working on %s...\n", ext_name_buf); /* Open/lock header */ r = mailbox_open_iwl(name, &mailbox); if (r) return r; for (recno = 1; recno <= mailbox->i.num_records; recno++) { r = mailbox_read_index_record(mailbox, recno, &record); if (r) goto done; if (record.system_flags & FLAG_EXPUNGED) continue; /* 1 day is close enough */ if (abs(record.internaldate - record.gmtime) < 86400) continue; time_to_rfc822(record.internaldate, olddate, sizeof(olddate)); time_to_rfc822(record.gmtime, newdate, sizeof(newdate)); printf(" %u: %s => %s\n", record.uid, olddate, newdate); /* switch internaldate */ record.internaldate = record.gmtime; r = mailbox_rewrite_index_record(mailbox, &record); if (r) goto done; } done: mailbox_close(&mailbox); return r; }
/* * mboxlist_findall() callback function to examine a mailbox */ static int do_timestamp(const char *name) { int r = 0; char ext_name_buf[MAX_MAILBOX_PATH+1]; struct mailbox *mailbox = NULL; const struct index_record *record; char olddate[RFC822_DATETIME_MAX+1]; char newdate[RFC822_DATETIME_MAX+1]; signals_poll(); /* Convert internal name to external */ (*recon_namespace.mboxname_toexternal)(&recon_namespace, name, "cyrus", ext_name_buf); printf("Working on %s...\n", ext_name_buf); /* Open/lock header */ r = mailbox_open_iwl(name, &mailbox); if (r) return r; struct mailbox_iter *iter = mailbox_iter_init(mailbox, 0, ITER_SKIP_EXPUNGED); while ((record = mailbox_iter_step(iter))) { /* 1 day is close enough */ if (labs(record->internaldate - record->gmtime) < 86400) continue; struct index_record copyrecord = *record; time_to_rfc822(copyrecord.internaldate, olddate, sizeof(olddate)); time_to_rfc822(copyrecord.gmtime, newdate, sizeof(newdate)); printf(" %u: %s => %s\n", copyrecord.uid, olddate, newdate); /* switch internaldate */ copyrecord.internaldate = copyrecord.gmtime; r = mailbox_rewrite_index_record(mailbox, ©record); if (r) goto done; } done: mailbox_iter_done(&iter); mailbox_close(&mailbox); return r; }
static int send_rejection(const char *origid, const char *rejto, const char *origreceip, const char *mailreceip, const char *reason, struct protstream *file) { FILE *sm; const char *smbuf[10]; char buf[8192], *namebuf; int i, sm_stat; time_t t; char datestr[RFC822_DATETIME_MAX+1]; pid_t sm_pid, p; duplicate_key_t dkey = DUPLICATE_INITIALIZER; smbuf[0] = "sendmail"; smbuf[1] = "-i"; /* ignore dots */ smbuf[2] = "-f"; smbuf[3] = "<>"; smbuf[4] = "--"; smbuf[5] = rejto; smbuf[6] = NULL; sm_pid = open_sendmail(smbuf, &sm); if (sm == NULL) { return -1; } t = time(NULL); p = getpid(); snprintf(buf, sizeof(buf), "<cmu-sieve-%d-%d-%d@%s>", (int) p, (int) t, global_outgoing_count++, config_servername); namebuf = make_sieve_db(mailreceip); time_to_rfc822(t, datestr, sizeof(datestr)); dkey.id = buf; dkey.to = namebuf; dkey.date = datestr; duplicate_mark(&dkey, t, 0); fprintf(sm, "Message-ID: %s\r\n", buf); fprintf(sm, "Date: %s\r\n", datestr); fprintf(sm, "X-Sieve: %s\r\n", SIEVE_VERSION); fprintf(sm, "From: Mail Sieve Subsystem <%s>\r\n", config_getstring(IMAPOPT_POSTMASTER)); fprintf(sm, "To: <%s>\r\n", rejto); fprintf(sm, "MIME-Version: 1.0\r\n"); fprintf(sm, "Content-Type: " "multipart/report; report-type=disposition-notification;" "\r\n\tboundary=\"%d/%s\"\r\n", (int) p, config_servername); fprintf(sm, "Subject: Automatically rejected mail\r\n"); fprintf(sm, "Auto-Submitted: auto-replied (rejected)\r\n"); fprintf(sm, "\r\nThis is a MIME-encapsulated message\r\n\r\n"); /* this is the human readable status report */ fprintf(sm, "--%d/%s\r\n", (int) p, config_servername); fprintf(sm, "Content-Type: text/plain; charset=utf-8\r\n"); fprintf(sm, "Content-Disposition: inline\r\n"); fprintf(sm, "Content-Transfer-Encoding: 8bit\r\n\r\n"); fprintf(sm, "Your message was automatically rejected by Sieve, a mail\r\n" "filtering language.\r\n\r\n"); fprintf(sm, "The following reason was given:\r\n%s\r\n\r\n", reason); /* this is the MDN status report */ fprintf(sm, "--%d/%s\r\n" "Content-Type: message/disposition-notification\r\n\r\n", (int) p, config_servername); fprintf(sm, "Reporting-UA: %s; Cyrus %s/%s\r\n", config_servername, cyrus_version(), SIEVE_VERSION); if (origreceip) fprintf(sm, "Original-Recipient: rfc822; %s\r\n", origreceip); fprintf(sm, "Final-Recipient: rfc822; %s\r\n", mailreceip); if (origid) fprintf(sm, "Original-Message-ID: %s\r\n", origid); fprintf(sm, "Disposition: " "automatic-action/MDN-sent-automatically; deleted\r\n"); fprintf(sm, "\r\n"); /* this is the original message */ fprintf(sm, "--%d/%s\r\nContent-Type: message/rfc822\r\n\r\n", (int) p, config_servername); prot_rewind(file); while ((i = prot_read(file, buf, sizeof(buf))) > 0) { fwrite(buf, i, 1, sm); } fprintf(sm, "\r\n\r\n"); fprintf(sm, "--%d/%s--\r\n", (int) p, config_servername); fclose(sm); while (waitpid(sm_pid, &sm_stat, 0) < 0); return sm_stat; /* sendmail exit value */ }
/* * file in the message structure 'm' from 'pin', assuming a dot-stuffed * stream a la lmtp. * * returns 0 on success, imap error code on failure */ static int savemsg(struct clientdata *cd, const struct lmtp_func *func, message_data_t *m) { FILE *f; struct stat sbuf; const char **body; int r; int nrcpts = m->rcpt_num; time_t now = time(NULL); static unsigned msgid_count = 0; char datestr[RFC822_DATETIME_MAX+1], tls_info[250] = ""; const char *skipheaders[] = { "Return-Path", /* need to remove (we add our own) */ NULL }; char *addbody, *fold[5], *p; int addlen, nfold, i; /* Copy to spool file */ f = func->spoolfile(m); if (!f) { prot_printf(cd->pout, "451 4.3.%c cannot create temporary file: %s\r\n", ( #ifdef EDQUOT errno == EDQUOT || #endif errno == ENOSPC) ? '1' : '2', error_message(errno)); return IMAP_IOERROR; } prot_printf(cd->pout, "354 go ahead\r\n"); if (m->return_path && func->addretpath) { /* add the return path */ char *rpath = m->return_path; const char *hostname = 0; clean_retpath(rpath); /* Append our hostname if there's no domain in address */ hostname = NULL; if (!strchr(rpath, '@') && strlen(rpath) > 0) { hostname = config_servername; } addlen = 2 + strlen(rpath) + (hostname ? 1 + strlen(hostname) : 0); addbody = xmalloc(addlen + 1); sprintf(addbody, "<%s%s%s>", rpath, hostname ? "@" : "", hostname ? hostname : ""); fprintf(f, "Return-Path: %s\r\n", addbody); spool_cache_header(xstrdup("Return-Path"), addbody, m->hdrcache); } /* add a received header */ time_to_rfc822(now, datestr, sizeof(datestr)); addlen = 8 + strlen(cd->lhlo_param) + strlen(cd->clienthost); if (m->authuser) addlen += 28 + strlen(m->authuser) + 5; /* +5 for ssf */ addlen += 25 + strlen(config_servername) + strlen(cyrus_version()); #ifdef HAVE_SSL if (cd->tls_conn) { addlen += 3 + tls_get_info(cd->tls_conn, tls_info, sizeof(tls_info)); } #endif addlen += 2 + strlen(datestr); p = addbody = xmalloc(addlen + 1); nfold = 0; p += sprintf(p, "from %s (%s)", cd->lhlo_param, cd->clienthost); fold[nfold++] = p; if (m->authuser) { const void *ssfp; sasl_ssf_t ssf; sasl_getprop(cd->conn, SASL_SSF, &ssfp); ssf = *((sasl_ssf_t *) ssfp); p += sprintf(p, " (authenticated user=%s bits=%d)", m->authuser, ssf); fold[nfold++] = p; } /* We are always atleast "with LMTPA" -- no unauth delivery */ p += sprintf(p, " by %s", config_servername); if (config_serverinfo == IMAP_ENUM_SERVERINFO_ON) { p += sprintf(p, " (Cyrus %s)", cyrus_version()); } p += sprintf(p, " with LMTP%s%s", cd->starttls_done ? "S" : "", cd->authenticated != NOAUTH ? "A" : ""); if (*tls_info) { fold[nfold++] = p; p += sprintf(p, " (%s)", tls_info); } strcat(p++, ";"); fold[nfold++] = p; p += sprintf(p, " %s", datestr); fprintf(f, "Received: "); for (i = 0, p = addbody; i < nfold; p = fold[i], i++) { fprintf(f, "%.*s\r\n\t", (int) (fold[i] - p), p); } fprintf(f, "%s\r\n", p); spool_cache_header(xstrdup("Received"), addbody, m->hdrcache); /* add any requested headers */ if (func->addheaders) { struct addheader *h; for (h = func->addheaders; h && h->name; h++) { fprintf(f, "%s: %s\r\n", h->name, h->body); spool_cache_header(xstrdup(h->name), xstrdup(h->body), m->hdrcache); } } /* fill the cache */ r = spool_fill_hdrcache(cd->pin, f, m->hdrcache, skipheaders); /* now, using our header cache, fill in the data that we want */ /* first check resent-message-id */ if ((body = msg_getheader(m, "resent-message-id")) && body[0][0]) { m->id = xstrdup(body[0]); } else if ((body = msg_getheader(m, "message-id")) && body[0][0]) { m->id = xstrdup(body[0]); } else if (body) { r = IMAP_MESSAGE_BADHEADER; /* empty message-id */ } else { /* no message-id, create one */ pid_t p = getpid(); m->id = xmalloc(40 + strlen(config_servername)); sprintf(m->id, "<cmu-lmtpd-%d-%d-%u@%s>", p, (int) now, msgid_count++, config_servername); fprintf(f, "Message-ID: %s\r\n", m->id); spool_cache_header(xstrdup("Message-ID"), xstrdup(m->id), m->hdrcache); } /* get date */ if (!(body = spool_getheader(m->hdrcache, "date"))) { /* no date, create one */ addbody = xstrdup(datestr); m->date = xstrdup(datestr); fprintf(f, "Date: %s\r\n", addbody); spool_cache_header(xstrdup("Date"), addbody, m->hdrcache); } else { m->date = xstrdup(body[0]); } if (!m->return_path && (body = msg_getheader(m, "return-path"))) { /* let's grab return_path */ m->return_path = xstrdup(body[0]); clean822space(m->return_path); clean_retpath(m->return_path); } r |= spool_copy_msg(cd->pin, f); if (r) { fclose(f); if (func->removespool) { /* remove the spool'd message */ func->removespool(m); } while (nrcpts--) { send_lmtp_error(cd->pout, r); } return r; } fflush(f); if (ferror(f)) { while (nrcpts--) { prot_printf(cd->pout, "451 4.3.%c cannot copy message to temporary file: %s\r\n", ( #ifdef EDQUOT errno == EDQUOT || #endif errno == ENOSPC) ? '1' : '2', error_message(errno)); } fclose(f); if (func->removespool) func->removespool(m); return IMAP_IOERROR; } if (fstat(fileno(f), &sbuf) == -1) { while (nrcpts--) { prot_printf(cd->pout, "451 4.3.2 cannot stat message temporary file: %s\r\n", error_message(errno)); } fclose(f); if (func->removespool) func->removespool(m); return IMAP_IOERROR; } m->size = sbuf.st_size; m->f = f; m->data = prot_new(fileno(f), 0); return 0; }