imap-client.c revision c9b76ca218d93dc97e27d6ec04a645e8dc6f228b
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikextern struct mail_storage_callbacks mail_storage_callbacks;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikextern struct imap_client_vfuncs imap_client_vfuncs;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstruct imap_module_register imap_module_register = { 0 };
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikunsigned int imap_client_count = 0;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic void client_idle_timeout(struct client *client)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client_send_line(client, "* BYE Disconnected for inactivity.");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client_destroy(client, "Disconnected for inactivity");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic void client_init_urlauth(struct client *client)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik config.url_host = client->set->imap_urlauth_host;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik config.url_port = client->set->imap_urlauth_port;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik config.socket_path = t_strconcat(client->user->set->base_dir,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik config.access_anonymous = client->user->anonymous;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik config.access_user = client->user->username;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client->urlauth_ctx = imap_urlauth_init(client->user, &config);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic bool user_has_special_use_mailboxes(struct mail_user *user)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik for (ns = user->namespaces; ns != NULL; ns = ns->next) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstruct client *client_create(int fd_in, int fd_out, const char *session_id,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik struct mail_storage_service_user *service_user,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik const struct mail_storage_settings *mail_set;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik const char *ident;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* always use nonblocking I/O */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik pool = pool_alloconly_create("imap client", 2048);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client->session_id = p_strdup(pool, session_id);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik o_stream_set_no_error_handling(client->output, TRUE);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik i_stream_set_name(client->input, "<imap client>");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik o_stream_set_name(client->output, "<imap client>");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik o_stream_set_flush_callback(client->output, client_output, client);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik p_array_init(&client->module_contexts, client->pool, 5);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client->io = io_add_istream(client->input, client_input, client);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik pool_alloconly_create(MEMPOOL_GROWING"client command", 1024*2);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mail_namespaces_set_storage_callbacks(user->namespaces,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_new(client->pool, sizeof(CAPABILITY_STRING)+64);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, CAPABILITY_STRING);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, set->imap_capability);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, CAPABILITY_STRING);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append_c(client->capability_string, ' ');
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, set->imap_capability + 1);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (user->fuzzy_search && !explicit_capability) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* Enable FUZZY capability only when it actually has
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik a chance of working */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, " SEARCH=FUZZY");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mail_set = mail_user_set_get_storage_set(user);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (mail_set->mailbox_list_index && !explicit_capability) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* NOTIFY is enabled only when mailbox list indexes are
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik enabled, although even that doesn't necessarily guarantee
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, " NOTIFY");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* Enable URLAUTH capability only when dict is
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik configured correctly */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, " URLAUTH URLAUTH=BINARY");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (set->imap_metadata && *mail_set->mail_attribute_dict != '\0') {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, " METADATA");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (!explicit_capability && user_has_special_use_mailboxes(user)) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* Advertise SPECIAL-USE only if there are actually some
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik SPECIAL-USE flags in mailbox configuration. */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(client->capability_string, " SPECIAL-USE");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik ident = mail_user_get_anvil_userip_ident(client->user);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (ident != NULL) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik master_service_anvil_send(master_service, t_strconcat(
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik "CONNECT\t", my_pid, "\timap/", ident, "\n", NULL));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid client_command_cancel(struct client_command_context **_cmd)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* a bit kludgy check: cancel command only if it has context
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik set. currently only append command matches this check. all
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik other commands haven't even started the processing yet. */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* fall through */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* commands haven't started yet */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik cmd_ret = !cmd->cancel || cmd->func == NULL ? TRUE :
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik i_panic("command didn't cancel itself: %s", cmd->name);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client_command_free(*_cmd != NULL ? _cmd : &cmd);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikconst char *client_stats(struct client *client)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik static struct var_expand_table static_tab[] = {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik memcpy(tab, static_tab, sizeof(static_tab));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[0].value = dec2str(i_stream_get_absolute_offset(client->input));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[1].value = dec2str(client->output->offset);
e59b73366d3067c576e39a214a34ace2f9a84878Lukas Slebodnik tab[3].value = dec2str(client->fetch_hdr_count);
e59b73366d3067c576e39a214a34ace2f9a84878Lukas Slebodnik tab[4].value = dec2str(client->fetch_hdr_bytes);
e59b73366d3067c576e39a214a34ace2f9a84878Lukas Slebodnik tab[5].value = dec2str(client->fetch_body_count);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[6].value = dec2str(client->fetch_body_bytes);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[7].value = dec2str(client->deleted_count);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[8].value = dec2str(client->expunged_count);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[9].value = dec2str(client->trashed_count);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik var_expand(str, client->set->imap_logout_format, tab);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid client_destroy(struct client *client, const char *reason)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic const char *client_get_commands_status(struct client *client)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik uint64_t running_usecs = 0, ioloop_wait_usecs;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik unsigned long long bytes_in = 0, bytes_out = 0;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik ioloop_wait_usecs = io_loop_get_wait_usecs(current_ioloop);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client->command_queue->start_ioloop_wait_usecs + 999) / 1000;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_printfa(str, " running for %d.%03d + waiting for %d.%03d secs",
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik msecs_in_ioloop / 1000, msecs_in_ioloop % 1000);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_printfa(str, ", %llu B in + %llu+%"PRIuSIZE_T" B out)",
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik o_stream_get_buffer_used_size(client->output));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic void client_default_destroy(struct client *client, const char *reason)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik reason = io_stream_get_disconnect_reason(client->input,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik cmd_status = client_get_commands_status(client);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik i_info("%s%s %s", reason, cmd_status, client_stats(client));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* finish off all the queued commands. */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client_command_cancel(&client->output_cmd_lock);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* handle the input_lock command last. it might have been waiting on
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik other queued commands (although we probably should just drop the
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik command at that point since it hasn't started running. but this may
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik change in future). */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik master_service_anvil_send(master_service, t_strconcat(
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mail_user_get_anvil_userip_ident(client->user),
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (array_is_created(&client->search_saved_uidset))
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (array_is_created(&client->search_updates))
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mail_storage_service_user_free(&client->service_user);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik master_service_client_connection_destroyed(master_service);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic void client_destroy_timeout(struct client *client)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid client_disconnect(struct client *client, const char *reason)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik i_info("Disconnected: %s %s", reason, client_stats(client));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client->to_idle = timeout_add(0, client_destroy_timeout, client);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid client_disconnect_with_error(struct client *client, const char *msg)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client_send_line(client, t_strconcat("* BYE ", msg, NULL));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid client_send_line(struct client *client, const char *data)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikint client_send_line_next(struct client *client, const char *data)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (o_stream_sendv(client->output, iov, 2) < 0)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (o_stream_get_buffer_used_size(client->output) >=
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* buffer full, try flushing */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikclient_cmd_append_timing_stats(struct client_command_context *cmd,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik ioloop_wait_usecs = io_loop_get_wait_usecs(current_ioloop);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik msecs_in_cmd = (cmd->running_usecs + 999) / 1000;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_printfa(str, " (%d.%03d + %d.%03d secs).",
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik msecs_in_ioloop / 1000, msecs_in_ioloop % 1000);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid client_send_tagline(struct client_command_context *cmd, const char *data)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik o_stream_nsend(client->output, str_data(str), str_len(str));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid client_send_command_error(struct client_command_context *cmd,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik msg = imap_parser_get_error(cmd->parser, &fatal);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik error = t_strconcat("BAD Error in IMAP tag: ", msg, NULL);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik error = t_strconcat("BAD Error in IMAP command: ", msg, NULL);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik error = t_strconcat("BAD Error in IMAP command ",
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik "Too many invalid IMAP commands.");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* client_read_args() failures rely on this being set, so that the
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik command processing is stopped even while command function returns
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid client_send_internal_error(struct client_command_context *cmd)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik t_strflocaltime("NO "MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikbool client_read_args(struct client_command_context *cmd, unsigned int count,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik unsigned int flags, const struct imap_arg **args_r)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik ret = imap_parser_read_args(cmd->parser, count, flags, args_r);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* all parameters read successfully */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik cmd->args = p_strdup(cmd->pool, str_c(str));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* need more data */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* disconnected */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* error, or missing arguments */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client_send_command_error(cmd, ret < 0 ? NULL :
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik "Missing arguments");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikbool client_read_string_args(struct client_command_context *cmd,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik unsigned int count, ...)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik unsigned int i;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (!client_read_args(cmd, count, 0, &imap_args))
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik for (i = 0; i < count; i++) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik const char **ret = va_arg(va, const char **);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client_send_command_error(cmd, "Missing arguments.");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (!imap_arg_get_astring(&imap_args[i], &str)) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik client_send_command_error(cmd, "Invalid arguments.");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikclient_command_find_with_flags(struct client_command_context *new_cmd,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik cmd != new_cmd && (cmd->cmd_flags & flags) != 0)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic bool client_command_is_ambiguous(struct client_command_context *cmd)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if ((cmd->cmd_flags & COMMAND_FLAG_REQUIRES_SYNC) != 0 &&
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* if there are pending commands that update the search
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik save result, wait */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik struct client_command_context *old_cmd = cmd->next;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik for (; old_cmd != NULL; old_cmd = old_cmd->next) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if ((cmd->cmd_flags & COMMAND_FLAG_BREAKS_MAILBOX) ==
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* there must be no other command running that uses the
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik selected mailbox */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik } else if ((cmd->cmd_flags & COMMAND_FLAG_USES_SEQS) != 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* no existing command must be breaking sequences */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik } else if ((cmd->cmd_flags & COMMAND_FLAG_BREAKS_SEQS) != 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* if existing command uses sequences, we'll have to block */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (client_command_find_with_flags(cmd, flags, max_state) == NULL) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* don't do anything until syncing is finished */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (cmd->client->mailbox_change_lock != NULL &&
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* don't do anything until mailbox is fully
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik "Command pipelining results in ambiguity.");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstruct client_command_context *client_command_alloc(struct client *client)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik cmd = p_new(client->command_pool, struct client_command_context, 1);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik p_array_init(&cmd->module_contexts, cmd->pool, 5);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik DLLIST_PREPEND(&client->command_queue, cmd);
1ba26271952de1beeb9e041bedf87d720d3f5680Lukas Slebodnik imap_parser_create(client->input, client->output,
1ba26271952de1beeb9e041bedf87d720d3f5680Lukas Slebodnikvoid client_add_missing_io(struct client *client)
1ba26271952de1beeb9e041bedf87d720d3f5680Lukas Slebodnik if (client->io == NULL && !client->disconnected)
1ba26271952de1beeb9e041bedf87d720d3f5680Lukas Slebodnik client->io = io_add_istream(client->input, client_input, client);
1ba26271952de1beeb9e041bedf87d720d3f5680Lukas Slebodnikvoid client_command_free(struct client_command_context **_cmd)
1ba26271952de1beeb9e041bedf87d720d3f5680Lukas Slebodnik enum client_command_state state = cmd->state;
1ba26271952de1beeb9e041bedf87d720d3f5680Lukas Slebodnik /* reset input idle time because command output might have taken a
1ba26271952de1beeb9e041bedf87d720d3f5680Lukas Slebodnik long time and we don't want to disconnect client immediately then */
e59b73366d3067c576e39a214a34ace2f9a84878Lukas Slebodnik client_send_tagline(cmd, "NO Command cancelled.");
const unsigned char *data;
for (i = 0; i < data_size; i++) {
return FALSE;
return TRUE;
return TRUE;
return TRUE;
return FALSE;
return TRUE;
return FALSE;
return FALSE;
return FALSE;
return FALSE;
T_BEGIN {
} T_END;
if (ret)
if (remove_io)
if (!handled_commands)
return FALSE;
return TRUE;
bool finished;
if (!finished)
int ret;
return ret;
return FALSE;
return TRUE;
int ret;
if (ret == 0) {
if (ret < 0) {
return ret;
struct imap_search_update *
unsigned int *idx_r)
unsigned int i, count;
return NULL;
for (i = 0; i < count; i++) {
*idx_r = i;
return &updates[i];
return NULL;