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); }
void hub_chat_history_add(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd) { char* msg_esc = adc_msg_get_argument(cmd, 0); char* message = adc_msg_unescape(msg_esc); char* log = hub_malloc(strlen(message) + strlen(user->id.nick) + 14); sprintf(log, "%s <%s> %s\n", get_timestamp(time(NULL)), user->id.nick, message); list_append(hub->chat_history, log); while (list_size(hub->chat_history) > (size_t) hub->config->max_chat_history) { char* msg = list_get_first(hub->chat_history); list_remove(hub->chat_history, msg); hub_free(msg); } hub_free(message); hub_free(msg_esc); }
int hub_handle_password(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd) { char* password = adc_msg_get_argument(cmd, 0); int ret = 0; if (u->state == state_verify) { if (acl_password_verify(hub, u, password)) { on_login_success(hub, u); } else { on_login_failure(hub, u, status_msg_auth_invalid_password); ret = -1; } } hub_free(password); return ret; }
int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc_message* cmd) { char* message = adc_msg_get_argument(cmd, 0); char* message_decoded = NULL; int ret = 0; int relay = 1; int broadcast; int private_msg; int command; int offset; if (!message) return 0; message_decoded = adc_msg_unescape(message); if (!message_decoded) { hub_free(message); return 0; } if (!user_is_logged_in(u)) { hub_free(message); return 0; } broadcast = (cmd->cache[0] == 'B'); private_msg = (cmd->cache[0] == 'D' || cmd->cache[0] == 'E'); command = (message[0] == '!' || message[0] == '+'); if (broadcast && command) { /* * A message such as "++message" is handled as "+message", by removing the first character. * The first character is removed by memmoving the string one byte to the left. */ if (message[1] == message[0]) { relay = 1; offset = adc_msg_get_arg_offset(cmd); memmove(cmd->cache+offset+1, cmd->cache+offset+2, cmd->length - offset); cmd->length--; } else { relay = command_invoke(hub->commands, u, message_decoded); } } /* FIXME: Plugin should do this! */ if (relay && (((hub->config->chat_is_privileged && !user_is_protected(u)) || (user_flag_get(u, flag_muted))) && broadcast)) { relay = 0; } if (relay) { plugin_st status = st_default; if (broadcast) { status = plugin_handle_chat_message(hub, u, message_decoded, 0); } else if (private_msg) { struct hub_user* target = uman_get_user_by_sid(hub->users, cmd->target); if (target) status = plugin_handle_private_message(hub, u, target, message_decoded, 0); else relay = 0; } if (status == st_deny) relay = 0; } if (relay) { /* adc_msg_remove_named_argument(cmd, "PM"); */ if (broadcast) { plugin_log_chat_message(hub, u, message_decoded, 0); } ret = route_message(hub, u, cmd); } hub_free(message); hub_free(message_decoded); return ret; }
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; }