From 318163c0660f3078bc01e234ae47f1767b36b622 Mon Sep 17 00:00:00 2001 From: Jan Vidar Krey Date: Fri, 9 Dec 2011 10:29:50 +0100 Subject: [PATCH] Added support for dynamic commands. Dynamic commands are user commands that can be added dynamically to the hub by a plugin. The example plugin (mod_example.c) adds a !example command that when invoked send a message to the user who invoked it. --- AUTHORS | 10 +- GNUmakefile | 10 +- src/adc/adcconst.h | 4 + src/core/commands.c | 749 +++++++++++++++++++++--------------- src/core/commands.h | 83 +++- src/core/commands_builtin.c | 0 src/core/commands_builtin.h | 3 + src/core/hub.c | 8 +- src/core/hub.h | 2 + src/core/inf.c | 2 +- src/core/plugincallback.c | 147 +++++++ src/core/plugincallback.h | 32 ++ src/core/plugininvoke.c | 76 ++-- src/core/plugininvoke.h | 2 +- src/core/pluginloader.c | 69 +++- src/core/pluginloader.h | 11 +- src/core/user.h | 8 +- src/plugin_api/handle.h | 98 ++--- src/plugins/mod_example.c | 36 +- src/tools/admin.c | 6 +- src/uhub.h | 2 + vs2010/uhub.sln | 6 + vs2010/uhub.vcxproj | 4 + 23 files changed, 907 insertions(+), 461 deletions(-) create mode 100644 src/core/commands_builtin.c create mode 100644 src/core/commands_builtin.h create mode 100644 src/core/plugincallback.c create mode 100644 src/core/plugincallback.h diff --git a/AUTHORS b/AUTHORS index 650d184..38e2985 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,11 +1,9 @@ -Authors of uHub +Authors of uhub =============== Jan Vidar Krey, Design and implementation E_zombie, Centos/RedHat customization scripts and heavy load testing - -Thanks to: -========== - -tehnick, Fixing Debian's lintian warnings. +FleetCommand, Hub topic +MiMic, Implemented user commands +tehnick, Debian and Ubuntu packaging. diff --git a/GNUmakefile b/GNUmakefile index cf65afc..b7347fd 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -139,6 +139,7 @@ libuhub_SOURCES := \ src/core/route.c \ src/core/user.c \ src/core/usermanager.c \ + src/core/plugincallback.c \ src/core/plugininvoke.c \ src/core/pluginloader.c \ src/network/backend.c \ @@ -208,6 +209,8 @@ plugin_auth_sqlite_SOURCES := src/plugins/mod_auth_sqlite.c plugin_auth_sqlite_TARGET := mod_auth_sqlite.so plugin_auth_sqlite_LIBS := -lsqlite3 +plugin_chat_history_SOURCE := src/plugins/mod_chat_history.c +plugin_chat_history_TARGET := mod_chat_history.so # Source to objects libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o) @@ -220,7 +223,7 @@ adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o) admin_OBJECTS := $(admin_SOURCES:.c=.o) all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(libutils_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS) -all_plugins := +all_plugins := $(plugin_example_TARGET) $(plugin_logging_TARGET) $(plugin_auth_TARGET) $(plugin_auth_sqlite_TARGET) $(plugin_chat_history_TARGET) uhub_BINARY=uhub$(BIN_EXT) adcrush_BINARY=adcrush$(BIN_EXT) @@ -247,12 +250,15 @@ $(plugin_auth_TARGET): $(plugin_auth_SOURCES) $(libutils_OBJECTS) $(plugin_auth_sqlite_TARGET): $(plugin_auth_sqlite_SOURCES) $(libutils_OBJECTS) $(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS) $(LDFLAGS) $(plugin_auth_sqlite_LIBS) -$(plugin_example_TARGET): $(plugin_example_SOURCES) +$(plugin_example_TARGET): $(plugin_example_SOURCES) $(libutils_OBJECTS) $(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS) $(plugin_logging_TARGET): $(plugin_logging_SOURCES) $(libutils_OBJECTS) $(libadc_common_OBJECTS) src/network/network.o $(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS) +$(plugin_chat_history_TARGET): $(plugin_chat_history_SOURCE) $(libutils_OBJECTS) + $(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS) + $(adcrush_BINARY): $(adcrush_OBJECTS) $(libuhub_OBJECTS) $(libutils_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS) $(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) diff --git a/src/adc/adcconst.h b/src/adc/adcconst.h index 35d6564..f78db84 100644 --- a/src/adc/adcconst.h +++ b/src/adc/adcconst.h @@ -20,7 +20,11 @@ #ifndef HAVE_UHUB_ADC_CONSTANTS_H #define HAVE_UHUB_ADC_CONSTANTS_H +#ifndef SID_T_DEFINED typedef uint32_t sid_t; +#define SID_T_DEFINED +#endif + typedef uint32_t fourcc_t; /* Internal uhub limit */ diff --git a/src/core/commands.c b/src/core/commands.c index 62b0f20..eac9c4d 100644 --- a/src/core/commands.c +++ b/src/core/commands.c @@ -25,90 +25,65 @@ #define MAX_HELP_MSG 1024 -struct hub_command +static int command_access_denied(struct command_base* cbase, struct hub_user* user, const char* prefix); +static int command_not_found(struct command_base* cbase, struct hub_user* user, const char* prefix); +static int command_syntax_error(struct command_base* cbase, struct hub_user* user); + +struct command_base { - const char* message; - char* prefix; - size_t prefix_len; - struct linked_list* args; + struct hub_info* hub; + struct linked_list* handlers; + size_t prefix_length_max; }; -typedef int (*command_handler)(struct hub_info* hub, struct hub_user* user, struct hub_command*); - -struct commands_handler +struct command_base* command_initialize(struct hub_info* hub) { - const char* prefix; - size_t length; - const char* args; - enum auth_credentials cred; - command_handler handler; - const char* description; -}; + struct command_base* cbase = (struct command_base*) hub_malloc(sizeof(struct command_base)); + uhub_assert(cbase != NULL); + uhub_assert(hub != NULL); -#define FORWARD_DECL_CMD(X) static int X(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) + cbase->hub = hub; + cbase->handlers = (struct linked_list*) list_create(); + cbase->prefix_length_max = 0; -FORWARD_DECL_CMD(command_ban); -FORWARD_DECL_CMD(command_broadcast); -FORWARD_DECL_CMD(command_crash); -FORWARD_DECL_CMD(command_getip); -FORWARD_DECL_CMD(command_help); -FORWARD_DECL_CMD(command_history); -FORWARD_DECL_CMD(command_kick); -FORWARD_DECL_CMD(command_log); -FORWARD_DECL_CMD(command_motd); -FORWARD_DECL_CMD(command_mute); -FORWARD_DECL_CMD(command_myip); -FORWARD_DECL_CMD(command_register); -FORWARD_DECL_CMD(command_reload); -FORWARD_DECL_CMD(command_rules); -FORWARD_DECL_CMD(command_password); -FORWARD_DECL_CMD(command_shutdown); -FORWARD_DECL_CMD(command_stats); -FORWARD_DECL_CMD(command_unban); -FORWARD_DECL_CMD(command_uptime); -FORWARD_DECL_CMD(command_useradd); -FORWARD_DECL_CMD(command_userdel); -FORWARD_DECL_CMD(command_userinfo); -FORWARD_DECL_CMD(command_usermod); -FORWARD_DECL_CMD(command_userpass); -FORWARD_DECL_CMD(command_version); -FORWARD_DECL_CMD(command_whoip); + uhub_assert(cbase->handlers != NULL); -#undef FORWARD_DECL_CMD + commands_builtin_add(cbase); -static struct commands_handler command_handlers[] = { - { "ban", 3, "n", auth_cred_operator, command_ban, "Ban a user" }, - { "broadcast", 9, "m", auth_cred_operator, command_broadcast,"Send a message to all users" }, -#ifdef CRASH_DEBUG - { "crash", 5, 0, auth_cred_admin, command_crash, "Crash the hub (DEBUG)." }, -#endif - { "getip", 5, "n", auth_cred_operator, command_getip, "Show IP address for a user" }, - { "help", 4, "?c",auth_cred_guest, command_help, "Show this help message." }, - { "history", 7, "?N",auth_cred_guest, command_history, "Show the last chat messages." }, - { "kick", 4, "n", auth_cred_operator, command_kick, "Kick a user" }, - { "log", 3, 0, auth_cred_operator, command_log, "Display log" }, - { "motd", 4, 0, auth_cred_guest, command_motd, "Show the message of the day" }, - { "mute", 4, "n", auth_cred_operator, command_mute, "Mute user" }, - { "myip", 4, 0, auth_cred_guest, command_myip, "Show your own IP." }, - { "register", 8, "p", auth_cred_guest, command_register, "Register your username." }, - { "reload", 6, 0, auth_cred_admin, command_reload, "Reload configuration files." }, - { "rules", 5, 0, auth_cred_guest, command_rules, "Show the hub rules" }, - { "password", 8, "p", auth_cred_user, command_password, "Change your own password." }, - { "shutdown", 8, 0, auth_cred_admin, command_shutdown, "Shutdown hub." }, - { "stats", 5, 0, auth_cred_super, command_stats, "Show hub statistics." }, - { "unban", 5, "n", auth_cred_operator, command_unban, "Lift ban on a user" }, - { "unmute", 6, "n", auth_cred_operator, command_mute, "Unmute user" }, - { "uptime", 6, 0, auth_cred_guest, command_uptime, "Display hub uptime info." }, - { "useradd", 7, "np",auth_cred_operator, command_useradd, "Register a new user." }, - { "userdel", 7, "n", auth_cred_operator, command_userdel, "Delete a registered user." }, - { "userinfo", 8, "n", auth_cred_operator, command_userinfo, "Show registered user info." }, - { "usermod", 7, "nC",auth_cred_admin, command_usermod, "Modify user credentials." }, - { "userpass", 8, "np",auth_cred_operator, command_userpass, "Change password for a user." }, - { "version", 7, 0, auth_cred_guest, command_version, "Show hub version info." }, - { "whoip", 5, "a", auth_cred_operator, command_whoip, "Show users matching IP range" }, - { 0, 0, 0, auth_cred_none, command_help, "" } -}; + return cbase; +} +void command_shutdown(struct command_base* cbase) +{ + commands_builtin_remove(cbase); + assert(list_size(cbase->handlers) == 0); + hub_free(cbase); +} + +int command_add(struct command_base* cbase, struct command_handle* cmd, void* ptr) +{ + uhub_assert(cbase != NULL); + uhub_assert(cmd != NULL); + uhub_assert(cmd->length == strlen(cmd->prefix)); + uhub_assert(cmd->handler != NULL); + uhub_assert(cmd->description && *cmd->description); + list_append(cbase->handlers, cmd); + cbase->prefix_length_max = MAX(cmd->length, cbase->prefix_length_max); + cmd->ptr = ptr; + return 1; +} + +int command_del(struct command_base* cbase, struct command_handle* cmd) +{ + uhub_assert(cbase != NULL); + uhub_assert(cmd != NULL); + list_remove(cbase->handlers, cmd); + return 1; +} + +/** + * Destroy / free a command created by command_create(). + */ static void command_destroy(struct hub_command* cmd) { if (!cmd) return; @@ -123,75 +98,192 @@ static void command_destroy(struct hub_command* cmd) hub_free(cmd); } -static struct hub_command* command_create(const char* message) +static struct command_handle* command_handler_lookup(struct command_base* cbase, const char* prefix) +{ + struct command_handle* handler = NULL; + size_t prefix_len = strlen(prefix); + + for (handler = (struct command_handle*) list_get_first(cbase->handlers); handler; handler = (struct command_handle*) list_get_next(cbase->handlers)) + { + if (prefix_len != handler->length) + continue; + + if (!strncmp(prefix, handler->prefix, handler->length)) + { + return handler; + } + } + return NULL; +} + +static struct linked_list* command_extract_arguments(struct command_base* cbase, struct command_handle* command, struct linked_list* tokens) +{ + int arg = 0; + int opt = 0; + char* token = NULL; + struct hub_user* target = NULL; + struct command_handle* target_command = NULL; + enum auth_credentials cred; + struct linked_list* args = list_create(); + + + if (!args) + return NULL; + + while ((token = list_get_first(tokens))) + { + switch (command->args[arg++]) + { + case '?': + uhub_assert(opt == 0); + opt = 1; + continue; + + case 'n': + target = uman_get_user_by_nick(cbase->hub, token); + if (!target) + { + list_destroy(args); + return NULL; + } + list_append(args, target); + break; + + case 'i': + uman_get_user_by_cid(cbase->hub, token); + if (!target) + { + list_destroy(args); + return NULL; + } + list_append(args, target); + break; + + case 'a': + if (!(ip_is_valid_ipv4(token) || ip_is_valid_ipv6(token))) + { + list_destroy(args); + return NULL; + } + list_append(args, token); + break; + + case 'm': + case 'p': + list_append(args, token); + break; + + case 'c': + target_command = command_handler_lookup(cbase, token); + if (!target_command) + { + list_destroy(args); + return NULL; + } + list_append(args, target_command); + break; + + case 'C': + if (!auth_string_to_cred(token, &cred)) + { + list_destroy(args); + return NULL; + } + list_append(args, (void*) cred); + break; + + case 'N': + list_append(args, (void*) (int*) (intptr_t) uhub_atoi(token)); + break; + + case '\0': + if (!opt) + { + list_destroy(args); + return NULL; + } + return args; + } + list_remove(tokens, token); + } + + return args; +} + +/** + * Parse a command and break it down into a struct hub_command. + */ +static int command_parse(struct command_base* cbase, struct hub_user* user, const char* message) { char* prefix; int n; struct hub_command* cmd = hub_malloc_zero(sizeof(struct hub_command)); + struct command_handle* handler = NULL; + struct linked_list* tokens = NULL; if (!cmd) return 0; cmd->message = message; - cmd->args = list_create(); + cmd->args = NULL; + tokens = list_create(); - n = split_string(message, "\\s", cmd->args, 0); + n = split_string(message, "\\s", tokens, 0); if (n <= 0) { command_destroy(cmd); + // FIXME return 0; } - prefix = list_get_first(cmd->args); + // Find a matching command handler + prefix = list_get_first(tokens); if (prefix && prefix[0] && prefix[1]) { cmd->prefix = hub_strdup(&prefix[1]); cmd->prefix_len = strlen(cmd->prefix); + handler = command_handler_lookup(cbase, cmd->prefix); + if (!handler) + { + return command_not_found(cbase, user, prefix); + } } else { command_destroy(cmd); + command_syntax_error(cbase, user); return 0; } - list_remove(cmd->args, prefix); + + // Remove the first token. + list_remove(tokens, prefix); hub_free(prefix); - return cmd; + + // Parse arguments + cmd->args = command_extract_arguments(cbase, handler, tokens); + list_clear(tokens, &hub_free); + list_destroy(tokens); + + if (!cmd->args) + { + command_destroy(cmd); + // FIXME + return 0; + } + + if (command_is_available(handler, user)) + { + handler->handler(cbase, user, handler, cmd); + command_destroy(cmd); + return 0; + } + else + { + command_destroy(cmd); + return command_access_denied(cbase, user, prefix); + } } -static void send_message(struct hub_info* hub, struct hub_user* user, const char* message) -{ - char* buffer = adc_msg_escape(message); - struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6); - adc_msg_add_argument(command, buffer); - route_to_user(hub, user, command); - adc_msg_free(command); - hub_free(buffer); -} - -static int command_access_denied(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) -{ - char temp[128]; - snprintf(temp, 128, "*** %s: Access denied.", cmd->prefix); - send_message(hub, user, temp); - return 0; -} - -static int command_not_found(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) -{ - char temp[128]; - snprintf(temp, 128, "*** %s: Command not found", cmd->prefix); - send_message(hub, user, temp); - return 0; -} - -static int command_status_user_not_found(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, const char* nick) -{ - char temp[128]; - snprintf(temp, 128, "*** %s: No user \"%s\"", cmd->prefix, nick); - send_message(hub, user, temp); - return 0; -} - -const char* command_get_syntax(struct commands_handler* handler) +const char* command_get_syntax(struct command_handle* handler) { static char args[128]; size_t n = 0; @@ -224,7 +316,43 @@ const char* command_get_syntax(struct commands_handler* handler) return args; } -static size_t command_count_required_args(struct commands_handler* handler) + +void send_message(struct command_base* cbase, struct hub_user* user, const char* message) +{ + char* buffer = adc_msg_escape(message); + struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6); + adc_msg_add_argument(command, buffer); + route_to_user(cbase->hub, user, command); + adc_msg_free(command); + hub_free(buffer); +} + +static int command_access_denied(struct command_base* cbase, struct hub_user* user, const char* prefix) +{ + char temp[128]; + snprintf(temp, 128, "*** %s: Access denied.", prefix); + send_message(cbase, user, temp); + return 0; +} + +static int command_not_found(struct command_base* cbase, struct hub_user* user, const char* prefix) +{ + char temp[128]; + snprintf(temp, 128, "*** %s: Command not found", prefix); + send_message(cbase, user, temp); + return 0; +} + + +static int command_syntax_error(struct command_base* cbase, struct hub_user* user) +{ + send_message(cbase, user, "*** Syntax error"); + return 0; +} + + + +static size_t command_count_required_args(struct command_handle* handler) { size_t n = 0; for (n = 0; n < strlen(handler->args); n++) @@ -235,7 +363,7 @@ static size_t command_count_required_args(struct commands_handler* handler) return n; } -int command_check_args(struct hub_command* cmd, struct commands_handler* handler) +int command_check_args(struct hub_command* cmd, struct command_handle* handler) { if (!handler->args) return 1; @@ -246,101 +374,89 @@ int command_check_args(struct hub_command* cmd, struct commands_handler* handler return 0; } -static int command_arg_mismatch(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, struct commands_handler* handler) +int command_invoke(struct command_base* cbase, struct hub_user* user, const char* message) { - char temp[256]; - const char* args = command_get_syntax(handler); - if (args) snprintf(temp, 256, "*** %s: Use: !%s %s", cmd->prefix, cmd->prefix, args); - else snprintf(temp, 256, "*** %s: Use: !%s", cmd->prefix, cmd->prefix); - send_message(hub, user, temp); - return 0; + return command_parse(cbase, user, message); } -static int command_status(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd, const char* message) +int command_is_available(struct command_handle* handle, struct hub_user* user) +{ + uhub_assert(handle != NULL); + uhub_assert(user != NULL); + return handle->cred <= user->credentials; +} + + +static int command_status(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd, const char* message) { char temp[1024]; snprintf(temp, 1024, "*** %s: %s", cmd->prefix, message); - send_message(hub, user, temp); + send_message(cbase, user, temp); return 0; } -static int command_stats(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_status_user_not_found(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd, const char* nick) { char temp[128]; - snprintf(temp, 128, PRINTF_SIZE_T " users, peak: " PRINTF_SIZE_T ". Network (up/down): %d/%d KB/s, peak: %d/%d KB/s", - hub->users->count, - hub->users->count_peak, - (int) hub->stats.net_tx / 1024, - (int) hub->stats.net_rx / 1024, - (int) hub->stats.net_tx_peak / 1024, - (int) hub->stats.net_rx_peak / 1024); - return command_status(hub, user, cmd, temp); + snprintf(temp, 128, "*** %s: No user \"%s\"", cmd->prefix, nick); + send_message(cbase, user, temp); + return 0; } -static int command_help(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_help(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - size_t n; char msg[MAX_HELP_MSG]; - char* command = list_get_first(cmd->args); + struct command_handle* command = list_get_first(cmd->args); + size_t n = 0; msg[0] = 0; if (!command) { strcat(msg, "Available commands:\n"); - for (n = 0; command_handlers[n].prefix; n++) + for (command = (struct command_handle*) list_get_first(cbase->handlers); command; command = (struct command_handle*) list_get_next(cbase->handlers)) { - if (command_handlers[n].cred <= user->credentials) + if (command_is_available(command, user)) { strcat(msg, "!"); - strcat(msg, command_handlers[n].prefix); - strcat(msg, " - "); - strcat(msg, command_handlers[n].description); + strcat(msg, command->prefix); + for (n = command->length; n < cbase->prefix_length_max; n++) + { + strcat(msg, " "); + } + strcat(msg, "- "); + strcat(msg, command->description); strcat(msg, "\n"); } } } else { - int found = 0; - for (n = 0; command_handlers[n].prefix; n++) + if (command_is_available(command, user)) { - if (strcmp(command, command_handlers[n].prefix) == 0) - { - found = 1; - if (command_handlers[n].cred <= user->credentials) - { - strcat(msg, "Usage: !"); - strcat(msg, command_handlers[n].prefix); - strcat(msg, " "); - strcat(msg, command_get_syntax(&command_handlers[n])); - strcat(msg, "\n"); - - strcat(msg, command_handlers[n].description); - strcat(msg, "\n"); - } - else - { - strcat(msg, "This command is not available to you.\n"); - } - } + strcat(msg, "Usage: !"); + strcat(msg, command->prefix); + strcat(msg, " "); + strcat(msg, command_get_syntax(command)); + strcat(msg, "\n"); + strcat(msg, command->description); + strcat(msg, "\n"); } - - if (!found) + else { - snprintf(msg, sizeof(msg), "Command \"%s\" not found.\n", command); + strcat(msg, "This command is not available to you.\n"); } } - return command_status(hub, user, cmd, msg); + return command_status(cbase, user, cmd, msg); } -static int command_uptime(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_uptime(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char tmp[128]; size_t d; size_t h; size_t m; - size_t D = (size_t) difftime(time(0), hub->tm_started); + size_t D = (size_t) difftime(time(0), cbase->hub->tm_started); d = D / (24 * 3600); D = D % (24 * 3600); @@ -363,66 +479,66 @@ static int command_uptime(struct hub_info* hub, struct hub_user* user, struct hu if (m < 10) strcat(tmp, "0"); strcat(tmp, uhub_itoa((int) m)); - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } -static int command_kick(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_kick(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char* nick = list_get_first(cmd->args); struct hub_user* target; if (!nick) return -1; // FIXME: bad syntax. - target = uman_get_user_by_nick(hub, nick); + target = uman_get_user_by_nick(cbase->hub, nick); if (!target) - return command_status_user_not_found(hub, user, cmd, nick); + return command_status_user_not_found(cbase, user, cmd, nick); if (target == user) - return command_status(hub, user, cmd, "Cannot kick yourself"); + return command_status(cbase, user, cmd, "Cannot kick yourself"); - hub_disconnect_user(hub, target, quit_kicked); - return command_status(hub, user, cmd, nick); + hub_disconnect_user(cbase->hub, target, quit_kicked); + return command_status(cbase, user, cmd, nick); } -static int command_ban(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_ban(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char* nick = list_get_first(cmd->args); struct hub_user* target; if (!nick) return -1; // FIXME: bad syntax. - target = uman_get_user_by_nick(hub, nick); + target = uman_get_user_by_nick(cbase->hub, nick); if (!target) - return command_status_user_not_found(hub, user, cmd, nick); + return command_status_user_not_found(cbase, user, cmd, nick); if (target == user) - return command_status(hub, user, cmd, "Cannot kick/ban yourself"); + return command_status(cbase, user, cmd, "Cannot kick/ban yourself"); - hub_disconnect_user(hub, target, quit_kicked); - acl_user_ban_nick(hub->acl, target->id.nick); - acl_user_ban_cid(hub->acl, target->id.cid); + hub_disconnect_user(cbase->hub, target, quit_kicked); + acl_user_ban_nick(cbase->hub->acl, target->id.nick); + acl_user_ban_cid(cbase->hub->acl, target->id.cid); - return command_status(hub, user, cmd, nick); + return command_status(cbase, user, cmd, nick); } -static int command_unban(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_unban(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - return command_status(hub, user, cmd, "Not implemented"); + return command_status(cbase, user, cmd, "Not implemented"); } -static int command_mute(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_mute(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char* nick = list_get_first(cmd->args); struct hub_user* target; if (!nick) return -1; // FIXME: bad syntax. - target = uman_get_user_by_nick(hub, nick); + target = uman_get_user_by_nick(cbase->hub, nick); if (!target) - return command_status_user_not_found(hub, user, cmd, nick); + return command_status_user_not_found(cbase, user, cmd, nick); if (strlen(cmd->prefix) == 4) { @@ -432,39 +548,39 @@ static int command_mute(struct hub_info* hub, struct hub_user* user, struct hub_ { user_flag_unset(target, flag_muted); } - return command_status(hub, user, cmd, nick); + return command_status(cbase, user, cmd, nick); } -static int command_reload(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_reload(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - hub->status = hub_status_restart; - return command_status(hub, user, cmd, "Reloading configuration..."); + cbase->hub->status = hub_status_restart; + return command_status(cbase, user, cmd, "Reloading configuration..."); } -static int command_shutdown(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_shutdown_hub(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - hub->status = hub_status_shutdown; - return command_status(hub, user, cmd, "Hub shutting down..."); + cbase->hub->status = hub_status_shutdown; + return command_status(cbase, user, cmd, "Hub shutting down..."); } -static int command_version(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_version(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { const char* tmp; - if (hub->config->show_banner_sys_info) + if (cbase->hub->config->show_banner_sys_info) tmp = "Powered by " PRODUCT_STRING " on " OPSYS "/" CPUINFO; else tmp = "Powered by " PRODUCT_STRING; - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } -static int command_myip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_myip(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char tmp[128]; snprintf(tmp, 128, "Your address is \"%s\"", user_get_address(user)); - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } -static int command_getip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_getip(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char tmp[128]; char* nick = list_get_first(cmd->args); @@ -473,16 +589,16 @@ static int command_getip(struct hub_info* hub, struct hub_user* user, struct hub if (!nick) return -1; // FIXME: bad syntax/OOM - target = uman_get_user_by_nick(hub, nick); + target = uman_get_user_by_nick(cbase->hub, nick); if (!target) - return command_status_user_not_found(hub, user, cmd, nick); + return command_status_user_not_found(cbase, user, cmd, nick); snprintf(tmp, 128, "%s has address \"%s\"", nick, user_get_address(target)); - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } -static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_whoip(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char* address = list_get_first(cmd->args); struct ip_range range; @@ -497,18 +613,18 @@ static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub ret = ip_convert_address_to_range(address, &range); if (!ret) - return command_status(hub, user, cmd, "Invalid IP address/range/mask"); + return command_status(cbase, user, cmd, "Invalid IP address/range/mask"); users = (struct linked_list*) list_create(); if (!users) return -1; // FIXME: OOM - ret = uman_get_user_by_addr(hub, users, &range); + ret = uman_get_user_by_addr(cbase->hub, users, &range); if (!ret) { list_destroy(users); - return command_status(hub, user, cmd, "No users found."); + return command_status(cbase, user, cmd, "No users found."); } snprintf(tmp, 128, "*** %s: Found %d match%s:", cmd->prefix, ret, ((ret != 1) ? "es" : "")); @@ -535,13 +651,13 @@ static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub } strcat(buffer, "\n"); - send_message(hub, user, buffer); + send_message(cbase, user, buffer); hub_free(buffer); list_destroy(users); return 0; } -static int command_broadcast(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_broadcast(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { size_t offset = 12; #if USE_OLD_BROADCAST_STYLE @@ -562,7 +678,7 @@ static int command_broadcast(struct hub_info* hub, struct hub_user* user, struct memcpy(from_sid, sid_to_string(user->id.sid), sizeof(from_sid)); memcpy(pm_flag + 2, from_sid, sizeof(from_sid)); - target = (struct hub_user*) list_get_first(hub->users->list); + target = (struct hub_user*) list_get_first(cbase->hub->users->list); while (target) { if (target != user) @@ -577,22 +693,22 @@ static int command_broadcast(struct hub_info* hub, struct hub_user* user, struct adc_msg_add_argument(command, (cmd->message + offset)); adc_msg_add_argument(command, pm_flag); - route_to_user(hub, target, command); + route_to_user(cbase->hub, target, command); adc_msg_free(command); } - target = (struct hub_user*) list_get_next(hub->users->list); + target = (struct hub_user*) list_get_next(cbase->hub->users->list); } snprintf(buffer, sizeof(buffer), "*** %s: Delivered to " PRINTF_SIZE_T " user%s", cmd->prefix, recipients, (recipients != 1 ? "s" : "")); - send_message(hub, user, buffer); + send_message(cbase, user, buffer); return 0; #endif } -static int command_history(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_history(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char* buffer; - struct linked_list* messages = hub->chat_history; + struct linked_list* messages = cbase->hub->chat_history; char* message = 0; int ret = (int) list_size(messages); size_t bufsize; @@ -603,7 +719,7 @@ static int command_history(struct hub_info* hub, struct hub_user* user, struct h if (!ret) { - return command_status(hub, user, cmd, "No messages."); + return command_status(cbase, user, cmd, "No messages."); } if (maxlines_str) @@ -633,7 +749,7 @@ static int command_history(struct hub_info* hub, struct hub_user* user, struct h buffer = hub_malloc(bufsize+4); if (!buffer) { - return command_status(hub, user, cmd, "Not enough memory."); + return command_status(cbase, user, cmd, "Not enough memory."); } buffer[0] = 0; @@ -649,14 +765,14 @@ static int command_history(struct hub_info* hub, struct hub_user* user, struct h } strcat(buffer, "\n"); - send_message(hub, user, buffer); + send_message(cbase, user, buffer); hub_free(buffer); return 0; } -static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_log(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - struct linked_list* messages = hub->logout_info; + struct linked_list* messages = cbase->hub->logout_info; struct hub_logout_info* log; char tmp[1024]; char* search = 0; @@ -665,7 +781,7 @@ static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_c if (!list_size(messages)) { - return command_status(hub, user, cmd, "No entries logged."); + return command_status(cbase, user, cmd, "No entries logged."); } search = list_get_first(cmd->args); @@ -682,7 +798,7 @@ static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_c { snprintf(tmp, sizeof(tmp), "Logged entries: " PRINTF_SIZE_T, list_size(messages)); } - command_status(hub, user, cmd, tmp); + command_status(cbase, user, cmd, tmp); log = (struct hub_logout_info*) list_get_first(messages); while (log) @@ -706,7 +822,7 @@ static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_c if (show) { snprintf(tmp, sizeof(tmp), "* %s %s, %s [%s] - %s", get_timestamp(log->time), log->cid, log->nick, ip_convert_to_string(&log->addr), user_get_quit_reason_string(log->reason)); - send_message(hub, user, tmp); + send_message(cbase, user, tmp); } log = (struct hub_logout_info*) list_get_next(messages); } @@ -714,13 +830,13 @@ static int command_log(struct hub_info* hub, struct hub_user* user, struct hub_c if (search_len) { snprintf(tmp, sizeof(tmp), PRINTF_SIZE_T " entries shown.", search_hits); - command_status(hub, user, cmd, tmp); + command_status(cbase, user, cmd, tmp); } return 0; } -static int command_register(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_register(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { struct auth_info data; char tmp[1024]; @@ -732,26 +848,19 @@ static int command_register(struct hub_info* hub, struct hub_user* user, struct data.password[MAX_PASS_LEN] = '\0'; data.credentials = auth_cred_user; - if (hub->config->register_self) + if (acl_register_user(cbase->hub, &data)) { - if (acl_register_user(hub, &data)) - { - snprintf(tmp, sizeof(tmp), "User \"%s\" registered.", user->id.nick); - return command_status(hub, user, cmd, tmp); - } - else - { - snprintf(tmp, sizeof(tmp), "Unable to register user \"%s\".", user->id.nick); - return command_status(hub, user, cmd, tmp); - } + snprintf(tmp, sizeof(tmp), "User \"%s\" registered.", user->id.nick); + return command_status(cbase, user, cmd, tmp); } else { - return command_status(hub, user, cmd, "You are not allowed to register."); + snprintf(tmp, sizeof(tmp), "Unable to register user \"%s\".", user->id.nick); + return command_status(cbase, user, cmd, tmp); } } -static int command_password(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_password(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { struct auth_info data; char tmp[1024]; @@ -763,18 +872,18 @@ static int command_password(struct hub_info* hub, struct hub_user* user, struct data.password[MAX_PASS_LEN] = '\0'; data.credentials = user->credentials; - if (acl_update_user(hub, &data)) + if (acl_update_user(cbase->hub, &data)) { - return command_status(hub, user, cmd, "Password changed."); + return command_status(cbase, user, cmd, "Password changed."); } else { snprintf(tmp, sizeof(tmp), "Unable to change password for user \"%s\".", user->id.nick); - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } } -static int command_useradd(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_useradd(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { struct auth_info data; char tmp[1024]; @@ -794,66 +903,66 @@ static int command_useradd(struct hub_info* hub, struct hub_user* user, struct h data.password[MAX_PASS_LEN] = '\0'; data.credentials = credentials; - if (acl_register_user(hub, &data)) + if (acl_register_user(cbase->hub, &data)) { snprintf(tmp, sizeof(tmp), "User \"%s\" registered.", nick); - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } else { snprintf(tmp, sizeof(tmp), "Unable to register user \"%s\".", nick); - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } } -static int command_userdel(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_userdel(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { char tmp[1024]; char* nick = list_get_first(cmd->args); - if (acl_delete_user(hub, nick)) + if (acl_delete_user(cbase->hub, nick)) { snprintf(tmp, sizeof(tmp), "User \"%s\" is deleted.", nick); - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } else { snprintf(tmp, sizeof(tmp), "Unable to delete user \"%s\".", nick); - return command_status(hub, user, cmd, tmp); + return command_status(cbase, user, cmd, tmp); } } -static int command_usermod(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_usermod(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - return command_status(hub, user, cmd, "Not implemented!"); + return command_status(cbase, user, cmd, "Not implemented!"); } -static int command_userinfo(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_userinfo(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - return command_status(hub, user, cmd, "Not implemented!"); + return command_status(cbase, user, cmd, "Not implemented!"); } -static int command_userpass(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_userpass(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - return command_status(hub, user, cmd, "Not implemented!"); + return command_status(cbase, user, cmd, "Not implemented!"); } -static int command_rules(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_rules(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - if (!hub_send_rules(hub, user)) - return command_status(hub, user, cmd, "no rules defined."); + if (!hub_send_rules(cbase->hub, user)) + return command_status(cbase, user, cmd, "no rules defined."); return 0; } -static int command_motd(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_motd(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - if (!hub_send_motd(hub, user)) - return command_status(hub, user, cmd, "no motd defined."); + if (!hub_send_motd(cbase->hub, user)) + return command_status(cbase, user, cmd, "no motd defined."); return 0; } #ifdef CRASH_DEBUG -static int command_crash(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +static int command_crash(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { void (*crash)(void) = NULL; crash(); @@ -861,47 +970,75 @@ static int command_crash(struct hub_info* hub, struct hub_user* user, struct hub } #endif -int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* message) +static int command_stats(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) { - size_t n = 0; - int rc; + char temp[128]; + struct hub_info* hub = cbase->hub; - /* Parse and validate the command */ - struct hub_command* cmd = command_create(message); - if (!cmd) return 0; - - for (n = 0; command_handlers[n].prefix; n++) - { - struct commands_handler* handler = &command_handlers[n]; - if (cmd->prefix_len != handler->length) - continue; - - if (!strncmp(cmd->prefix, handler->prefix, handler->length)) - { - if (handler->cred <= user->credentials) - { - if (command_check_args(cmd, handler)) - { - rc = handler->handler(hub, user, cmd); - } - else - { - rc = command_arg_mismatch(hub, user, cmd, handler); - } - command_destroy(cmd); - return rc; - } - else - { - rc = command_access_denied(hub, user, cmd); - command_destroy(cmd); - return rc; - } - } - } - - command_not_found(hub, user, cmd); - command_destroy(cmd); - return 0; + snprintf(temp, 128, PRINTF_SIZE_T " users, peak: " PRINTF_SIZE_T ". Network (up/down): %d/%d KB/s, peak: %d/%d KB/s", + hub->users->count, + hub->users->count_peak, + (int) hub->stats.net_tx / 1024, + (int) hub->stats.net_rx / 1024, + (int) hub->stats.net_tx_peak / 1024, + (int) hub->stats.net_rx_peak / 1024); + return command_status(cbase, user, cmd, temp); } +static struct command_handle* add_builtin(const char* prefix, const char* args, enum auth_credentials cred, command_handler handler, const char* description) +{ + struct command_handle* handle = (struct command_handle*) hub_malloc_zero(sizeof(struct command_handle)); + handle->prefix = strdup(prefix); + handle->length = strlen(prefix); + handle->args = args ? strdup(args) : NULL; + handle->cred = cred; + handle->handler = handler; + handle->description = strdup(description); + handle->origin = "built-in"; + return handle; +} + +#define ADD_COMMAND(PREFIX, LENGTH, ARGS, CREDENTIALS, FUNCTION, DESCRIPTION) \ + command_add(cbase, add_builtin(PREFIX, ARGS, CREDENTIALS, FUNCTION, DESCRIPTION), NULL) + +void commands_builtin_add(struct command_base* cbase) +{ + ADD_COMMAND("ban", 3, "n", auth_cred_operator, command_ban, "Ban a user" ); + ADD_COMMAND("broadcast", 9, "m", auth_cred_operator, command_broadcast,"Send a message to all users" ); +#ifdef CRASH_DEBUG + ADD_COMMAND("crash", 5, 0, auth_cred_admin, command_crash, "Crash the hub (DEBUG)." ); +#endif + ADD_COMMAND("getip", 5, "n", auth_cred_operator, command_getip, "Show IP address for a user" ); + ADD_COMMAND("help", 4, "?c",auth_cred_guest, command_help, "Show this help message." ); + ADD_COMMAND("history", 7, "?N",auth_cred_guest, command_history, "Show the last chat messages." ); + ADD_COMMAND("kick", 4, "n", auth_cred_operator, command_kick, "Kick a user" ); + ADD_COMMAND("log", 3, 0, auth_cred_operator, command_log, "Display log" ); + ADD_COMMAND("motd", 4, 0, auth_cred_guest, command_motd, "Show the message of the day" ); + ADD_COMMAND("mute", 4, "n", auth_cred_operator, command_mute, "Mute user" ); + ADD_COMMAND("myip", 4, 0, auth_cred_guest, command_myip, "Show your own IP." ); + ADD_COMMAND("register", 8, "p", auth_cred_guest, command_register, "Register your username." ); + ADD_COMMAND("reload", 6, 0, auth_cred_admin, command_reload, "Reload configuration files." ); + ADD_COMMAND("rules", 5, 0, auth_cred_guest, command_rules, "Show the hub rules" ); + ADD_COMMAND("password", 8, "p", auth_cred_user, command_password, "Change your own password." ); + ADD_COMMAND("shutdown", 8, 0, auth_cred_admin, command_shutdown_hub, "Shutdown hub." ); + ADD_COMMAND("stats", 5, 0, auth_cred_super, command_stats, "Show hub statistics." ); + ADD_COMMAND("unban", 5, "n", auth_cred_operator, command_unban, "Lift ban on a user" ); + ADD_COMMAND("unmute", 6, "n", auth_cred_operator, command_mute, "Unmute user" ); + ADD_COMMAND("uptime", 6, 0, auth_cred_guest, command_uptime, "Display hub uptime info." ); + ADD_COMMAND("useradd", 7, "np",auth_cred_operator, command_useradd, "Register a new user." ); + ADD_COMMAND("userdel", 7, "n", auth_cred_operator, command_userdel, "Delete a registered user." ); + ADD_COMMAND("userinfo", 8, "n", auth_cred_operator, command_userinfo, "Show registered user info." ); + ADD_COMMAND("usermod", 7, "nC",auth_cred_admin, command_usermod, "Modify user credentials." ); + ADD_COMMAND("userpass", 8, "np",auth_cred_operator, command_userpass, "Change password for a user." ); + ADD_COMMAND("version", 7, 0, auth_cred_guest, command_version, "Show hub version info." ); + ADD_COMMAND("whoip", 5, "a", auth_cred_operator, command_whoip, "Show users matching IP range" ); +} + +void commands_builtin_remove(struct command_base* cbase) +{ + struct command_handle* command; + while ((command = list_get_first(cbase->handlers))) + { + command_del(cbase, command); + } +} diff --git a/src/core/commands.h b/src/core/commands.h index 45f211e..a8413df 100644 --- a/src/core/commands.h +++ b/src/core/commands.h @@ -1,6 +1,6 @@ /* * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2010, Jan Vidar Krey + * Copyright (C) 2007-2011, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,4 +19,83 @@ #include "uhub.h" -extern int command_dipatcher(struct hub_info* hub, struct hub_user* user, const char* message); +struct command_base; +struct command_handle; + +struct hub_command +{ + const char* message; + char* prefix; + size_t prefix_len; + struct linked_list* args; +}; + +typedef int (*command_handler)(struct command_base*, struct hub_user* user, struct command_handle*, struct hub_command*); + +/** + * Argument codes are used to automatically parse arguments + * for a a hub command. + * + * n = nick name (must exist in hub session) + * i = CID (must exist in hub) + * a = (IP) address (must be a valid IPv4 or IPv6 address) + * m = message (string) + * p = password (string) + * C = credentials (see auth_string_to_cred). + * c = command (name of command) + * N = number (integer) + * + * Prefix an argument with ? to make it optional. + * NOTE; if an argument is optional then all following arguments must also be optional. + * + * Example: + * "nia" means "nick cid ip" + * "n?p" means "nick [password]" where password is optional. + * + */ +struct command_handle +{ + const char* prefix; /**<<< "Command prefix, for instance 'help' would be the prefix for the !help command." */ + size_t length; /**<<< "Length of the prefix" */ + const char* args; /**<<< "Argument codes (see above)" */ + enum auth_credentials cred; /**<<< "Minimum access level for the command" */ + command_handler handler; /**<<< "Function pointer for the command" */ + const char* description; /**<<< "Description for the command" */ + const char* origin; /**<<< "Name of module where the command is implemented." */ + void* ptr; +}; + + + +/** + * Returns NULL on error, or handle + */ +extern struct command_base* command_initialize(struct hub_info* hub); +extern void command_shutdown(struct command_base* cbase); + +/** + * Add a new command to the command base. + * Returns 1 on success, or 0 on error. + */ +extern int command_add(struct command_base*, struct command_handle*, void* ptr); + +/** + * Remove a command from the command base. + * Returns 1 on success, or 0 on error. + */ +extern int command_del(struct command_base*, struct command_handle*); + +/** + * Returns 1 if a command is available to a user (user has access to run it.) + */ +extern int command_is_available(struct command_handle*, struct hub_user* user); + +/** + * Dispatch a message and forward it as a command. + * Returns 1 if the message should be forwarded as a chat message, or 0 if + * it is supposed to be handled internally in the dispatcher. + * + * This will break the message down into a struct hub_command and invoke the command handler + * for that command if the sufficient access credentials are met. + */ +extern int command_invoke(struct command_base*, struct hub_user* user, const char* message); diff --git a/src/core/commands_builtin.c b/src/core/commands_builtin.c new file mode 100644 index 0000000..e69de29 diff --git a/src/core/commands_builtin.h b/src/core/commands_builtin.h new file mode 100644 index 0000000..af19fa5 --- /dev/null +++ b/src/core/commands_builtin.h @@ -0,0 +1,3 @@ + +void commands_builtin_add(struct command_base*); +void commands_builtin_remove(struct command_base*); \ No newline at end of file diff --git a/src/core/hub.c b/src/core/hub.c index 839f063..c437135 100644 --- a/src/core/hub.c +++ b/src/core/hub.c @@ -289,7 +289,7 @@ int hub_handle_chat_message(struct hub_info* hub, struct hub_user* u, struct adc } else { - relay = command_dipatcher(hub, u, message); + relay = command_invoke(hub->commands, u, message); } } @@ -813,6 +813,9 @@ struct hub_info* hub_start_service(struct hub_config* config) hub->status = hub_status_running; g_hub = hub; + + // Start the hub command sub-system + hub->commands = command_initialize(hub); return hub; } @@ -836,6 +839,7 @@ void hub_shutdown_service(struct hub_info* hub) list_destroy(hub->chat_history); list_clear(hub->logout_info, &hub_free); list_destroy(hub->logout_info); + command_shutdown(hub->commands); hub_free(hub); hub = 0; g_hub = 0; @@ -851,7 +855,7 @@ int hub_plugins_load(struct hub_info* hub) if (!hub->plugins) return -1; - if (plugin_initialize(hub->config, hub->plugins) < 0) + if (plugin_initialize(hub->config, hub) < 0) { hub_free(hub->plugins); hub->plugins = 0; diff --git a/src/core/hub.h b/src/core/hub.h index 5f8581b..6bb231e 100644 --- a/src/core/hub.h +++ b/src/core/hub.h @@ -114,6 +114,8 @@ struct hub_info struct linked_list* chat_history; /* Chat history */ struct linked_list* logout_info; /* Log of people logging out. */ + struct command_base* commands; /* Hub command handler */ + #ifdef PLUGIN_SUPPORT struct uhub_plugins* plugins; #endif diff --git a/src/core/inf.c b/src/core/inf.c index e68513e..c477af0 100644 --- a/src/core/inf.c +++ b/src/core/inf.c @@ -378,7 +378,7 @@ static int check_user_agent(struct hub_info* hub, struct hub_user* user, struct ua = adc_msg_unescape(ua_encoded); if (ua) { - memcpy(user->user_agent, ua, MIN(strlen(ua), MAX_UA_LEN)); + memcpy(user->id.user_agent, ua, MIN(strlen(ua), MAX_UA_LEN)); hub_free(ua); } } diff --git a/src/core/plugincallback.c b/src/core/plugincallback.c new file mode 100644 index 0000000..22aa57f --- /dev/null +++ b/src/core/plugincallback.c @@ -0,0 +1,147 @@ +/* + * uhub - A tiny ADC p2p connection hub + * Copyright (C) 2007-2011, Jan Vidar Krey + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "uhub.h" +#include "plugin_api/command_api.h" + +struct plugin_callback_data +{ + struct linked_list* commands; +}; + +static struct plugin_callback_data* get_callback_data(struct plugin_handle* plugin) +{ + struct plugin_callback_data* data; + uhub_assert(plugin && plugin->handle && plugin->handle->internals); + data = (struct plugin_callback_data*) plugin->handle->internals; + return data; +} + +static int plugin_command_dispatch(struct command_base* cbase, struct hub_user* user, struct command_handle* handle, struct hub_command* cmd) +{ + struct plugin_handle* plugin = (struct plugin_handle*) handle->ptr; + struct plugin_callback_data* data = get_callback_data(plugin); + struct plugin_command_handle* cmdh; + struct plugin_user* puser = (struct plugin_user*) user; // FIXME: Use a proper conversion function instead. + struct plugin_command* pcommand = (struct plugin_command*) cmd; // FIXME: Use a proper conversion function instead. + + LOG_INFO("plugin_command_dispatch: cmd=%s", cmd->prefix); + + cmdh = (struct plugin_command_handle*) list_get_first(data->commands); + while (cmdh) + { + if (cmdh->length != cmd->prefix_len) + continue; + + if (strcmp(cmdh->prefix, cmd->prefix) == 0) + return cmdh->handler(plugin, puser, pcommand); + + cmdh = (struct plugin_command_handle*) list_get_next(data->commands); + } + return 0; +} + +struct plugin_callback_data* plugin_callback_data_create() +{ + struct plugin_callback_data* data = (struct plugin_callback_data*) hub_malloc_zero(sizeof(struct plugin_callback_data)); + data->commands = list_create(); + return data; +} + +void plugin_callback_data_destroy(struct plugin_callback_data* data) +{ + if (data->commands) + { + uhub_assert(list_size(data->commands) == 0); + list_destroy(data->commands); + } + + hub_free(data); +} + +static struct hub_user* convert_user_type(struct plugin_user* user) +{ + struct hub_user* huser = (struct hub_user*) user; + return huser; +} + +static int cbfunc_send_message(struct plugin_handle* plugin, struct plugin_user* user, const char* message) +{ +// struct plugin_callback_data* data = get_callback_data(plugin); + char* buffer = adc_msg_escape(message); + struct adc_message* command = adc_msg_construct(ADC_CMD_IMSG, strlen(buffer) + 6); + adc_msg_add_argument(command, buffer); + route_to_user(plugin_get_hub(plugin), convert_user_type(user), command); + adc_msg_free(command); + hub_free(buffer); + return 1; +} + + +static int cbfunc_user_disconnect(struct plugin_handle* plugin, struct plugin_user* user) +{ + // struct plugin_callback_data* data = get_callback_data(plugin); + hub_disconnect_user(plugin_get_hub(plugin), convert_user_type(user), quit_kicked); + return 0; +} + +static int cbfunc_command_add(struct plugin_handle* plugin, struct plugin_command_handle* cmdh) +{ + struct plugin_callback_data* data = get_callback_data(plugin); + struct command_handle* command = (struct command_handle*) hub_malloc_zero(sizeof(struct command_handle)); + + command->prefix = cmdh->prefix; + command->length = cmdh->length; + command->args = cmdh->args; + command->cred = cmdh->cred; + command->description = cmdh->description; + command->origin = cmdh->origin; + command->handler = plugin_command_dispatch; + + cmdh->internal_handle = data; + list_append(data->commands, cmdh); + command_add(plugin_get_hub(plugin)->commands, command, (void*) plugin); + return 0; +} + +static int cbfunc_command_del(struct plugin_handle* plugin, struct plugin_command_handle* cmdh) +{ + struct plugin_callback_data* data = get_callback_data(plugin); + struct command_handle* command = (struct command_handle*) cmdh->internal_handle; + + list_remove(data->commands, cmdh); + cmdh->internal_handle = 0; + + command_del(plugin_get_hub(plugin)->commands, (void*) command); + + return 0; +} + + +void plugin_register_callback_functions(struct plugin_handle* handle) +{ + handle->hub.send_message = cbfunc_send_message; + handle->hub.user_disconnect = cbfunc_user_disconnect; + handle->hub.command_add = cbfunc_command_add; + handle->hub.command_del = cbfunc_command_del; +} + +void plugin_unregister_callback_functions(struct plugin_handle* handle) +{ +} diff --git a/src/core/plugincallback.h b/src/core/plugincallback.h new file mode 100644 index 0000000..ab82366 --- /dev/null +++ b/src/core/plugincallback.h @@ -0,0 +1,32 @@ +/* + * uhub - A tiny ADC p2p connection hub + * Copyright (C) 2007-2011, Jan Vidar Krey + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef HAVE_UHUB_PLUGIN_CALLBACK_H +#define HAVE_UHUB_PLUGIN_CALLBACK_H + +struct plugin_handle; +struct uhub_plugin; + +extern struct plugin_callback_data* plugin_callback_data_create(); +extern void plugin_callback_data_destroy(struct plugin_callback_data* data); + +extern void plugin_register_callback_functions(struct plugin_handle* plugin); +extern void plugin_unregister_callback_functions(struct plugin_handle* plugin); + +#endif /* HAVE_UHUB_PLUGIN_CALLBACK_H */ \ No newline at end of file diff --git a/src/core/plugininvoke.c b/src/core/plugininvoke.c index 683c572..77b410a 100644 --- a/src/core/plugininvoke.c +++ b/src/core/plugininvoke.c @@ -1,6 +1,6 @@ /* * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2010, Jan Vidar Krey + * Copyright (C) 2007-2011, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -74,14 +74,10 @@ #define PLUGIN_INVOKE_3(HUB, FUNCNAME, ARG1, ARG2, ARG3) INVOKE(HUB, FUNCNAME, { plugin->funcs.FUNCNAME(plugin, ARG1, ARG2, ARG3); }) -static void convert_user_type(struct plugin_user* puser, struct hub_user* user) +static struct plugin_user* convert_user_type(struct hub_user* user) { - puser->sid = user->id.sid; - puser->nick = user->id.nick; - puser->cid = user->id.cid; - puser->user_agent = user->user_agent; - puser->addr = user->id.addr; - puser->credentials = user->credentials; + struct plugin_user* puser = (struct plugin_user*) user; + return puser; } plugin_st plugin_check_ip_early(struct hub_info* hub, struct ip_addr_encap* addr) @@ -106,85 +102,71 @@ void plugin_log_connection_denied(struct hub_info* hub, struct ip_addr_encap* ip void plugin_log_user_login_success(struct hub_info* hub, struct hub_user* who) { - struct plugin_user user; - convert_user_type(&user, who); - PLUGIN_INVOKE_1(hub, on_user_login, &user); + struct plugin_user* user = convert_user_type(who); + PLUGIN_INVOKE_1(hub, on_user_login, user); } void plugin_log_user_login_error(struct hub_info* hub, struct hub_user* who, const char* reason) { - struct plugin_user user; - convert_user_type(&user, who); - PLUGIN_INVOKE_2(hub, on_user_login_error, &user, reason); + struct plugin_user* user = convert_user_type(who); + PLUGIN_INVOKE_2(hub, on_user_login_error, user, reason); } void plugin_log_user_logout(struct hub_info* hub, struct hub_user* who, const char* reason) { - struct plugin_user user; - convert_user_type(&user, who); - PLUGIN_INVOKE_2(hub, on_user_logout, &user, reason); + struct plugin_user* user = convert_user_type(who); + PLUGIN_INVOKE_2(hub, on_user_logout, user, reason); } void plugin_log_user_nick_change(struct hub_info* hub, struct hub_user* who, const char* new_nick) { - struct plugin_user user; - convert_user_type(&user, who); - PLUGIN_INVOKE_2(hub, on_user_nick_change, &user, new_nick); + struct plugin_user* user = convert_user_type(who); + PLUGIN_INVOKE_2(hub, on_user_nick_change, user, new_nick); } void plugin_log_user_update_error(struct hub_info* hub, struct hub_user* who, const char* reason) { - struct plugin_user user; - convert_user_type(&user, who); - PLUGIN_INVOKE_2(hub, on_user_update_error, &user, reason); + struct plugin_user* user = convert_user_type(who); + PLUGIN_INVOKE_2(hub, on_user_update_error, user, reason); } void plugin_log_chat_message(struct hub_info* hub, struct hub_user* who, const char* message, int flags) { - struct plugin_user user; - convert_user_type(&user, who); - PLUGIN_INVOKE_3(hub, on_user_chat_message, &user, message, flags); + struct plugin_user* user = convert_user_type(who); + PLUGIN_INVOKE_3(hub, on_user_chat_message, user, message, flags); } plugin_st plugin_handle_chat_message(struct hub_info* hub, struct hub_user* from, const char* message, int flags) { - struct plugin_user user; - convert_user_type(&user, from); - PLUGIN_INVOKE_STATUS_2(hub, on_chat_msg, &user, message); + struct plugin_user* user = convert_user_type(from); + PLUGIN_INVOKE_STATUS_2(hub, on_chat_msg, user, message); } plugin_st plugin_handle_private_message(struct hub_info* hub, struct hub_user* from, struct hub_user* to, const char* message, int flags) { - struct plugin_user user1; - struct plugin_user user2; - convert_user_type(&user1, from); - convert_user_type(&user2, to); - PLUGIN_INVOKE_STATUS_3(hub, on_private_msg, &user1, &user2, message); + struct plugin_user* user1 = convert_user_type(from); + struct plugin_user* user2 = convert_user_type(to); + PLUGIN_INVOKE_STATUS_3(hub, on_private_msg, user1, user2, message); } plugin_st plugin_handle_search(struct hub_info* hub, struct hub_user* from, const char* data) { - struct plugin_user user; - convert_user_type(&user, from); - PLUGIN_INVOKE_STATUS_2(hub, on_search, &user, data); + struct plugin_user* user = convert_user_type(from); + PLUGIN_INVOKE_STATUS_2(hub, on_search, user, data); } plugin_st plugin_handle_connect(struct hub_info* hub, struct hub_user* from, struct hub_user* to) { - struct plugin_user user1; - struct plugin_user user2; - convert_user_type(&user1, from); - convert_user_type(&user2, to); - PLUGIN_INVOKE_STATUS_2(hub, on_p2p_connect, &user1, &user2); + struct plugin_user* user1 = convert_user_type(from); + struct plugin_user* user2 = convert_user_type(to); + PLUGIN_INVOKE_STATUS_2(hub, on_p2p_connect, user1, user2); } plugin_st plugin_handle_revconnect(struct hub_info* hub, struct hub_user* from, struct hub_user* to) { - struct plugin_user user1; - struct plugin_user user2; - convert_user_type(&user1, from); - convert_user_type(&user2, to); - PLUGIN_INVOKE_STATUS_2(hub, on_p2p_revconnect, &user1, &user2); + struct plugin_user* user1 = convert_user_type(from); + struct plugin_user* user2 = convert_user_type(to); + PLUGIN_INVOKE_STATUS_2(hub, on_p2p_revconnect, user1, user2); } plugin_st plugin_auth_get_user(struct hub_info* hub, const char* nickname, struct auth_info* info) diff --git a/src/core/plugininvoke.h b/src/core/plugininvoke.h index 4f3086b..d99b9b5 100644 --- a/src/core/plugininvoke.h +++ b/src/core/plugininvoke.h @@ -1,6 +1,6 @@ /* * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2010, Jan Vidar Krey + * Copyright (C) 2007-2011, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/core/pluginloader.c b/src/core/pluginloader.c index cf4036c..8411c10 100644 --- a/src/core/pluginloader.c +++ b/src/core/pluginloader.c @@ -1,6 +1,6 @@ /* * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2010, Jan Vidar Krey + * Copyright (C) 2007-2011, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,23 @@ #ifdef PLUGIN_SUPPORT #include "plugin_api/handle.h" +struct plugin_callback_data; + +struct plugin_hub_internals +{ + struct hub_info* hub; + plugin_unregister_f unregister; /* The unregister function. */ + struct plugin_callback_data* callback_data; /* callback data that is unique for the plugin */ +}; + +static struct plugin_hub_internals* get_internals(struct plugin_handle* handle) +{ + struct plugin_hub_internals* internals; + assert(handle && handle->handle && handle->handle->internals); + internals = (struct plugin_hub_internals*) handle->handle->internals; + return internals; +} + struct uhub_plugin* plugin_open(const char* filename) { struct uhub_plugin* plugin; @@ -51,12 +68,14 @@ struct uhub_plugin* plugin_open(const char* filename) } plugin->filename = strdup(filename); + plugin->internals = hub_malloc_zero(sizeof(struct plugin_hub_internals)); return plugin; } void plugin_close(struct uhub_plugin* plugin) { LOG_TRACE("plugin_close: \"%s\"", plugin->filename); + hub_free(plugin->internals); #ifdef HAVE_DLOPEN dlclose(plugin->handle); #else @@ -77,13 +96,16 @@ void* plugin_lookup_symbol(struct uhub_plugin* plugin, const char* symbol) #endif } -struct plugin_handle* plugin_load(const char* filename, const char* config) + + +struct plugin_handle* plugin_load(const char* filename, const char* config, struct hub_info* hub) { plugin_register_f register_f; plugin_unregister_f unregister_f; int ret; - struct plugin_handle* handle = hub_malloc_zero(sizeof(struct plugin_handle)); + struct plugin_handle* handle = (struct plugin_handle*) hub_malloc_zero(sizeof(struct plugin_handle)); struct uhub_plugin* plugin = plugin_open(filename); + struct plugin_hub_internals* internals = (struct plugin_hub_internals*) plugin->internals; if (!plugin) return NULL; @@ -98,6 +120,14 @@ struct plugin_handle* plugin_load(const char* filename, const char* config) register_f = plugin_lookup_symbol(plugin, "plugin_register"); unregister_f = plugin_lookup_symbol(plugin, "plugin_unregister"); + // register hub internals + internals->unregister = unregister_f; + internals->hub = hub; + internals->callback_data = plugin_callback_data_create(); + + // setup callback functions, where the plugin can contact the hub. + plugin_register_callback_functions(handle); + if (register_f && unregister_f) { ret = register_f(handle, config); @@ -107,7 +137,6 @@ struct plugin_handle* plugin_load(const char* filename, const char* config) { LOG_INFO("Loaded plugin: %s: %s, version %s.", filename, handle->name, handle->version); LOG_TRACE("Plugin API version: %d (func table size: " PRINTF_SIZE_T ")", handle->plugin_api_version, handle->plugin_funcs_size); - plugin->unregister = unregister_f; return handle; } else @@ -128,16 +157,19 @@ struct plugin_handle* plugin_load(const char* filename, const char* config) void plugin_unload(struct plugin_handle* plugin) { - plugin->handle->unregister(plugin); + struct plugin_hub_internals* internals = get_internals(plugin); + plugin_unregister_callback_functions(plugin); + internals->unregister(plugin); plugin_close(plugin->handle); hub_free(plugin); } static int plugin_parse_line(char* line, int line_count, void* ptr_data) { - struct uhub_plugins* handle = (struct uhub_plugins*) ptr_data; - struct plugin_handle* plugin; + struct hub_info* hub = (struct hub_info*) ptr_data; + struct uhub_plugins* handle = hub->plugins; struct cfg_tokens* tokens = cfg_tokenize(line); + struct plugin_handle* plugin; char *directive, *soname, *params; if (cfg_token_count(tokens) == 0) @@ -162,7 +194,7 @@ static int plugin_parse_line(char* line, int line_count, void* ptr_data) params = ""; LOG_TRACE("Load plugin: \"%s\", params=\"%s\"", soname, params); - plugin = plugin_load(soname, params); + plugin = plugin_load(soname, params, hub); if (plugin) { list_append(handle->loaded, plugin); @@ -175,12 +207,12 @@ static int plugin_parse_line(char* line, int line_count, void* ptr_data) return -1; } -int plugin_initialize(struct hub_config* config, struct uhub_plugins* handle) +int plugin_initialize(struct hub_config* config, struct hub_info* hub) { int ret; - handle->loaded = list_create(); - if (!handle->loaded) + hub->plugins->loaded = list_create(); + if (!hub->plugins->loaded) return -1; if (config) @@ -188,12 +220,12 @@ int plugin_initialize(struct hub_config* config, struct uhub_plugins* handle) if (!*config->file_plugins) return 0; - ret = file_read_lines(config->file_plugins, handle, &plugin_parse_line); + ret = file_read_lines(config->file_plugins, hub, &plugin_parse_line); if (ret == -1) { - list_clear(handle->loaded, hub_free); - list_destroy(handle->loaded); - handle->loaded = 0; + list_clear(hub->plugins->loaded, hub_free); + list_destroy(hub->plugins->loaded); + hub->plugins->loaded = 0; return -1; } } @@ -213,4 +245,11 @@ void plugin_shutdown(struct uhub_plugins* handle) list_destroy(handle->loaded); } +// Used internally only +struct hub_info* plugin_get_hub(struct plugin_handle* plugin) +{ + struct plugin_hub_internals* data = get_internals(plugin); + return data->hub; +} + #endif /* PLUGIN_SUPPORT */ diff --git a/src/core/pluginloader.h b/src/core/pluginloader.h index 2d32e76..b2d6143 100644 --- a/src/core/pluginloader.h +++ b/src/core/pluginloader.h @@ -1,6 +1,6 @@ /* * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2010, Jan Vidar Krey + * Copyright (C) 2007-2011, Jan Vidar Krey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include "plugin_api/handle.h" struct hub_config; +struct hub_info; struct linked_list; struct plugin_handle; @@ -31,6 +32,7 @@ struct uhub_plugin void* handle; plugin_unregister_f unregister; char* filename; + void* internals; // Hub internal stuff }; struct uhub_plugins @@ -39,11 +41,11 @@ struct uhub_plugins }; // High level plugin loader ode -extern struct plugin_handle* plugin_load(const char* filename, const char* config); +extern struct plugin_handle* plugin_load(const char* filename, const char* config, struct hub_info* hub); extern void plugin_unload(struct plugin_handle* plugin); // extern void plugin_unload(struct plugin_handle*); -extern int plugin_initialize(struct hub_config* config, struct uhub_plugins* handle); +extern int plugin_initialize(struct hub_config* config, struct hub_info* hub); extern void plugin_shutdown(struct uhub_plugins* handle); // Low level plugin loader code (used internally) @@ -51,5 +53,8 @@ extern struct uhub_plugin* plugin_open(const char* filename); extern void plugin_close(struct uhub_plugin*); extern void* plugin_lookup_symbol(struct uhub_plugin*, const char* symbol); +// Used internally only +extern struct hub_info* plugin_get_hub(struct plugin_handle*); + #endif /* HAVE_UHUB_PLUGIN_LOADER_H */ diff --git a/src/core/user.h b/src/core/user.h index 00894a8..96d399c 100644 --- a/src/core/user.h +++ b/src/core/user.h @@ -82,8 +82,9 @@ extern const char* user_get_quit_reason_string(enum user_quit_reason); struct hub_user_info { sid_t sid; /** session ID */ - char cid[MAX_CID_LEN+1]; /** global client ID */ char nick[MAX_NICK_LEN+1]; /** User's nick name */ + char cid[MAX_CID_LEN+1]; /** global client ID */ + char user_agent[MAX_UA_LEN+1];/** User agent string */ struct ip_addr_encap addr; /** User's IP address */ }; @@ -105,11 +106,10 @@ struct hub_user_limits struct hub_user { - enum user_state state; /** see enum user_state */ - enum auth_credentials credentials; /** see enum user_credentials */ struct hub_user_info id; /** Contains nick name and CID */ + enum auth_credentials credentials; /** see enum user_credentials */ + enum user_state state; /** see enum user_state */ uint32_t flags; /** see enum user_features */ - char user_agent[MAX_UA_LEN+1];/** User agent string */ struct linked_list* feature_cast; /** Features supported by feature cast */ struct adc_message* info; /** ADC 'INF' message (broadcasted to everyone joining the hub) */ struct hub_info* hub; /** The hub instance this user belong to */ diff --git a/src/plugin_api/handle.h b/src/plugin_api/handle.h index 991d463..3faded5 100644 --- a/src/plugin_api/handle.h +++ b/src/plugin_api/handle.h @@ -20,74 +20,14 @@ #ifndef HAVE_UHUB_PLUGIN_HANDLE_H #define HAVE_UHUB_PLUGIN_HANDLE_H +/** + * This file describes the interface a uhub uses to interact with plugins. + */ + #include "system.h" #include "util/credentials.h" #include "util/ipcalc.h" - -#define PLUGIN_API_VERSION 1 - -#ifndef MAX_NICK_LEN -#define MAX_NICK_LEN 64 -#endif - -#ifndef MAX_PASS_LEN -#define MAX_PASS_LEN 64 -#endif - -#ifndef MAX_CID_LEN -#define MAX_CID_LEN 39 -#endif - - -struct plugin_handle; - -struct plugin_user -{ - unsigned int sid; - const char* nick; - const char* cid; - const char* user_agent; - struct ip_addr_encap addr; - enum auth_credentials credentials; -}; - -struct plugin_hub_info -{ - const char* description; -}; - -enum plugin_status -{ - st_default = 0, /* Use default */ - st_allow = 1, /* Allow action */ - st_deny = -1, /* Deny action */ -}; - -typedef enum plugin_status plugin_st; - -struct auth_info -{ - char nickname[MAX_NICK_LEN+1]; - char password[MAX_PASS_LEN+1]; - enum auth_credentials credentials; -}; - -enum ban_flags -{ - ban_nickname = 0x01, /* Nickname is banned */ - ban_cid = 0x02, /* CID is banned */ - ban_ip = 0x04, /* IP address (range) is banned */ -}; - -struct ban_info -{ - unsigned int flags; /* See enum ban_flags. */ - char nickname[MAX_NICK_LEN+1]; /* Nickname - only defined if (ban_nickname & flags). */ - char cid[MAX_CID_LEN+1]; /* CID - only defined if (ban_cid & flags). */ - struct ip_addr_encap ip_addr_lo; /* Low IP address of an IP range */ - struct ip_addr_encap ip_addr_hi; /* High IP address of an IP range */ - time_t expiry; /* Time when the ban record expires */ -}; +#include "plugin_api/types.h" typedef plugin_st (*on_chat_msg_t)(struct plugin_handle*, struct plugin_user* from, const char* message); typedef plugin_st (*on_private_msg_t)(struct plugin_handle*, struct plugin_user* from, struct plugin_user* to, const char* message); @@ -122,6 +62,9 @@ typedef plugin_st (*auth_register_user_t)(struct plugin_handle*, struct auth_inf typedef plugin_st (*auth_update_user_t)(struct plugin_handle*, struct auth_info* user); typedef plugin_st (*auth_delete_user_t)(struct plugin_handle*, struct auth_info* user); +/** + * These are callbacks used for the hub to invoke functions in plugins. + */ struct plugin_funcs { // Log events for connections @@ -158,9 +101,28 @@ struct plugin_funcs // Login check functions on_check_ip_early_t login_check_ip_early; on_check_ip_late_t login_check_ip_late; - }; +struct plugin_command_handle; + +typedef int (*hfunc_send_message)(struct plugin_handle*, struct plugin_user* user, const char* message); +typedef int (*hfunc_user_disconnect)(struct plugin_handle*, struct plugin_user* user); +typedef int (*hfunc_command_add)(struct plugin_handle*, struct plugin_command_handle*); +typedef int (*hfunc_command_del)(struct plugin_handle*, struct plugin_command_handle*); + +/** + * These are functions created and initialized by the hub and which can be used + * by plugins to access functionality internal to the hub. + */ +struct plugin_hub_funcs +{ + hfunc_send_message send_message; + hfunc_user_disconnect user_disconnect; + hfunc_command_add command_add; + hfunc_command_del command_del; +}; + + struct plugin_handle { struct uhub_plugin* handle; /* Must NOT be modified by the plugin */ @@ -171,9 +133,11 @@ struct plugin_handle const char* error_msg; /* Error message for registration error. */ size_t plugin_api_version; /* Plugin API version */ size_t plugin_funcs_size; /* Size of the plugin funcs */ - struct plugin_funcs funcs; + struct plugin_funcs funcs; /* Table of functions that can be implemented by a plugin */ + struct plugin_hub_funcs hub; /* Table of core hub functions that can be used by a plugin */ }; + #define PLUGIN_INITIALIZE(PTR, NAME, VERSION, DESCRIPTION) \ do { \ PTR->name = NAME; \ diff --git a/src/plugins/mod_example.c b/src/plugins/mod_example.c index 4eaf99c..d03a067 100644 --- a/src/plugins/mod_example.c +++ b/src/plugins/mod_example.c @@ -3,16 +3,50 @@ */ #include "plugin_api/handle.h" +#include "plugin_api/command_api.h" +#include "util/memory.h" + +struct example_plugin_data +{ + struct plugin_command_handle* example; +}; + +static int example_command_handler(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd) +{ + plugin->hub.send_message(plugin, user, "Hello from mod_example."); + return 1; +} + +static void command_register(struct plugin_handle* plugin) +{ + struct example_plugin_data* data = (struct example_plugin_data*) hub_malloc(sizeof(struct example_plugin_data)); + data->example = hub_malloc_zero(sizeof(struct plugin_command_handle)); + PLUGIN_COMMAND_INITIALIZE(data->example, (void*) data, "example", "", auth_cred_guest, example_command_handler, "This is an example command that is added dynamically by loading the mod_example plug-in."); + plugin->hub.command_add(plugin, data->example); + plugin->ptr = data; +} + +static void command_unregister(struct plugin_handle* plugin) +{ + struct example_plugin_data* data = (struct example_plugin_data*) plugin->ptr; + + plugin->hub.command_del(plugin, data->example); + hub_free(data->example); + + hub_free(data); + plugin->ptr = NULL; +} int plugin_register(struct plugin_handle* plugin, const char* config) { PLUGIN_INITIALIZE(plugin, "Example plugin", "1.0", "A simple example plugin"); + command_register(plugin); return 0; } int plugin_unregister(struct plugin_handle* plugin) { - /* No need to do anything! */ + command_unregister(plugin); return 0; } diff --git a/src/tools/admin.c b/src/tools/admin.c index aebd868..2b622e5 100644 --- a/src/tools/admin.c +++ b/src/tools/admin.c @@ -30,6 +30,7 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type, case ADC_CLIENT_PASSWORD_REQ: puts("*** Requesting password."); + break; case ADC_CLIENT_LOGGED_IN: puts("*** Logged in."); @@ -84,10 +85,7 @@ int main(int argc, char** argv) ADC_client_set_callback(&client, handle); ADC_client_connect(&client, argv[1]); - while (running) - { - net_backend_process(); - } + while (running && net_backend_process()) { } ADC_client_destroy(&client); net_destroy(); diff --git a/src/uhub.h b/src/uhub.h index 44dcba4..8321240 100644 --- a/src/uhub.h +++ b/src/uhub.h @@ -90,8 +90,10 @@ extern "C" { #include "core/pluginloader.h" #include "core/hub.h" #include "core/commands.h" +#include "core/commands_builtin.h" #include "core/inf.h" #include "core/hubevent.h" +#include "core/plugincallback.h" #include "core/plugininvoke.h" #include "core/pluginloader.h" diff --git a/vs2010/uhub.sln b/vs2010/uhub.sln index 7709818..7698138 100644 --- a/vs2010/uhub.sln +++ b/vs2010/uhub.sln @@ -13,6 +13,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_auth_simple", "plugins\ {0A3C1519-D877-47D9-A82E-40AC1BC79D75} = {0A3C1519-D877-47D9-A82E-40AC1BC79D75} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_example", "plugins\mod_example\mod_example.vcxproj", "{9BBAEFDA-8E0E-4E7F-B8B6-0050432FC45B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -31,6 +33,10 @@ Global {A6674BB3-1B23-4E99-AF9B-1CCDB4EB049A}.Debug|Win32.Build.0 = Debug|Win32 {A6674BB3-1B23-4E99-AF9B-1CCDB4EB049A}.Release|Win32.ActiveCfg = Release|Win32 {A6674BB3-1B23-4E99-AF9B-1CCDB4EB049A}.Release|Win32.Build.0 = Release|Win32 + {9BBAEFDA-8E0E-4E7F-B8B6-0050432FC45B}.Debug|Win32.ActiveCfg = Debug|Win32 + {9BBAEFDA-8E0E-4E7F-B8B6-0050432FC45B}.Debug|Win32.Build.0 = Debug|Win32 + {9BBAEFDA-8E0E-4E7F-B8B6-0050432FC45B}.Release|Win32.ActiveCfg = Release|Win32 + {9BBAEFDA-8E0E-4E7F-B8B6-0050432FC45B}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs2010/uhub.vcxproj b/vs2010/uhub.vcxproj index 3b0a471..239b8cd 100644 --- a/vs2010/uhub.vcxproj +++ b/vs2010/uhub.vcxproj @@ -93,6 +93,7 @@ + @@ -115,6 +116,7 @@ + @@ -124,6 +126,7 @@ + @@ -135,6 +138,7 @@ +