static int cmd_append_catenate_mpurl(struct client_command_context *cmd, const char *caturl, struct imap_msgpart_url *mpurl) { struct cmd_append_context *ctx = cmd->context; struct imap_msgpart_open_result mpresult; uoff_t newsize; const char *error; int ret; /* catenate URL */ ret = imap_msgpart_url_read_part(mpurl, &mpresult, &error); if (ret < 0) { client_send_box_error(cmd, ctx->box); return -1; } if (ret == 0) { /* invalid url, abort */ client_send_tagline(cmd, t_strdup_printf("NO [BADURL %s] %s.", caturl, error)); return -1; } if (mpresult.size == 0) { /* empty input */ return 0; } newsize = ctx->cat_msg_size + mpresult.size; if (newsize < ctx->cat_msg_size) { client_send_tagline(cmd, "NO [TOOBIG] Composed message grows too big."); return -1; } ctx->cat_msg_size = newsize; /* add this input stream to chain */ i_stream_chain_append(ctx->catchain, mpresult.input); /* save by reading the chain stream */ while (!i_stream_is_eof(mpresult.input)) { ret = i_stream_read(mpresult.input); i_assert(ret != 0); /* we can handle only blocking input here */ if (mailbox_save_continue(ctx->save_ctx) < 0 || ret == -1) break; } if (mpresult.input->stream_errno != 0) { errno = mpresult.input->stream_errno; mail_storage_set_critical(ctx->box->storage, "read(%s) failed: %s (for CATENATE URL %s)", i_stream_get_name(mpresult.input), i_stream_get_error(mpresult.input), caturl); client_send_box_error(cmd, ctx->box); ret = -1; } else if (!mpresult.input->eof) { /* save failed */ client_send_box_error(cmd, ctx->box); ret = -1; } else { /* all the input must be consumed, so istream-chain's read() unreferences the stream and we can free its parent mail */ i_assert(!i_stream_have_bytes_left(mpresult.input)); ret = 0; } return ret; }
void client_send_internal_error(struct client_command_context *cmd) { client_send_tagline(cmd, t_strflocaltime("NO "MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time)); }
static bool cmd_xapplepushservice(struct client_command_context *cmd) { /* * Parse arguments. We expect four key value pairs. We only take * those that we understand for version 2 of this extension. * * TODO: We are ignoring the mailboxes parameter for now and just * default to INBOX always. */ const struct imap_arg *args; const char *arg_key, *arg_val; const char *aps_version = NULL, *aps_account_id = NULL, *aps_device_token = NULL, *aps_subtopic = NULL; if (!client_read_args(cmd, 0, 0, &args)) { client_send_command_error(cmd, "Invalid arguments."); return FALSE; } for (int i = 0; i < 4; i++) { if (!imap_arg_get_astring(&args[i*2+0], &arg_key)) { client_send_command_error(cmd, "Invalid arguments."); return FALSE; } if (!imap_arg_get_astring(&args[i*2+1], &arg_val)) { client_send_command_error(cmd, "Invalid arguments."); return FALSE; } if (strcasecmp(arg_key, "aps-version") == 0) { aps_version = arg_val; } else if (strcasecmp(arg_key, "aps-account-id") == 0) { aps_account_id = arg_val; } else if (strcasecmp(arg_key, "aps-device-token") == 0) { aps_device_token = arg_val; } else if (strcasecmp(arg_key, "aps-subtopic") == 0) { aps_subtopic = arg_val; } } /* * Check if this is a version we expect */ if (!aps_version || (strcmp(aps_version, "1") != 0 && strcmp(aps_version, "2") != 0)) { client_send_command_error(cmd, "Unknown aps-version."); return FALSE; } /* * If this is version 2 then also need to grab the mailboxes, which * is a list of mailbox names. */ const struct imap_arg *mailboxes = NULL; if (strcmp(aps_version, "2") == 0) { if (!imap_arg_get_astring(&args[8], &arg_key)) { client_send_command_error(cmd, "Invalid arguments."); return FALSE; } if (strcmp(arg_key, "mailboxes") != 0) { client_send_command_error(cmd, "Invalid arguments. (Expected mailboxes)"); return FALSE; } if (!imap_arg_get_list(&args[9], &mailboxes)) { client_send_command_error(cmd, "Invalid arguments."); return FALSE; } } /* * Check if all of the parameters are there. */ if (!aps_account_id || strlen(aps_account_id) == 0) { client_send_command_error(cmd, "Incomplete or empty aps-account-id parameter."); return FALSE; } if (!aps_device_token || strlen(aps_device_token) == 0) { client_send_command_error(cmd, "Incomplete or empty aps-device-token parameter."); return FALSE; } if (!aps_subtopic || strlen(aps_subtopic) == 0) { client_send_command_error(cmd, "Incomplete or empty aps-subtopic parameter."); return FALSE; } /* * Forward to the helper daemon. The helper will return the * aps-topic, which in reality is the subject of the certificate. I * think it is only used to make sure that the binding between the * client and the APS server and the IMAP server stays current. */ struct client *client = cmd->client; struct mail_user *user = client->user; const char *aps_topic = mail_user_plugin_getenv(user, "xaps_topic"); if (xaps_register(aps_account_id, aps_device_token, aps_subtopic, user->username, mailboxes) != 0) { client_send_command_error(cmd, "Registration failed."); i_info("Registration failed."); return FALSE; } /* * Return success. We assume that aps_version and aps_topic do not * contain anything that needs to be escaped. */ client_send_line(cmd->client, t_strdup_printf("* XAPPLEPUSHSERVICE aps-version \"%s\" aps-topic \"%s\"", aps_version, aps_topic)); client_send_tagline(cmd, "OK XAPPLEPUSHSERVICE Registration successful."); return TRUE; }
static bool cmd_x_apple_push_service(struct client_command_context *cmd) { const struct imap_arg *args; struct mail_user *user = cmd->client->user; const char *aps_topic = mail_user_plugin_getenv(user, "push_notify_aps_topic"); if (!client_read_args(cmd, 0, 0, &args)) return FALSE; const char *aps_ver=NULL; const char *aps_acct_id=NULL; const char *aps_dev_token=NULL; const char *aps_sub_topic=NULL; const struct imap_arg *mailbox_list=NULL; unsigned int mailbox_count=NULL; bool mailbox_subscriptions=FALSE; const char *key, *value; /* must have a topic */ if (aps_topic == NULL || *aps_topic == '\0') return FALSE; /* scarf off the aps keys/values */ while (imap_arg_get_astring(&args[0], &key)) { if (imap_arg_get_astring(&args[1], &value)) { if (strcasecmp(key, "aps-version") == 0) aps_ver = t_strdup(value); else if (strcasecmp(key, "aps-account-id") == 0) aps_acct_id = t_strdup(value); else if (strcasecmp(key, "aps-device-token") == 0) aps_dev_token = t_strdup(value); else if (strcasecmp(key, "aps-subtopic") == 0) aps_sub_topic = t_strdup(value); else return FALSE; } else if (strcasecmp(key, "mailboxes") == 0) { mailbox_subscriptions = imap_arg_get_list_full(&args[1], &mailbox_list, &mailbox_count); } args += 2; } /* save notification settings */ if ( aps_ver && aps_acct_id && aps_dev_token && aps_sub_topic ) { msg_data_t msg_data; /* subscribe to notification node */ memset(&msg_data, 0, sizeof(struct msg_data_s)); msg_data.msg = 2; i_strocpy(msg_data.d1, user->username, sizeof(msg_data.d1)); i_strocpy(msg_data.d2, aps_acct_id, sizeof(msg_data.d2)); i_strocpy(msg_data.d3, aps_dev_token, sizeof(msg_data.d3)); i_strocpy(msg_data.d4, aps_sub_topic, sizeof(msg_data.d4)); send_msg_data(&msg_data); if(mailbox_subscriptions) { const char *mailbox; while (imap_arg_get_astring(&mailbox_list[0], &mailbox)) { T_BEGIN; string_t *mailbox_str = t_str_new(256); imap_append_quoted( mailbox_str, "mailbox"); str_append_c( mailbox_str, ' '); imap_append_quoted( mailbox_str, mailbox); send_response(cmd->client, mailbox_str); msg_data.msg = 4; i_strocpy(msg_data.d4, mailbox, sizeof(msg_data.d4)); send_msg_data(&msg_data); T_END; mailbox_list += 1; } } /* generate aps response */ string_t *str = t_str_new(256); imap_append_quoted( str, "aps-version" ); str_append_c(str, ' '); imap_append_quoted( str, APS_VERSION ); str_append_c(str, ' '); imap_append_quoted( str, "aps-topic" ); str_append_c(str, ' '); imap_append_quoted( str, aps_topic ); send_response(cmd->client, str); } client_send_tagline(cmd, "OK Provisioned"); return TRUE; }
static int cmd_append_handle_args(struct client_command_context *cmd, const struct imap_arg *args, bool *nonsync_r) { struct client *client = cmd->client; struct cmd_append_context *ctx = cmd->context; const struct imap_arg *flags_list; const struct imap_arg *cat_list = NULL; enum mail_flags flags; const char *const *keywords_list; struct mail_keywords *keywords; struct istream *input; const char *internal_date_str; time_t internal_date; int ret, timezone_offset; bool valid; /* [<flags>] */ if (!imap_arg_get_list(args, &flags_list)) flags_list = NULL; else args++; /* [<internal date>] */ if (args->type != IMAP_ARG_STRING) internal_date_str = NULL; else { internal_date_str = imap_arg_as_astring(args); args++; } /* <message literal> | CATENATE (..) */ valid = FALSE; *nonsync_r = FALSE; ctx->catenate = FALSE; if (imap_arg_atom_equals(args, "CATENATE")) { args++; if (imap_arg_get_list(args, &cat_list)) { valid = TRUE; ctx->catenate = TRUE; } /* We'll do BINARY conversion only if the CATENATE's first part is a literal8. If it doesn't and a literal8 is seen later we'll abort the append with UNKNOWN-CTE. */ ctx->binary_input = imap_arg_atom_equals(&cat_list[0], "TEXT") && cat_list[1].literal8; } else if (imap_arg_get_literal_size(args, &ctx->literal_size)) { *nonsync_r = args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC; ctx->binary_input = args->literal8; valid = TRUE; } if (!IMAP_ARG_IS_EOL(&args[1])) valid = FALSE; if (!valid) { client->input_skip_line = TRUE; if (!ctx->failed) client_send_command_error(cmd, "Invalid arguments."); return -1; } if (flags_list == NULL || ctx->failed) { flags = 0; keywords = NULL; } else { if (!client_parse_mail_flags(cmd, flags_list, &flags, &keywords_list)) return -1; if (keywords_list == NULL) keywords = NULL; else if (mailbox_keywords_create(ctx->box, keywords_list, &keywords) < 0) { /* invalid keywords - delay failure */ client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } } if (internal_date_str == NULL || ctx->failed) { /* no time given, default to now. */ internal_date = (time_t)-1; timezone_offset = 0; } else if (!imap_parse_datetime(internal_date_str, &internal_date, &timezone_offset)) { client_send_command_error(cmd, "Invalid internal date."); if (keywords != NULL) mailbox_keywords_unref(&keywords); return -1; } if (internal_date != (time_t)-1 && internal_date > ioloop_time + INTERNALDATE_MAX_FUTURE_SECS) { /* the client specified a time in the future, set it to now. */ internal_date = (time_t)-1; timezone_offset = 0; } if (cat_list != NULL) { ctx->cat_msg_size = 0; ctx->input = i_stream_create_chain(&ctx->catchain); } else { if (ctx->literal_size == 0) { /* no message data, abort */ if (!ctx->failed) { client_send_tagline(cmd, "NO Can't save a zero byte message."); ctx->failed = TRUE; } if (!*nonsync_r) { if (keywords != NULL) mailbox_keywords_unref(&keywords); return -1; } /* {0+} used. although there isn't any point in using MULTIAPPEND here and adding more messages, it is technically valid so we'll continue parsing.. */ } ctx->litinput = i_stream_create_limit(client->input, ctx->literal_size); ctx->input = ctx->litinput; i_stream_ref(ctx->input); } if (ctx->binary_input) { input = i_stream_create_binary_converter(ctx->input); i_stream_unref(&ctx->input); ctx->input = input; } if (!ctx->failed) { /* save the mail */ ctx->save_ctx = mailbox_save_alloc(ctx->t); mailbox_save_set_flags(ctx->save_ctx, flags, keywords); mailbox_save_set_received_date(ctx->save_ctx, internal_date, timezone_offset); if (mailbox_save_begin(&ctx->save_ctx, ctx->input) < 0) { /* save initialization failed */ client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } } if (keywords != NULL) mailbox_keywords_unref(&keywords); ctx->count++; if (cat_list == NULL) { /* normal APPEND */ return 1; } else if (cat_list->type == IMAP_ARG_EOL) { /* zero parts */ if (!ctx->failed) client_send_command_error(cmd, "Empty CATENATE list."); client->input_skip_line = TRUE; return -1; } else if ((ret = cmd_append_catenate(cmd, cat_list, nonsync_r)) < 0) { /* invalid parameters, abort immediately */ return -1; } else if (ret == 0) { /* CATENATE consisted only of URLs */ return 0; } else { /* TEXT part found from CATENATE */ return 1; } }