diff mcabber/src/commands.c @ 1607:14690e624e9d

Add modules
author Myhailo Danylenko <isbear@ukrpost.net>
date Sun, 11 Oct 2009 16:01:52 +0200
parents 54029aba9452
children 055ea3cdbcd3
line wrap: on
line diff
--- a/mcabber/src/commands.c	Sun Oct 11 16:01:31 2009 +0200
+++ b/mcabber/src/commands.c	Sun Oct 11 16:01:52 2009 +0200
@@ -93,11 +93,47 @@
 // Global variable for the commands list
 static GSList *Commands;
 
+#ifdef MODULES_ENABLE
+#include <gmodule.h>
+
+static void do_load(char *arg);
+static void do_unload(char *arg);
+
+typedef struct {
+  char *name;
+  GModule *module;
+} loaded_module_t;
+
+GSList *loaded_modules = NULL;
+
+static gint cmd_del_comparator (cmd *a, const char *name)
+{
+  return strcmp(a->name, name);
+}
+
+gpointer cmd_del(const char *name)
+{
+  GSList *command = g_slist_find_custom (Commands, name, (GCompareFunc) cmd_del_comparator);
+  if (command) {
+    cmd *cmnd = command->data;
+    gpointer userdata = cmnd->userdata;
+    Commands = g_slist_delete_link(Commands, command);
+    compl_del_category_word(COMPL_CMD, cmnd->name);
+    g_free(cmnd);
+    return userdata;
+  }
+  return NULL;
+}
 
 //  cmd_add()
 // Adds a command to the commands list and to the CMD completion list
+void cmd_add(const char *name, const char *help, guint flags_row1,
+             guint flags_row2, void (*f)(char*), gpointer userdata)
+#define cmd_add(A, B, C, D, E) cmd_add (A, B, C, D, E, NULL);
+#else
 static void cmd_add(const char *name, const char *help,
         guint flags_row1, guint flags_row2, void (*f)(char*))
+#endif
 {
   cmd *n_cmd = g_new0(cmd, 1);
   strncpy(n_cmd->name, name, 32-1);
@@ -105,6 +141,9 @@
   n_cmd->completion_flags[0] = flags_row1;
   n_cmd->completion_flags[1] = flags_row2;
   n_cmd->func = f;
+#ifdef MODULES_ENABLE
+  n_cmd->userdata = userdata;
+#endif
   Commands = g_slist_append(Commands, n_cmd);
   // Add to completion CMD category
   compl_add_category_word(COMPL_CMD, name);
@@ -165,6 +204,10 @@
   cmd_add("status_to", "Show or set your status for one recipient",
           COMPL_JID, COMPL_STATUS, &do_status_to);
   cmd_add("version", "Show mcabber version", 0, 0, &do_version);
+#ifdef MODULES_ENABLE
+  cmd_add("load", "Load module", 0, 0, &do_load);
+  cmd_add("unload", "Unload module", 0, 0, &do_unload);
+#endif
 
   // Status category
   compl_add_category_word(COMPL_STATUS, "online");
@@ -299,6 +342,23 @@
   compl_add_category_word(COMPL_COLOR, "mucnick");
 }
 
+#ifdef MODULES_ENABLE
+void cmd_deinit ()
+{
+  GSList *el = loaded_modules;
+  while (el) {
+    loaded_module_t *module = el->data;
+    if (!g_module_close ((GModule *) module->module))
+      scr_LogPrint (LPRINT_LOGNORM, "* Module unloading failed: %s",
+                    g_module_error ());
+    g_free (module->name);
+    g_free (module);
+    el = g_slist_next (el);
+  }
+  g_slist_free (loaded_modules);
+}
+#endif
+
 //  expandalias(line)
 // If there is one, expand the alias in line and returns a new allocated line
 // If no alias is found, returns line
@@ -435,7 +495,14 @@
     p++;
   // Call command-specific function
   retval_for_cmds = 0;
+#ifdef MODULES_ENABLE
+  if (curcmd->userdata)
+    (*(void (*)(char *p, gpointer u))curcmd->func)(p, curcmd->userdata);
+  else
+    (*curcmd->func)(p);
+#else
   (*curcmd->func)(p);
+#endif
   g_free(xpline);
   return retval_for_cmds;
 }
@@ -2902,6 +2969,57 @@
   g_slist_free(bm);
 }
 
+#ifdef MODULES_ENABLE
+static void do_load(char *arg)
+{
+  if (!arg || !*arg) {
+    scr_LogPrint (LPRINT_LOGNORM, "Missing modulename.");
+    return;
+  }
+  char *mdir = expand_filename (settings_opt_get ("modules_dir"));
+  char *path = g_module_build_path (mdir, arg);
+  GModule *mod = g_module_open (path, G_MODULE_BIND_LAZY);
+  if (!mod)
+    scr_LogPrint (LPRINT_LOGNORM, "Module %s loading failed: %s",
+                  path, g_module_error ());
+  else {
+    loaded_module_t *module = g_new (loaded_module_t, 1);
+    module->name = g_strdup (arg);
+    module->module = mod;
+    loaded_modules = g_slist_prepend (loaded_modules, module);
+    scr_LogPrint (LPRINT_LOGNORM, "Loaded module %s", arg);
+  }
+  g_free (path);
+  if (mdir)
+    g_free (mdir);
+}
+
+static int module_list_comparator (loaded_module_t *module, const char *name)
+{
+  return g_strcmp0 (module->name, name);
+}
+
+static void do_unload(char *arg)
+{
+  if (!arg || !*arg) {
+    scr_LogPrint (LPRINT_LOGNORM, "Missing modulename.");
+    return;
+  }
+  GSList *module = g_slist_find_custom (loaded_modules, arg, (GCompareFunc) module_list_comparator);
+  if (module) {
+    loaded_module_t *mod = module->data;
+    if (!g_module_close ((GModule *) mod->module))
+      scr_LogPrint (LPRINT_LOGNORM, "Module unloading failed: %s",
+                    g_module_error ());
+    else {
+      g_free (mod->name);
+      g_free (mod);
+      loaded_modules = g_slist_delete_link (loaded_modules, module);
+    }
+  } else
+    scr_LogPrint (LPRINT_LOGNORM, "Module %s not loaded.", arg);
+}
+#endif
 
 static void do_room(char *arg)
 {