static int index_mail_cache_sent_date(struct index_mail *mail) { struct index_mail_data *data = &mail->data; const char *str; time_t t; int ret, tz; if (data->sent_date.time != (uint32_t)-1) return 0; if ((ret = mail_get_first_header(&mail->mail.mail, "Date", &str)) < 0) return ret; if (ret == 0 || !message_date_parse((const unsigned char *)str, strlen(str), &t, &tz)) { /* 0 = not found / invalid */ t = 0; tz = 0; } data->sent_date.time = t; data->sent_date.timezone = tz; index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE, &data->sent_date, sizeof(data->sent_date)); return 0; }
static int cmd_deduplicate_box(struct doveadm_mail_cmd_context *_ctx, const struct mailbox_info *info, struct mail_search_args *search_args) { struct deduplicate_cmd_context *ctx = (struct deduplicate_cmd_context *)_ctx; struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; enum mail_error error; pool_t pool; HASH_TABLE(const char *, struct uidlist *) hash; const char *key, *errstr; struct uidlist *value; int ret = 0; if (doveadm_mail_iter_init(_ctx, info, search_args, 0, NULL, &iter) < 0) return -1; pool = pool_alloconly_create("deduplicate", 10240); hash_table_create(&hash, pool, 0, str_hash, strcmp); while (doveadm_mail_iter_next(iter, &mail)) { if (ctx->by_msgid) { if (mail_get_first_header(mail, "Message-ID", &key) < 0) { errstr = mailbox_get_last_error(mail->box, &error); if (error == MAIL_ERROR_NOTFOUND) continue; i_error("Couldn't lookup Message-ID: for UID=%u: %s", mail->uid, errstr); doveadm_mail_failed_error(_ctx, error); ret = -1; break; } } else { if (mail_get_special(mail, MAIL_FETCH_GUID, &key) < 0) { errstr = mailbox_get_last_error(mail->box, &error); if (error == MAIL_ERROR_NOTFOUND) continue; i_error("Couldn't lookup GUID: for UID=%u: %s", mail->uid, errstr); doveadm_mail_failed_error(_ctx, error); ret = -1; break; } } if (key != NULL && *key != '\0') { value = p_new(pool, struct uidlist, 1); value->uid = mail->uid; value->next = hash_table_lookup(hash, key); if (value->next == NULL) { key = p_strdup(pool, key); hash_table_insert(hash, key, value); } else { hash_table_update(hash, key, value); } } }
static const struct var_expand_table * get_var_expand_table(struct mail *mail, const char *reason, const char *recipient) { static struct var_expand_table static_tab[] = { { 'n', NULL, "crlf" }, { 'r', NULL, "reason" }, { 's', NULL, "subject" }, { 't', NULL, "to" }, { '\0', NULL, NULL } }; struct var_expand_table *tab; const char *subject; tab = t_malloc(sizeof(static_tab)); memcpy(tab, static_tab, sizeof(static_tab)); tab[0].value = "\r\n"; tab[1].value = reason; if (mail_get_first_header(mail, "Subject", &subject) <= 0) subject = ""; tab[2].value = str_sanitize(subject, 80); tab[3].value = recipient; return tab; }
static void mail_log_append_mail_header(string_t *str, struct mail *mail, const char *name, const char *header) { const char *value; if (mail_get_first_header(mail, header, &value) <= 0) value = ""; str_printfa(str, "%s=%s", name, str_sanitize(value, HEADER_LOG_LEN)); }
void sieve_tool_get_envelope_data (struct mail *mail, const char **recipient, const char **sender) { /* Get recipient address */ if ( *recipient == NULL ) (void)mail_get_first_header(mail, "Envelope-To", recipient); if ( *recipient == NULL ) (void)mail_get_first_header(mail, "To", recipient); if ( *recipient == NULL ) *recipient = "*****@*****.**"; /* Get sender address */ if ( *sender == NULL ) (void)mail_get_first_header(mail, "Return-path", sender); if ( *sender == NULL ) (void)mail_get_first_header(mail, "Sender", sender); if ( *sender == NULL ) (void)mail_get_first_header(mail, "From", sender); if ( *sender == NULL ) *sender = "*****@*****.**"; }
int index_sort_header_get(struct mail_search_sort_program *program, uint32_t seq, enum mail_sort_type sort_type, string_t *dest) { struct mail *mail = program->temp_mail; const char *str; int ret; bool reply_or_fw; index_sort_set_seq(program, mail, seq); str_truncate(dest, 0); switch (sort_type & MAIL_SORT_MASK) { case MAIL_SORT_SUBJECT: ret = mail_get_first_header(mail, "Subject", &str); if (ret < 0) break; if (ret == 0) { /* nonexistent header */ return 1; } str = imap_get_base_subject_cased(pool_datastack_create(), str, &reply_or_fw); str_append(dest, str); return 1; case MAIL_SORT_CC: ret = get_first_mailbox(mail, "Cc", &str); break; case MAIL_SORT_FROM: ret = get_first_mailbox(mail, "From", &str); break; case MAIL_SORT_TO: ret = get_first_mailbox(mail, "To", &str); break; case MAIL_SORT_DISPLAYFROM: ret = get_display_name(mail, "From", &str); break; case MAIL_SORT_DISPLAYTO: ret = get_display_name(mail, "To", &str); break; default: i_unreached(); } if (ret < 0) { index_sort_program_set_mail_failed(program, mail); if (!program->failed) return 0; return -1; } (void)uni_utf8_to_decomposed_titlecase(str, strlen(str), dest); return 1; }
static const char * testsuite_message_get_address(struct mail *mail, const char *header) { struct message_address *addr; const char *str; if (mail_get_first_header(mail, header, &str) <= 0) return NULL; addr = message_address_parse(pool_datastack_create(), (const unsigned char *)str, strlen(str), 1, FALSE); return (addr == NULL || addr->mailbox == NULL || *addr->mailbox == '\0' ? NULL : ( addr->domain == NULL || *addr->domain == '\0' ? addr->mailbox : t_strconcat(addr->mailbox, "@", addr->domain, NULL))); }
static int get_first_addr(struct mail *mail, const char *header, struct message_address **addr_r) { const char *str; int ret; if ((ret = mail_get_first_header(mail, header, &str)) <= 0) { *addr_r = NULL; return ret; } *addr_r = message_address_parse(pool_datastack_create(), (const unsigned char *)str, strlen(str), 1, TRUE); return 0; }
static void testsuite_message_set_data(struct mail *mail) { const char *recipient = NULL, *sender = NULL; /* * Collect necessary message data */ /* Get recipient address */ recipient = testsuite_message_get_address(mail, "Envelope-To"); if ( recipient == NULL ) recipient = testsuite_message_get_address(mail, "To"); if ( recipient == NULL ) recipient = "*****@*****.**"; /* Get sender address */ sender = testsuite_message_get_address(mail, "Return-path"); if ( sender == NULL ) sender = testsuite_message_get_address(mail, "Sender"); if ( sender == NULL ) sender = testsuite_message_get_address(mail, "From"); if ( sender == NULL ) sender = "*****@*****.**"; memset(&testsuite_msgdata, 0, sizeof(testsuite_msgdata)); testsuite_msgdata.mail = mail; testsuite_msgdata.auth_user = sieve_tool_get_username(sieve_tool); str_truncate(envelope_from, 0); str_append(envelope_from, sender); testsuite_msgdata.return_path = str_c(envelope_from); str_truncate(envelope_to, 0); str_append(envelope_to, recipient); testsuite_msgdata.final_envelope_to = str_c(envelope_to); str_truncate(envelope_orig_to, 0); str_append(envelope_orig_to, recipient); testsuite_msgdata.orig_envelope_to = str_c(envelope_orig_to); (void)mail_get_first_header(mail, "Message-ID", &testsuite_msgdata.id); }
int index_sort_header_get(struct mail *mail, uint32_t seq, enum mail_sort_type sort_type, string_t *dest) { const char *str; int ret; bool reply_or_fw; mail_set_seq(mail, seq); str_truncate(dest, 0); switch (sort_type & MAIL_SORT_MASK) { case MAIL_SORT_SUBJECT: if ((ret = mail_get_first_header(mail, "Subject", &str)) <= 0) return ret; str = imap_get_base_subject_cased(pool_datastack_create(), str, &reply_or_fw); str_append(dest, str); return 0; case MAIL_SORT_CC: ret = get_first_mailbox(mail, "Cc", &str); break; case MAIL_SORT_FROM: ret = get_first_mailbox(mail, "From", &str); break; case MAIL_SORT_TO: ret = get_first_mailbox(mail, "To", &str); break; case MAIL_SORT_DISPLAYFROM: ret = get_display_name(mail, "From", &str); break; case MAIL_SORT_DISPLAYTO: ret = get_display_name(mail, "To", &str); break; default: i_unreached(); } (void)uni_utf8_to_decomposed_titlecase(str, strlen(str), dest); return ret; }
static const char * i_stream_mail_get_cached_mail_id(struct mail_istream *mstream) { static const char *headers[] = { "Message-Id", "Date", "Subject" }; struct mail *mail = mstream->mail; enum mail_lookup_abort orig_lookup_abort; const char *value, *ret = ""; unsigned int i; orig_lookup_abort = mail->lookup_abort; mail->lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE; for (i = 0; i < N_ELEMENTS(headers); i++) { if (mail_get_first_header(mail, headers[i], &value) > 0) { ret = t_strdup_printf("%s=%s", headers[i], value); break; } } mail->lookup_abort = orig_lookup_abort; return ret; }
int mail_send_rejection(struct mail_deliver_context *ctx, const char *recipient, const char *reason) { struct mail *mail = ctx->src_mail; struct istream *input; struct smtp_client *smtp_client; struct ostream *output; const char *return_addr, *hdr; const char *value, *msgid, *orig_msgid, *boundary; string_t *str; int ret; if (mail_get_first_header(mail, "Message-ID", &orig_msgid) < 0) orig_msgid = NULL; if (mail_get_first_header(mail, "Auto-Submitted", &value) > 0 && strcasecmp(value, "no") != 0) { i_info("msgid=%s: Auto-submitted message discarded: %s", orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), str_sanitize(reason, 512)); return 0; } return_addr = mail_deliver_get_return_address(ctx); if (return_addr == NULL) { i_info("msgid=%s: Return-Path missing, rejection reason: %s", orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), str_sanitize(reason, 512)); return 0; } if (mailbox_get_settings(mail->box)->mail_debug) { i_debug("Sending a rejection to %s: %s", recipient, str_sanitize(reason, 512)); } smtp_client = smtp_client_open(ctx->set, return_addr, NULL, &output); msgid = mail_deliver_get_new_message_id(ctx); boundary = t_strdup_printf("%s/%s", my_pid, ctx->set->hostname); str = t_str_new(512); str_printfa(str, "Message-ID: %s\r\n", msgid); str_printfa(str, "Date: %s\r\n", message_date_create(ioloop_time)); str_printfa(str, "From: Mail Delivery Subsystem <%s>\r\n", ctx->set->postmaster_address); str_printfa(str, "To: <%s>\r\n", return_addr); str_append(str, "MIME-Version: 1.0\r\n"); str_printfa(str, "Content-Type: " "multipart/report; report-type=%s;\r\n" "\tboundary=\"%s\"\r\n", ctx->dsn ? "delivery-status" : "disposition-notification", boundary); str_append(str, "Subject: "); var_expand(str, ctx->set->rejection_subject, get_var_expand_table(mail, reason, recipient)); str_append(str, "\r\n"); str_append(str, "Auto-Submitted: auto-replied (rejected)\r\n"); str_append(str, "Precedence: bulk\r\n"); str_append(str, "\r\nThis is a MIME-encapsulated message\r\n\r\n"); /* human readable status report */ str_printfa(str, "--%s\r\n", boundary); str_append(str, "Content-Type: text/plain; charset=utf-8\r\n"); str_append(str, "Content-Disposition: inline\r\n"); str_append(str, "Content-Transfer-Encoding: 8bit\r\n\r\n"); var_expand(str, ctx->set->rejection_reason, get_var_expand_table(mail, reason, recipient)); str_append(str, "\r\n"); if (ctx->dsn) { /* DSN status report: For LDA rejects. currently only used when user is out of quota */ str_printfa(str, "--%s\r\n" "Content-Type: message/delivery-status\r\n\r\n", boundary); str_printfa(str, "Reporting-MTA: dns; %s\r\n", ctx->set->hostname); if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0) str_printfa(str, "Original-Recipient: rfc822; %s\r\n", hdr); str_printfa(str, "Final-Recipient: rfc822; %s\r\n", recipient); str_append(str, "Action: failed\r\n"); str_printfa(str, "Status: %s\r\n", ctx->mailbox_full ? "5.2.2" : "5.2.0"); } else { /* MDN status report: For Sieve "reject" */ str_printfa(str, "--%s\r\n" "Content-Type: message/disposition-notification\r\n\r\n", boundary); str_printfa(str, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n", ctx->set->hostname); if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0) str_printfa(str, "Original-Recipient: rfc822; %s\r\n", hdr); str_printfa(str, "Final-Recipient: rfc822; %s\r\n", recipient); if (orig_msgid != NULL) str_printfa(str, "Original-Message-ID: %s\r\n", orig_msgid); str_append(str, "Disposition: " "automatic-action/MDN-sent-automatically; deleted\r\n"); } str_append(str, "\r\n"); /* original message's headers */ str_printfa(str, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary); o_stream_nsend(output, str_data(str), str_len(str)); if (mail_get_hdr_stream(mail, NULL, &input) == 0) { /* Note: If you add more headers, they need to be sorted. We'll drop Content-Type because we're not including the message body, and having a multipart Content-Type may confuse some MIME parsers when they don't see the message boundaries. */ static const char *const exclude_headers[] = { "Content-Type" }; input = i_stream_create_header_filter(input, HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR | HEADER_FILTER_HIDE_BODY, exclude_headers, N_ELEMENTS(exclude_headers), *null_header_filter_callback, (void *)NULL); ret = o_stream_send_istream(output, input); i_stream_unref(&input); i_assert(ret != 0); } str_truncate(str, 0); str_printfa(str, "\r\n\r\n--%s--\r\n", boundary); o_stream_nsend(output, str_data(str), str_len(str)); return smtp_client_close(smtp_client); }