Exemple #1
0
static struct mailbox_node *
imapc_list_update_tree(struct imapc_mailbox_list *list,
		       struct mailbox_tree_context *tree,
		       const struct imap_arg *args)
{
	struct mailbox_node *node;
	const struct imap_arg *flags;
	const char *name, *flag;
	enum mailbox_info_flags info_flag, info_flags = 0;
	bool created;

	if (!imap_arg_get_list(&args[0], &flags) ||
	    args[1].type == IMAP_ARG_EOL ||
	    !imap_arg_get_astring(&args[2], &name))
		return NULL;

	while (imap_arg_get_atom(flags, &flag)) {
		if (imap_list_flag_parse(flag, &info_flag))
			info_flags |= info_flag;
		flags++;
	}

	T_BEGIN {
		const char *vname = imapc_list_to_vname(list, name);

		if ((info_flags & MAILBOX_NONEXISTENT) != 0)
			node = mailbox_tree_lookup(tree, vname);
		else
			node = mailbox_tree_get(tree, vname, &created);
	} T_END;
	if (node != NULL)
		node->flags = info_flags;
	return node;
}
Exemple #2
0
static bool cmd_append_args_can_stop(struct cmd_append_context *ctx,
				     const struct imap_arg *args,
				     bool *last_literal_r)
{
	const struct imap_arg *cat_list;

	*last_literal_r = FALSE;
	if (args->type == IMAP_ARG_EOL)
		return TRUE;

	/* [(flags)] ["internal date"] <message literal> | CATENATE (..) */
	if (args->type == IMAP_ARG_LIST)
		args++;
	if (args->type == IMAP_ARG_STRING)
		args++;

	if (args->type == IMAP_ARG_LITERAL_SIZE ||
	    args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC)
		return TRUE;
	if (imap_arg_atom_equals(args, "CATENATE") &&
	    imap_arg_get_list(&args[1], &cat_list)) {
		if (catenate_args_can_stop(ctx, cat_list))
			return TRUE;
		*last_literal_r = TRUE;
	}
	return FALSE;
}
Exemple #3
0
const struct imap_arg *
imap_arg_as_list(const struct imap_arg *arg)
{
	const struct imap_arg *ret;

	if (!imap_arg_get_list(arg, &ret))
		i_unreached();
	return ret;
}
static bool
store_parse_args(struct imap_store_context *ctx, const struct imap_arg *args)
{
	struct client_command_context *cmd = ctx->cmd;
	const struct imap_arg *list_args;
	const char *type;
	const char *const *keywords_list = NULL;

	ctx->max_modseq = (uint64_t)-1;
	if (imap_arg_get_list(args, &list_args)) {
		if (!store_parse_modifiers(ctx, list_args))
			return FALSE;
		args++;
	}

	if (!imap_arg_get_astring(args, &type) ||
	    !get_modify_type(ctx, type)) {
		client_send_command_error(cmd, "Invalid arguments.");
		return FALSE;
	}
	args++;

	if (imap_arg_get_list(args, &list_args)) {
		if (!client_parse_mail_flags(cmd, list_args,
					     &ctx->flags, &keywords_list))
			return FALSE;
	} else {
		if (!client_parse_mail_flags(cmd, args,
					     &ctx->flags, &keywords_list))
			return FALSE;
	}

	if (keywords_list != NULL || ctx->modify_type == MODIFY_REPLACE) {
		if (mailbox_keywords_create(cmd->client->mailbox, keywords_list,
					    &ctx->keywords) < 0) {
			/* invalid keywords */
			client_send_box_error(cmd, cmd->client->mailbox);
			return FALSE;
		}
	}
	return TRUE;
}
Exemple #5
0
bool cmd_sort(struct client_command_context *cmd)
{
	struct imap_search_context *ctx;
	struct mail_search_args *sargs;
	enum mail_sort_type sort_program[MAX_SORT_PROGRAM_SIZE];
	const struct imap_arg *args, *list_args;
	const char *charset;
	int ret;

	if (!client_read_args(cmd, 0, 0, &args))
		return FALSE;

	if (!client_verify_open_mailbox(cmd))
		return TRUE;

	ctx = p_new(cmd->pool, struct imap_search_context, 1);
	ctx->cmd = cmd;

	if ((ret = cmd_search_parse_return_if_found(ctx, &args)) <= 0) {
		/* error / waiting for unambiguity */
		return ret < 0;
	}

	/* sort program */
	if (!imap_arg_get_list(args, &list_args)) {
		client_send_command_error(cmd, "Invalid sort argument.");
		return TRUE;
	}

	if (get_sort_program(cmd, list_args, sort_program) < 0)
		return TRUE;
	args++;

	/* charset */
	if (!imap_arg_get_astring(args, &charset)) {
		client_send_command_error(cmd, "Invalid charset argument.");
		return TRUE;
	}
	args++;

	ret = imap_search_args_build(cmd, args, charset, &sargs);
	if (ret <= 0)
		return ret < 0;

	return imap_search_start(ctx, sargs, sort_program);
}
Exemple #6
0
bool cmd_status(struct client_command_context *cmd)
{
	struct client *client = cmd->client;
	const struct imap_arg *args, *list_args;
	struct imap_status_items items;
	struct imap_status_result result;
	struct mail_namespace *ns;
	const char *mailbox, *orig_mailbox;
	bool selected_mailbox;

	/* <mailbox> <status items> */
	if (!client_read_args(cmd, 2, 0, &args))
		return FALSE;

	if (!imap_arg_get_astring(&args[0], &mailbox) ||
	    !imap_arg_get_list(&args[1], &list_args)) {
		client_send_command_error(cmd, "Invalid arguments.");
		return TRUE;
	}

	/* get the items client wants */
	if (imap_status_parse_items(cmd, list_args, &items) < 0)
		return TRUE;

	orig_mailbox = mailbox;
	ns = client_find_namespace(cmd, &mailbox);
	if (ns == NULL)
		return TRUE;

	selected_mailbox = client->mailbox != NULL &&
		mailbox_equals(client->mailbox, ns, mailbox);
	if (imap_status_get(cmd, ns, mailbox, &items, &result) < 0) {
		client_send_tagline(cmd, result.errstr);
		return TRUE;
	}

	imap_status_send(client, orig_mailbox, &items, &result);
	if (!selected_mailbox)
		client_send_tagline(cmd, "OK Status completed.");
	else {
		client_send_tagline(cmd, "OK ["IMAP_RESP_CODE_CLIENTBUG"] "
				    "Status on selected mailbox completed.");
	}
	return TRUE;
}
const char *imap_id_args_get_log_reply(const struct imap_arg *args,
				       const char *settings)
{
	const char *const *keys, *key, *value;
	string_t *reply;
	bool log_all;

	if (settings == NULL || *settings == '\0')
		return NULL;
	if (!imap_arg_get_list(args, &args))
		return NULL;

	log_all = strcmp(settings, "*") == 0;
	reply = t_str_new(256);
	keys = t_strsplit_spaces(settings, " ");
	while (!IMAP_ARG_IS_EOL(&args[0]) &&
	       !IMAP_ARG_IS_EOL(&args[1])) {
		if (!imap_arg_get_string(args, &key)) {
			/* broken input */
			args += 2;
			continue;
		}
		args++;
		if (strlen(key) > 30) {
			/* broken: ID spec requires fields to be max. 30
			   octets */
			args++;
			continue;
		}

		if (log_all || str_array_icase_find(keys, key)) {
			if (!imap_arg_get_nstring(args, &value))
				value = "";
			else if (value == NULL)
				value = "NIL";
			if (str_len(reply) > 0)
				str_append(reply, ", ");
			str_append(reply, str_sanitize(key, 30));
			str_append_c(reply, '=');
			str_append(reply, str_sanitize(value, 80));
		}
		args++;
	}
	return str_len(reply) == 0 ? NULL : str_c(reply);
}
static bool cmd_setquota(struct client_command_context *cmd)
{
	struct quota_root *root;
        const struct imap_arg *args, *list_args;
	const char *root_name, *name, *value_str, *error;
	uint64_t value;

	/* <quota root> <resource limits> */
	if (!client_read_args(cmd, 2, 0, &args))
		return FALSE;

	if (!imap_arg_get_astring(&args[0], &root_name) ||
	    !imap_arg_get_list(&args[1], &list_args)) {
		client_send_command_error(cmd, "Invalid arguments.");
		return TRUE;
	}

	root = quota_root_lookup(cmd->client->user, root_name);
	if (root == NULL) {
		client_send_tagline(cmd, "NO Quota root doesn't exist.");
		return TRUE;
	}

	for (; !IMAP_ARG_IS_EOL(list_args); list_args += 2) {
		if (!imap_arg_get_atom(&list_args[0], &name) ||
		    !imap_arg_get_atom(&list_args[1], &value_str) ||
		    str_to_uint64(value_str, &value) < 0) {
			client_send_command_error(cmd, "Invalid arguments.");
			return TRUE;
		}

		if (quota_set_resource(root, name, value, &error) < 0) {
			client_send_command_error(cmd, error);
			return TRUE;
		}
	}

	client_send_tagline(cmd, "OK Setquota completed.");
	return TRUE;
}
Exemple #9
0
bool cmd_fetch(struct client_command_context *cmd)
{
	struct client *client = cmd->client;
	struct imap_fetch_context *ctx;
	const struct imap_arg *args, *next_arg, *list_arg;
	struct mail_search_args *search_args;
	struct imap_fetch_qresync_args qresync_args;
	const char *messageset;
	bool send_vanished = FALSE;
	int ret;

	if (!client_read_args(cmd, 0, 0, &args))
		return FALSE;

	if (!client_verify_open_mailbox(cmd))
		return TRUE;

	/* <messageset> <field(s)> [(modifiers)] */
	if (!imap_arg_get_atom(&args[0], &messageset) ||
	    (args[1].type != IMAP_ARG_LIST && args[1].type != IMAP_ARG_ATOM) ||
	    (!IMAP_ARG_IS_EOL(&args[2]) && args[2].type != IMAP_ARG_LIST)) {
		client_send_command_error(cmd, "Invalid arguments.");
		return TRUE;
	}

	/* UID FETCH VANISHED needs the uidset, so convert it to
	   sequence set later */
	ret = imap_search_get_anyset(cmd, messageset, cmd->uid, &search_args);
	if (ret <= 0)
		return ret < 0;

	ctx = imap_fetch_alloc(client, cmd->pool);

	if (!fetch_parse_args(ctx, cmd, &args[1], &next_arg) ||
	    (imap_arg_get_list(next_arg, &list_arg) &&
	     !fetch_parse_modifiers(ctx, cmd, search_args, list_arg,
				    &send_vanished))) {
		imap_fetch_free(&ctx);
		mail_search_args_unref(&search_args);
		return TRUE;
	}

	if (send_vanished) {
		memset(&qresync_args, 0, sizeof(qresync_args));
		if (imap_fetch_send_vanished(client, client->mailbox,
					     search_args, &qresync_args) < 0) {
			mail_search_args_unref(&search_args);
			return cmd_fetch_finish(ctx, cmd);
		}
	}

	imap_fetch_begin(ctx, client->mailbox, search_args);
	mail_search_args_unref(&search_args);

	if (imap_fetch_more(ctx, cmd) == 0) {
		/* unfinished */
		cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;

		cmd->func = cmd_fetch_continue;
		cmd->context = ctx;
		return FALSE;
	}
	return cmd_fetch_finish(ctx, cmd);
}
Exemple #10
0
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_get_literal_size(args, &ctx->literal_size)) {
		*nonsync_r = args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC;
		ctx->binary_input = args->literal8;
		valid = TRUE;
	} else if (!imap_arg_atom_equals(args, "CATENATE")) {
		/* invalid */
	} else if (!imap_arg_get_list(++args, &cat_list)) {
		/* invalid */
	} else {
		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;

	}
	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;
			keywords = NULL;
		}
	}

	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;
	}
}
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;
}