int cmd_mail(struct client *client, const char *args) { const char *addr, *const *argv; if (client->state.mail_from != NULL) { client_send_line(client, "503 5.5.1 MAIL already given"); return 0; } if (strncasecmp(args, "FROM:", 5) != 0 || parse_address(args + 5, &addr, &args) < 0) { client_send_line(client, "501 5.5.4 Invalid parameters"); return 0; } argv = t_strsplit(args, " "); for (; *argv != NULL; argv++) { if (strcasecmp(*argv, "BODY=7BIT") == 0) client->state.mail_body_7bit = TRUE; else if (strcasecmp(*argv, "BODY=8BITMIME") == 0) client->state.mail_body_8bitmime = TRUE; else { client_send_line(client, "501 5.5.4 Unsupported options"); return 0; } } client->state.mail_from = p_strdup(client->state_pool, addr); p_array_init(&client->state.rcpt_to, client->state_pool, 64); client_send_line(client, "250 2.1.0 OK"); client_state_set(client, "MAIL FROM"); return 0; }
void client_cmd_starttls(struct client *client) { if (client->tls) { client_send_line(client, CLIENT_CMD_REPLY_BAD, "TLS is already active."); return; } if (!ssl_initialized) { client_send_line(client, CLIENT_CMD_REPLY_BAD, "TLS support isn't enabled."); return; } /* remove input handler, SSL proxy gives us a new fd. we also have to remove it in case we have to wait for buffer to be flushed */ if (client->io != NULL) io_remove(&client->io); client_send_line(client, CLIENT_CMD_REPLY_OK, "Begin TLS negotiation now."); /* uncork the old fd */ o_stream_uncork(client->output); if (o_stream_flush(client->output) <= 0) { /* the buffer has to be flushed */ o_stream_set_flush_pending(client->output, TRUE); o_stream_set_flush_callback(client->output, client_output_starttls, client); } else { client_start_tls(client); } }
static const char *get_size(struct client *client, const char *args, uoff_t *size) { uoff_t num, last_num; num = 0; while (*args != '\0' && *args != ' ') { if (*args < '0' || *args > '9') { client_send_line(client, "-ERR Invalid size: %s", args); return NULL; } last_num = num; num = num*10 + (*args - '0'); if (num < last_num) { client_send_line(client, "-ERR Size too large: %s", args); return NULL; } args++; } while (*args == ' ') args++; *size = num; return args; }
static void client_start_tls(struct client *client) { int fd_ssl; client_ref(client); if (!client_unref(&client) || client->destroyed) return; fd_ssl = ssl_proxy_alloc(client->fd, &client->ip, client->set, &client->ssl_proxy); if (fd_ssl == -1) { client_send_line(client, CLIENT_CMD_REPLY_BYE, "TLS initialization failed."); client_destroy(client, "Disconnected: TLS initialization failed."); return; } ssl_proxy_set_client(client->ssl_proxy, client); ssl_proxy_start(client->ssl_proxy); client->starttls = TRUE; client->tls = TRUE; client->secured = TRUE; login_refresh_proctitle(); client->fd = fd_ssl; client->io = io_add(client->fd, IO_READ, client_input, client); i_stream_unref(&client->input); o_stream_unref(&client->output); client_open_streams(client); client->v.starttls(client); }
static bool cmd_getquotaroot(struct client_command_context *cmd) { struct client *client = cmd->client; struct quota_user *quser = QUOTA_USER_CONTEXT(client->user); struct mail_namespace *ns; struct mailbox *box; struct quota_root_iter *iter; struct quota_root *root; const char *mailbox, *storage_name, *name; string_t *quotaroot_reply, *quota_reply; /* <mailbox> */ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); if (ns == NULL) return TRUE; if (quser == NULL) { client_send_tagline(cmd, "OK No quota."); return TRUE; } if (ns->owner != NULL && ns->owner != client->user && !client->user->admin) { client_send_tagline(cmd, "NO Not showing other users' quota."); return TRUE; } box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT); /* build QUOTAROOT reply and QUOTA reply for all quota roots */ quotaroot_reply = t_str_new(128); quota_reply = t_str_new(256); str_append(quotaroot_reply, "* QUOTAROOT "); imap_quote_append_string(quotaroot_reply, mailbox, FALSE); iter = quota_root_iter_init(box); while ((root = quota_root_iter_next(iter)) != NULL) { str_append_c(quotaroot_reply, ' '); name = imap_quota_root_get_name(client->user, ns->owner, root); imap_quote_append_string(quotaroot_reply, name, FALSE); quota_reply_write(quota_reply, client->user, ns->owner, root); } quota_root_iter_deinit(&iter); mailbox_free(&box); /* send replies */ if (str_len(quota_reply) == 0) client_send_tagline(cmd, "OK No quota."); else { client_send_line(client, str_c(quotaroot_reply)); o_stream_send(client->output, str_data(quota_reply), str_len(quota_reply)); client_send_tagline(cmd, "OK Getquotaroot completed."); } return TRUE; }
static int lmtp_rcpt_to_is_over_quota(struct client *client, const struct mail_recipient *rcpt) { struct mail_user *user; struct mail_namespace *ns; struct mailbox *box; struct mailbox_status status; const char *errstr; enum mail_error error; int ret; if (!client->lmtp_set->lmtp_rcpt_check_quota) return 0; ret = mail_storage_service_next(storage_service, rcpt->service_user, &user); if (ret < 0) return -1; ns = mail_namespace_find_inbox(user->namespaces); box = mailbox_alloc(ns->list, "INBOX", 0); ret = mailbox_get_status(box, STATUS_CHECK_OVER_QUOTA, &status); if (ret < 0) { errstr = mailbox_get_last_error(box, &error); if (error == MAIL_ERROR_NOSPACE) { client_send_line(client, "552 5.2.2 <%s> %s", rcpt->address, errstr); ret = 1; } } mailbox_free(&box); mail_user_unref(&user); return ret; }
bool cmd_idle(struct client_command_context *cmd) { struct client *client = cmd->client; struct cmd_idle_context *ctx; ctx = p_new(cmd->pool, struct cmd_idle_context, 1); ctx->cmd = cmd; ctx->client = client; idle_add_keepalive_timeout(ctx); idle_add_hibernate_timeout(ctx); if (client->mailbox != NULL) mailbox_notify_changes(client->mailbox, idle_callback, ctx); if (!client->state_import_idle_continue) client_send_line(client, "+ idling"); else { /* continuing an IDLE after hibernation */ client->state_import_idle_continue = FALSE; } io_remove(&client->io); client->io = io_add_istream(client->input, idle_client_input, ctx); cmd->func = cmd_idle_continue; cmd->context = ctx; /* check immediately if there are changes. if they came before we added mailbox-notifier, we wouldn't see them otherwise. */ if (client->mailbox != NULL) idle_sync_now(client->mailbox, ctx); return idle_client_handle_input(ctx, FALSE); }
bool cmd_idle(struct client_command_context *cmd) { struct client *client = cmd->client; struct cmd_idle_context *ctx; ctx = p_new(cmd->pool, struct cmd_idle_context, 1); ctx->cmd = cmd; ctx->client = client; idle_add_keepalive_timeout(ctx); if (client->mailbox != NULL) mailbox_notify_changes(client->mailbox, idle_callback, ctx); client_send_line(client, "+ idling"); io_remove(&client->io); client->io = io_add(i_stream_get_fd(client->input), IO_READ, idle_client_input, ctx); cmd->func = cmd_idle_continue; cmd->context = ctx; /* check immediately if there are changes. if they came before we added mailbox-notifier, we wouldn't see them otherwise. */ if (client->mailbox != NULL) idle_sync_now(client->mailbox, ctx); return idle_client_handle_input(ctx, FALSE); }
bool cmd_x_state(struct client_command_context *cmd) { /* FIXME: state importing can cause unnecessarily large memory usage by specifying an old modseq, because the EXPUNGE/FETCH replies aren't currently sent asynchronously. so this command is disabled for now. */ #if 0 const struct imap_arg *args; const char *str, *error; buffer_t *state, *state_encoded; int ret; if (!client_read_args(cmd, 0, 0, &args)) return FALSE; state = buffer_create_dynamic(cmd->pool, 256); if (imap_arg_get_astring(&args[0], &str)) { if (cmd->client->mailbox != NULL) { client_send_tagline(cmd, "BAD Can't be used in SELECTED state"); return TRUE; } if (base64_decode(str, strlen(str), NULL, state) < 0) ret = 0; else { ret = imap_state_import_external(cmd->client, state->data, state->used, &error); } if (ret < 0) { client_send_tagline(cmd, t_strdup_printf( "NO Failed to restore state: %s", error)); } else if (ret == 0) { client_send_tagline(cmd, t_strdup_printf( "BAD Broken state: %s", error)); } else { client_send_tagline(cmd, "OK State imported."); } return TRUE; } else if (args[0].type == IMAP_ARG_EOL) { if (!imap_state_export_external(cmd->client, state, &error)) { client_send_tagline(cmd, t_strdup_printf( "NO Can't save state: %s", error)); return TRUE; } state_encoded = buffer_create_dynamic(cmd->pool, MAX_BASE64_ENCODED_SIZE(state->used)+10); str_append(state_encoded, "* STATE "); base64_encode(state->data, state->used, state_encoded); client_send_line(cmd->client, str_c(state_encoded)); client_send_tagline(cmd, "OK State exported."); return TRUE; } else { client_send_command_error(cmd, "Invalid arguments."); return TRUE; } #else client_send_command_error(cmd, "Command is disabled for now."); return TRUE; #endif }
bool cmd_enable(struct client_command_context *cmd) { const struct imap_arg *args; const char *str; string_t *reply; if (!client_read_args(cmd, 0, 0, &args)) return FALSE; reply = t_str_new(64); str_append(reply, "* ENABLED"); for (; !IMAP_ARG_IS_EOL(args); args++) { if (!imap_arg_get_atom(args, &str)) { client_send_command_error(cmd, "Invalid arguments."); return TRUE; } str = t_str_ucase(str); if (strcmp(str, "CONDSTORE") == 0) { client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE); str_append(reply, " CONDSTORE"); } else if (strcmp(str, "QRESYNC") == 0) { client_enable(cmd->client, MAILBOX_FEATURE_QRESYNC | MAILBOX_FEATURE_CONDSTORE); str_append(reply, " QRESYNC"); } } if (str_len(reply) > 9) client_send_line(cmd->client, str_c(reply)); client_send_tagline(cmd, "OK Enabled."); return TRUE; }
int client_enable(struct client *client, enum mailbox_feature features) { struct mailbox_status status; int ret; if ((client->enabled_features & features) == features) return 0; client->enabled_features |= features; if (client->mailbox == NULL) return 0; ret = mailbox_enable(client->mailbox, features); if ((features & MAILBOX_FEATURE_CONDSTORE) != 0 && ret == 0) { /* CONDSTORE being enabled while mailbox is selected. Notify client of the latest HIGHESTMODSEQ. */ ret = mailbox_get_status(client->mailbox, STATUS_HIGHESTMODSEQ, &status); if (ret == 0) { client_send_line(client, t_strdup_printf( "* OK [HIGHESTMODSEQ %llu] Highest", (unsigned long long)status.highest_modseq)); } } if (ret < 0) { client_send_untagged_storage_error(client, mailbox_get_storage(client->mailbox)); } return ret; }
bool cmd_capability(struct client_command_context *cmd) { client_send_line(cmd->client, t_strconcat( "* CAPABILITY ", str_c(cmd->client->capability_string), NULL)); client_send_tagline(cmd, "OK Capability completed."); return TRUE; }
static void client_kill_idle(struct client *client) { if (client->output_cmd_lock != NULL) return; client_send_line(client, "* BYE Server shutting down."); client_destroy(client, "Server shutting down."); }
void clients_destroy_all(struct mail_storage_service_ctx *storage_service) { while (imap_clients != NULL) { client_send_line(imap_clients, "* BYE Server shutting down."); mail_storage_service_io_activate_user(imap_clients->service_user); client_destroy(imap_clients, "Server shutting down."); } mail_storage_service_io_deactivate(storage_service); }
void client_destroy_internal_failure(struct client *client) { client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP, "Internal login failure. " "Refer to server log for more information."); client_destroy(client, t_strdup_printf( "Internal login failure (pid=%s id=%u)", my_pid, client->master_auth_id)); }
static void client_idle_timeout(struct client *client) { if (client->cmd != NULL) { client_destroy(client, "Disconnected for inactivity in reading our output"); } else { client_send_line(client, "-ERR Disconnected for inactivity."); client_destroy(client, "Disconnected for inactivity"); } }
void client_send_mailbox_flags(struct client *client, bool selecting) { struct mailbox_status status; unsigned int count = array_count(client->keywords.names); const char *const *keywords; string_t *str; if (!selecting && count == client->keywords.announce_count) { /* no changes to keywords and we're not selecting a mailbox */ return; } client->keywords.announce_count = count; mailbox_get_open_status(client->mailbox, STATUS_PERMANENT_FLAGS, &status); keywords = count == 0 ? NULL : array_idx(client->keywords.names, 0); str = t_str_new(128); str_append(str, "* FLAGS ("); imap_write_flags(str, MAIL_FLAGS_NONRECENT, keywords); str_append_c(str, ')'); client_send_line(client, str_c(str)); if (!status.permanent_keywords) keywords = NULL; str_truncate(str, 0); str_append(str, "* OK [PERMANENTFLAGS ("); imap_write_flags(str, status.permanent_flags, keywords); if (status.allow_new_keywords) { if (status.permanent_flags != 0 || keywords != NULL) str_append_c(str, ' '); str_append(str, "\\*"); } str_append(str, ")] "); if (mailbox_is_readonly(client->mailbox)) str_append(str, "Read-only mailbox."); else str_append(str, "Flags permitted."); client_send_line(client, str_c(str)); }
static void client_send_line_overquota(struct client *client, const struct mail_recipient *rcpt, const char *error) { struct lda_settings *lda_set = mail_storage_service_user_get_set(rcpt->service_user)[1]; client_send_line(client, "%s <%s> %s", lda_set->quota_full_tempfail ? "452 4.2.2" : "552 5.2.2", rcpt->address, error); }
static const char *get_msgnum(struct client *client, const char *args, unsigned int *msgnum) { unsigned int num, last_num; num = 0; while (*args != '\0' && *args != ' ') { if (*args < '0' || *args > '9') { client_send_line(client, "-ERR Invalid message number: %s", args); return NULL; } last_num = num; num = num*10 + (*args - '0'); if (num < last_num) { client_send_line(client, "-ERR Message number too large: %s", args); return NULL; } args++; } if (num == 0 || num > client->messages_count) { client_send_line(client, "-ERR There's no message %u.", num); return NULL; } num--; if (client->deleted) { if (client->deleted_bitmask[num / CHAR_BIT] & (1 << (num % CHAR_BIT))) { client_send_line(client, "-ERR Message is deleted."); return NULL; } } while (*args == ' ') args++; *msgnum = num; return args; }
static void client_add_input(struct client *client, const buffer_t *buf) { struct ostream *output; struct client_input input; if (buf != NULL && buf->used > 0) { client_parse_input(buf->data, buf->used, &input); if (input.input_size > 0 && !i_stream_add_data(client->input, input.input, input.input_size)) i_panic("Couldn't add client input to stream"); } else { /* IMAPLOGINTAG environment is compatible with mailfront */ memset(&input, 0, sizeof(input)); input.tag = getenv("IMAPLOGINTAG"); } output = client->output; o_stream_ref(output); o_stream_cork(output); if (input.tag == NULL) { client_send_line(client, t_strconcat( "* PREAUTH [CAPABILITY ", str_c(client->capability_string), "] " "Logged in as ", client->user->username, NULL)); } else if (input.send_untagged_capability) { /* client doesn't seem to understand tagged capabilities. send untagged instead and hope that it works. */ client_send_line(client, t_strconcat("* CAPABILITY ", str_c(client->capability_string), NULL)); client_send_line(client, t_strconcat(input.tag, " OK Logged in", NULL)); } else { client_send_line(client, t_strconcat( input.tag, " OK [CAPABILITY ", str_c(client->capability_string), "] Logged in", NULL)); } (void)client_handle_input(client); o_stream_uncork(output); o_stream_unref(&output); }
bool cmd_getscript(struct client_command_context *cmd) { struct client *client = cmd->client; struct cmd_getscript_context *ctx; const char *scriptname; enum sieve_error error; /* <scriptname> */ if ( !client_read_string_args(cmd, TRUE, 1, &scriptname) ) return FALSE; ctx = p_new(cmd->pool, struct cmd_getscript_context, 1); ctx->cmd = cmd; ctx->client = client; ctx->storage = client->storage; ctx->failed = FALSE; ctx->script = sieve_storage_open_script (client->storage, scriptname, NULL); if (ctx->script == NULL) { ctx->failed = TRUE; return cmd_getscript_finish(ctx); } if ( sieve_script_get_stream (ctx->script, &ctx->script_stream, &error) < 0 ) { if ( error == SIEVE_ERROR_NOT_FOUND ) sieve_storage_set_error(client->storage, error, "Script does not exist."); ctx->failed = TRUE; return cmd_getscript_finish(ctx); } if ( sieve_script_get_size(ctx->script, &ctx->script_size) <= 0 ) { sieve_storage_set_critical(ctx->storage, "failed to obtain script size for script `%s' from %s", sieve_script_name(ctx->script), sieve_script_location(ctx->script)); ctx->failed = TRUE; return cmd_getscript_finish(ctx); } i_assert(ctx->script_stream->v_offset == 0); client_send_line (client, t_strdup_printf("{%"PRIuUOFF_T"}", ctx->script_size)); client->command_pending = TRUE; cmd->func = cmd_getscript_continue; cmd->context = ctx; return cmd_getscript_continue(cmd); }
void client_send_untagged_storage_error(struct client *client, struct mail_storage *storage) { const char *error_string; enum mail_error error; error_string = mail_storage_get_last_error(storage, &error); client_send_line(client, t_strconcat("* NO ", error_string, NULL)); if (client->mailbox != NULL && mailbox_is_inconsistent(client->mailbox)) { /* we can't do forced CLOSE, so have to disconnect */ client_disconnect_with_error(client, "IMAP session state is inconsistent, please relogin."); } }
bool cmd_genurlauth(struct client_command_context *cmd) { const struct imap_arg *args; string_t *response; int ret; if (cmd->client->urlauth_ctx == NULL) { client_send_command_error(cmd, "URLAUTH disabled."); return TRUE; } if (!client_read_args(cmd, 0, 0, &args)) return FALSE; response = t_str_new(1024); str_append(response, "* GENURLAUTH"); for (;;) { const char *url_rump, *mechanism, *url, *error; if (IMAP_ARG_IS_EOL(args)) break; if (!imap_arg_get_astring(args++, &url_rump) || !imap_arg_get_atom(args++, &mechanism)) { client_send_command_error(cmd, "Invalid arguments."); return FALSE; } ret = imap_urlauth_generate(cmd->client->urlauth_ctx, mechanism, url_rump, &url, &error); if (ret <= 0) { if (ret < 0) client_send_internal_error(cmd); else client_send_command_error(cmd, error); return TRUE; } str_append_c(response, ' '); imap_append_astring(response, url); } client_send_line(cmd->client, str_c(response)); client_send_tagline(cmd, "OK GENURLAUTH completed."); return TRUE; }
static void client_add_input(struct client *client, const buffer_t *buf) { struct ostream *output; if (buf != NULL && buf->used > 0) { if (!i_stream_add_data(client->input, buf->data, buf->used)) i_panic("Couldn't add client input to stream"); } output = client->output; o_stream_ref(output); o_stream_cork(output); if (!IS_STANDALONE()) client_send_line(client, "+OK Logged in."); (void)client_handle_input(client); o_stream_uncork(output); o_stream_unref(&output); }
bool cmd_getscript(struct client_command_context *cmd) { struct client *client = cmd->client; struct cmd_getscript_context *ctx; const char *scriptname; enum sieve_error error; /* <scriptname> */ if ( !client_read_string_args(cmd, 1, TRUE, &scriptname) ) return FALSE; ctx = p_new(cmd->pool, struct cmd_getscript_context, 1); ctx->cmd = cmd; ctx->client = client; ctx->storage = client->storage; ctx->failed = FALSE; ctx->script = sieve_storage_script_init(client->storage, scriptname); if (ctx->script == NULL) { ctx->failed = TRUE; return cmd_getscript_finish(ctx); } ctx->script_stream = sieve_script_open(ctx->script, &error); if ( ctx->script_stream == NULL ) { ctx->failed = TRUE; if ( error == SIEVE_ERROR_NOT_FOUND ) sieve_storage_set_error(client->storage, error, "Script does not exist."); return cmd_getscript_finish(ctx); } ctx->script_size = sieve_script_get_size(ctx->script); ctx->script_offset = 0; client_send_line (client, t_strdup_printf("{%"PRIuUOFF_T"}", ctx->script_size)); client->command_pending = TRUE; cmd->func = cmd_getscript_continue; cmd->context = ctx; return cmd_getscript_continue(cmd); }
int cmd_lhlo(struct client *client, const char *args) { struct rfc822_parser_context parser; string_t *domain = t_str_new(128); const char *p; int ret = 0; if (*args == '\0') { client_send_line(client, "501 Missing hostname"); return 0; } /* domain / address-literal */ rfc822_parser_init(&parser, (const unsigned char *)args, strlen(args), NULL); if (*args != '[') ret = rfc822_parse_dot_atom(&parser, domain); else { for (p = args+1; *p != ']'; p++) { if (*p == '\\' || *p == '[') break; } if (strcmp(p, "]") != 0) ret = -1; } if (ret < 0) { str_truncate(domain, 0); str_append(domain, "invalid"); } client_state_reset(client, "LHLO"); client_send_line(client, "250-%s", client->my_domain); if (master_service_ssl_is_enabled(master_service) && client->ssl_iostream == NULL) client_send_line(client, "250-STARTTLS"); if (client_is_trusted(client)) client_send_line(client, "250-XCLIENT ADDR PORT TTL TIMEOUT"); client_send_line(client, "250-8BITMIME"); client_send_line(client, "250-ENHANCEDSTATUSCODES"); client_send_line(client, "250 PIPELINING"); i_free(client->lhlo); client->lhlo = i_strdup(str_c(domain)); client_state_set(client, "LHLO", ""); return 0; }
bool cmd_listscripts(struct client_command_context *cmd) { struct client *client = cmd->client; struct sieve_storage_list_context *ctx; const char *scriptname; bool active; string_t *str; /* no arguments */ if ( !client_read_no_args(cmd) ) return FALSE; if ( (ctx = sieve_storage_list_init(client->storage)) == NULL ) { client_send_storage_error(client, client->storage); return TRUE; } /* FIXME: This will be quite slow for large script lists. Implement * some buffering to fix this. Wont truely be an issue with managesieve * though. */ while ((scriptname = sieve_storage_list_next(ctx, &active)) != NULL) { T_BEGIN { str = t_str_new(128); managesieve_quote_append_string(str, scriptname, FALSE); if ( active ) str_append(str, " ACTIVE"); client_send_line(client, str_c(str)); } T_END; } if ( sieve_storage_list_deinit(&ctx) < 0 ) { client_send_storage_error(client, client->storage); return TRUE; } client_send_ok(client, "Listscripts completed."); return TRUE; }
bool cmd_namespace(struct client_command_context *cmd) { struct client *client = cmd->client; string_t *str; str = t_str_new(256); str_append(str, "* NAMESPACE "); list_namespaces(client->user->namespaces, MAIL_NAMESPACE_TYPE_PRIVATE, str); str_append_c(str, ' '); list_namespaces(client->user->namespaces, MAIL_NAMESPACE_TYPE_SHARED, str); str_append_c(str, ' '); list_namespaces(client->user->namespaces, MAIL_NAMESPACE_TYPE_PUBLIC, str); client_send_line(client, str_c(str)); client_send_tagline(cmd, "OK Namespace completed."); return TRUE; }
static bool cmd_getscript_finish(struct cmd_getscript_context *ctx) { struct client *client = ctx->client; if ( ctx->script != NULL ) sieve_script_unref(&ctx->script); if ( ctx->failed ) { if ( client->output->closed ) { client_disconnect(client, "Disconnected"); return TRUE; } client_send_storage_error(client, client->storage); return TRUE; } client_send_line(client, ""); client_send_ok(client, "Getscript completed."); return TRUE; }
static int client_create_from_input(const struct mail_storage_service_input *input, int fd_in, int fd_out, const buffer_t *input_buf, const char **error_r) { const char *lookup_error_str = "-ERR [SYS/TEMP] "MAIL_ERRSTR_CRITICAL_MSG"\r\n"; struct mail_storage_service_user *user; struct mail_user *mail_user; struct client *client; const struct pop3_settings *set; const char *error; if (mail_storage_service_lookup_next(storage_service, input, &user, &mail_user, error_r) <= 0) { if (write(fd_out, lookup_error_str, strlen(lookup_error_str)) < 0) { /* ignored */ } return -1; } restrict_access_allow_coredumps(TRUE); set = mail_storage_service_user_get_set(user)[1]; if (set->verbose_proctitle) verbose_proctitle = TRUE; if (client_create(fd_in, fd_out, input->session_id, mail_user, user, set, &client) < 0) return 0; if (!IS_STANDALONE()) client_send_line(client, "+OK Logged in."); if (client_init_mailbox(client, &error) == 0) client_add_input(client, input_buf); else { i_error("%s", error); client_destroy(client, error); } return 0; }