Fix bug #158 - Added plugin for setting topic (hub description).

Load plugin mod_topic, and it will provide 3 new user commands:

!topic - set new topic
!cleartopic - reset the topic (use default hub description)
!showtopic - show the current topic
This commit is contained in:
Jan Vidar Krey 2012-04-19 00:21:49 +02:00
parent df7bbc094f
commit 1dba731cc3
8 changed files with 303 additions and 4 deletions

View File

@ -232,6 +232,9 @@ plugin_chat_history_TARGET := mod_chat_history.so
plugin_chat_only_SOURCE := src/plugins/mod_chat_only.c
plugin_chat_only_TARGET := mod_chat_only.so
plugin_topic_SOURCES := src/plugins/mod_topic.c
plugin_topic_TARGET := mod_topic.so
# Source to objects
libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o)
libutils_OBJECTS := $(libutils_SOURCES:.c=.o)
@ -243,7 +246,7 @@ 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_welcome_TARGET) $(plugin_chat_history_TARGET) $(plugin_chat_only_TARGET)
all_plugins := $(plugin_example_TARGET) $(plugin_logging_TARGET) $(plugin_auth_TARGET) $(plugin_auth_sqlite_TARGET) $(plugin_welcome_TARGET) $(plugin_chat_history_TARGET) $(plugin_chat_only_TARGET) $(plugin_topic_TARGET)
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(libutils_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS) $(libadc_common_OBJECTS) $(libadc_client_OBJECTS)
all_OBJECTS += $(all_plugins)
@ -289,6 +292,10 @@ $(plugin_chat_only_TARGET): $(plugin_chat_only_SOURCE) $(libutils_OBJECTS)
$(plugin_welcome_TARGET): $(plugin_welcome_SOURCES) $(libutils_OBJECTS)
$(MSG_CC) $(CC) -shared -fPIC -o $@ $^ $(CFLAGS)
$(plugin_topic_TARGET): $(plugin_topic_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)

View File

@ -148,8 +148,11 @@ static enum command_parse_status command_extract_arguments(struct command_base*
{
int arg = 0;
int opt = 0;
int greedy = 0;
char arg_code;
char* token = NULL;
char* tmp = NULL;
size_t size = 0;
struct hub_command_arg_data* data = NULL;
enum command_parse_status status = cmd_status_ok;
@ -159,8 +162,28 @@ static enum command_parse_status command_extract_arguments(struct command_base*
hub_free(token);
while (status == cmd_status_ok && (arg_code = command->args[arg++]))
{
if (greedy)
{
size = 1;
for (tmp = (char*) list_get_first(tokens); tmp; tmp = (char*) list_get_next(tokens))
size += (strlen(tmp) + 1);
token = hub_malloc_zero(size);
while ((tmp = list_get_first(tokens)))
{
if (*token)
strcat(token, " ");
strcat(token, tmp);
list_remove(tokens, tmp);
hub_free(tmp);
}
}
else
{
token = list_get_first(tokens);
}
if (!token || !*token)
{
status = (arg_code == '?' ? cmd_status_ok : cmd_status_missing_args);
@ -173,6 +196,10 @@ static enum command_parse_status command_extract_arguments(struct command_base*
opt = 1;
continue;
case '+':
greedy = 1;
continue;
case 'u':
data = hub_malloc(sizeof(*data));
data->type = type_user;

View File

@ -128,12 +128,16 @@ extern struct hub_command_arg_data* hub_command_arg_next(struct hub_command* cmd
* 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.
* Prefix with + to make the argument greedy, which causes it to grab the rest of the line ignoring boundaries (only supported for string types).
*
* NOTE: if an argument is optional then all following arguments must also be optional.
* NOTE: You can combine optional and greedy, example: "?+m" would match "", "a", "a b c", etc.
*
* Example:
* "nia" means "nick cid ip"
* "n?p" means "nick [password]" where password is optional.
*
* "?N?N" means two optional integers, this can also be expressed as "?NN".
* "?+m" means an optional string which may contain spaces that would otherwise be split into separate arguments.
*/
struct command_handle
{

View File

@ -159,6 +159,58 @@ struct plugin_command_arg_data* cbfunc_command_arg_next(struct plugin_handle* pl
return (struct plugin_command_arg_data*) hub_command_arg_next((struct hub_command*) cmd, (enum hub_command_arg_type) t);
}
static char* cbfunc_get_hub_name(struct plugin_handle* plugin)
{
struct hub_info* hub = plugin_get_hub(plugin);
char* str_encoded = adc_msg_get_named_argument(hub->command_info, ADC_INF_FLAG_NICK);
char* str = adc_msg_unescape(str_encoded);
hub_free(str_encoded);
return str;
}
static char* cbfunc_get_hub_description(struct plugin_handle* plugin)
{
struct hub_info* hub = plugin_get_hub(plugin);
char* str_encoded = adc_msg_get_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION);
char* str = adc_msg_unescape(str_encoded);
hub_free(str_encoded);
return str;
}
static void cbfunc_set_hub_name(struct plugin_handle* plugin, const char* str)
{
struct hub_info* hub = plugin_get_hub(plugin);
struct adc_message* command;
char* new_str = adc_msg_escape(str ? str : hub->config->hub_name);
adc_msg_replace_named_argument(hub->command_info, ADC_INF_FLAG_NICK, new_str);
// Broadcast hub name
command = adc_msg_construct(ADC_CMD_IINF, (strlen(new_str) + 8));
adc_msg_add_named_argument(command, ADC_INF_FLAG_NICK, new_str);
route_to_all(hub, command);
adc_msg_free(command);
hub_free(new_str);
}
static void cbfunc_set_hub_description(struct plugin_handle* plugin, const char* str)
{
struct hub_info* hub = plugin_get_hub(plugin);
struct adc_message* command;
char* new_str = adc_msg_escape(str ? str : hub->config->hub_description);
adc_msg_replace_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION, new_str);
// Broadcast hub description
command = adc_msg_construct(ADC_CMD_IINF, (strlen(new_str) + 8));
adc_msg_add_named_argument(command, ADC_INF_FLAG_DESCRIPTION, new_str);
route_to_all(hub, command);
adc_msg_free(command);
hub_free(new_str);
}
void plugin_register_callback_functions(struct plugin_handle* handle)
{
handle->hub.send_message = cbfunc_send_message;
@ -168,6 +220,10 @@ void plugin_register_callback_functions(struct plugin_handle* handle)
handle->hub.command_del = cbfunc_command_del;
handle->hub.command_arg_reset = cbfunc_command_arg_reset;
handle->hub.command_arg_next = cbfunc_command_arg_next;
handle->hub.get_name = cbfunc_get_hub_name;
handle->hub.set_name = cbfunc_set_hub_name;
handle->hub.get_description = cbfunc_get_hub_description;
handle->hub.set_description = cbfunc_set_hub_description;
}
void plugin_unregister_callback_functions(struct plugin_handle* handle)

View File

@ -118,6 +118,11 @@ typedef int (*hfunc_command_del)(struct plugin_handle*, struct plugin_command_ha
typedef size_t (*hfunc_command_arg_reset)(struct plugin_handle*, struct plugin_command*);
typedef struct plugin_command_arg_data* (*hfunc_command_arg_next)(struct plugin_handle*, struct plugin_command*, enum plugin_command_arg_type);
typedef char* (*hfunc_get_hub_name)(struct plugin_handle*);
typedef char* (*hfunc_get_hub_description)(struct plugin_handle*);
typedef void (*hfunc_set_hub_name)(struct plugin_handle*, const char*);
typedef void (*hfunc_set_hub_description)(struct plugin_handle*, const char*);
/**
* These are functions created and initialized by the hub and which can be used
* by plugins to access functionality internal to the hub.
@ -131,6 +136,10 @@ struct plugin_hub_funcs
hfunc_command_del command_del;
hfunc_command_arg_reset command_arg_reset;
hfunc_command_arg_next command_arg_next;
hfunc_get_hub_name get_name;
hfunc_get_hub_description get_description;
hfunc_set_hub_name set_name;
hfunc_set_hub_description set_description;
};
struct plugin_handle

101
src/plugins/mod_topic.c Normal file
View File

@ -0,0 +1,101 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2012, 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 <http://www.gnu.org/licenses/>.
*
*/
#include "plugin_api/handle.h"
#include "plugin_api/command_api.h"
#include "util/memory.h"
#include "util/cbuffer.h"
struct topic_plugin_data
{
struct plugin_command_handle* topic;
struct plugin_command_handle* cleartopic;
struct plugin_command_handle* showtopic;
};
static int command_topic_handler(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
struct cbuffer* buf = cbuf_create(128);
struct plugin_command_arg_data* arg = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_string);
plugin->hub.set_description(plugin, arg ? arg->data.string : NULL);
cbuf_append_format(buf, "*** %s: Topic set to \"%s\"", cmd->prefix, arg->data.string);
plugin->hub.send_message(plugin, user, cbuf_get(buf));
cbuf_destroy(buf);
return 0;
}
static int command_cleartopic_handler(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
struct cbuffer* buf = cbuf_create(128);
plugin->hub.set_description(plugin, NULL);
cbuf_append_format(buf, "*** %s: Topic cleared.", cmd->prefix);
plugin->hub.send_message(plugin, user, cbuf_get(buf));
cbuf_destroy(buf);
return 0;
}
static int command_showtopic_handler(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
struct cbuffer* buf = cbuf_create(128);
char* topic = plugin->hub.get_description(plugin);
cbuf_append_format(buf, "*** %s: Current topic is: \"%s\"", cmd->prefix, topic);
plugin->hub.send_message(plugin, user, cbuf_get(buf));
cbuf_destroy(buf);
hub_free(topic);
return 0;
}
int plugin_register(struct plugin_handle* plugin, const char* config)
{
struct topic_plugin_data* data = (struct topic_plugin_data*) hub_malloc(sizeof(struct topic_plugin_data));
data->topic = (struct plugin_command_handle*) hub_malloc_zero(sizeof(struct plugin_command_handle));
data->cleartopic = (struct plugin_command_handle*) hub_malloc_zero(sizeof(struct plugin_command_handle));
data->showtopic = (struct plugin_command_handle*) hub_malloc_zero(sizeof(struct plugin_command_handle));
PLUGIN_INITIALIZE(plugin, "Topic plugin", "1.0", "Add commands for changing the hub topic (description)");
PLUGIN_COMMAND_INITIALIZE(data->topic, (void*) data, "topic", "+m", auth_cred_operator, command_topic_handler, "Set new topic");
PLUGIN_COMMAND_INITIALIZE(data->cleartopic, (void*) data, "cleartopic", "", auth_cred_operator, command_cleartopic_handler, "Clear the current topic");
PLUGIN_COMMAND_INITIALIZE(data->showtopic, (void*) data, "showtopic", "", auth_cred_guest, command_showtopic_handler, "Shows the current topic");
plugin->hub.command_add(plugin, data->topic);
plugin->hub.command_add(plugin, data->cleartopic);
plugin->hub.command_add(plugin, data->showtopic);
plugin->ptr = data;
return 0;
}
int plugin_unregister(struct plugin_handle* plugin)
{
struct topic_plugin_data* data = (struct topic_plugin_data*) plugin->ptr;
plugin->hub.command_del(plugin, data->topic);
plugin->hub.command_del(plugin, data->cleartopic);
plugin->hub.command_del(plugin, data->showtopic);
hub_free(data->topic);
hub_free(data->showtopic);
hub_free(data);
plugin->ptr = NULL;
return 0;
}

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9BBAEFDA-8E0E-4E7F-B8B6-00A3432FC45B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>mod_topic</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)..\src;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)vs2010\$(Configuration);$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXAMPLE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(SolutionDir)\$(Configuration)\uhub_utils.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXAMPLE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\plugins\mod_topic.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -32,6 +32,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uhub-passwd", "uhub-passwd\
{A4FC9D62-D544-4D2A-88D7-A58529C3460B} = {A4FC9D62-D544-4D2A-88D7-A58529C3460B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_topic", "plugins\mod_topic\mod_topic.vcxproj", "{9BBAEFDA-8E0E-4E7F-B8B6-00A3432FC45B}"
ProjectSection(ProjectDependencies) = postProject
{0A3C1519-D877-47D9-A82E-40AC1BC79D75} = {0A3C1519-D877-47D9-A82E-40AC1BC79D75}
{98D8BFE9-DACD-40E1-B7BE-C9079ABF832E} = {98D8BFE9-DACD-40E1-B7BE-C9079ABF832E}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -66,6 +72,10 @@ Global
{E92EB860-AE9E-4532-A75F-0929A7BCF6D0}.Debug|Win32.Build.0 = Debug|Win32
{E92EB860-AE9E-4532-A75F-0929A7BCF6D0}.Release|Win32.ActiveCfg = Release|Win32
{E92EB860-AE9E-4532-A75F-0929A7BCF6D0}.Release|Win32.Build.0 = Release|Win32
{9BBAEFDA-8E0E-4E7F-B8B6-00A3432FC45B}.Debug|Win32.ActiveCfg = Debug|Win32
{9BBAEFDA-8E0E-4E7F-B8B6-00A3432FC45B}.Debug|Win32.Build.0 = Debug|Win32
{9BBAEFDA-8E0E-4E7F-B8B6-00A3432FC45B}.Release|Win32.ActiveCfg = Release|Win32
{9BBAEFDA-8E0E-4E7F-B8B6-00A3432FC45B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE