int mail_save_copy_default_metadata(struct mail_save_context *ctx, struct mail *mail) { const char *from_envelope, *guid; time_t received_date; if (ctx->data.received_date == (time_t)-1) { if (mail_get_received_date(mail, &received_date) < 0) { mail_copy_set_failed(ctx, mail, "received-date"); return -1; } mailbox_save_set_received_date(ctx, received_date, 0); } if (ctx->data.from_envelope == NULL) { if (mail_get_special(mail, MAIL_FETCH_FROM_ENVELOPE, &from_envelope) < 0) { mail_copy_set_failed(ctx, mail, "from-envelope"); return -1; } if (*from_envelope != '\0') mailbox_save_set_from_envelope(ctx, from_envelope); } if (ctx->data.guid == NULL) { if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) < 0) { mail_copy_set_failed(ctx, mail, "guid"); return -1; } if (*guid != '\0') mailbox_save_set_guid(ctx, guid); } 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 int exporter_get_guids(struct dsync_mailbox_exporter *exporter, struct mail *mail, const char **guid_r, const char **hdr_hash_r) { *guid_r = ""; *hdr_hash_r = NULL; /* always try to get GUID, even if we're also getting header hash */ if (mail_get_special(mail, MAIL_FETCH_GUID, guid_r) < 0) return dsync_mail_error(exporter, mail, "GUID"); if (!exporter->mails_have_guids) { /* get header hash also */ if (dsync_mail_get_hdr_hash(mail, hdr_hash_r) < 0) return dsync_mail_error(exporter, mail, "hdr-stream"); return 1; } else if (**guid_r == '\0') { exporter->error = "Backend doesn't support GUIDs, " "sync with header hashes instead"; return -1; } else { /* GUIDs are required, we don't need header hash */ return 1; } }
static float index_sort_get_relevancy(struct mail *mail) { const char *str; if (mail_get_special(mail, MAIL_FETCH_SEARCH_RELEVANCY, &str) < 0) return 0; else return strtod(str, NULL); }
static float index_sort_get_score(struct mail *mail) { const char *str; if (mail_get_special(mail, MAIL_FETCH_SEARCH_SCORE, &str) < 0) return 0; else return strtod(str, NULL); }
static uoff_t index_sort_get_pop3_order(struct mail *mail) { const char *str; uoff_t size; if (mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str) < 0 || str_to_uoff(str, &size) < 0) return (uint32_t)-1; else return size; }
static int index_sort_get_relevancy(struct mail *mail, float *result_r) { const char *str; if (mail_get_special(mail, MAIL_FETCH_SEARCH_RELEVANCY, &str) < 0) { *result_r = 0; return -1; } *result_r = strtod(str, NULL); return 0; }
static int index_sort_get_pop3_order(struct mail *mail, uoff_t *size_r) { const char *str; if (mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str) < 0) { *size_r = (uint32_t)-1; return -1; } if (str_to_uoff(str, size_r) < 0) *size_r = (uint32_t)-1; return 0; }
int dsync_mail_fill(struct mail *mail, struct dsync_mail *dmail_r, const char **error_field_r) { const char *guid, *str; memset(dmail_r, 0, sizeof(*dmail_r)); if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) < 0) { *error_field_r = "GUID"; return -1; } dmail_r->guid = guid; dmail_r->uid = mail->uid; dmail_r->input_mail = mail; dmail_r->input_mail_uid = mail->uid; if (mail_get_stream(mail, NULL, NULL, &dmail_r->input) < 0) { *error_field_r = "body"; return -1; } if (mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &dmail_r->pop3_uidl) < 0) { *error_field_r = "pop3-uidl"; return -1; } if (mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str) < 0) { *error_field_r = "pop3-order"; return -1; } if (*str != '\0') { if (str_to_uint(str, &dmail_r->pop3_order) < 0) i_unreached(); } if (mail_get_received_date(mail, &dmail_r->received_date) < 0) { *error_field_r = "received-date"; return -1; } return 0; }
/* Returns >0 = matched, 0 = not matched, -1 = unknown */ static int search_arg_match_mailbox(struct index_search_context *ctx, struct mail_search_arg *arg) { const char *str; switch (arg->type) { case SEARCH_MAILBOX: if (mail_get_special(ctx->mail, MAIL_FETCH_MAILBOX_NAME, &str) < 0) return -1; if (strcasecmp(str, "INBOX") == 0) return strcasecmp(arg->value.str, "INBOX") == 0; return strcmp(str, arg->value.str) == 0; case SEARCH_MAILBOX_GLOB: if (mail_get_special(ctx->mail, MAIL_FETCH_MAILBOX_NAME, &str) < 0) return -1; return imap_match(arg->value.mailbox_glob, str) == IMAP_MATCH_YES; default: return -1; } }
static int virtual_mail_get_special(struct mail *mail, enum mail_fetch_field field, const char **value_r) { struct virtual_mail *vmail = (struct virtual_mail *)mail; struct mailbox *box = vmail->backend_mail->box; if (virtual_mail_handle_lost(vmail) < 0) return -1; if (mail_get_special(vmail->backend_mail, field, value_r) < 0) { virtual_box_copy_error(mail->box, box); return -1; } return 0; }
static int mail_parse_parts(struct mail *mail, struct message_part **parts_r) { const char *structure, *error; struct mail_private *pmail = (struct mail_private*)mail; /* need to get bodystructure first */ if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE, &structure) < 0) return -1; if (imap_bodystructure_parse_full(structure, pmail->data_pool, parts_r, &error) < 0) { mail_set_critical(mail, "imap_bodystructure_parse() failed: %s", error); return -1; } return 0; }
static int maildir_copy_hardlink(struct mail_save_context *ctx, struct mail *mail) { struct maildir_mailbox *dest_mbox = (struct maildir_mailbox *)ctx->transaction->box; struct maildir_mailbox *src_mbox; struct maildir_filename *mf; struct hardlink_ctx do_ctx; const char *path, *guid, *dest_fname; uoff_t vsize, size; enum mail_lookup_abort old_abort; if (strcmp(mail->box->storage->name, MAILDIR_STORAGE_NAME) == 0) src_mbox = (struct maildir_mailbox *)mail->box; else if (strcmp(mail->box->storage->name, "raw") == 0) { /* lda uses raw format */ src_mbox = NULL; } else { /* Can't hard link files from the source storage */ return 0; } /* hard link to tmp/ with a newly generated filename and later when we have uidlist locked, move it to new/cur. */ dest_fname = maildir_filename_generate(); memset(&do_ctx, 0, sizeof(do_ctx)); do_ctx.dest_path = t_strdup_printf("%s/tmp/%s", mailbox_get_path(&dest_mbox->box), dest_fname); if (src_mbox != NULL) { /* maildir */ if (maildir_file_do(src_mbox, mail->uid, do_hardlink, &do_ctx) < 0) return -1; } else { /* raw / lda */ if (mail_get_special(mail, MAIL_FETCH_UIDL_FILE_NAME, &path) < 0 || *path == '\0') return 0; if (do_hardlink(dest_mbox, path, &do_ctx) < 0) return -1; } if (!do_ctx.success) { /* couldn't copy with hardlinking, fallback to copying */ return 0; } /* hardlinked to tmp/, treat as normal copied mail */ mf = maildir_save_add(ctx, dest_fname, mail); if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) == 0) { if (*guid != '\0') maildir_save_set_dest_basename(ctx, mf, guid); } /* remember size/vsize if possible */ old_abort = mail->lookup_abort; mail->lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL; if (mail_get_physical_size(mail, &size) < 0) size = (uoff_t)-1; if (mail_get_virtual_size(mail, &vsize) < 0) vsize = (uoff_t)-1; maildir_save_set_sizes(mf, size, vsize); mail->lookup_abort = old_abort; return 1; }
static int pop3_map_read(struct mail_storage *storage) { struct pop3_migration_mail_storage *mstorage = POP3_MIGRATION_CONTEXT(storage); struct mailbox *pop3_box = mstorage->pop3_box; struct mailbox_transaction_context *t; struct mail_search_args *search_args; struct mail_search_context *ctx; struct mail *mail; struct pop3_uidl_map *map; const char *uidl; uoff_t size; int ret = 0; if (array_is_created(&mstorage->pop3_uidl_map)) { /* already read these, just reset the imap_uids */ array_foreach_modifiable(&mstorage->pop3_uidl_map, map) map->imap_uid = 0; return 0; } i_array_init(&mstorage->pop3_uidl_map, 128); if (mailbox_sync(pop3_box, 0) < 0) { i_error("pop3_migration: Couldn't sync mailbox %s: %s", pop3_box->vname, mailbox_get_last_error(pop3_box, NULL)); return -1; } t = mailbox_transaction_begin(pop3_box, 0); search_args = mail_search_build_init(); mail_search_build_add_all(search_args); ctx = mailbox_search_init(t, search_args, NULL, MAIL_FETCH_VIRTUAL_SIZE, NULL); mail_search_args_unref(&search_args); while (mailbox_search_next(ctx, &mail)) { if (mail_get_virtual_size(mail, &size) < 0) { i_error("pop3_migration: Failed to get size for msg %u: %s", mail->seq, mailbox_get_last_error(pop3_box, NULL)); ret = -1; break; } if (mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &uidl) < 0) { i_error("pop3_migration: Failed to get UIDL for msg %u: %s", mail->seq, mailbox_get_last_error(pop3_box, NULL)); ret = -1; break; } if (*uidl == '\0') { i_warning("pop3_migration: UIDL for msg %u is empty", mail->seq); continue; } map = array_append_space(&mstorage->pop3_uidl_map); map->pop3_seq = mail->seq; map->pop3_uidl = p_strdup(storage->pool, uidl); map->size = size; } if (mailbox_search_deinit(&ctx) < 0) ret = -1; (void)mailbox_transaction_commit(&t); return ret; }
/* Returns >0 = matched, 0 = not matched, -1 = unknown */ static int search_arg_match_cached(struct index_search_context *ctx, struct mail_search_arg *arg) { const char *str; struct tm *tm; uoff_t virtual_size; time_t date; int tz_offset; bool have_tz_offset; switch (arg->type) { /* internal dates */ case SEARCH_BEFORE: case SEARCH_ON: case SEARCH_SINCE: have_tz_offset = FALSE; tz_offset = 0; date = (time_t)-1; switch (arg->value.date_type) { case MAIL_SEARCH_DATE_TYPE_SENT: if (mail_get_date(ctx->mail, &date, &tz_offset) < 0) return -1; have_tz_offset = TRUE; break; case MAIL_SEARCH_DATE_TYPE_RECEIVED: if (mail_get_received_date(ctx->mail, &date) < 0) return -1; break; case MAIL_SEARCH_DATE_TYPE_SAVED: if (mail_get_save_date(ctx->mail, &date) < 0) return -1; break; } if ((arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) == 0) { if (!have_tz_offset) { tm = localtime(&date); tz_offset = utc_offset(tm, date); } date += tz_offset * 60; } switch (arg->type) { case SEARCH_BEFORE: return date < arg->value.time; case SEARCH_ON: return date >= arg->value.time && date < arg->value.time + 3600*24; case SEARCH_SINCE: return date >= arg->value.time; default: /* unreachable */ break; } /* sizes */ case SEARCH_SMALLER: case SEARCH_LARGER: if (mail_get_virtual_size(ctx->mail, &virtual_size) < 0) return -1; if (arg->type == SEARCH_SMALLER) return virtual_size < arg->value.size; else return virtual_size > arg->value.size; case SEARCH_GUID: if (mail_get_special(ctx->mail, MAIL_FETCH_GUID, &str) < 0) return -1; return strcmp(str, arg->value.str) == 0; default: return -1; } }