/* gets the header "head" from msg. */ static int getheader(void *v, const char *phead, const char ***body) { message_data_t *m = ((deliver_data_t *) v)->m; if (phead==NULL) return SIEVE_FAIL; *body = msg_getheader(m, phead); if (*body) { return SIEVE_OK; } else { return SIEVE_FAIL; } }
/* * 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; }