static struct mailbox *antispam_mailbox_open(struct mail_storage *storage, const char *name, struct istream *input, enum mailbox_open_flags flags) { struct antispam_mail_storage *as_storage = ANTISPAM_CONTEXT(storage); struct mailbox *box; struct antispam_mailbox *asbox; box = as_storage->super.mailbox_open(storage, name, input, flags); if (box == NULL) return NULL; asbox = p_new(box->pool, struct antispam_mailbox, 1); asbox->super = box->v; asbox->save_hack = FALSE; asbox->movetype = MMT_APPEND; if (need_folder_hook) { /* override save_init to override want_mail, we need that */ box->v.save_init = antispam_save_init; box->v.save_finish = antispam_save_finish; box->v.transaction_begin = antispam_mailbox_transaction_begin; box->v.transaction_commit = antispam_mailbox_transaction_commit; box->v.transaction_rollback = antispam_mailbox_transaction_rollback; box->v.copy = antispam_copy; } if (need_keyword_hook) box->v.mail_alloc = antispam_mailbox_mail_alloc; array_idx_set(&box->module_contexts, antispam_storage_module_id, &asbox); return box; }
static struct mail * antispam_mailbox_mail_alloc(struct mailbox_transaction_context *ctx, enum mail_fetch_field wanted_fields, struct mailbox_header_lookup_ctx *wanted_headers) { struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(ctx->box); struct antispam_mail *amail = i_new(struct antispam_mail, 1); struct mail_private *pmail; /* XXX: is this cast the right thing to do? */ pmail = (struct mail_private *) asbox->super.mail_alloc( ctx, wanted_fields, wanted_headers); amail->super = pmail->v; array_idx_set(&pmail->module_contexts, antispam_storage_module_id, &amail); pmail->v.update_keywords = antispam_mail_update_keywords; pmail->v.free = antispam_mail_free; return (struct mail *)pmail; }
void sieve_generator_extension_set_context (struct sieve_generator *gentr, const struct sieve_extension *ext, void *context) { if ( ext->id < 0 ) return; array_idx_set(&gentr->ext_contexts, (unsigned int) ext->id, &context); }
static void ext_reset_update_atomic(struct mail_index_transaction *t, uint32_t ext_id, uint32_t expected_reset_id) { const struct mail_index_ext *map_ext; struct mail_transaction_ext_reset *reset; uint32_t idx, reset_id; if (!mail_index_map_get_ext_idx(t->view->index->map, ext_id, &idx)) { /* new extension */ reset_id = 1; } else { map_ext = array_idx(&t->view->index->map->extensions, idx); reset_id = map_ext->reset_id + 1; } if (reset_id != expected_reset_id) { /* ignore this extension update */ mail_index_ext_set_reset_id(t, ext_id, 0); return; } if (reset_id == 0) reset_id++; array_idx_set(&t->ext_reset_ids, ext_id, &reset_id); /* reseting existing data is optional */ if (array_is_created(&t->ext_resets)) { reset = array_idx_modifiable(&t->ext_resets, ext_id); if (reset->new_reset_id == (uint32_t)-1) reset->new_reset_id = reset_id; } }
static void mail_cache_compress_field(struct mail_cache_copy_context *ctx, const struct mail_cache_iterate_field *field) { struct mail_cache_field *cache_field; enum mail_cache_decision_type dec; uint32_t file_field_idx, size32; uint8_t *field_seen; file_field_idx = ctx->field_file_map[field->field_idx]; if (file_field_idx == (uint32_t)-1) return; cache_field = &ctx->cache->fields[field->field_idx].field; field_seen = buffer_get_space_unsafe(ctx->field_seen, field->field_idx, 1); if (*field_seen == ctx->field_seen_value) { /* duplicate */ if (cache_field->type == MAIL_CACHE_FIELD_BITMASK) mail_cache_merge_bitmask(ctx, field); return; } *field_seen = ctx->field_seen_value; dec = cache_field->decision & ~MAIL_CACHE_DECISION_FORCED; if (ctx->new_msg) { if (dec == MAIL_CACHE_DECISION_NO) return; } else { if (dec != MAIL_CACHE_DECISION_YES) return; } buffer_append(ctx->buffer, &file_field_idx, sizeof(file_field_idx)); if (cache_field->field_size == UINT_MAX) { size32 = (uint32_t)field->size; buffer_append(ctx->buffer, &size32, sizeof(size32)); } if (cache_field->type == MAIL_CACHE_FIELD_BITMASK) { /* remember the position in case we need to update it */ unsigned int pos = ctx->buffer->used; array_idx_set(&ctx->bitmask_pos, field->field_idx, &pos); } buffer_append(ctx->buffer, field->data, field->size); if ((field->size & 3) != 0) buffer_append_zero(ctx->buffer, 4 - (field->size & 3)); }
static struct mailbox_transaction_context * antispam_mailbox_transaction_begin(struct mailbox *box, enum mailbox_transaction_flags flags) { struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(box); struct mailbox_transaction_context *t; struct antispam_transaction_context *ast; t = asbox->super.transaction_begin(box, flags); ast = antispam_transaction_begin(box); array_idx_set(&t->module_contexts, antispam_storage_module_id, &ast); return t; }
void antispam_mail_storage_created(struct mail_storage *storage) { struct antispam_mail_storage *as_storage; if (antispam_next_hook_mail_storage_created != NULL) antispam_next_hook_mail_storage_created(storage); as_storage = p_new(storage->pool, struct antispam_mail_storage, 1); as_storage->super = storage->v; storage->v.mailbox_open = antispam_mailbox_open; if (!antispam_storage_module_id_set) { antispam_storage_module_id = mail_storage_module_id++; antispam_storage_module_id_set = TRUE; } array_idx_set(&storage->module_contexts, antispam_storage_module_id, &as_storage); }
static void index_mail_parse_header_register_all_wanted(struct index_mail *mail) { struct mail *_mail = &mail->mail.mail; const struct mail_cache_field *all_cache_fields; unsigned int i, count; all_cache_fields = mail_cache_register_get_list(_mail->box->cache, pool_datastack_create(), &count); for (i = 0; i < count; i++) { if (strncasecmp(all_cache_fields[i].name, "hdr.", 4) != 0) continue; if (!mail_cache_field_want_add(_mail->transaction->cache_trans, _mail->seq, i)) continue; array_idx_set(&mail->header_match, all_cache_fields[i].idx, &mail->header_match_value); } }
static void index_mail_parse_header_finish(struct index_mail *mail) { struct mail *_mail = &mail->mail.mail; const struct index_mail_line *lines; const unsigned char *header, *data; const uint8_t *match; buffer_t *buf; size_t data_size; unsigned int i, j, count, match_idx, match_count; bool noncontiguous; /* sort it first so fields are grouped together and ordered by line number */ array_sort(&mail->header_lines, header_line_cmp); lines = array_get(&mail->header_lines, &count); match = array_get(&mail->header_match, &match_count); header = buffer_get_data(mail->header_data, NULL); buf = buffer_create_dynamic(pool_datastack_create(), 256); /* go through all the header lines we found */ for (i = match_idx = 0; i < count; i = j) { /* matches and header lines are both sorted, all matches until lines[i] weren't found */ while (match_idx < lines[i].field_idx && match_idx < match_count) { if (HEADER_MATCH_USABLE(mail, match[match_idx]) && mail_cache_field_can_add(_mail->transaction->cache_trans, _mail->seq, match_idx)) { /* this header doesn't exist. remember that. */ i_assert((match[match_idx] & HEADER_MATCH_FLAG_FOUND) == 0); index_mail_cache_add_idx(mail, match_idx, "", 0); } match_idx++; } if (match_idx < match_count) { /* save index to first header line */ j = i + 1; array_idx_set(&mail->header_match_lines, match_idx, &j); match_idx++; } if (!mail_cache_field_can_add(_mail->transaction->cache_trans, _mail->seq, lines[i].field_idx)) { /* header is already cached */ j = i + 1; continue; } /* buffer contains: { uint32_t line_num[], 0, header texts } noncontiguous is just a small optimization.. */ buffer_set_used_size(buf, 0); buffer_append(buf, &lines[i].line_num, sizeof(lines[i].line_num)); noncontiguous = FALSE; for (j = i+1; j < count; j++) { if (lines[j].field_idx != lines[i].field_idx) break; if (lines[j].start_pos != lines[j-1].end_pos) noncontiguous = TRUE; buffer_append(buf, &lines[j].line_num, sizeof(lines[j].line_num)); } buffer_append_zero(buf, sizeof(uint32_t)); if (noncontiguous) { for (; i < j; i++) { buffer_append(buf, header + lines[i].start_pos, lines[i].end_pos - lines[i].start_pos); } i--; } else { buffer_append(buf, header + lines[i].start_pos, lines[j-1].end_pos - lines[i].start_pos); } data = buffer_get_data(buf, &data_size); index_mail_cache_add_idx(mail, lines[i].field_idx, data, data_size); } for (; match_idx < match_count; match_idx++) { if (HEADER_MATCH_USABLE(mail, match[match_idx]) && mail_cache_field_can_add(_mail->transaction->cache_trans, _mail->seq, match_idx)) { /* this header doesn't exist. remember that. */ i_assert((match[match_idx] & HEADER_MATCH_FLAG_FOUND) == 0); index_mail_cache_add_idx(mail, match_idx, "", 0); } } mail->data.dont_cache_field_idx = UINT_MAX; }
void index_mail_parse_header_init(struct index_mail *mail, struct mailbox_header_lookup_ctx *headers) { struct index_mail_data *data = &mail->data; const uint8_t *match; unsigned int i, field_idx, match_count; mail->header_seq = data->seq; if (mail->header_data == NULL) { mail->header_data = buffer_create_dynamic(default_pool, 4096); i_array_init(&mail->header_lines, 32); i_array_init(&mail->header_match, 32); i_array_init(&mail->header_match_lines, 32); mail->header_match_value = HEADER_MATCH_SKIP_COUNT; } else { buffer_set_used_size(mail->header_data, 0); array_clear(&mail->header_lines); array_clear(&mail->header_match_lines); mail->header_match_value += HEADER_MATCH_SKIP_COUNT; i_assert((mail->header_match_value & (HEADER_MATCH_SKIP_COUNT-1)) == 0); if (mail->header_match_value == 0) { /* wrapped, we'll have to clear the buffer */ array_clear(&mail->header_match); mail->header_match_value = HEADER_MATCH_SKIP_COUNT; } } if (headers != NULL) { for (i = 0; i < headers->count; i++) { array_idx_set(&mail->header_match, headers->idx[i], &mail->header_match_value); } } if (data->wanted_headers != NULL && data->wanted_headers != headers) { headers = data->wanted_headers; for (i = 0; i < headers->count; i++) { array_idx_set(&mail->header_match, headers->idx[i], &mail->header_match_value); } } /* register also all the other headers that exist in cache file */ T_BEGIN { index_mail_parse_header_register_all_wanted(mail); } T_END; /* if we want sent date, it doesn't mean that we also want to cache Date: header. if we have Date field's index set at this point we know that we want it. otherwise add it and remember that we don't want it cached. */ field_idx = get_header_field_idx(mail->mail.mail.box, "Date", MAIL_CACHE_DECISION_NO); match = array_get(&mail->header_match, &match_count); if (field_idx < match_count && match[field_idx] == mail->header_match_value) { /* cache Date: header */ } else if ((data->cache_fetch_fields & MAIL_FETCH_DATE) != 0 || data->save_sent_date) { /* parse Date: header, but don't cache it. */ data->dont_cache_field_idx = field_idx; array_idx_set(&mail->header_match, field_idx, &mail->header_match_value); } }