Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
void client_send_internal_error(struct client_command_context *cmd)
{
	client_send_tagline(cmd,
		t_strflocaltime("NO "MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time));
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 5
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_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;
	}
}