diff --git a/GNUmakefile b/GNUmakefile
index b0cb5a4..90bd88f 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -155,7 +155,6 @@ libuhub_SOURCES := \
src/network/connection.c \
src/network/epoll.c \
src/network/kqueue.c \
- src/network/network.c \
src/network/select.c \
src/network/timeout.c \
src/network/timer.c
@@ -175,6 +174,7 @@ libutils_SOURCES := \
src/util/log.c \
src/util/memory.c \
src/util/misc.c \
+ src/network/network.c \
src/util/rbtree.c \
src/util/tiger.c
@@ -213,6 +213,9 @@ autotest_OBJECTS = autotest.o
plugin_example_SOURCES := src/plugins/mod_example.c
plugin_example_TARGET := mod_example.so
+plugin_welcome_SOURCES := src/plugins/mod_welcome.c
+plugin_welcome_TARGET := mod_welcome.so
+
plugin_logging_SOURCES := src/plugins/mod_logging.c
plugin_logging_TARGET := mod_logging.so
@@ -237,8 +240,9 @@ uhub-passwd_OBJECTS := $(uhub-passwd_SOURCES:.c=.o)
adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o)
admin_OBJECTS := $(admin_SOURCES:.c=.o)
+all_plugins := $(plugin_example_TARGET) $(plugin_logging_TARGET) $(plugin_auth_TARGET) $(plugin_auth_sqlite_TARGET) $(plugin_chat_history_TARGET) $(plugin_welcome_TARGET)
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(libutils_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS)
-all_plugins := $(plugin_example_TARGET) $(plugin_logging_TARGET) $(plugin_auth_TARGET) $(plugin_auth_sqlite_TARGET) $(plugin_chat_history_TARGET)
+all_OBJECTS += $(all_plugins)
uhub_BINARY=uhub$(BIN_EXT)
uhub-passwd_BINARY=uhub-passwd$(BIN_EXT)
@@ -246,16 +250,17 @@ adcrush_BINARY=adcrush$(BIN_EXT)
admin_BINARY=uhub-admin$(BIN_EXT)
autotest_BINARY=autotest/test$(BIN_EXT)
-ifeq ($(USE_PLUGINS),YES)
-all_plugins := $(plugin_example_TARGET) $(plugin_logging_TARGET) $(plugin_auth_TARGET) $(plugin_auth_sqlite_TARGET)
-all_OBJECTS += $(all_plugins)
-endif
.PHONY: revision.h.tmp all plugins
%.o: %.c version.h revision.h
$(MSG_CC) $(CC) -fPIC -c $(CFLAGS) -o $@ $<
+
+#%.so: %.c
+# $(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS)
+
+
all: $(uhub_BINARY) $(uhub-passwd_BINARY) plugins
plugins: $(uhub_BINARY) $(all_plugins)
@@ -275,6 +280,9 @@ $(plugin_logging_TARGET): $(plugin_logging_SOURCES) $(libutils_OBJECTS) $(libadc
$(plugin_chat_history_TARGET): $(plugin_chat_history_SOURCE) $(libutils_OBJECTS)
$(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS)
+$(plugin_welcome_TARGET): $(plugin_welcome_SOURCES) $(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/plugins/mod_welcome.c b/src/plugins/mod_welcome.c
new file mode 100644
index 0000000..4dc8547
--- /dev/null
+++ b/src/plugins/mod_welcome.c
@@ -0,0 +1,301 @@
+/*
+ * 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 "system.h"
+#include "adc/adcconst.h"
+#include "adc/sid.h"
+#include "util/cbuffer.h"
+#include "util/memory.h"
+#include "util/ipcalc.h"
+#include "plugin_api/handle.h"
+#include "plugin_api/command_api.h"
+
+#include "util/misc.h"
+#include "util/config_token.h"
+#include
+
+#define MAX_WELCOME_SIZE 16384
+
+struct welcome_data
+{
+ char* motd_file;
+ char* motd;
+ char* rules_file;
+ char* rules;
+ struct plugin_command_handle* cmd_motd;
+ struct plugin_command_handle* cmd_rules;
+};
+
+static int command_handler_motd(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd);
+static int command_handler_rules(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd);
+
+static char* read_file(const char* filename)
+{
+ char* str;
+ char buf[MAX_WELCOME_SIZE];
+ int fd = open(filename, O_RDONLY);
+ int ret;
+
+ if (fd == -1)
+ return NULL;
+
+ ret = read(fd, buf, MAX_WELCOME_SIZE);
+ close(fd);
+
+ buf[ret > 0 ? ret : 0] = 0;
+ str = strdup(buf);
+
+ return str;
+}
+
+int read_motd(struct welcome_data* data)
+{
+ data->motd = read_file(data->motd_file);
+ return !!data->motd;
+}
+
+int read_rules(struct welcome_data* data)
+{
+ data->rules = read_file(data->rules_file);
+ return !!data->rules;
+}
+
+static void free_welcome_data(struct welcome_data* data)
+{
+ hub_free(data->cmd_motd);
+ hub_free(data->motd_file);
+ hub_free(data->motd);
+ hub_free(data->cmd_rules);
+ hub_free(data->rules_file);
+ hub_free(data->rules);
+ hub_free(data);
+}
+
+
+static void set_error_message(struct plugin_handle* plugin, const char* msg)
+{
+ plugin->error_msg = msg;
+}
+
+static struct welcome_data* parse_config(const char* line, struct plugin_handle* plugin)
+{
+ struct welcome_data* data = (struct welcome_data*) hub_malloc_zero(sizeof(struct welcome_data));
+ struct cfg_tokens* tokens = cfg_tokenize(line);
+ char* token = cfg_token_get_first(tokens);
+
+ if (!data)
+ return 0;
+
+ while (token)
+ {
+ struct cfg_settings* setting = cfg_settings_split(token);
+
+ if (!setting)
+ {
+ set_error_message(plugin, "Unable to parse startup parameters");
+ cfg_tokens_free(tokens);
+ free_welcome_data(data);
+ return 0;
+ }
+
+ if (strcmp(cfg_settings_get_key(setting), "motd") == 0)
+ {
+ data->motd_file = strdup(cfg_settings_get_value(setting));
+ if (!read_motd(data))
+ {
+ set_error_message(plugin, "Unable to read motd file.");
+ cfg_tokens_free(tokens);
+ cfg_settings_free(setting);
+ free_welcome_data(data);
+ return 0;
+ }
+
+ data->cmd_motd = hub_malloc_zero(sizeof(struct plugin_command_handle));
+ PLUGIN_COMMAND_INITIALIZE(data->cmd_motd, (void*) data, "msg", "", auth_cred_guest, command_handler_motd, "Show the message of the day.");
+ }
+ else if (strcmp(cfg_settings_get_key(setting), "rules") == 0)
+ {
+ data->rules_file = strdup(cfg_settings_get_value(setting));
+ if (!read_rules(data))
+ {
+ set_error_message(plugin, "Unable to read rules file.");
+ cfg_tokens_free(tokens);
+ cfg_settings_free(setting);
+ free_welcome_data(data);
+ return 0;
+ }
+
+ data->cmd_rules = hub_malloc_zero(sizeof(struct plugin_command_handle));
+ PLUGIN_COMMAND_INITIALIZE(data->cmd_rules, (void*) data, "rule", "", auth_cred_guest, command_handler_rules, "Show the hub rules.");
+ }
+ else
+ {
+ set_error_message(plugin, "Unknown startup parameters given");
+ cfg_tokens_free(tokens);
+ cfg_settings_free(setting);
+ free_welcome_data(data);
+ return 0;
+ }
+
+ cfg_settings_free(setting);
+ token = cfg_token_get_next(tokens);
+ }
+
+ cfg_tokens_free(tokens);
+ return data;
+}
+
+
+static struct cbuffer* parse_message(struct plugin_user* user, const char* msg)
+{
+ struct cbuffer* buf = cbuf_create(strlen(msg));
+ const char* start = msg;
+ const char* offset = NULL;
+ time_t timestamp = time(NULL);
+ struct tm* now = localtime(×tamp);
+
+ while ((offset = strchr(start, '%')))
+ {
+ cbuf_append_bytes(buf, start, (offset - start));
+
+ offset++;
+ switch (offset[0])
+ {
+ case 'n':
+ cbuf_append(buf, user->nick);
+ break;
+
+ case 'a':
+ cbuf_append(buf, ip_convert_to_string(&user->addr));
+ break;
+
+ case '%':
+ cbuf_append(buf, "%");
+ break;
+
+ case 'H':
+ cbuf_append_strftime(buf, "%H", now);
+ break;
+
+ case 'I':
+ cbuf_append_strftime(buf, "%I", now);
+ break;
+
+ case 'P':
+ cbuf_append_strftime(buf, "%P", now);
+ break;
+
+ case 'p':
+ cbuf_append_strftime(buf, "%p", now);
+ break;
+
+ case 'M':
+ cbuf_append_strftime(buf, "%M", now);
+ break;
+
+ case 'S':
+ cbuf_append_strftime(buf, "%S", now);
+ break;
+ }
+
+ start = offset + 1;
+ }
+
+ if (*start)
+ cbuf_append(buf, start);
+
+ return buf;
+}
+
+static void send_motd(struct plugin_handle* plugin, struct plugin_user* user)
+{
+ struct welcome_data* data = (struct welcome_data*) plugin->ptr;
+ struct cbuffer* buf = NULL;
+ if (data->motd)
+ {
+ buf = parse_message(user, data->motd);
+ plugin->hub.send_message(plugin, user, cbuf_get(buf));
+ cbuf_destroy(buf);
+ }
+}
+
+static void send_rules(struct plugin_handle* plugin, struct plugin_user* user)
+{
+ struct welcome_data* data = (struct welcome_data*) plugin->ptr;
+ struct cbuffer* buf = NULL;
+ if (data->rules)
+ {
+ buf = parse_message(user, data->rules);
+ plugin->hub.send_message(plugin, user, cbuf_get(buf));
+ cbuf_destroy(buf);
+ }
+}
+
+static void on_user_login(struct plugin_handle* plugin, struct plugin_user* user)
+{
+ send_motd(plugin, user);
+}
+
+static int command_handler_motd(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
+{
+ send_motd(plugin, user);
+ return 1;
+}
+
+static int command_handler_rules(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
+{
+ send_rules(plugin, user);
+ return 1;
+}
+
+int plugin_register(struct plugin_handle* plugin, const char* config)
+{
+ struct welcome_data* data;
+ PLUGIN_INITIALIZE(plugin, "Welcome plugin", "0.1", "Sends a welcome message to users when they log into the hub.");
+ data = parse_config(config, plugin);
+
+ if (!data)
+ return -1;
+
+ plugin->ptr = data;
+ plugin->funcs.on_user_login = on_user_login;
+
+ if (data->cmd_motd)
+ plugin->hub.command_add(plugin, data->cmd_motd);
+
+ if (data->cmd_rules)
+ plugin->hub.command_add(plugin, data->cmd_rules);
+
+ return 0;
+}
+
+int plugin_unregister(struct plugin_handle* plugin)
+{
+ struct welcome_data* data = (struct welcome_data*) plugin->ptr;
+
+ if (data->cmd_motd)
+ plugin->hub.command_del(plugin, data->cmd_motd);
+
+ if (data->cmd_rules)
+ plugin->hub.command_del(plugin, data->cmd_rules);
+
+ free_welcome_data(data);
+ return 0;
+}
+