예제 #1
0
static void dsync_connected_callback(int exit_code, const char *error,
				     void *context)
{
	struct dsync_cmd_context *ctx = context;

	ctx->ctx.exit_code = exit_code;
	switch (exit_code) {
	case 0:
		server_connection_extract(ctx->tcp_conn, &ctx->input,
					  &ctx->output, &ctx->ssl_iostream);
		break;
	case SERVER_EXIT_CODE_DISCONNECTED:
		ctx->error = p_strdup_printf(ctx->ctx.pool,
			"Disconnected from remote: %s", error);
		break;
	case EX_NOUSER:
		ctx->error = "Unknown user in remote";
		break;
	default:
		ctx->error = p_strdup_printf(ctx->ctx.pool,
			"Failed to start dsync-server command: %u", exit_code);
		break;
	}
	io_loop_stop(current_ioloop);
}
예제 #2
0
static void mail_crypt_mail_user_created(struct mail_user *user)
{
	struct mail_user_vfuncs *v = user->vlast;
	struct mail_crypt_user *muser;
	const char *error = NULL;

	muser = p_new(user->pool, struct mail_crypt_user, 1);
	muser->module_ctx.super = *v;
	user->vlast = &muser->module_ctx.super;

	const char *curve = mail_user_plugin_getenv(user, "mail_crypt_curve");
	buffer_t *tmp = t_str_new(64);
	if (curve == NULL) {
		if (user->mail_debug) {
			i_debug("mail_crypt_plugin: mail_crypt_curve setting "
				"missing - generating EC keys disabled");
		}
	} else if (!dcrypt_name2oid(curve, tmp, &error)) {
		user->error = p_strdup_printf(user->pool,
			"mail_crypt_plugin: "
			"invalid mail_crypt_curve setting %s: %s - "
			"plugin disabled",
			curve, error);
	} else {
		muser->curve = p_strdup(user->pool, curve);
	}

	const char *version = mail_user_plugin_getenv(user,
			"mail_crypt_save_version");

	if (version == NULL) {
		user->error = p_strdup_printf(user->pool,
				"mail_crypt_plugin: "
				"mail_crypt_save_version setting missing "
				"- plugin disabled");
	} else if (version[0] == '0') {
		muser->save_version = 0;
	} else if (version[0] == '1') {
		muser->save_version = 1;
	} else if (version[0] == '2') {
		muser->save_version = 2;
	} else {
		user->error = p_strdup_printf(user->pool,
				"mail_crypt_plugin: Invalid "
				"mail_crypt_save_version %s: use 0, 1, or 2 ",
				version);
	}

	if (mail_crypt_global_keys_load(user, "mail_crypt_global",
					&muser->global_keys, FALSE, &error) < 0) {
		user->error = p_strdup_printf(user->pool,
				"mail_crypt_plugin: %s", error);
	}

	v->deinit = mail_crypt_mail_user_deinit;
	MODULE_CONTEXT_SET(user, mail_crypt_user_module, muser);
}
static void
mail_filter_parse_setting(struct mail_user *user, const char *name,
			  const char **socket_path_r, const char **args_r)
{
	const char *value, *p;

	value = mail_user_plugin_getenv(user, name);
	if (value == NULL)
		return;

	p = strchr(value, ' ');
	if (p == NULL) {
		*socket_path_r = p_strdup(user->pool, value);
		*args_r = "";
	} else {
		*socket_path_r = p_strdup_until(user->pool, value, p);
		*args_r = p_strdup(user->pool, p + 1);
	}
	if (**socket_path_r != '/') {
		/* relative to base_dir */
		*socket_path_r = p_strdup_printf(user->pool, "%s/%s",
			user->set->base_dir, *socket_path_r);
	}
	if (user->mail_debug) {
		i_debug("mail_filter: Filtering %s via socket %s",
			name, *socket_path_r);
	}
}
예제 #4
0
static void
mail_user_expand_plugins_envs(struct mail_user *user)
{
	const char **envs, *home;
	string_t *str;
	unsigned int i, count;

	if (!array_is_created(&user->set->plugin_envs))
		return;

	str = t_str_new(256);
	envs = array_get_modifiable(&user->set->plugin_envs, &count);
	i_assert((count % 2) == 0);
	for (i = 0; i < count; i += 2) {
		if (user->_home == NULL &&
		    var_has_key(envs[i+1], 'h', "home") &&
		    mail_user_get_home(user, &home) <= 0) {
			user->error = p_strdup_printf(user->pool,
				"userdb didn't return a home directory, "
				"but plugin setting %s used it (%%h): %s",
				envs[i], envs[i+1]);
			return;
		}
		str_truncate(str, 0);
		var_expand(str, envs[i+1], mail_user_var_expand_table(user));
		envs[i+1] = p_strdup(user->pool, str_c(str));
	}
}
static void
search_update_flag_changes(struct dsync_mailbox_exporter *exporter,
                           struct mail *mail, struct dsync_mail_change *change)
{
    const char *const *keywords;
    unsigned int i;
    char type;

    i_assert((change->add_flags & change->remove_flags) == 0);

    change->modseq = mail_get_modseq(mail);
    change->pvt_modseq = mail_get_pvt_modseq(mail);
    change->final_flags = mail_get_flags(mail);

    keywords = mail_get_keywords(mail);
    if (!array_is_created(&change->keyword_changes) &&
            keywords[0] != NULL) {
        p_array_init(&change->keyword_changes, exporter->pool,
                     str_array_length(keywords));
    }
    for (i = 0; keywords[i] != NULL; i++) {
        /* add the final keyword if it's not already there
           as +keyword */
        if (!final_keyword_check(change, keywords[i], &type)) {
            const char *keyword_change =
                p_strdup_printf(exporter->pool, "%c%s",
                                type, keywords[i]);
            array_append(&change->keyword_changes,
                         &keyword_change, 1);
        }
    }
}
예제 #6
0
static void http_client_request_do_submit(struct http_client_request *req)
{
	struct http_client *client = req->client;
	struct http_client_host *host;
	const struct http_url *proxy_url = client->set.proxy_url;
	const char *authority, *target;

	i_assert(req->state == HTTP_REQUEST_STATE_NEW);

	authority = http_url_create_authority(&req->origin_url);
	if (req->connect_tunnel) {
		/* connect requests require authority form for request target */
		target = authority;
	} else {
		/* absolute target url */
		target = t_strconcat
			(http_url_create_host(&req->origin_url), req->target, NULL);
	}

	/* determine what host to contact to submit this request */
	if (proxy_url != NULL) {
		if (req->origin_url.have_ssl && !client->set.no_ssl_tunnel &&
			!req->connect_tunnel) {
			req->host_url = &req->origin_url;  /* tunnel to origin server */
			req->ssl_tunnel = TRUE;
		} else {
			req->host_url = proxy_url;         /* proxy server */
		}
	} else {
		req->host_url = &req->origin_url;    /* origin server */
	}

	/* use submission date if no date is set explicitly */
	if (req->date == (time_t)-1)
		req->date = ioloop_time;
	
	/* prepare value for Host header */
	req->authority = p_strdup(req->pool, authority);

	/* debug label */
	req->label = p_strdup_printf(req->pool, "[%s %s]", req->method, target);

	/* update request target */
	if (req->connect_tunnel || proxy_url != NULL)
		req->target = p_strdup(req->pool, target);

	if (proxy_url == NULL) {
		/* if we don't have a proxy, CONNECT requests are handled by creating
		   the requested connection directly */
		req->connect_direct = req->connect_tunnel;
		if (req->connect_direct)
			req->urgent = TRUE;
	}

	host = http_client_host_get(req->client, req->host_url);
	req->state = HTTP_REQUEST_STATE_QUEUED;

	http_client_host_submit_request(host, req);
}
예제 #7
0
const char *
http_client_request_label(struct http_client_request *req)
{
	if (req->label == NULL) {
		req->label = p_strdup_printf(req->pool,
			"[Req%u: %s %s%s]", req->id,
			req->method, http_url_create(&req->origin_url), req->target);
	}
	return req->label;
}
void script_client_set_env
(struct script_client *sclient, const char *name, const char *value)
{
	const char *env;

	if ( !array_is_created(&sclient->envs) )
		p_array_init(&sclient->envs, sclient->pool, 16);

	env = p_strdup_printf(sclient->pool, "%s=%s", name, value);
	array_append(&sclient->envs, &env, 1);
}
예제 #9
0
void program_client_set_env
(struct program_client *pclient, const char *name, const char *value)
{
	const char *env;

	if ( !array_is_created(&pclient->envs) )
		p_array_init(&pclient->envs, pclient->pool, 16);

	env = p_strdup_printf(pclient->pool, "%s=%s", name, value);
	array_append(&pclient->envs, &env, 1);
}
static int dsync_mail_error(struct dsync_mailbox_exporter *exporter,
                            struct mail *mail, const char *field)
{
    const char *errstr;
    enum mail_error error;

    errstr = mailbox_get_last_error(exporter->box, &error);
    if (error == MAIL_ERROR_EXPUNGED)
        return 0;

    exporter->error = p_strdup_printf(exporter->pool,
                                      "Can't lookup %s for UID=%u: %s",
                                      field, mail->uid, errstr);
    return -1;
}
static void
mailbox_list_index_generate_name(struct mailbox_list_index *ilist,
				 struct mailbox_list_index_node *node)
{
	guid_128_t guid;
	char *name;

	guid_128_generate(guid);
	name = p_strdup_printf(ilist->mailbox_pool, "unknown-%s",
			       guid_128_to_string(guid));
	node->name = name;

	hash_table_insert(ilist->mailbox_names,
			  POINTER_CAST(node->name_id), name);
	if (ilist->highest_name_id < node->name_id)
		ilist->highest_name_id = node->name_id;
}
예제 #12
0
static void
userdb_nss_load_module(struct nss_userdb_module *module, pool_t pool)
{
	const char *name = module->nss_module.name;
	char *path;

	path = p_strdup_printf(pool, "/usr/lib/libnss_%s.so", name);
	module->nss_module.handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
	if (module->nss_module.handle == NULL)
		i_fatal("dlopen(%s) failed: %s", path, dlerror());
	module->nss_module.path = path;

	module->getpwnam_r =
		module_get_symbol(&module->nss_module,
				  t_strdup_printf("_nss_%s_getpwnam_r", name));
	if (module->getpwnam_r == NULL)
		i_fatal("userdb nss: Module %s missing getpwnam_r()", path);
}
예제 #13
0
int mail_user_init(struct mail_user *user, const char **error_r)
{
	const struct mail_storage_settings *mail_set;
	const char *home, *key, *value;
	bool need_home_dir;

	need_home_dir = user->_home == NULL &&
		settings_vars_have_key(user->set_info, user->set,
				       'h', "home", &key, &value);
	if (need_home_dir && mail_user_get_home(user, &home) <= 0) {
		user->error = p_strdup_printf(user->pool,
			"userdb didn't return a home directory, "
			"but %s used it (%%h): %s", key, value);
	}

	/* expand settings after we can expand %h */
	settings_var_expand_with_funcs(user->set_info, user->set,
				       user->pool, mail_user_var_expand_table(user),
				       mail_user_var_expand_func_table, user);
	user->settings_expanded = TRUE;
	mail_user_expand_plugins_envs(user);

	/* autocreated users for shared mailboxes need to be fully initialized
	   if they don't exist, since they're going to be used anyway */
	if (user->error == NULL || user->nonexistent) {
		mail_set = mail_user_set_get_storage_set(user);
		user->mail_debug = mail_set->mail_debug;

		user->initialized = TRUE;
		hook_mail_user_created(user);
	}

	if (user->error != NULL) {
		*error_r = t_strdup(user->error);
		return -1;
	}
	return 0;
}
예제 #14
0
파일: imapc-mail.c 프로젝트: bjacke/core
static int
imapc_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
		       const char **value_r)
{
	struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
	struct index_mail *imail = (struct index_mail *)_mail;
	uint64_t num;

	switch (field) {
	case MAIL_FETCH_GUID:
		if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_GUID_FORCED) &&
		    mbox->guid_fetch_field_name == NULL) {
			/* GUIDs not supported by server */
			break;
		}
		*value_r = "";
		return imapc_mail_get_guid(_mail, value_r);
	case MAIL_FETCH_UIDL_BACKEND:
		if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_GMAIL_MIGRATION))
			break;
		if (imapc_mail_get_guid(_mail, value_r) < 0)
			return -1;
		if (str_to_uint64(*value_r, &num) < 0) {
			mail_storage_set_critical(_mail->box->storage,
				"X-GM-MSGID not 64bit integer as expected for POP3 UIDL generation: %s", *value_r);
			return -1;
		}

		*value_r = p_strdup_printf(imail->mail.data_pool, "GmailId%llx",
					   (unsigned long long)num);
		return 0;
	default:
		break;
	}

	return index_mail_get_special(_mail, field, value_r);
}
예제 #15
0
static int
maildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
			 const char **value_r)
{
	struct index_mail *mail = (struct index_mail *)_mail;
	struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
	const char *path, *fname = NULL, *end, *guid, *uidl, *order;
	struct stat st;

	switch (field) {
	case MAIL_FETCH_GUID:
		/* use GUID from uidlist if it exists */
		i_assert(!_mail->saving);

		if (mail->data.guid != NULL) {
			*value_r = mail->data.guid;
			return 0;
		}

		/* first make sure that we have a refreshed uidlist */
		if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
			return -1;

		guid = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
						  MAILDIR_UIDLIST_REC_EXT_GUID);
		if (guid != NULL) {
			if (*guid != '\0') {
				*value_r = mail->data.guid =
					p_strdup(mail->mail.data_pool, guid);
				return 0;
			}

			mail_storage_set_critical(_mail->box->storage,
				"Maildir %s: Corrupted dovecot-uidlist: "
				"UID %u had empty GUID, clearing it",
				mailbox_get_path(_mail->box), _mail->uid);
			maildir_uidlist_unset_ext(mbox->uidlist, _mail->uid,
				MAILDIR_UIDLIST_REC_EXT_GUID);
		}

		/* default to base filename: */
		if (maildir_mail_get_special(_mail, MAIL_FETCH_STORAGE_ID,
					     value_r) < 0)
			return -1;
		mail->data.guid = mail->data.filename;
		return 0;
	case MAIL_FETCH_STORAGE_ID:
		if (mail->data.filename != NULL) {
			*value_r = mail->data.filename;
			return 0;
		}
		if (fname != NULL) {
			/* we came here from MAIL_FETCH_GUID,
			   avoid a second lookup */
		} else if (!_mail->saving) {
			if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
				return -1;
		} else {
			path = maildir_save_file_get_path(_mail->transaction,
							  _mail->seq);
			fname = strrchr(path, '/');
			fname = fname != NULL ? fname + 1 : path;
		}
		end = strchr(fname, MAILDIR_INFO_SEP);
		mail->data.filename = end == NULL ?
			p_strdup(mail->mail.data_pool, fname) :
			p_strdup_until(mail->mail.data_pool, fname, end);
		*value_r = mail->data.filename;
		return 0;
	case MAIL_FETCH_UIDL_BACKEND:
		uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
					MAILDIR_UIDLIST_REC_EXT_POP3_UIDL);
		if (uidl == NULL) {
			/* use the default */
			*value_r = "";
		} else if (*uidl == '\0') {
			/* special optimization case: use the base file name */
			return maildir_mail_get_special(_mail,
					MAIL_FETCH_STORAGE_ID, value_r);
		} else {
			*value_r = p_strdup(mail->mail.data_pool, uidl);
		}
		return 0;
	case MAIL_FETCH_POP3_ORDER:
		order = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
					MAILDIR_UIDLIST_REC_EXT_POP3_ORDER);
		if (order == NULL) {
			*value_r = "";
		} else {
			*value_r = p_strdup(mail->mail.data_pool, order);
		}
		return 0;
	case MAIL_FETCH_REFCOUNT:
		if (maildir_mail_stat(_mail, &st) < 0)
			return -1;
		*value_r = p_strdup_printf(mail->mail.data_pool, "%lu",
					   (unsigned long)st.st_nlink);
		return 0;
	default:
		return index_mail_get_special(_mail, field, value_r);
	}
}
예제 #16
0
bool imap_fetch_binary_init(struct imap_fetch_init_context *ctx)
{
	struct imap_fetch_body_data *body;
	const struct imap_arg *list_args;
	unsigned int list_count;
	const char *str, *p, *error;

	i_assert(strncmp(ctx->name, "BINARY", 6) == 0);
	p = ctx->name + 6;

	body = p_new(ctx->pool, struct imap_fetch_body_data, 1);
	body->binary = TRUE;

	if (strncmp(p, ".SIZE", 5) == 0) {
		/* fetch decoded size of the section */
		p += 5;
		body->binary_size = TRUE;
	} else if (strncmp(p, ".PEEK", 5) == 0) {
		p += 5;
	} else {
		ctx->fetch_ctx->flags_update_seen = TRUE;
	}
	if (*p != '[') {
		ctx->error = "Invalid BINARY[..] parameter: Missing '['";
		return FALSE;
	}

	if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) {
		/* BINARY[HEADER.FIELDS.. (headers list)] */
		if (!imap_arg_get_atom(&ctx->args[1], &str) ||
		    str[0] != ']') {
			ctx->error = "Invalid BINARY[..] parameter: Missing ']'";
			return FALSE;
		}
		if (body_header_fields_parse(ctx, body, p+1,
					     list_args, list_count) < 0)
			return FALSE;
		p = str+1;
		ctx->args += 2;
	} else {
		/* no headers list */
		body->section = p+1;
		p = strchr(body->section, ']');
		if (p == NULL) {
			ctx->error = "Invalid BINARY[..] parameter: Missing ']'";
			return FALSE;
		}
		body->section = p_strdup_until(ctx->pool, body->section, p);
		p++;
	}
	if (imap_msgpart_parse(body->section, &body->msgpart) < 0) {
		ctx->error = "Invalid BINARY[..] section";
		return FALSE;
	}
	imap_msgpart_set_decode_to_binary(body->msgpart);
	ctx->fetch_ctx->fetch_data |=
		imap_msgpart_get_fetch_data(body->msgpart);

	if (!body->binary_size) {
		if (body_parse_partial(body, p, &error) < 0) {
			ctx->error = p_strdup_printf(ctx->pool,
				"Invalid BINARY[..] parameter: %s", error);
			return FALSE;
		}
	}

	/* update the section name for the imap_fetch_add_handler() */
	ctx->name = p_strdup(ctx->pool, get_body_name(body));
	if (body->binary_size) {
		imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT,
				       "0", fetch_binary_size, body);
	} else {
		imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT,
				       "NIL", fetch_body_msgpart, body);
	}
	return TRUE;
}
예제 #17
0
파일: commands.c 프로젝트: makunterry/core
int cmd_rcpt(struct client *client, const char *args)
{
	struct mail_recipient *rcpt;
	struct mail_storage_service_input input;
	const char *params, *address, *username, *detail, *prefix;
	const char *const *argv;
	const char *error = NULL;
	char delim = '\0';
	int ret = 0;

	if (client->state.mail_from == NULL) {
		client_send_line(client, "503 5.5.1 MAIL needed first");
		return 0;
	}

	if (strncasecmp(args, "TO:", 3) != 0 ||
	    parse_address(args + 3, &address, &params) < 0) {
		client_send_line(client, "501 5.5.4 Invalid parameters");
		return 0;
	}

	rcpt = p_new(client->state_pool, struct mail_recipient, 1);
	rcpt->client = client;
	address = lmtp_unescape_address(address);

	argv = t_strsplit(params, " ");
	for (; *argv != NULL; argv++) {
		if (strncasecmp(*argv, "ORCPT=", 6) == 0) {
			rcpt->params.dsn_orcpt = parse_xtext(client, *argv + 6);
		} else {
			client_send_line(client, "501 5.5.4 Unsupported options");
			return 0;
		}
	}
	rcpt_address_parse(client, address, &username, &delim, &detail);

	client_state_set(client, "RCPT TO", address);

	if (client->lmtp_set->lmtp_proxy) {
		if (client_proxy_rcpt(client, address, username, detail, delim,
				      &rcpt->params))
			return 0;
	}

	/* Use a unique session_id for each mail delivery. This is especially
	   important for stats process to not see duplicate sessions. */
	if (array_count(&client->state.rcpt_to) == 0)
		rcpt->session_id = client->state.session_id;
	else {
		rcpt->session_id =
			p_strdup_printf(client->state_pool, "%s:%u",
					client->state.session_id,
					array_count(&client->state.rcpt_to)+1);
	}

	memset(&input, 0, sizeof(input));
	input.module = input.service = "lmtp";
	input.username = username;
	input.local_ip = client->local_ip;
	input.remote_ip = client->remote_ip;
	input.local_port = client->local_port;
	input.remote_port = client->remote_port;
	input.session_id = rcpt->session_id;

	ret = mail_storage_service_lookup(storage_service, &input,
					  &rcpt->service_user, &error);

	if (ret < 0) {
		prefix = t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL_PREFIX,
					 username);
		client_send_line(client, "%s%s", prefix, error);
		return 0;
	}
	if (ret == 0) {
		client_send_line(client,
				 "550 5.1.1 <%s> User doesn't exist: %s",
				 address, username);
		return 0;
	}
	if (client->proxy != NULL) {
		/* NOTE: if this restriction is ever removed, we'll also need
		   to send different message bodies to local and proxy
		   (with and without Return-Path: header) */
		client_send_line(client, "451 4.3.0 <%s> "
			"Can't handle mixed proxy/non-proxy destinations",
			address);
		mail_storage_service_user_free(&rcpt->service_user);
		return 0;
	}

	lmtp_address_translate(client, &address);

	rcpt->address = p_strdup(client->state_pool, address);
	rcpt->detail = p_strdup(client->state_pool, detail);
	if ((ret = lmtp_rcpt_to_is_over_quota(client, rcpt)) != 0) {
		if (ret < 0) {
			client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
					 rcpt->address);
		}
		mail_storage_service_user_free(&rcpt->service_user);
		return 0;
	}
	array_append(&client->state.rcpt_to, &rcpt, 1);
	client_send_line(client, "250 2.1.5 OK");

	if (client->lmtp_set->lmtp_user_concurrency_limit > 0) {
		const char *query = t_strconcat("LOOKUP\t",
			master_service_get_name(master_service),
			"/", str_tabescape(username), NULL);
		client->state.anvil_queries++;
		rcpt->anvil_query = anvil_client_query(anvil, query,
					rcpt_anvil_lookup_callback, rcpt);
	}
	return 0;
}
예제 #18
0
static void
settings_export(struct config_export_context *ctx,
		const struct setting_parser_info *info,
		bool parent_unique_deflist,
		const void *set, const void *change_set)
{
	const struct setting_define *def;
	const void *value, *default_value, *change_value;
	void *const *children = NULL, *const *change_children = NULL;
	unsigned int i, count, count2, prefix_len;
	const char *str;
	char *key;
	bool dump, dump_default = FALSE;

	for (def = info->defines; def->key != NULL; def++) {
		value = CONST_PTR_OFFSET(set, def->offset);
		default_value = info->defaults == NULL ? NULL :
			CONST_PTR_OFFSET(info->defaults, def->offset);
		change_value = CONST_PTR_OFFSET(change_set, def->offset);
		switch (ctx->scope) {
		case CONFIG_DUMP_SCOPE_ALL:
			dump_default = TRUE;
			break;
		case CONFIG_DUMP_SCOPE_SET:
			dump_default = *((const char *)change_value) != 0;
			break;
		case CONFIG_DUMP_SCOPE_CHANGED:
			dump_default = FALSE;
			break;
		}
		if (!parent_unique_deflist ||
		    (ctx->flags & CONFIG_DUMP_FLAG_HIDE_LIST_DEFAULTS) == 0) {
			/* .. */
		} else if (*((const char *)change_value) == 0 &&
			   def->offset != info->type_offset) {
			/* this is mainly for service {} blocks. if value
			   hasn't changed, it's the default. even if
			   info->defaults has a different value. */
			default_value = value;
		} else {
			/* value is set explicitly, but we don't know the
			   default here. assume it's not the default. */
			dump_default = TRUE;
		}

		dump = FALSE;
		count = 0;
		str_truncate(ctx->value, 0);
		switch (def->type) {
		case SET_BOOL:
		case SET_SIZE:
		case SET_UINT:
		case SET_UINT_OCT:
		case SET_TIME:
		case SET_STR_VARS:
		case SET_STR:
		case SET_ENUM:
			if (!config_export_type(ctx->value, value,
						default_value, def->type,
						dump_default, &dump))
				i_unreached();
			break;
		case SET_DEFLIST:
		case SET_DEFLIST_UNIQUE: {
			const ARRAY_TYPE(void_array) *val = value;
			const ARRAY_TYPE(void_array) *change_val = change_value;

			if (!array_is_created(val))
				break;

			children = array_get(val, &count);
			for (i = 0; i < count; i++) {
				if (i > 0)
					str_append_c(ctx->value, ' ');
				setting_export_section_name(ctx->value, def, children[i], i);
			}
			change_children = array_get(change_val, &count2);
			i_assert(count == count2);
			break;
		}
		case SET_STRLIST: {
			const ARRAY_TYPE(const_string) *val = value;
			const char *const *strings;

			if (!array_is_created(val))
				break;

			key = p_strconcat(ctx->pool, str_c(ctx->prefix),
					  def->key, NULL);

			if (hash_table_lookup(ctx->keys, key) != NULL) {
				/* already added all of these */
				break;
			}
			hash_table_insert(ctx->keys, key, key);
			/* for doveconf -n to see this KEY_LIST */
			ctx->callback(key, "", CONFIG_KEY_LIST, ctx->context);

			strings = array_get(val, &count);
			i_assert(count % 2 == 0);
			for (i = 0; i < count; i += 2) {
				str = p_strdup_printf(ctx->pool, "%s%s%c%s",
						      str_c(ctx->prefix),
						      def->key,
						      SETTINGS_SEPARATOR,
						      strings[i]);
				ctx->callback(str, strings[i+1],
					      CONFIG_KEY_NORMAL, ctx->context);
			}
			count = 0;
			break;
		}
		case SET_ALIAS:
			break;
		}
		if (str_len(ctx->value) > 0 || dump) {
			key = p_strconcat(ctx->pool, str_c(ctx->prefix),
					  def->key, NULL);
			if (hash_table_lookup(ctx->keys, key) == NULL) {
				enum config_key_type type;

				if (def->offset == info->type_offset &&
				    parent_unique_deflist)
					type = CONFIG_KEY_UNIQUE_KEY;
				else if (SETTING_TYPE_IS_DEFLIST(def->type))
					type = CONFIG_KEY_LIST;
				else
					type = CONFIG_KEY_NORMAL;
				ctx->callback(key, str_c(ctx->value), type,
					ctx->context);
				hash_table_insert(ctx->keys, key, key);
			}
		}

		prefix_len = str_len(ctx->prefix);
		for (i = 0; i < count; i++) {
			str_append(ctx->prefix, def->key);
			str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
			setting_export_section_name(ctx->prefix, def, children[i], i);
			str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
			settings_export(ctx, def->list_info,
					def->type == SET_DEFLIST_UNIQUE,
					children[i], change_children[i]);

			str_truncate(ctx->prefix, prefix_len);
		}
	}
}
예제 #19
0
void http_client_request_redirect(struct http_client_request *req,
	unsigned int status, const char *location)
{
	struct http_url *url;
	const char *error, *target, *origin_url;

	i_assert(!req->payload_wait);

	/* parse URL */
	if (http_url_parse(location, NULL, 0,
			   pool_datastack_create(), &url, &error) < 0) {
		http_client_request_error(&req, HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
			t_strdup_printf("Invalid redirect location: %s", error));
		return;
	}

	if (++req->redirects > req->client->set.max_redirects) {
		if (req->client->set.max_redirects > 0) {
			http_client_request_error(&req,
				HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
				t_strdup_printf("Redirected more than %d times",
					req->client->set.max_redirects));
		} else {
			http_client_request_error(&req,
				HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
					"Redirect refused");
		}
		return;
	}

	/* rewind payload stream */
	if (req->payload_input != NULL && req->payload_size > 0 && status != 303) {
		if (req->payload_input->v_offset != req->payload_offset &&
			!req->payload_input->seekable) {
			http_client_request_error(&req,
				HTTP_CLIENT_REQUEST_ERROR_ABORTED,
				"Redirect failed: Cannot resend payload; stream is not seekable");
			return;
		} else {
			i_stream_seek(req->payload_input, req->payload_offset);
		}
	}

	/* drop payload output stream from previous attempt */
	if (req->payload_output != NULL)
		o_stream_unref(&req->payload_output);

	target = http_url_create_target(url);

	http_url_copy(req->pool, &req->origin_url, url);
	req->target = p_strdup(req->pool, target);
	
	req->host = NULL;
	req->conn = NULL;

	origin_url = http_url_create(&req->origin_url);

	http_client_request_debug(req, "Redirecting to %s%s",
		origin_url, target);

	req->label = p_strdup_printf(req->pool, "[%s %s%s]",
		req->method, origin_url, req->target);

	/* RFC 7231, Section 6.4.4:
	
	   -> A 303 `See Other' redirect status response is handled a bit differently.
	   Basically, the response content is located elsewhere, but the original
	   (POST) request is handled already.
	 */
	if (status == 303 && strcasecmp(req->method, "HEAD") != 0 &&
		strcasecmp(req->method, "GET") != 0) {
		// FIXME: should we provide the means to skip this step? The original
		// request was already handled at this point.
		req->method = p_strdup(req->pool, "GET");

		/* drop payload */
		if (req->payload_input != NULL)
			i_stream_unref(&req->payload_input);
		req->payload_size = 0;
		req->payload_offset = 0;
	}

	/* resubmit */
	req->state = HTTP_REQUEST_STATE_NEW;
	http_client_request_do_submit(req);
}