Пример #1
0
void hub_free_variables(struct hub_info* hub)
{
	hub_plugins_unload(hub);

	adc_msg_free(hub->command_info);
	adc_msg_free(hub->command_banner);
	adc_msg_free(hub->command_support);
}
Пример #2
0
void ADC_client_destroy(struct ADC_client* client)
{
	ADC_TRACE;
	ADC_client_disconnect(client);
	ioq_send_destroy(client->send_queue);
	ioq_recv_destroy(client->recv_queue);
	hub_free(client->timer);
	adc_msg_free(client->info);
	hub_free(client->nick);
	hub_free(client->desc);
	hub_free(client->address.hostname);
	hub_free(client);

	if (g_adc_client && g_adc_client->references > 0)
	{
		g_adc_client->references--;
		if (!g_adc_client->references)
		{
#ifdef SSL_SUPPORT
			net_ssl_context_destroy(g_adc_client->ctx);
			g_adc_client->ctx = NULL;
#endif
			hub_free(g_adc_client);
			g_adc_client = NULL;
		}
	}
}
Пример #3
0
void user_update_info(struct hub_user* u, struct adc_message* cmd)
{
	char prefix[2];
	char* argument;
	size_t n = 0;
	struct adc_message* cmd_new = adc_msg_copy(u->info);
	if (!cmd_new)
	{
		/* FIXME: OOM! */
		return;
	}

	/*
	 * FIXME: Optimization potential:
	 *
	 * remove parts of cmd that do not really change anything in cmd_new.
	 * this can save bandwidth if clients send multiple updates for information
	 * that does not really change anything.
	 */
	argument = adc_msg_get_argument(cmd, n++);
	while (argument)
	{
		if (strlen(argument) >= 2)
		{
			prefix[0] = argument[0];
			prefix[1] = argument[1];
			adc_msg_replace_named_argument(cmd_new, prefix, argument+2);
		}
		
		hub_free(argument);
		argument = adc_msg_get_argument(cmd, n++);
	}
	user_set_info(u, cmd_new);
	adc_msg_free(cmd_new);
}
Пример #4
0
int route_info_message(struct hub_info* hub, struct hub_user* u)
{
	if (!user_is_nat_override(u))
	{
		return route_to_all(hub, u->info);
	}
	else
	{
		struct adc_message* cmd = adc_msg_copy(u->info);
		const char* address = user_get_address(u);
		struct hub_user* user = 0;
		
		adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
		adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address);
	
		user = (struct hub_user*) list_get_first(hub->users->list);
		while (user)
		{
			if (user_is_nat_override(user))
				route_to_user(hub, user, cmd);
			else
				route_to_user(hub, user, u->info);
			
			user = (struct hub_user*) list_get_next(hub->users->list);
		}
		adc_msg_free(cmd);
	}
	return 0;
}
Пример #5
0
Файл: hub.c Проект: q3k/uhub
void hub_free_variables(struct hub_info* hub)
{
#ifdef PLUGIN_SUPPORT
	hub_plugins_unload(hub);
#endif

	adc_msg_free(hub->command_info);
	adc_msg_free(hub->command_banner);

	if (hub->command_motd)
		adc_msg_free(hub->command_motd);

	if (hub->command_rules)
		adc_msg_free(hub->command_rules);

	adc_msg_free(hub->command_support);
}
Пример #6
0
void hub_send_password_challenge(struct hub_info* hub, struct hub_user* u)
{
	struct adc_message* igpa;
	igpa = adc_msg_construct(ADC_CMD_IGPA, 38);
	adc_msg_add_argument(igpa, acl_password_generate_challenge(hub, u));
	user_set_state(u, state_verify);
	route_to_user(hub, u, igpa);
	adc_msg_free(igpa);
}
Пример #7
0
struct adc_message* adc_msg_copy(const struct adc_message* cmd)
{
    char* tmp = 0;
    struct adc_message* copy = (struct adc_message*) msg_malloc_zero(sizeof(struct adc_message));
    if (!copy) return NULL; /* OOM */

    ADC_MSG_ASSERT(cmd);

    /* deep copy */
    copy->cmd                  = cmd->cmd;
    copy->source               = cmd->source;
    copy->target               = cmd->target;
    copy->cache                = 0;
    copy->length               = cmd->length;
    copy->capacity             = 0;
    copy->priority             = cmd->priority;
    copy->references           = 1;
    copy->feature_cast_include = 0;
    copy->feature_cast_exclude = 0;

    if (!adc_msg_grow(copy, copy->length))
    {
        adc_msg_free(copy);
        return NULL; /* OOM */
    }

    if (!copy->cache)
    {
        adc_msg_free(copy);
        return NULL;
    }

    memcpy(copy->cache, cmd->cache, cmd->length);
    copy->cache[copy->length] = 0;

    if (cmd->feature_cast_include)
    {
        copy->feature_cast_include = list_create();
        LIST_FOREACH(char*, tmp, cmd->feature_cast_include,
        {
            list_append(copy->feature_cast_include, hub_strdup(tmp));
        });
Пример #8
0
void hub_send_ping(struct hub_info* hub, struct hub_user* user)
{
	/* This will just send a newline, despite appearing to do more below. */
	struct adc_message* ping = adc_msg_construct(0, 0);
	ping->cache[0]     = '\n';
	ping->cache[1]     = 0;
	ping->length       = 1;
	ping->priority     = 1;
	route_to_user(hub, user, ping);
	adc_msg_free(ping);
}
Пример #9
0
static void ADC_client_send_handshake(struct ADC_client* client)
{
	ADC_TRACE;
	struct adc_message* handshake = adc_msg_create(ADC_HANDSHAKE);

	client->callback(client, ADC_CLIENT_CONNECTED, 0);
	net_con_update(client->con, NET_EVENT_READ);
	ADC_client_send(client, handshake);
	ADC_client_set_state(client, ps_protocol);
	adc_msg_free(handshake);
}
Пример #10
0
void user_set_info(struct hub_user* user, struct adc_message* cmd)
{
	adc_msg_free(user->info);
	if (cmd)
	{
		user->info = adc_msg_incref(cmd);
	}
	else
	{
		user->info = 0;
	}
}
Пример #11
0
void uman_send_quit_message(struct hub_info* hub, struct hub_user* leaving)
{
	struct adc_message* command = adc_msg_construct(ADC_CMD_IQUI, 6);
	adc_msg_add_argument(command, (const char*) sid_to_string(leaving->id.sid));

	if (leaving->quit_reason == quit_banned || leaving->quit_reason == quit_kicked)
	{
		adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
	}
	route_to_all(hub, command);
	adc_msg_free(command);
}
Пример #12
0
Файл: hub.c Проект: q3k/uhub
void hub_send_sid(struct hub_info* hub, struct hub_user* u)
{
	sid_t sid;
	struct adc_message* command;
	if (user_is_connecting(u))
	{
		command = adc_msg_construct(ADC_CMD_ISID, 10);
		sid = uman_get_free_sid(hub, u);
		adc_msg_add_argument(command, (const char*) sid_to_string(sid));
		route_to_user(hub, u, command);
		adc_msg_free(command);
	}
}
Пример #13
0
void user_destroy(struct hub_user* user)
{
	LOG_TRACE("user_destroy(), user=%p", user);

	ioq_recv_destroy(user->recv_queue);
	ioq_send_destroy(user->send_queue);

	if (user->connection)
	{
		LOG_TRACE("user_destory() -> net_con_close(%p)", user->connection);
		net_con_close(user->connection);
	}

	adc_msg_free(user->info);
	user_clear_feature_cast_support(user);
	hub_free(user);
}
Пример #14
0
void hub_send_flood_warning(struct hub_info* hub, struct hub_user* u, const char* message)
{
	struct adc_message* msg;
	char* tmp;

	if (user_flag_get(u, flag_flood))
		return;

	msg = adc_msg_construct(ADC_CMD_ISTA, 128);
	if (msg)
	{
		tmp = adc_msg_escape(message);
		adc_msg_add_argument(msg, "110");
		adc_msg_add_argument(msg, tmp);
		hub_free(tmp);

		route_to_user(hub, u, msg);
		user_flag_set(u, flag_flood);
		adc_msg_free(msg);
	}
}
Пример #15
0
/**
 * @param hub The hub instance this message is sent from.
 * @param user The user this message is sent to.
 * @param msg See enum status_message
 * @param level See enum status_level
 */
void hub_send_status(struct hub_info* hub, struct hub_user* user, enum status_message msg, enum msg_status_level level)
{
	struct hub_config* cfg = hub->config;
	struct adc_message* cmd = adc_msg_construct(ADC_CMD_ISTA, 6);
	struct adc_message* qui = adc_msg_construct(ADC_CMD_IQUI, 512);
	char code[4];
	char buf[256];
	const char* text = 0;
	const char* flag = 0;
	char* escaped_text = 0;
	int reconnect_time = 0;
	int redirect = 0;

	if (!cmd || !qui)
	{
		adc_msg_free(cmd);
		adc_msg_free(qui);
		return;
	}

#define STATUS(CODE, MSG, FLAG, RCONTIME, REDIRECT) case status_ ## MSG : set_status_code(level, CODE, code); text = cfg->MSG; flag = FLAG; reconnect_time = RCONTIME; redirect = REDIRECT; break
	switch (msg)
	{
		STATUS(11, msg_hub_full, 0, 600, 1); /* FIXME: Proper timeout? */
		STATUS(12, msg_hub_disabled, 0, -1, 1);
		STATUS(26, msg_hub_registered_users_only, 0, 0, 1);
		STATUS(43, msg_inf_error_nick_missing, 0, 0, 0);
		STATUS(43, msg_inf_error_nick_multiple, 0, 0, 0);
		STATUS(21, msg_inf_error_nick_invalid, 0, 0, 0);
		STATUS(21, msg_inf_error_nick_long, 0, 0, 0);
		STATUS(21, msg_inf_error_nick_short, 0, 0, 0);
		STATUS(21, msg_inf_error_nick_spaces, 0, 0, 0);
		STATUS(21, msg_inf_error_nick_bad_chars, 0, 0, 0);
		STATUS(21, msg_inf_error_nick_not_utf8, 0, 0, 0);
		STATUS(22, msg_inf_error_nick_taken, 0, 0, 0);
		STATUS(21, msg_inf_error_nick_restricted, 0, 0, 0);
		STATUS(43, msg_inf_error_cid_invalid, "FBID", 0, 0);
		STATUS(43, msg_inf_error_cid_missing, "FMID", 0, 0);
		STATUS(24, msg_inf_error_cid_taken, 0, 0, 0);
		STATUS(43, msg_inf_error_pid_missing, "FMPD", 0, 0);
		STATUS(27, msg_inf_error_pid_invalid, "FBPD", 0, 0);
		STATUS(31, msg_ban_permanently, 0, 0, 0);
		STATUS(32, msg_ban_temporarily, "TL600", 600, 0); /* FIXME: Proper timeout? */
		STATUS(23, msg_auth_invalid_password, 0, 0, 0);
		STATUS(20, msg_auth_user_not_found, 0, 0, 0);
		STATUS(30, msg_error_no_memory, 0, 0, 0);
		STATUS(43, msg_user_share_size_low,   "FB" ADC_INF_FLAG_SHARED_SIZE, 0, 1);
		STATUS(43, msg_user_share_size_high,  "FB" ADC_INF_FLAG_SHARED_SIZE, 0, 1);
		STATUS(43, msg_user_slots_low,        "FB" ADC_INF_FLAG_UPLOAD_SLOTS, 0, 1);
		STATUS(43, msg_user_slots_high,       "FB" ADC_INF_FLAG_UPLOAD_SLOTS, 0, 1);
		STATUS(43, msg_user_hub_limit_low, 0, 0, 1);
		STATUS(43, msg_user_hub_limit_high, 0, 0, 1);
		STATUS(47, msg_proto_no_common_hash, 0, -1, 1);
		STATUS(40, msg_proto_obsolete_adc0, 0, -1, 1);
	}
#undef STATUS

	escaped_text = adc_msg_escape(text);

	adc_msg_add_argument(cmd, code);
	adc_msg_add_argument(cmd, escaped_text);

	if (flag)
	{
		adc_msg_add_argument(cmd, flag);
	}

	route_to_user(hub, user, cmd);

	if (level >= status_level_fatal)
	{
		adc_msg_add_argument(qui, sid_to_string(user->id.sid));

		snprintf(buf, 230, "MS%s", escaped_text);
		adc_msg_add_argument(qui, buf);

		if (reconnect_time != 0)
		{
			snprintf(buf, 10, "TL%d", reconnect_time);
			adc_msg_add_argument(qui, buf);
		}

		if (redirect && *hub->config->redirect_addr)
		{
			snprintf(buf, 255, "RD%s", hub->config->redirect_addr);
			adc_msg_add_argument(qui, buf);
		}
		route_to_user(hub, user, qui);
	}

	hub_free(escaped_text);
	adc_msg_free(cmd);
	adc_msg_free(qui);
}
Пример #16
0
int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* line, size_t length)
{
	int ret = 0;
	struct adc_message* cmd = 0;

	LOG_PROTO("recv %s: %s", sid_to_string(u->id.sid), line);

	if (user_is_disconnecting(u))
		return -1;

	cmd = adc_msg_parse_verify(u, line, length);
	if (cmd)
	{
		switch (cmd->cmd)
		{
			case ADC_CMD_HSUP:
				CHECK_FLOOD(extras, 0);
				ret = hub_handle_support(hub, u, cmd);
				break;

			case ADC_CMD_HPAS:
				CHECK_FLOOD(extras, 0);
				ret = hub_handle_password(hub, u, cmd);
				break;

			case ADC_CMD_BINF:
				CHECK_FLOOD(update, 1);
				ret = hub_handle_info(hub, u, cmd);
				break;

			case ADC_CMD_DINF:
			case ADC_CMD_EINF:
			case ADC_CMD_FINF:
			case ADC_CMD_BQUI:
			case ADC_CMD_DQUI:
			case ADC_CMD_EQUI:
			case ADC_CMD_FQUI:
				/* these must never be allowed for security reasons, so we ignore them. */
				CHECK_FLOOD(extras, 1);
				break;

			case ADC_CMD_EMSG:
			case ADC_CMD_DMSG:
			case ADC_CMD_BMSG:
			case ADC_CMD_FMSG:
				CHECK_FLOOD(chat, 1);
				ret = hub_handle_chat_message(hub, u, cmd);
				break;

			case ADC_CMD_BSCH:
			case ADC_CMD_DSCH:
			case ADC_CMD_ESCH:
			case ADC_CMD_FSCH:
				cmd->priority = -1;
				if (plugin_handle_search(hub, u, cmd->cache) == st_deny)
					break;
				CHECK_FLOOD(search, 1);
				ROUTE_MSG;

			case ADC_CMD_FRES: // spam
			case ADC_CMD_BRES: // spam
			case ADC_CMD_ERES: // pointless.
				CHECK_FLOOD(extras, 1);
				break;

			case ADC_CMD_DRES:
				cmd->priority = -1;
				if (plugin_handle_search_result(hub, u, uman_get_user_by_sid(hub->users, cmd->target), cmd->cache) == st_deny)
					break;
				/* CHECK_FLOOD(search, 0); */
				ROUTE_MSG;

			case ADC_CMD_DRCM:
				cmd->priority = -1;
				if (plugin_handle_revconnect(hub, u, uman_get_user_by_sid(hub->users, cmd->target)) == st_deny)
					break;
				CHECK_FLOOD(connect, 1);
				ROUTE_MSG;

			case ADC_CMD_DCTM:
				cmd->priority = -1;
				if (plugin_handle_connect(hub, u, uman_get_user_by_sid(hub->users, cmd->target)) == st_deny)
					break;
				CHECK_FLOOD(connect, 1);
				ROUTE_MSG;

			case ADC_CMD_BCMD:
			case ADC_CMD_DCMD:
			case ADC_CMD_ECMD:
			case ADC_CMD_FCMD:
			case ADC_CMD_HCMD:
				CHECK_FLOOD(extras, 1);
				break;

			default:
				CHECK_FLOOD(extras, 1);
				ROUTE_MSG;
		}
		adc_msg_free(cmd);
	}
	else
	{
		if (!user_is_logged_in(u))
		{
			ret = -1;
		}
	}

	return ret;
}
Пример #17
0
void hub_send_hubinfo(struct hub_info* hub, struct hub_user* u)
{
	struct adc_message* info = adc_msg_copy(hub->command_info);
	int value = 0;
	uint64_t size = 0;

	if (user_flag_get(u, feature_ping))
	{
/*
		FIXME: These are missing:
		HH - Hub Host address ( DNS or IP )
		WS - Hub Website
		NE - Hub Network
		OW - Hub Owner name
*/
		adc_msg_add_named_argument(info, "UC", uhub_itoa(hub_get_user_count(hub)));
		adc_msg_add_named_argument(info, "MC", uhub_itoa(hub_get_max_user_count(hub)));
		adc_msg_add_named_argument(info, "SS", uhub_ulltoa(hub_get_shared_size(hub)));
		adc_msg_add_named_argument(info, "SF", uhub_ulltoa(hub_get_shared_files(hub)));

		/* Maximum/minimum share size */
		size = hub_get_max_share(hub);
		if (size) adc_msg_add_named_argument(info, "XS", uhub_ulltoa(size));
		size = hub_get_min_share(hub);
		if (size) adc_msg_add_named_argument(info, "MS", uhub_ulltoa(size));

		/* Maximum/minimum upload slots allowed per user */
		value = hub_get_max_slots(hub);
		if (value) adc_msg_add_named_argument(info, "XL", uhub_itoa(value));
		value = hub_get_min_slots(hub);
		if (value) adc_msg_add_named_argument(info, "ML", uhub_itoa(value));

		/* guest users must be on min/max hubs */
		value = hub_get_max_hubs_user(hub);
		if (value) adc_msg_add_named_argument(info, "XU", uhub_itoa(value));
		value = hub_get_min_hubs_user(hub);
		if (value) adc_msg_add_named_argument(info, "MU", uhub_itoa(value));

		/* registered users must be on min/max hubs */
		value = hub_get_max_hubs_reg(hub);
		if (value) adc_msg_add_named_argument(info, "XR", uhub_itoa(value));
		value = hub_get_min_hubs_reg(hub);
		if (value) adc_msg_add_named_argument(info, "MR", uhub_itoa(value));

		/* operators must be on min/max hubs */
		value = hub_get_max_hubs_op(hub);
		if (value) adc_msg_add_named_argument(info, "XO", uhub_itoa(value));
		value = hub_get_min_hubs_op(hub);
		if (value) adc_msg_add_named_argument(info, "MO", uhub_itoa(value));

		/* uptime in seconds */
		adc_msg_add_named_argument(info, "UP", uhub_itoa((int) difftime(time(0), hub->tm_started)));
	}

	if (user_is_connecting(u) || user_is_logged_in(u))
	{
		route_to_user(hub, u, info);
	}
	adc_msg_free(info);

	/* Only send banner when connecting */
	if (hub->config->show_banner && user_is_connecting(u))
	{
		route_to_user(hub, u, hub->command_banner);
	}
}
Пример #18
0
int hub_handle_support(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd)
{
	int ret = 0;
	int index = 0;
	int ok = 1;
	char* arg = adc_msg_get_argument(cmd, index);

	if (hub->status == hub_status_disabled && u->state == state_protocol)
	{
		on_login_failure(hub, u, status_msg_hub_disabled);
		hub_free(arg);
		return -1;
	}

	while (arg)
	{
		if (strlen(arg) == 6)
		{
			fourcc_t fourcc = FOURCC(arg[2], arg[3], arg[4], arg[5]);
			if (strncmp(arg, ADC_SUP_FLAG_ADD, 2) == 0)
			{
				user_support_add(u, fourcc);
			}
			else if (strncmp(arg, ADC_SUP_FLAG_REMOVE, 2) == 0)
			{
				user_support_remove(u, fourcc);
			}
			else
			{
				ok = 0;
			}
		}
		else
		{
			ok = 0;
		}

		index++;
		hub_free(arg);
		arg = adc_msg_get_argument(cmd, index);
	}

	if (u->state == state_protocol)
	{
		if (index == 0) ok = 0; /* Need to support *SOMETHING*, at least BASE */
		if (!ok)
		{
			/* disconnect user. Do not send crap during initial handshake! */
			hub_disconnect_user(hub, u, quit_logon_error);
			return -1;
		}

		if (user_flag_get(u, feature_base))
		{
			/* User supports ADC/1.0 and a hash we know */
			if (user_flag_get(u, feature_tiger))
			{
				hub_send_handshake(hub, u);
				/* TODO: timeouts for mux users */
				if (u->connection)
					net_con_set_timeout(u->connection, TIMEOUT_HANDSHAKE);
			}
			else
			{
				// no common hash algorithm.
				hub_send_status(hub, u, status_msg_proto_no_common_hash, status_level_fatal);
				hub_disconnect_user(hub, u, quit_protocol_error);
			}
		}
		else if (user_flag_get(u, feature_bas0))
		{
			if (hub->config->obsolete_clients)
			{
				hub_send_handshake(hub, u);
				/* TODO: timeouts for mux users */
				if (u->connection)
					net_con_set_timeout(u->connection, TIMEOUT_HANDSHAKE);
			}
			else
			{
				/* disconnect user for using an obsolete client. */
				char* tmp = adc_msg_escape(hub->config->msg_proto_obsolete_adc0);
				struct adc_message* message = adc_msg_construct(ADC_CMD_IMSG, 6 + strlen(tmp));
				adc_msg_add_argument(message, tmp);
				hub_free(tmp);
				route_to_user(hub, u, message);
				adc_msg_free(message);
				hub_disconnect_user(hub, u, quit_protocol_error);
			}
		}
		else
		{
			/* Not speaking a compatible protocol - just disconnect. */
			hub_disconnect_user(hub, u, quit_logon_error);
		}
	}

	return ret;
}
Пример #19
0
Файл: hub.c Проект: q3k/uhub
int hub_handle_message(struct hub_info* hub, struct hub_user* u, const char* line, size_t length)
{
	int ret = 0;
	struct adc_message* cmd = 0;

	LOG_PROTO("recv %s: %s", sid_to_string(u->id.sid), line);

	if (user_is_disconnecting(u))
		return -1;

	cmd = adc_msg_parse_verify(u, line, length);
	if (cmd)
	{
		switch (cmd->cmd)
		{
			case ADC_CMD_HSUP:
				CHECK_FLOOD(extras, 0);
				ret = hub_handle_support(hub, u, cmd);
				break;

			case ADC_CMD_HPAS:
				CHECK_FLOOD(extras, 0);
				ret = hub_handle_password(hub, u, cmd);
				break;

			case ADC_CMD_BINF:
				CHECK_FLOOD(update, 1);
				ret = hub_handle_info(hub, u, cmd);
				break;

			case ADC_CMD_DINF:
			case ADC_CMD_EINF:
			case ADC_CMD_FINF:
				/* these must never be allowed for security reasons, so we ignore them. */
				break;

			case ADC_CMD_EMSG:
			case ADC_CMD_DMSG:
			case ADC_CMD_BMSG:
			case ADC_CMD_FMSG:
				CHECK_FLOOD(chat, 1);
				ret = hub_handle_chat_message(hub, u, cmd);
				break;

			case ADC_CMD_BSCH:
			case ADC_CMD_DSCH:
			case ADC_CMD_ESCH:
			case ADC_CMD_FSCH:
				cmd->priority = -1;
				CHECK_CHAT_ONLY;
				CHECK_FLOOD(search, 1);
				ROUTE_MSG;

			case ADC_CMD_DRES:
				cmd->priority = -1;
				CHECK_CHAT_ONLY;
				/* CHECK_FLOOD(search, 0); */
				ROUTE_MSG;

			case ADC_CMD_DRCM:
			case ADC_CMD_DCTM:
				cmd->priority = -1;
				CHECK_CHAT_ONLY;
				CHECK_FLOOD(connect, 1);
				ROUTE_MSG;

			default:
				CHECK_FLOOD(extras, 1);
				ROUTE_MSG;
		}
		adc_msg_free(cmd);
	}
	else
	{
		if (!user_is_logged_in(u))
		{
			ret = -1;
		}
	}

	return ret;
}
Пример #20
0
/*
 * If user is in the connecting state, we need to do fairly
 * strict checking of all arguments.
 * This means we disconnect users when they provide invalid data
 * during the login sequence.
 * When users are merely updating their data after successful login
 * we can just ignore any invalid data and not broadcast it.
 *
 * The data we need to check is:
 * - nick name (valid, not taken, etc)
 * - CID/PID (valid, not taken, etc).
 * - IP addresses (IPv4 and IPv6)
 */
int hub_handle_info(struct hub_info* hub, struct hub_user* user, const struct adc_message* cmd_unmodified)
{
	int ret;
	struct adc_message* cmd = adc_msg_copy(cmd_unmodified);
	if (!cmd) return -1; /* OOM */

	cmd->priority = 1;

	hub_handle_info_common(user, cmd);

	/* If user is logging in, perform more checks,
	   otherwise only a few things need to be checked.
	 */
	if (user_is_connecting(user))
	{
		/*
		 * Don't allow the user to send multiple INF messages in this stage!
		 * Since that can have serious side-effects.
		 */
		if (user->info)
		{
			adc_msg_free(cmd);
			return 0;
		}

		ret = hub_handle_info_login(hub, user, cmd);
		if (ret < 0)
		{
			on_login_failure(hub, user, ret);
			adc_msg_free(cmd);
			return -1;
		}
		else
		{
			/* Post a message, the user has joined */
			struct event_data post;
			memset(&post, 0, sizeof(post));
			post.id    = UHUB_EVENT_USER_JOIN;
			post.ptr   = user;
			post.flags = ret; /* 0 - all OK, 1 - need authentication */
			event_queue_post(hub->queue, &post);
			adc_msg_free(cmd);
			return 0;
		}
	}
	else
	{
		/* These must not be allowed updated, let's remove them! */
		adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_PRIVATE_ID);
		adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_CLIENT_ID);

		/*
		 * If the nick is not accepted, do not relay it.
		 * Otherwise, the nickname will be updated.
		 */
		if (adc_msg_has_named_argument(cmd, ADC_INF_FLAG_NICK))
		{
#ifdef ALLOW_CHANGE_NICK
			if (!check_nick(hub, user, cmd))
#endif
				adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_NICK);
		}

		ret = check_limits(hub, user, cmd);
		if (ret < 0)
		{
			on_update_failure(hub, user, ret);
			adc_msg_free(cmd);
			return -1;
		}

		strip_network(user, cmd);
		hub_handle_info_low_bandwidth(hub, user, cmd);

		user_update_info(user, cmd);

		if (!adc_msg_is_empty(cmd))
		{
			route_message(hub, user, cmd);
		}

		adc_msg_free(cmd);
	}

	return 0;
}
Пример #21
0
static int ADC_client_on_recv_line(struct ADC_client* client, const char* line, size_t length)
{
	struct ADC_chat_message chat;
	struct ADC_client_callback_data data;

	ADC_TRACE;
#ifdef ADC_CLIENT_DEBUG_PROTO
	ADC_client_debug(client, "- LINE: '%s'", line);
#endif

	/* Parse message */
	struct adc_message* msg = adc_msg_parse(line, length);
	if (!msg)
	{
		ADC_client_debug(client, "WARNING: Message cannot be decoded: \"%s\"", line);
		return -1;
	}

	if (length < 4)
	{
		ADC_client_debug(client, "Unexpected response from hub: '%s'", line);
		return -1;
	}

	switch (msg->cmd)
	{
		case ADC_CMD_ISUP:
			break;

		case ADC_CMD_ISID:
			if (client->state == ps_protocol)
			{
				client->sid = string_to_sid(&line[5]);
				client->callback(client, ADC_CLIENT_LOGGING_IN, 0);
				ADC_client_set_state(client, ps_identify);
				ADC_client_send_info(client);
			}
			break;

		case ADC_CMD_BMSG:
		case ADC_CMD_EMSG:
		case ADC_CMD_DMSG:
		case ADC_CMD_IMSG:
		{
			chat.from_sid       = msg->source;
			chat.to_sid         = msg->target;
			data.chat = &chat;
			EXTRACT_POS_ARG(msg, 0, chat.message);
			chat.flags = 0;

			if (adc_msg_has_named_argument(msg, ADC_MSG_FLAG_ACTION))
				chat.flags |= chat_flags_action;

			if (adc_msg_has_named_argument(msg, ADC_MSG_FLAG_PRIVATE))
				chat.flags |= chat_flags_private;

			client->callback(client, ADC_CLIENT_MESSAGE, &data);
			hub_free(chat.message);
			break;
		}

		case ADC_CMD_IINF:
		{
			struct ADC_hub_info hubinfo;
			EXTRACT_NAMED_ARG(msg, "NI", hubinfo.name);
			EXTRACT_NAMED_ARG(msg, "DE", hubinfo.description);
			EXTRACT_NAMED_ARG(msg, "VE", hubinfo.version);

			struct ADC_client_callback_data data;
			data.hubinfo = &hubinfo;
			client->callback(client, ADC_CLIENT_HUB_INFO, &data);
			hub_free(hubinfo.name);
			hub_free(hubinfo.description);
			hub_free(hubinfo.version);
			break;
		}

		case ADC_CMD_BSCH:
		case ADC_CMD_FSCH:
		{
			client->callback(client, ADC_CLIENT_SEARCH_REQ, 0);
			break;
		}

		case ADC_CMD_BINF:
		{
			if (msg->source == client->sid)
			{
				if (client->state == ps_verify || client->state == ps_identify)
				{
					ADC_client_on_login(client);
				}
			}
			else
			{
				if (adc_msg_has_named_argument(msg, "ID"))
				{
					struct ADC_user user;
					user.sid = msg->source;
					EXTRACT_NAMED_ARG_X(msg, "NI", user.name, sizeof(user.name));
					EXTRACT_NAMED_ARG_X(msg, "DE", user.description, sizeof(user.description));
					EXTRACT_NAMED_ARG_X(msg, "VE", user.version, sizeof(user.version));
					EXTRACT_NAMED_ARG_X(msg, "ID", user.cid, sizeof(user.cid));
					EXTRACT_NAMED_ARG_X(msg, "I4", user.address, sizeof(user.address));

					struct ADC_client_callback_data data;
					data.user = &user;
					client->callback(client, ADC_CLIENT_USER_JOIN, &data);
				}
			}
		}
		break;

		case ADC_CMD_IQUI:
		{
			struct ADC_client_quit_reason reason;
			memset(&reason, 0, sizeof(reason));
			reason.sid = string_to_sid(&line[5]);

			if (adc_msg_has_named_argument(msg, ADC_QUI_FLAG_DISCONNECT))
				reason.flags |= 1;

			data.quit = &reason;
			client->callback(client, ADC_CLIENT_USER_QUIT, &data);
			break;
		}

		case ADC_CMD_ISTA:
			/*
			if (strncmp(line, "ISTA 000", 8))
			{
				ADC_client_debug(client, "status: '%s'\n", (start + 9));
			}
			*/
			break;

		default:
			break;
	}

	adc_msg_free(msg);
	return 0;
}