int acl_rights_update_import(struct acl_rights_update *update, const char *id, const char *const *rights, const char **error_r) { ARRAY_TYPE(const_string) dest_rights, dest_neg_rights, *dest; unsigned int i, j; if (acl_identifier_parse(id, &update->rights) < 0) { *error_r = t_strdup_printf("Invalid ID: %s", id); return -1; } if (rights == NULL) { update->modify_mode = ACL_MODIFY_MODE_CLEAR; update->neg_modify_mode = ACL_MODIFY_MODE_CLEAR; return 0; } t_array_init(&dest_rights, 8); t_array_init(&dest_neg_rights, 8); for (i = 0; rights[i] != NULL; i++) { const char *right = rights[i]; if (right[0] != '-') dest = &dest_rights; else { right++; dest = &dest_neg_rights; } if (strcmp(right, "all") != 0) { if (*right == ':') { /* non-standard right */ right++; array_append(dest, &right, 1); } else if (is_standard_right(right)) { array_append(dest, &right, 1); } else { *error_r = t_strdup_printf("Invalid right '%s'", right); return -1; } } else { for (j = 0; all_mailbox_rights[j] != NULL; j++) array_append(dest, &all_mailbox_rights[j], 1); } } if (array_count(&dest_rights) > 0) { array_append_zero(&dest_rights); update->rights.rights = array_idx(&dest_rights, 0); } else if (update->modify_mode == ACL_MODIFY_MODE_REPLACE) { update->modify_mode = ACL_MODIFY_MODE_CLEAR; } if (array_count(&dest_neg_rights) > 0) { array_append_zero(&dest_neg_rights); update->rights.neg_rights = array_idx(&dest_neg_rights, 0); } else if (update->neg_modify_mode == ACL_MODIFY_MODE_REPLACE) { update->neg_modify_mode = ACL_MODIFY_MODE_CLEAR; } return 0; }
static uint32_t maildir_save_set_recent_flags(struct maildir_save_context *ctx) { struct maildir_mailbox *mbox = ctx->mbox; ARRAY_TYPE(seq_range) saved_sorted_uids; const struct seq_range *uids; unsigned int i, count; uint32_t uid; count = array_count(&ctx->ctx.transaction->changes->saved_uids); if (count == 0) return 0; t_array_init(&saved_sorted_uids, count); array_append_array(&saved_sorted_uids, &ctx->ctx.transaction->changes->saved_uids); array_sort(&saved_sorted_uids, seq_range_cmp); uids = array_get(&saved_sorted_uids, &count); for (i = 0; i < count; i++) { for (uid = uids[i].seq1; uid <= uids[i].seq2; uid++) mailbox_recent_flags_set_uid(&mbox->box, uid); } return uids[count-1].seq2 + 1; }
static int cmd_deduplicate_uidlist(struct mailbox *box, struct uidlist *uidlist) { struct mailbox_transaction_context *trans; struct mail_search_context *search_ctx; struct mail_search_args *search_args; struct mail_search_arg *arg; struct mail *mail; ARRAY_TYPE(seq_range) uids; int ret = 0; /* the uidlist is reversed with oldest mails at the end. we'll delete everything but the oldest mail. */ if (uidlist->next == NULL) return 0; t_array_init(&uids, 8); for (; uidlist->next != NULL; uidlist = uidlist->next) seq_range_array_add(&uids, uidlist->uid); search_args = mail_search_build_init(); arg = mail_search_build_add(search_args, SEARCH_UIDSET); arg->value.seqset = uids; trans = mailbox_transaction_begin(box, 0); search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL); mail_search_args_unref(&search_args); while (mailbox_search_next(search_ctx, &mail)) mail_expunge(mail); if (mailbox_search_deinit(&search_ctx) < 0) ret = -1; if (mailbox_transaction_commit(&trans) < 0) ret = -1; return ret; }
static void dbox_sync_index_copy_from_old(struct dbox_sync_rebuild_context *ctx, struct mail_index_view *view, uint32_t old_seq, uint32_t new_seq) { struct mail_index *index = mail_index_view_get_index(view); const struct mail_index_record *rec; ARRAY_TYPE(keyword_indexes) old_keywords; struct mail_keywords *kw; uint64_t modseq; /* copy flags */ rec = mail_index_lookup(view, old_seq); mail_index_update_flags(ctx->trans, new_seq, MODIFY_REPLACE, rec->flags); /* copy keywords */ t_array_init(&old_keywords, 32); mail_index_lookup_keywords(view, old_seq, &old_keywords); kw = mail_index_keywords_create_from_indexes(index, &old_keywords); mail_index_update_keywords(ctx->trans, new_seq, MODIFY_REPLACE, kw); mail_index_keywords_unref(&kw); /* copy modseq */ modseq = mail_index_modseq_lookup(view, old_seq); mail_index_update_modseq(ctx->trans, new_seq, modseq); dbox_sync_index_copy_cache(ctx, view, old_seq, new_seq); }
static void env_clean_except_real(const char *const preserve_envs[]) { ARRAY_TYPE(const_string) copy; const char *value, *const *envp; unsigned int i; t_array_init(©, 16); for (i = 0; preserve_envs[i] != NULL; i++) { const char *key = preserve_envs[i]; value = getenv(key); if (value != NULL) { value = t_strconcat(key, "=", value, NULL); array_append(©, &value, 1); } } /* Note that if the original environment was set with env_put(), the environment strings will be invalid after env_clean(). That's why we t_strconcat() them above. */ env_clean(); array_foreach(©, envp) env_put(*envp); }
static void mirror_get_remote_cmd_line(const char *const *argv, const char *const **cmd_args_r) { ARRAY_TYPE(const_string) cmd_args; unsigned int i; const char *p; i_assert(argv[0] != NULL); t_array_init(&cmd_args, 16); for (i = 0; argv[i] != NULL; i++) { p = argv[i]; array_append(&cmd_args, &p, 1); } if (legacy_dsync) { /* we're executing dsync */ p = "server"; } else { /* we're executing doveadm */ p = "dsync-server"; } array_append(&cmd_args, &p, 1); array_append_zero(&cmd_args); *cmd_args_r = array_idx(&cmd_args, 0); }
static void boundaries_permute(uint32_t *input, unsigned int i, unsigned int count) { ARRAY_TYPE(seq_range) range; const struct seq_range *seqs; unsigned int seqs_count; uint32_t tmp; unsigned int j; if (i+1 < count) { for (j = i; j < count; j++) { tmp = input[i]; input[i] = input[j]; input[j] = tmp; boundaries_permute(input, i+1, count); tmp = input[i]; input[i] = input[j]; input[j] = tmp; } return; } t_array_init(&range, 4); for (i = 0; i < count; i++) seq_range_array_add(&range, input[i]); seqs = array_get(&range, &seqs_count); test_assert(seqs_count == 2); test_assert(seqs[0].seq1 == 0); test_assert(seqs[0].seq2 == 1); test_assert(seqs[1].seq1 == (uint32_t)-2); test_assert(seqs[1].seq2 == (uint32_t)-1); }
static void test_seq_range_array_remove_nth(void) { ARRAY_TYPE(seq_range) range; const struct seq_range *r; test_begin("seq_range_array_remove_nth()"); t_array_init(&range, 8); seq_range_array_add_range(&range, 1, 5); seq_range_array_add(&range, 7); seq_range_array_add_range(&range, 10,20); test_assert(array_count(&range) == 3); seq_range_array_remove_nth(&range, 0, 2); r = array_idx(&range, 0); test_assert(r->seq1 == 3 && r->seq2 == 5); seq_range_array_remove_nth(&range, 1, 4); r = array_idx(&range, 0); test_assert(r->seq1 == 3 && r->seq2 == 3); r = array_idx(&range, 1); test_assert(r->seq1 == 11 && r->seq2 == 20); seq_range_array_remove_nth(&range, 5, (uint32_t)-1); r = array_idx(&range, 1); test_assert(r->seq1 == 11 && r->seq2 == 14); test_assert(array_count(&range) == 2); test_end(); }
int main(int argc, char *argv[]) { ARRAY_TYPE(const_string) aenvs; const char *binary; const char *const *envs; int c, i; master_service = master_service_init("script", 0, &argc, &argv, "+e:"); t_array_init(&aenvs, 16); while ((c = master_getopt(master_service)) > 0) { switch (c) { case 'e': envs = t_strsplit_spaces(optarg,", \t"); while (*envs != NULL) { array_append(&aenvs, envs, 1); envs++; } break; default: return FATAL_DEFAULT; } } argc -= optind; argv += optind; array_append_zero(&aenvs); accepted_envs = p_strarray_dup(default_pool, array_idx(&aenvs, 0)); master_service_init_log(master_service, "script: "); if (argv[0] == NULL) i_fatal("Missing script path"); restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL); restrict_access_allow_coredumps(TRUE); master_service_init_finish(master_service); master_service_set_service_count(master_service, 1); if (argv[0][0] == '/') binary = argv[0]; else binary = t_strconcat(PKG_LIBEXECDIR"/", argv[0], NULL); i_array_init(&exec_args, argc + 16); array_append(&exec_args, &binary, 1); for (i = 1; i < argc; i++) { const char *arg = argv[i]; array_append(&exec_args, &arg, 1); } master_service_run(master_service, client_connected); array_free(&exec_args); i_free(accepted_envs); master_service_deinit(&master_service); return 0; }
static void test_seq_range_array_add_merge(void) { ARRAY_TYPE(seq_range) range; test_begin("seq_range_array_add() merging"); t_array_init(&range, 8); seq_range_array_add(&range, 4); seq_range_array_add(&range, 1); seq_range_array_add(&range, 2); test_assert(array_count(&range) == 2); test_end(); }
static const char * maildir_filename_guess(struct maildir_mailbox *mbox, uint32_t uid, const char *fname, enum maildir_uidlist_rec_flag *uidlist_flags, bool *have_flags_r) { struct mail_index_view *view = mbox->flags_view; struct maildir_keywords_sync_ctx *kw_ctx; enum mail_flags flags; ARRAY_TYPE(keyword_indexes) keywords; const char *p; uint32_t seq; if (view == NULL || !mail_index_lookup_seq(view, uid, &seq)) { *have_flags_r = FALSE; return fname; } t_array_init(&keywords, 32); mail_index_lookup_view_flags(view, seq, &flags, &keywords); if (array_count(&keywords) == 0) { *have_flags_r = (flags & MAIL_FLAGS_NONRECENT) != 0; fname = maildir_filename_flags_set(fname, flags); } else { *have_flags_r = TRUE; kw_ctx = maildir_keywords_sync_init_readonly(mbox->keywords, mbox->box.index); fname = maildir_filename_flags_kw_set(kw_ctx, fname, flags, &keywords); maildir_keywords_sync_deinit(&kw_ctx); } if (*have_flags_r) { /* don't even bother looking into new/ dir */ *uidlist_flags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; } else if ((*uidlist_flags & MAILDIR_UIDLIST_REC_FLAG_MOVED) == 0 && ((*uidlist_flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 || mailbox_recent_flags_have_uid(&mbox->box, uid))) { /* probably in new/ dir, drop ":2," from fname */ *uidlist_flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; p = strrchr(fname, MAILDIR_INFO_SEP); if (p != NULL) fname = t_strdup_until(fname, p); } return fname; }
static struct imap_match_glob * imap_match_dup_real(pool_t pool, const struct imap_match_glob *glob) { ARRAY_TYPE(const_string) patterns; const struct imap_match_pattern *p; bool inboxcase = FALSE; t_array_init(&patterns, 8); for (p = glob->patterns; p->pattern != NULL; p++) { if (p->inboxcase) inboxcase = TRUE; array_append(&patterns, &p->pattern, 1); } array_append_zero(&patterns); return imap_match_init_multiple_real(pool, array_idx(&patterns, 0), inboxcase, glob->sep); }
static void index_storage_mailbox_update_cache(struct mailbox *box, const struct mailbox_update *update) { const struct mailbox_cache_field *updates = update->cache_updates; ARRAY(struct mail_cache_field) new_fields; const struct mail_cache_field *old_fields; struct mail_cache_field field; unsigned int i, j, old_count; old_fields = mail_cache_register_get_list(box->cache, pool_datastack_create(), &old_count); /* There shouldn't be many fields, so don't worry about O(n^2). */ t_array_init(&new_fields, 32); for (i = 0; updates[i].name != NULL; i++) { /* see if it's an existing field */ for (j = 0; j < old_count; j++) { if (strcmp(updates[i].name, old_fields[j].name) == 0) break; } if (j != old_count) { field = old_fields[j]; } else if (strncmp(updates[i].name, "hdr.", 4) == 0) { /* new header */ memset(&field, 0, sizeof(field)); field.name = updates[i].name; field.type = MAIL_CACHE_FIELD_HEADER; } else { /* new unknown field. we can't do anything about this since we don't know its type */ continue; } field.decision = updates[i].decision; if (updates[i].last_used != (time_t)-1) field.last_used = updates[i].last_used; array_append(&new_fields, &field, 1); } if (array_count(&new_fields) > 0) { mail_cache_register_fields(box->cache, array_idx_modifiable(&new_fields, 0), array_count(&new_fields)); } }
static void dsync_brain_slave_send_mailbox_lost(struct dsync_brain *brain, const struct dsync_mailbox *dsync_box) { struct dsync_mailbox delete_box; if (brain->debug) { i_debug("brain %c: We don't have mailbox %s", brain->master_brain ? 'M' : 'S', guid_128_to_string(dsync_box->mailbox_guid)); } memset(&delete_box, 0, sizeof(delete_box)); memcpy(delete_box.mailbox_guid, dsync_box->mailbox_guid, sizeof(delete_box.mailbox_guid)); t_array_init(&delete_box.cache_fields, 0); delete_box.mailbox_lost = TRUE; dsync_ibc_send_mailbox(brain->ibc, &delete_box); }
static int tst_test_multiscript_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { struct sieve_stringlist *scripts_list; string_t *script_name; ARRAY_TYPE (const_string) scriptfiles; bool result = TRUE; int ret; /* * Read operands */ if ( (ret=sieve_opr_stringlist_read(renv, address, "scripts", &scripts_list)) <= 0 ) return ret; /* * Perform operation */ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "testsuite: test_multiscript test"); sieve_runtime_trace_descend(renv); t_array_init(&scriptfiles, 16); script_name = NULL; while ( result && (ret=sieve_stringlist_next_item(scripts_list, &script_name)) > 0 ) { const char *script = t_strdup(str_c(script_name)); array_append(&scriptfiles, &script, 1); } result = result && (ret >= 0) && testsuite_script_multiscript(renv, &scriptfiles); /* Set result */ sieve_interpreter_set_test_result(renv->interp, result); return SIEVE_EXEC_OK; }
static struct mail_keywords * mailbox_keywords_create_skip(struct mailbox *box, const char *const keywords[]) { struct mail_keywords *kw; T_BEGIN { ARRAY(const char *) valid_keywords; const char *error; t_array_init(&valid_keywords, 32); for (; *keywords != NULL; keywords++) { if (mailbox_keyword_is_valid(box, *keywords, &error)) array_append(&valid_keywords, keywords, 1); } array_append_zero(&valid_keywords); /* NULL-terminate */ kw = mail_index_keywords_create(box->index, keywords); } T_END; return kw; }
static void index_storage_get_status_cache_fields(struct mailbox *box, struct mailbox_status *status_r) { const struct mail_cache_field *fields; enum mail_cache_decision_type dec; ARRAY_TYPE(const_string) *cache_fields; unsigned int i, count; fields = mail_cache_register_get_list(box->cache, pool_datastack_create(), &count); cache_fields = t_new(ARRAY_TYPE(const_string), 1); t_array_init(cache_fields, count); for (i = 0; i < count; i++) { dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED; if (dec != MAIL_CACHE_DECISION_NO) array_append(cache_fields, &fields[i].name, 1); } status_r->cache_fields = cache_fields; }
static struct mail_search_register * mail_search_register_init_human(struct mail_search_register *imap_register) { struct mail_search_register *reg; mail_search_register_fallback_t *fallback; ARRAY(struct mail_search_register_arg) copy_args; const struct mail_search_register_arg *human_args, *imap_args; unsigned int i, j, human_count, imap_count; int ret; reg = mail_search_register_init(); mail_search_register_add(reg, human_register_args, N_ELEMENTS(human_register_args)); /* find and register args in imap that don't exist in human */ imap_args = mail_search_register_get(imap_register, &imap_count); human_args = mail_search_register_get(reg, &human_count); t_array_init(©_args, imap_count); for (i = j = 0; i < imap_count && j < human_count; ) { ret = strcmp(imap_args[i].key, human_args[j].key); if (ret < 0) { array_append(©_args, &imap_args[i], 1); i++; } else if (ret > 0) { j++; } else { i++; j++; } } for (; i < imap_count; i++) array_append(©_args, &imap_args[i], 1); imap_args = array_get(©_args, &imap_count); mail_search_register_add(reg, imap_args, imap_count); if (mail_search_register_get_fallback(imap_register, &fallback)) mail_search_register_fallback(reg, fallback); return reg; }
static const char *test_aqueue2(unsigned int initial_size) { ARRAY(unsigned int) aqueue_array; unsigned int i, j, k; for (i = 0; i < N_ELEMENTS(aqueue_input); i++) { for (k = 0; k < N_ELEMENTS(aqueue_input); k++) { struct aqueue *aqueue; t_array_init(&aqueue_array, initial_size); aqueue = aqueue_init(&aqueue_array.arr); aqueue->head = aqueue->tail = initial_size - 1; for (j = 0; j < k; j++) { aqueue_append(aqueue, &aqueue_input[j]); if (aqueue_count(aqueue) != j + 1) { return t_strdup_printf("Wrong count after append %u vs %u)", aqueue_count(aqueue), j + 1); } if (!aqueue_is_ok(aqueue, UINT_MAX)) return "Invalid data after append"; } if (k != 0 && i < k) { aqueue_delete(aqueue, i); if (aqueue_count(aqueue) != k - 1) return "Wrong count after delete"; if (!aqueue_is_ok(aqueue, i)) return "Invalid data after delete"; } aqueue_clear(aqueue); if (aqueue_count(aqueue) != 0) return "aqueue_clear() broken"; aqueue_deinit(&aqueue); } } return NULL; }
static int search_arg_match_keywords(struct index_search_context *ctx, struct mail_search_arg *arg) { ARRAY_TYPE(keyword_indexes) keyword_indexes_arr; const struct mail_keywords *search_kws = arg->value.keywords; const unsigned int *keyword_indexes; unsigned int i, j, count; t_array_init(&keyword_indexes_arr, 128); mail_index_lookup_keywords(ctx->view, ctx->mail_ctx.seq, &keyword_indexes_arr); keyword_indexes = array_get(&keyword_indexes_arr, &count); /* there probably aren't many keywords, so O(n*m) for now */ for (i = 0; i < search_kws->count; i++) { for (j = 0; j < count; j++) { if (search_kws->idx[i] == keyword_indexes[j]) break; } if (j == count) return 0; } return 1; }
static bool client_exec_script(struct master_service_connection *conn) { ARRAY_TYPE(const_string) envs; const char *const *args; string_t *input; void *buf; size_t prev_size, scanpos; bool header_complete = FALSE, noreply = FALSE; ssize_t ret; int status; pid_t pid; net_set_nonblock(conn->fd, FALSE); input = t_buffer_create(IO_BLOCK_SIZE); /* Input contains: VERSION .. <lf> [alarm=<secs> <lf>] "noreply" | "-" (or anything really) <lf> arg 1 <lf> arg 2 <lf> ... <lf> DATA This is quite a horrible protocol. If alarm is specified, it MUST be before "noreply". If "noreply" isn't given, something other string (typically "-") must be given which is eaten away. */ alarm(SCRIPT_READ_TIMEOUT_SECS); scanpos = 1; while (!header_complete) { const unsigned char *pos, *end; prev_size = input->used; buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE); /* peek in socket input buffer */ ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK); if (ret <= 0) { buffer_set_used_size(input, prev_size); if (strchr(str_c(input), '\n') != NULL) script_verify_version(t_strcut(str_c(input), '\n')); if (ret < 0) i_fatal("recv(MSG_PEEK) failed: %m"); i_fatal("recv(MSG_PEEK) failed: disconnected"); } /* scan for final \n\n */ pos = CONST_PTR_OFFSET(input->data, scanpos); end = CONST_PTR_OFFSET(input->data, prev_size + ret); for (; pos < end; pos++) { if (pos[-1] == '\n' && pos[0] == '\n') { header_complete = TRUE; pos++; break; } } scanpos = pos - (const unsigned char *)input->data; /* read data for real (up to and including \n\n) */ ret = recv(conn->fd, buf, scanpos-prev_size, 0); if (prev_size+ret != scanpos) { if (ret < 0) i_fatal("recv() failed: %m"); if (ret == 0) i_fatal("recv() failed: disconnected"); i_fatal("recv() failed: size of definitive recv() differs from peek"); } buffer_set_used_size(input, scanpos); } alarm(0); /* drop the last two LFs */ buffer_set_used_size(input, scanpos-2); args = t_strsplit(str_c(input), "\n"); script_verify_version(*args); args++; t_array_init(&envs, 16); if (*args != NULL) { const char *p; if (str_begins(*args, "alarm=")) { unsigned int seconds; if (str_to_uint(*args + 6, &seconds) < 0) i_fatal("invalid alarm option"); alarm(seconds); args++; } while (str_begins(*args, "env_")) { const char *envname, *env; env = t_str_tabunescape(*args+4); p = strchr(env, '='); if (p == NULL) i_fatal("invalid environment variable"); envname = t_strdup_until(*args+4, p); if (str_array_find(accepted_envs, envname)) array_append(&envs, &env, 1); args++; } if (strcmp(*args, "noreply") == 0) { noreply = TRUE; } if (**args == '\0') i_fatal("empty options"); args++; } array_append_zero(&envs); if (noreply) { /* no need to fork and check exit status */ exec_child(conn, args, array_idx(&envs, 0)); i_unreached(); } if ((pid = fork()) == (pid_t)-1) { i_error("fork() failed: %m"); return FALSE; } if (pid == 0) { /* child */ exec_child(conn, args, array_idx(&envs, 0)); i_unreached(); } /* parent */ /* check script exit status */ if (waitpid(pid, &status, 0) < 0) { i_error("waitpid() failed: %m"); return FALSE; } else if (WIFEXITED(status)) { ret = WEXITSTATUS(status); if (ret != 0) { i_error("Script terminated abnormally, exit status %d", (int)ret); return FALSE; } } else if (WIFSIGNALED(status)) { i_error("Script terminated abnormally, signal %d", WTERMSIG(status)); return FALSE; } else if (WIFSTOPPED(status)) { i_fatal("Script stopped, signal %d", WSTOPSIG(status)); return FALSE; } else { i_fatal("Script terminated abnormally, return status %d", status); return FALSE; } return TRUE; }
int rfc2231_parse(struct rfc822_parser_context *ctx, const char *const **result_r) { ARRAY_TYPE(const_string) result; ARRAY(struct rfc2231_parameter) rfc2231_params_arr; struct rfc2231_parameter rfc2231_param; const struct rfc2231_parameter *rfc2231_params; const char *key, *value, *p, *p2; string_t *str; unsigned int i, j, count, next, next_idx; bool ok, have_extended, broken = FALSE; int ret; /* Get a list of all parameters. RFC 2231 uses key*<n>[*]=value pairs, which we want to merge to a key[*]=value pair. Save them to a separate array. */ memset(&rfc2231_param, 0, sizeof(rfc2231_param)); t_array_init(&result, 8); t_array_init(&rfc2231_params_arr, 8); while ((ret = rfc822_parse_content_param(ctx, &key, &value)) != 0) { if (ret < 0) { /* try to continue anyway.. */ broken = TRUE; if (ctx->data == ctx->end) break; ctx->data++; continue; } p = strchr(key, '*'); if (p != NULL) { p2 = p; if (p[1] != '\0') { p++; rfc2231_param.idx = 0; for (; *p >= '0' && *p <= '9'; p++) { rfc2231_param.idx = rfc2231_param.idx*10 + *p - '0'; } } if (*p != '*') rfc2231_param.extended = FALSE; else { rfc2231_param.extended = TRUE; p++; } if (*p != '\0') p = NULL; else { rfc2231_param.key = t_strdup_until(key, p2); rfc2231_param.value = value; array_append(&rfc2231_params_arr, &rfc2231_param, 1); } } if (p == NULL) { array_append(&result, &key, 1); array_append(&result, &value, 1); } } if (array_count(&rfc2231_params_arr) == 0) { /* No RFC 2231 parameters */ array_append_zero(&result); /* NULL-terminate */ *result_r = array_idx(&result, 0); return broken ? -1 : 0; } /* Merge the RFC 2231 parameters. Since their order isn't guaranteed to be ascending, start by sorting them. */ array_sort(&rfc2231_params_arr, rfc2231_parameter_cmp); rfc2231_params = array_get(&rfc2231_params_arr, &count); /* keys are now sorted primarily by their name and secondarily by their index. If any indexes are missing, fallback to assuming these aren't RFC 2231 encoded parameters. */ str = t_str_new(64); for (i = 0; i < count; i = next) { ok = TRUE; have_extended = FALSE; next_idx = 0; for (j = i; j < count; j++) { if (strcasecmp(rfc2231_params[i].key, rfc2231_params[j].key) != 0) break; if (rfc2231_params[j].idx != next_idx) { /* missing indexes */ ok = FALSE; } if (rfc2231_params[j].extended) have_extended = TRUE; next_idx++; } next = j; if (!ok) { /* missing indexes */ for (j = i; j < next; j++) { key = t_strdup_printf( rfc2231_params[j].extended ? "%s*%u*" : "%s*%u", rfc2231_params[j].key, rfc2231_params[j].idx); array_append(&result, &key, 1); array_append(&result, &rfc2231_params[j].value, 1); } } else { /* everything was successful */ str_truncate(str, 0); if (!rfc2231_params[i].extended && have_extended) str_append(str, "''"); for (j = i; j < next; j++) { if (!rfc2231_params[j].extended && have_extended) { rfc2231_escape(str, rfc2231_params[j].value); } else { str_append(str, rfc2231_params[j].value); } } key = rfc2231_params[i].key; if (have_extended) key = t_strconcat(key, "*", NULL); value = t_strdup(str_c(str)); array_append(&result, &key, 1); array_append(&result, &value, 1); } } array_append_zero(&result); /* NULL-terminate */ *result_r = array_idx(&result, 0); return broken ? -1 : 0; }
static void service_dup_fds(struct service *service) { struct service_listener *const *listeners; ARRAY_TYPE(dup2) dups; string_t *listener_settings; int fd = MASTER_LISTEN_FD_FIRST; unsigned int i, count, socket_listener_count; /* stdin/stdout is already redirected to /dev/null. Other master fds should have been opened with fd_close_on_exec() so we don't have to worry about them. because the destination fd might be another one's source fd we have to be careful not to overwrite anything. dup() the fd when needed */ socket_listener_count = 0; listeners = array_get(&service->listeners, &count); t_array_init(&dups, count + 10); switch (service->type) { case SERVICE_TYPE_LOG: i_assert(fd == MASTER_LISTEN_FD_FIRST); services_log_dup2(&dups, service->list, fd, &socket_listener_count); fd += socket_listener_count; break; case SERVICE_TYPE_ANVIL: dup2_append(&dups, service_anvil_global->log_fdpass_fd[0], MASTER_ANVIL_LOG_FDPASS_FD); /* nonblocking anvil fd must be the first one. anvil treats it as the master's fd */ dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++); dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++); socket_listener_count += 2; break; default: break; } /* add listeners */ listener_settings = t_str_new(256); for (i = 0; i < count; i++) { if (listeners[i]->fd != -1) { str_truncate(listener_settings, 0); str_append_tabescaped(listener_settings, listeners[i]->name); if (listeners[i]->type == SERVICE_LISTENER_INET) { if (listeners[i]->set.inetset.set->ssl) str_append(listener_settings, "\tssl"); if (listeners[i]->set.inetset.set->haproxy) str_append(listener_settings, "\thaproxy"); } dup2_append(&dups, listeners[i]->fd, fd++); env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s", socket_listener_count, str_c(listener_settings))); socket_listener_count++; } } if (service->login_notify_fd != -1) { dup2_append(&dups, service->login_notify_fd, MASTER_LOGIN_NOTIFY_FD); } switch (service->type) { case SERVICE_TYPE_LOG: case SERVICE_TYPE_ANVIL: case SERVICE_TYPE_CONFIG: dup2_append(&dups, null_fd, MASTER_ANVIL_FD); break; case SERVICE_TYPE_UNKNOWN: case SERVICE_TYPE_LOGIN: case SERVICE_TYPE_STARTUP: dup2_append(&dups, service_anvil_global->blocking_fd[1], MASTER_ANVIL_FD); break; } dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD); if (service->type != SERVICE_TYPE_ANVIL) { dup2_append(&dups, service->list->master_dead_pipe_fd[1], MASTER_DEAD_FD); } else { dup2_append(&dups, global_master_dead_pipe_fd[1], MASTER_DEAD_FD); } if (service->type == SERVICE_TYPE_LOG) { /* keep stderr as-is. this is especially important when log_path=/dev/stderr, but might be helpful even in other situations for logging startup errors */ } else { /* set log file to stderr. dup2() here immediately so that we can set up logging to it without causing any log messages to be lost. */ i_assert(service->log_fd[1] != -1); env_put("LOG_SERVICE=1"); if (dup2(service->log_fd[1], STDERR_FILENO) < 0) i_fatal("dup2(log fd) failed: %m"); i_set_failure_internal(); } /* make sure we don't leak syslog fd. try to do it as late as possible, but also before dup2()s in case syslog fd is one of them. */ closelog(); if (dup2_array(&dups) < 0) i_fatal("service(%s): dup2s failed", service->set->name); i_assert(fd == MASTER_LISTEN_FD_FIRST + (int)socket_listener_count); env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count)); }
static bool parse_x_keywords_real(struct mbox_sync_mail_context *ctx, struct message_header_line *hdr) { struct mailbox *box = &ctx->sync_ctx->mbox->box; ARRAY_TYPE(keyword_indexes) keyword_list; const unsigned int *list; string_t *keyword; size_t keyword_start; unsigned int i, idx, count; size_t pos; if (array_is_created(&ctx->mail.keywords)) return FALSE; /* duplicate header, delete */ /* read keyword indexes to temporary array first */ keyword = t_str_new(128); t_array_init(&keyword_list, 16); for (pos = 0; pos < hdr->full_value_len; ) { if (IS_LWSP_LF(hdr->full_value[pos])) { pos++; continue; } /* read the keyword string */ keyword_start = pos; for (; pos < hdr->full_value_len; pos++) { if (IS_LWSP_LF(hdr->full_value[pos])) break; } str_truncate(keyword, 0); str_append_n(keyword, hdr->full_value + keyword_start, pos - keyword_start); if (!mail_index_keyword_lookup(box->index, str_c(keyword), &idx)) { /* keyword wasn't found. that means the sent mail originally contained X-Keywords header. Delete it. */ return FALSE; } /* check that the keyword isn't already added there. we don't want duplicates. */ list = array_get(&keyword_list, &count); for (i = 0; i < count; i++) { if (list[i] == idx) break; } if (i == count) array_append(&keyword_list, &idx, 1); } /* once we know how many keywords there are, we can allocate the array from mail_keyword_pool without wasting memory. */ if (array_count(&keyword_list) > 0) { p_array_init(&ctx->mail.keywords, ctx->sync_ctx->mail_keyword_pool, array_count(&keyword_list)); array_append_array(&ctx->mail.keywords, &keyword_list); } ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = str_len(ctx->header); parse_trailing_whitespace(ctx, hdr); return TRUE; }
int uri_parse_path(struct uri_parser *parser, int *relative_r, const char *const **path_r) { const unsigned char *pbegin = parser->cur; ARRAY_TYPE(const_string) segments; const char *segment = NULL; unsigned int count; int relative = 1; int ret; t_array_init(&segments, 16); /* check for a leading '/' and indicate absolute path when it is present */ if (parser->cur < parser->end && *parser->cur == '/') { parser->cur++; relative = 0; } /* parse first segment */ if ((ret = uri_parse_path_segment(parser, &segment)) < 0) return -1; for (;;) { if (ret > 0) { /* strip dot segments */ if (segment[0] == '.') { if (segment[1] == '.') { if (segment[2] == '\0') { /* '..' -> skip and... */ segment = NULL; /* ... pop last segment (if any) */ count = array_count(&segments); if (count > 0) { array_delete(&segments, count-1, 1); } else if ( relative > 0 ) { relative++; } } } else if (segment[1] == '\0') { /* '.' -> skip */ segment = NULL; } } } else { segment = ""; } if (segment != NULL) array_append(&segments, &segment, 1); if (parser->cur >= parser->end || *parser->cur != '/') break; parser->cur++; /* parse next path segment */ if ((ret = uri_parse_path_segment(parser, &segment)) < 0) return -1; } *path_r = NULL; *relative_r = relative; if (parser->cur == pbegin) { /* path part of URI is empty */ return 0; } /* special treatment for a trailing '..' or '.' */ if (segment == NULL) { segment = ""; array_append(&segments, &segment, 1); } array_append_zero(&segments); *path_r = array_get(&segments, &count); return 1; }
int main(int argc, char *argv[]) { static const struct setting_parser_info *set_roots[] = { &imap_urlauth_worker_setting_parser_info, NULL }; enum master_service_flags service_flags = 0; enum mail_storage_service_flags storage_service_flags = MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP | MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT; ARRAY_TYPE (const_string) access_apps; const char *access_user = NULL; int c; if (IS_STANDALONE()) { service_flags |= MASTER_SERVICE_FLAG_STANDALONE | MASTER_SERVICE_FLAG_STD_CLIENT; } else { service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN; storage_service_flags |= MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT; } master_service = master_service_init("imap-urlauth-worker", service_flags, &argc, &argv, "a:"); t_array_init(&access_apps, 4); while ((c = master_getopt(master_service)) > 0) { switch (c) { case 'a': { const char *app = t_strdup(optarg); array_append(&access_apps, &app, 1); break; } default: return FATAL_DEFAULT; } } if ( optind < argc ) { access_user = argv[optind++]; } if (optind != argc) { i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]); } master_service_init_log(master_service, t_strdup_printf("imap-urlauth[%s]: ", my_pid)); master_service_init_finish(master_service); master_service_set_die_callback(master_service, imap_urlauth_worker_die); random_init(); storage_service = mail_storage_service_init(master_service, set_roots, storage_service_flags); /* fake that we're running, so we know if client was destroyed while handling its initial input */ io_loop_set_running(current_ioloop); if (IS_STANDALONE()) { T_BEGIN { if (array_count(&access_apps) > 0) { (void)array_append_space(&access_apps); main_stdio_run(access_user, array_idx(&access_apps,0)); } else { main_stdio_run(access_user, NULL); } } T_END; } else {
static void dsync_cache_fields_update(const struct dsync_mailbox *local_box, const struct dsync_mailbox *remote_box, struct mailbox_update *update) { ARRAY_TYPE(mailbox_cache_field) local_sorted, remote_sorted, changes; const struct mailbox_cache_field *local_fields, *remote_fields; unsigned int li, ri, local_count, remote_count; time_t drop_older_timestamp; int ret; if (array_count(&remote_box->cache_fields) == 0) { /* remote has no cached fields. there's nothing to update. */ return; } t_array_init(&local_sorted, array_count(&local_box->cache_fields)); t_array_init(&remote_sorted, array_count(&remote_box->cache_fields)); array_append_array(&local_sorted, &local_box->cache_fields); array_append_array(&remote_sorted, &remote_box->cache_fields); array_sort(&local_sorted, mailbox_cache_field_name_cmp); array_sort(&remote_sorted, mailbox_cache_field_name_cmp); if (array_count(&local_sorted) == 0) { /* local has no cached fields. set them to same as remote. */ array_append_zero(&remote_sorted); update->cache_updates = array_idx(&remote_sorted, 0); return; } /* figure out what to change */ local_fields = array_get(&local_sorted, &local_count); remote_fields = array_get(&remote_sorted, &remote_count); t_array_init(&changes, local_count + remote_count); drop_older_timestamp = ioloop_time - MAIL_CACHE_FIELD_DROP_SECS; for (li = ri = 0; li < local_count || ri < remote_count; ) { ret = li == local_count ? 1 : ri == remote_count ? -1 : strcmp(local_fields[li].name, remote_fields[ri].name); if (ret == 0) { /* field exists in both local and remote */ const struct mailbox_cache_field *lf = &local_fields[li]; const struct mailbox_cache_field *rf = &remote_fields[ri]; if (lf->last_used > rf->last_used || (lf->last_used == rf->last_used && lf->decision > rf->decision)) { /* use local decision and timestamp */ } else { array_append(&changes, rf, 1); } li++; ri++; } else if (ret < 0) { /* remote field doesn't exist */ li++; } else { /* local field doesn't exist */ if (remote_fields[ri].last_used < drop_older_timestamp) { /* field hasn't be used for a long time, remote will probably drop this soon as well */ } else { array_append(&changes, &remote_fields[ri], 1); } ri++; } } i_assert(li == local_count && ri == remote_count); if (array_count(&changes) > 0) { array_append_zero(&changes); update->cache_updates = array_idx(&changes, 0); } }
bool sieve_extprogram_name_is_valid(string_t *name) { ARRAY_TYPE(unichars) uni_name; unsigned int count, i; const unichar_t *name_chars; size_t namelen = str_len(name); /* Check minimum length */ if ( namelen == 0 ) return FALSE; /* Check worst-case maximum length */ if ( namelen > SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN * 4 ) return FALSE; /* Intialize array for unicode characters */ t_array_init(&uni_name, namelen * 4); /* Convert UTF-8 to UCS4/UTF-32 */ if ( uni_utf8_to_ucs4_n(str_data(name), namelen, &uni_name) < 0 ) return FALSE; name_chars = array_get(&uni_name, &count); /* Check true maximum length */ if ( count > SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN ) return FALSE; /* Scan name for invalid characters * FIXME: compliance with Net-Unicode Definition (Section 2 of * RFC 5198) is not checked fully and no normalization * is performed. */ for ( i = 0; i < count; i++ ) { /* 0000-001F; [CONTROL CHARACTERS] */ if ( name_chars[i] <= 0x001f ) return FALSE; /* 002F; SLASH */ if ( name_chars[i] == 0x002f ) return FALSE; /* 007F; DELETE */ if ( name_chars[i] == 0x007f ) return FALSE; /* 0080-009F; [CONTROL CHARACTERS] */ if ( name_chars[i] >= 0x0080 && name_chars[i] <= 0x009f ) return FALSE; /* 00FF */ if ( name_chars[i] == 0x00ff ) return FALSE; /* 2028; LINE SEPARATOR */ /* 2029; PARAGRAPH SEPARATOR */ if ( name_chars[i] == 0x2028 || name_chars[i] == 0x2029 ) return FALSE; } return TRUE; }
static int cmd_altmove_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct altmove_cmd_context *ctx = (struct altmove_cmd_context *)_ctx; const enum mailbox_list_iter_flags iter_flags = MAILBOX_LIST_ITER_NO_AUTO_BOXES | MAILBOX_LIST_ITER_RETURN_NO_FLAGS; struct doveadm_mailbox_list_iter *iter; const struct mailbox_info *info; struct mail_namespace *ns, *prev_ns = NULL; ARRAY(struct mail_storage *) purged_storages; struct mail_storage *const *storages, *ns_storage, *prev_storage = NULL; unsigned int i, count; int ret = 0; t_array_init(&purged_storages, 8); iter = doveadm_mailbox_list_iter_init(_ctx, user, _ctx->search_args, iter_flags); while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN { ns_storage = mail_namespace_get_default_storage(info->ns); if (ns_storage != prev_storage) { if (prev_storage != NULL) { if (ns_purge(_ctx, prev_ns, prev_storage) < 0) ret = -1; array_append(&purged_storages, &prev_storage, 1); } prev_storage = ns_storage; prev_ns = info->ns; } if (cmd_altmove_box(_ctx, info, _ctx->search_args, ctx->reverse) < 0) ret = -1; } T_END; if (doveadm_mailbox_list_iter_deinit(&iter) < 0) ret = -1; if (prev_storage != NULL) { if (ns_purge(_ctx, prev_ns, prev_storage) < 0) ret = -1; array_append(&purged_storages, &prev_storage, 1); } /* make sure all private storages have been purged */ storages = array_get(&purged_storages, &count); for (ns = user->namespaces; ns != NULL; ns = ns->next) { if (ns->type != MAIL_NAMESPACE_TYPE_PRIVATE) continue; ns_storage = mail_namespace_get_default_storage(ns); for (i = 0; i < count; i++) { if (ns_storage == storages[i]) break; } if (i == count) { if (ns_purge(_ctx, ns, ns_storage) < 0) ret = -1; array_append(&purged_storages, &ns_storage, 1); storages = array_get(&purged_storages, &count); } } return ret; }
void sieve_jumplist_init_temp (struct sieve_jumplist *jlist, struct sieve_binary_block *sblock) { jlist->block = sblock; t_array_init(&jlist->jumps, 4); }