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; }
void hub_send_support(struct hub_info* hub, struct hub_user* u) { if (user_is_connecting(u) || user_is_logged_in(u)) { route_to_user(hub, u, hub->command_support); } }
int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate users */ { struct hub_user* user; LIST_FOREACH(struct hub_user*, user, hub->users->list, { route_to_user(hub, user, command); });
int uman_send_user_list(struct hub_info* hub, struct hub_user* target) { int ret = 1; struct hub_user* user; user_flag_set(target, flag_user_list); user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on INF or PAS msg */ while (user) { if (user_is_logged_in(user)) { ret = route_to_user(hub, target, user->info); if (!ret) break; } user = (struct hub_user*) list_get_next(hub->users->list); } #if 0 FIXME: FIXME FIXME handle send queue excess if (!target->send_queue_size) { user_flag_unset(target, flag_user_list); } #endif return ret; }
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); }
int hub_send_rules(struct hub_info* hub, struct hub_user* u) { if (hub->command_rules) { route_to_user(hub, u, hub->command_rules); return 1; } return 0; }
int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate users */ { struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); while (user) { route_to_user(hub, user, command); user = (struct hub_user*) list_get_next(hub->users->list); } return 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); }
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); } }
int route_message(struct hub_info* hub, struct hub_user* u, struct adc_message* msg) { struct hub_user* target = NULL; switch (msg->cache[0]) { case 'B': /* Broadcast to all logged in clients */ route_to_all(hub, msg); break; case 'D': target = uman_get_user_by_sid(hub->users, msg->target); if (target) { route_to_user(hub, target, msg); } break; case 'E': target = uman_get_user_by_sid(hub->users, msg->target); if (target) { route_to_user(hub, target, msg); route_to_user(hub, u, msg); } break; case 'F': route_to_subscribers(hub, msg); break; default: /* Ignore the message */ break; } return 0; }
int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* iterate users */ { int do_send; char* tmp; struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); while (user) { if (user->feature_cast) { do_send = 1; tmp = list_get_first(command->feature_cast_include); while (tmp) { if (!user_have_feature_cast_support(user, tmp)) { do_send = 0; break; } tmp = list_get_next(command->feature_cast_include);; } if (!do_send) { user = (struct hub_user*) list_get_next(hub->users->list); continue; } tmp = list_get_first(command->feature_cast_exclude); while (tmp) { if (user_have_feature_cast_support(user, tmp)) { do_send = 0; break; } tmp = list_get_next(command->feature_cast_exclude); } if (do_send) { route_to_user(hub, user, command); } } user = (struct hub_user*) list_get_next(hub->users->list); } return 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); } }
/** * @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); }
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); } }
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; }