irom static app_action_t set_unset_flag(application_parameters_t ap, bool_t value)
{
	uint16_t length;

	if(ap.nargs < 2)
	{
		length = snprintf(ap.dst, ap.size, "%s", "flags: ");
		ap.dst += length;
		ap.size -= length;

		length = config_flags_to_string(ap.size, ap.dst, config->flags);
		ap.dst += length;
		ap.size -= length;

		strlcpy(ap.dst, "\n", ap.size);

		return(app_action_normal);
	}

	if(!config_set_flag_by_name((*ap.args)[1], value))
	{
		snprintf(ap.dst, ap.size, "> unknown flag %s\n", (*ap.args)[1]);
		return(app_action_error);
	}

	snprintf(ap.dst, ap.size, "> flag %s %s\n", (*ap.args)[1], onoff(value));

	return(app_action_normal);
}
irom void config_dump(string_t *dst, const config_t *cfg)
{
	string_new(static, ntp_server, 32);

	string_clear(&ntp_server);
	string_ip(&ntp_server, cfg->ntp.server);

	string_format(dst, 
			"> config magic: %04x\n"
			"> config version: %d\n"
			"> wlan client ssid: %s\n"
			"> wlan client passwd: %s\n"
			"> wlan ap ssid: %s\n"
			"> wlan ap passwd: %s\n"
			"> wlan ap channel: %d\n"
			"> wlan mode: %s mode\n"
			"> bridge tcp port: %u\n"
			"> bridge tcp timeout: %u\n"
			"> command tcp port: %u\n"
			"> command tcp timeout: %u\n"
			"> ntp server: %s\n"
			"> ntp time zone: GMT%c%u\n"
			"> display flip timeout: %u\n"
			"> display default message: %s\n"
			"> status trigger gpio (-1 is disabled): %d/%d\n"
			"> wlan association trigger gpio (-1 is disabled): %d/%d\n"
			"> flags: ", 
		cfg->magic,
		cfg->version,
		cfg->client_wlan.ssid,
		cfg->client_wlan.passwd,
		cfg->ap_wlan.ssid,
		cfg->ap_wlan.passwd,
		cfg->ap_wlan.channel,
		cfg->wlan_mode == config_wlan_mode_client ? "client" : "ap",
		cfg->bridge.port,
		cfg->bridge.timeout,
		cfg->command.port,
		cfg->command.timeout,
		string_to_ptr(&ntp_server),
		cfg->ntp.timezone >= 0 ? '+' : '-',
		cfg->ntp.timezone >= 0 ? cfg->ntp.timezone : 0 - cfg->ntp.timezone,
		cfg->display.flip_timeout,
		cfg->display.default_msg,
		cfg->status_trigger.io,
		cfg->status_trigger.pin,
		cfg->assoc_trigger.io,
		cfg->assoc_trigger.pin);

	config_flags_to_string(dst, 0, 0, cfg->flags);

	string_cat(dst, "\n> uart: ");
	uart_parameters_to_string(dst, &cfg->uart);
	string_cat(dst, "\n> gpios:\n");
	io_config_dump(dst, cfg, -1, -1, false);
}
irom static app_action_t set_unset_flag(const string_t *src, string_t *dst, bool_t value)
{
	if(parse_string(1, src, dst) == parse_ok)
	{
		if(!config_set_flag_by_name(dst, value))
		{
			string_copy(dst, "> unknown flag\n");
			return(app_action_error);
		}
	}

	config_flags_to_string(dst, "flags: ", "\n", config.flags);

	return(app_action_normal);
}