changeset 11187:744c0708d11f

[gaim-migrate @ 13303] gaim-remote.py implements the functionality of standard gaim-remote, but using DBus. It can also call all gaim functions exported via DBus. dbus-analize-function.py can now produce dbus bindings for GHashTable arguments. committer: Tailor Script <tailor@pidgin.im>
author Piotr Zielinski <zielaj>
date Wed, 03 Aug 2005 23:54:37 +0000
parents bbe84acea03a
children 12fc7a3fbc88
files src/Makefile.am src/dbus-analyze-functions.py src/dbus-bindings.h src/dbus-server.c src/dbus-useful.c src/gaim-remote.py src/status.c
diffstat 7 files changed, 485 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Wed Aug 03 22:58:06 2005 +0000
+++ b/src/Makefile.am	Wed Aug 03 23:54:37 2005 +0000
@@ -146,12 +146,12 @@
 
 if ENABLE_DBUS
 
-dbus_sources  = dbus-server.c dbus-useful.c
+dbus_sources  = dbus-server.c dbus-useful.c 
 dbus_headers  = dbus-server.h dbus-useful.h dbus-maybe.h 
 
 CLEANFILES    = dbus-bindings.c
 
-dbus_exported = dbus-useful.h dbus-define-api.h account.h blist.h connection.h conversation.h core.h roomlist.h
+dbus_exported = dbus-useful.h dbus-define-api.h account.h blist.h connection.h conversation.h core.h roomlist.h status.h server.h
 
 
 dbus-bindings.c: dbus-analyze-functions.py $(dbus_exported)
--- a/src/dbus-analyze-functions.py	Wed Aug 03 22:58:06 2005 +0000
+++ b/src/dbus-analyze-functions.py	Wed Aug 03 23:54:37 2005 +0000
@@ -39,6 +39,7 @@
 #     "gboolean" : ("i", "int")
 #     }
 
+
 simpletypes = ["int", "gint", "guint", "gboolean"]
 
 # for enum in file("dbus-auto-enums.txt"):
@@ -47,7 +48,10 @@
 # functions that shouldn't be exported 
 
 excluded = ["gaim_accounts_load", "gaim_account_set_presence",
-            "gaim_conv_placement_get_fnc_id", "gaim_conv_placement_add_fnc"]
+            "gaim_conv_placement_get_fnc_id", "gaim_conv_placement_add_fnc",
+            "gaim_presence_add_list"]
+
+stringlists = []
 
 pointer = "#pointer#"
 
@@ -77,7 +81,7 @@
     for decl in cdecls:
         print decl
 
-    print "dbus_message_get_args(message_DBUS, error_DBUS, ",
+    print "%s(message_DBUS, error_DBUS, " % argfunc,
     for param in cparams:
         print "DBUS_TYPE_%s, &%s," % param,
     print "DBUS_TYPE_INVALID);"
@@ -105,13 +109,14 @@
     functions.append((function, dparams))
 
 def c_clear():
-    global cparams, cdecls, ccode, cparamsout, ccodeout, dparams
+    global cparams, cdecls, ccode, cparamsout, ccodeout, dparams, argfunc
     dparams = ""
     cparams = []
     cdecls  = []
     ccode  = []
     cparamsout = []
     ccodeout = []
+    argfunc = "dbus_message_get_args"
 
 
 def addstring(*items):
@@ -137,22 +142,30 @@
 # processing an input parameter
 
 def inputvar(mytype, name):
-    global ccode, cparams, cdecls
+    global ccode, cparams, cdecls, ccodeout, argfunc
     const = False
     if mytype[0] == "const":
         mytype = mytype[1:]
         const = True
 
-    # simple types (int, gboolean, etc.) and enums
-    if (len(mytype) == 1) and \
-           ((mytype[0] in simpletypes) or (mytype[0].startswith("Gaim"))):
-        cdecls.append("dbus_int32_t %s;" % name)
-        cparams.append(("INT32", name))
-        addintype("i", name)
-        return
+        
+
 
-    # pointers ...
+    if len(mytype) == 1:
+        # simple types (int, gboolean, etc.) and enums
+        if (mytype[0] in simpletypes) or (mytype[0].startswith("Gaim")):
+            cdecls.append("dbus_int32_t %s;" % name)
+            cparams.append(("INT32", name))
+            addintype("i", name)
+            return
 
+        # va_list, replace by NULL
+        if mytype[0] == "va_list":
+            cdecls.append("va_list %s;" % name);
+            ccode.append("%s = NULL;" % name);
+            return
+
+    # pointers ... 
     if (len(mytype) == 2) and (mytype[1] == pointer):
         # strings
         if mytype[0] == "char":
@@ -165,6 +178,19 @@
             else:
                 raise myexception
 
+        # memory leak if an error occurs later ...
+        elif mytype[0] == "GHashTable":
+            argfunc = "gaim_dbus_message_get_args"
+            cdecls.append("DBusMessageIter %s_ITER;" % name)
+            cdecls.append("GHashTable *%s;" % name)
+            cparams.append(("ARRAY", "%s_ITER" % name))
+            ccode.append("%s = gaim_dbus_iter_hash_table(&%s_ITER, error_DBUS);" \
+                         % (name, name))
+            ccode.append("CHECK_ERROR(error_DBUS);")
+            ccodeout.append("g_hash_table_destroy(%s);" % name)
+            addintype("a{ss}", name)
+            return
+
         # known object types are transformed to integer handles
         elif mytype[0].startswith("Gaim"):
             cdecls.append("dbus_int32_t %s_ID;" %  name)
@@ -190,18 +216,26 @@
 
 # processing an output parameter
 
-def outputvar(mytype, name, call):
+def outputvar(mytype, name, call, function):
     # the "void" type is simple ...
     if mytype == ["void"]:
         ccode.append("%s;" % call) # just call the function
         return
 
-    # a constant string
-    if mytype == ["const", "char", pointer]:
+    const = False
+    if mytype[0] == "const":
+        mytype = mytype[1:]
+        const = True
+
+
+    # a string
+    if mytype == ["char", pointer]:
         cdecls.append("const char *%s;" % name)
         ccode.append("%s = null_to_empty(%s);" % (name, call))
         cparamsout.append(("STRING", name))
         addouttype("s", name)
+        if not const:
+            ccodeout.append("g_free(%s);" % name)
         return
 
     # simple types (ints, booleans, enums, ...)
@@ -225,17 +259,31 @@
             return
 
         # GList*, GSList*, assume that list is a list of objects
-        # not a list of strings!!!
-        # this does NOT release memory occupied by the list
+
+        # fixme: at the moment, we do NOT free the memory occupied by
+        # the list, we should free it if the list has NOT been declared const
+
+        # fixme: we assume that this is a list of objects, not a list
+        # of strings
+
         if mytype[0] in ["GList", "GSList"]:
             cdecls.append("dbus_int32_t %s_LEN;" % name)
-            cdecls.append("dbus_int32_t *%s;" % name)
-            ccode.append("%s = gaim_dbusify_%s(%s, FALSE, &%s_LEN);" % \
-                         (name, mytype[0], call, name))
-            cparamsout.append("DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &%s, %s_LEN" \
+            ccodeout.append("g_free(%s);" % name)
+
+            if function in stringlists:
+                cdecls.append("char **%s;" % name)
+                ccode.append("%s = gaim_%s_to_array(%s, FALSE, &%s_LEN);" % \
+                             (name, mytype[0], call, name))
+                cparamsout.append("DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &%s, %s_LEN" \
                               % (name, name))
-            ccodeout.append("g_free(%s);" % name)
-            addouttype("ai", name)
+                addouttype("as", name)
+            else:
+                cdecls.append("dbus_int32_t *%s;" % name)
+                ccode.append("%s = gaim_dbusify_%s(%s, FALSE, &%s_LEN);" % \
+                             (name, mytype[0], call, name))
+                cparamsout.append("DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &%s, %s_LEN" \
+                                  % (name, name))
+                addouttype("ai", name)
             return
 
     raise myexception
@@ -255,16 +303,21 @@
     function = function.lower()
 
     names = []
+    unnamed = 0
     for param in paramlist:
         tokens = param.split()
-        if len(tokens) < 2:
+        if len(tokens) == 0:
             raise myexception
-        type, name = tokens[:-1], tokens[-1]
+        if (len(tokens) == 1) or (tokens[-1] == pointer):
+            unnamed += 1
+            type, name = tokens, "param%i" % unnamed
+        else:
+            type, name = tokens[:-1], tokens[-1]
         inputvar(type, name)
         names.append(name)
 
     outputvar(functiontype, "RESULT",
-              "%s(%s)" % (origfunction, ", ".join(names)))
+              "%s(%s)" % (origfunction, ", ".join(names)), function)
 
     c_print(function)
 
--- a/src/dbus-bindings.h	Wed Aug 03 22:58:06 2005 +0000
+++ b/src/dbus-bindings.h	Wed Aug 03 23:54:37 2005 +0000
@@ -56,10 +56,40 @@
 	CHECK_ERROR(error);						\
     } G_STMT_END
 
+
+dbus_bool_t
+gaim_dbus_message_get_args (DBusMessage     *message,
+			    DBusError       *error,
+			    int              first_arg_type,
+			    ...);
+dbus_bool_t
+gaim_dbus_message_get_args_valist (DBusMessage     *message,
+				   DBusError       *error,
+				   int              first_arg_type,
+				   va_list          var_args);
+
+dbus_bool_t
+gaim_dbus_message_iter_get_args (DBusMessageIter *iter,
+				 DBusError       *error,
+				 int              first_arg_type,
+				 ...);
+
+dbus_bool_t
+gaim_dbus_message_iter_get_args_valist (DBusMessageIter *iter,
+					DBusError       *error,
+					int              first_arg_type,
+					va_list          var_args);
+
 dbus_int32_t* gaim_dbusify_GList(GList *list, gboolean free_memory, 
 				 dbus_int32_t *len);
 dbus_int32_t* gaim_dbusify_GSList(GSList *list, gboolean free_memory,
 				  dbus_int32_t *len);
+gpointer* gaim_GList_to_array(GList *list, gboolean free_memory,
+			      dbus_int32_t *len);
+gpointer* gaim_GSList_to_array(GSList *list, gboolean free_memory,
+			      dbus_int32_t *len);
+GHashTable *gaim_dbus_iter_hash_table(DBusMessageIter *iter, DBusError *error);
+
 const char* empty_to_null(const char *str);
 const char* null_to_empty(const char *s);
 
--- a/src/dbus-server.c	Wed Aug 03 22:58:06 2005 +0000
+++ b/src/dbus-server.c	Wed Aug 03 23:54:37 2005 +0000
@@ -96,7 +96,7 @@
 
 gint gaim_dbus_pointer_to_id(gpointer node) {
     gint id = GPOINTER_TO_INT(g_hash_table_lookup(map_node_id, node));
-    g_return_val_if_fail(id, 0);
+    g_return_val_if_fail(id || node == NULL, 0);
     return id;
 }
 	
@@ -136,7 +136,109 @@
     
     return ptr;
 }
+
+
+/**************************************************************************/
+/** @name Modified versions of some DBus functions                        */
+/**************************************************************************/
+
+dbus_bool_t
+gaim_dbus_message_get_args (DBusMessage     *message,
+                       DBusError       *error,
+		       int              first_arg_type,
+		       ...)
+{
+  dbus_bool_t retval;
+  va_list var_args;
+
+  va_start (var_args, first_arg_type);
+  retval = gaim_dbus_message_get_args_valist (message, error, first_arg_type, var_args);
+  va_end (var_args);
+
+  return retval;
+}
+
+dbus_bool_t
+gaim_dbus_message_get_args_valist (DBusMessage     *message,
+				   DBusError       *error,
+				   int              first_arg_type,
+				   va_list          var_args)
+{
+  DBusMessageIter iter;
+
+  dbus_message_iter_init (message, &iter);
+  return gaim_dbus_message_iter_get_args_valist (&iter, error, first_arg_type, var_args);
+}
+
+dbus_bool_t
+gaim_dbus_message_iter_get_args(DBusMessageIter *iter,
+				DBusError       *error,
+				int              first_arg_type,
+				...)
+{
+  dbus_bool_t retval;
+  va_list var_args;
+
+  va_start (var_args, first_arg_type);
+  retval = gaim_dbus_message_iter_get_args_valist(iter, error, first_arg_type, var_args);
+  va_end (var_args);
+
+  return retval;
+}
+
+#define TYPE_IS_CONTAINER(typecode)             \
+    ((typecode) == DBUS_TYPE_STRUCT ||          \
+     (typecode) == DBUS_TYPE_DICT_ENTRY ||      \
+     (typecode) == DBUS_TYPE_VARIANT ||         \
+     (typecode) == DBUS_TYPE_ARRAY)
+
+
+dbus_bool_t
+gaim_dbus_message_iter_get_args_valist (DBusMessageIter *iter,
+					DBusError       *error,
+					int              first_arg_type,
+					va_list          var_args)
+{
+    int spec_type, msg_type, i;
+
+    spec_type = first_arg_type;
+    
+    for(i=0; spec_type != DBUS_TYPE_INVALID; i++) {
+	msg_type = dbus_message_iter_get_arg_type (iter);
+
+	if (msg_type != spec_type) {
+	    dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+			    "Argument %d is specified to be of type \"%i\", but "
+			    "is actually of type \"%i\"\n", i,
+			    spec_type, msg_type);
+          return FALSE;
+	}
+
+	if (!TYPE_IS_CONTAINER(spec_type)) {
+	    gpointer ptr;
+	    ptr = va_arg (var_args, gpointer);
+	    dbus_message_iter_get_basic(iter, ptr);
+	}
+	else {
+	    DBusMessageIter *sub;
+	    sub = va_arg (var_args, DBusMessageIter*);
+	    dbus_message_iter_recurse(iter, sub);
+	    g_print("subiter %i:%i\n", (int) sub, * (int*) sub);
+	    break;		/* for testing only! */
+	}
 	
+	spec_type = va_arg (var_args, int);
+	if (!dbus_message_iter_next(iter) && spec_type != DBUS_TYPE_INVALID) {
+	    dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+			    "Message has only %d arguments, but more were expected", i);
+	    return FALSE;
+        }
+    }
+  return TRUE;
+}
+
+
+
 /**************************************************************************/
 /** @name Useful functions                                                */
 /**************************************************************************/
@@ -155,9 +257,6 @@
 		return "";
 }
 
-
-
-
 dbus_int32_t* gaim_dbusify_GList(GList *list, gboolean free_memory,
 				 dbus_int32_t *len)
  {
@@ -194,6 +293,78 @@
 	return array;
 }
 
+gpointer* gaim_GList_to_array(GList *list, gboolean free_memory,
+			      dbus_int32_t *len)
+{
+	gpointer *array;
+	int i;
+	GList *elem;
+
+	*len = g_list_length(list);
+	array = g_new0(gpointer, g_list_length(list));
+	for(i = 0, elem = list; elem != NULL; elem = elem->next, i++) 
+		array[i] = elem->data;
+
+	if (free_memory)
+		g_list_free(list);
+
+	return array;
+}
+
+gpointer* gaim_GSList_to_array(GSList *list, gboolean free_memory,
+			      dbus_int32_t *len)
+{
+	gpointer *array;
+	int i;
+	GSList *elem;
+
+	*len = g_slist_length(list);
+	array = g_new0(gpointer, g_slist_length(list));
+	for(i = 0, elem = list; elem != NULL; elem = elem->next, i++) 
+		array[i] = elem->data;
+
+	if (free_memory)
+		g_slist_free(list);
+
+	return array;
+}
+
+GHashTable *gaim_dbus_iter_hash_table(DBusMessageIter *iter, DBusError *error) {
+    GHashTable *hash;
+
+    /* we do not need to destroy strings because they are part of the message */
+    hash = g_hash_table_new(g_str_hash, g_str_equal); 
+
+    do {
+	char *key, *value;
+	DBusMessageIter subiter;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) 
+	    goto error;		/* With all due respect to Dijkstra,
+				   this goto is for exception
+				   handling, and it is ok because it
+				   avoids duplication of the code
+				   responsible for destroying the hash
+				   table.  Exceptional instructions
+				   for exceptional situations. */	    
+
+	dbus_message_iter_recurse(iter, &subiter);
+	if (!gaim_dbus_message_iter_get_args(&subiter, error, 
+					     DBUS_TYPE_STRING, &key,
+					     DBUS_TYPE_STRING, &value,
+					     DBUS_TYPE_INVALID))
+	    goto error;		/* same here */
+
+	g_hash_table_insert(hash, key, value);
+    } while (dbus_message_iter_next(iter));
+    
+    return hash;
+
+ error:
+    g_hash_table_destroy(hash);
+    return NULL;
+}
+
 /**************************************************************/
 /* DBus bindings ...                                          */
 /**************************************************************/
@@ -260,7 +431,9 @@
 }
 
 
-/* Introspection */
+/**************************************************************************/
+/** @name Signals                                                         */
+/**************************************************************************/
 
 static const char *gettext(const char **ptr) {
     const char *text = *ptr;
@@ -307,9 +480,9 @@
 		type = gettext(&text);
 		name = gettext(&text);
 		
-	    g_string_append_printf(str, 
-				   "<arg name='%s' type='%s' direction='%s'/>\n",
-				   name, type, direction);
+		g_string_append_printf(str, 
+				       "<arg name='%s' type='%s' direction='%s'/>\n",
+				       name, type, direction);
 	    }
 	    g_string_append(str, "</method>\n");
 	}
@@ -535,7 +708,3 @@
 }
 
 
-/* Introspection support */
-
-
-
--- a/src/dbus-useful.c	Wed Aug 03 22:58:06 2005 +0000
+++ b/src/dbus-useful.c	Wed Aug 03 23:54:37 2005 +0000
@@ -1,4 +1,9 @@
+#include <string.h>
+#include <glib.h>
+
 #include "conversation.h"
+#include "util.h"
+
 
 
 GaimAccount *
@@ -46,3 +51,25 @@
 }
 
 
+/* DBusMessage *gaim_account_set_status_DBUS(DBusMessage *message_DBUS, DBusError *error_DBUS)  */
+/* { */
+/*     DBusMessage *reply; */
+/*     DBusMessageIter iter; */
+
+/*     dbus_int32_t account, active;     */
+/*     char *status_id; */
+    
+/*     dbus_message_iter_init(message, &iter); */
+/* const char *name; */
+/* const char *protocol; */
+
+/* dbus_message_get_args(message_DBUS, error_DBUS,  DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &protocol, DBUS_TYPE_INVALID); */
+/* CHECK_ERROR(error_DBUS); */
+/* NULLIFY(name); */
+/* NULLIFY(protocol); */
+/* GAIM_DBUS_POINTER_TO_ID(RESULT, gaim_accounts_find_any(name, protocol), error_DBUS); */
+/* reply_DBUS =  dbus_message_new_method_return (message_DBUS); */
+/* dbus_message_append_args(reply_DBUS,  DBUS_TYPE_INT32, &RESULT,  DBUS_TYPE_INVALID); */
+/* return reply_DBUS; */
+
+/* } */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gaim-remote.py	Wed Aug 03 23:54:37 2005 +0000
@@ -0,0 +1,157 @@
+#!/usr/bin/python
+
+import dbus
+import re
+import urllib
+import sys
+
+import xml.dom.minidom 
+
+xml.dom.minidom.Element.all   = xml.dom.minidom.Element.getElementsByTagName
+
+obj = dbus.SessionBus().get_object("org.gaim.GaimService", "/org/gaim/GaimObject")
+gaim = dbus.Interface(obj, "org.gaim.GaimInterface")
+
+class CheckedObject:
+    def __init__(self, obj):
+        self.obj = obj
+
+    def __getattr__(self, attr):
+        return CheckedAttribute(self, attr)
+
+class CheckedAttribute:
+    def __init__(self, cobj, attr):
+        self.cobj = cobj
+        self.attr = attr
+        
+    def __call__(self, *args):
+        result = self.cobj.obj.__getattr__(self.attr)(*args)
+        if result == 0:
+            raise "Error: " + self.attr + " " + str(args) + " returned " + str(result)
+        return result
+            
+cgaim = CheckedObject(gaim)
+
+urlregexp = r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?"
+
+def extendlist(list, length, fill):
+    if len(list) < length:
+        return list + [fill] * (length - len(list))
+    else:
+        return list
+
+def convert(value):
+    try:
+        return int(value)
+    except:
+        return value
+
+def execute(uri):
+    match = re.match(urlregexp, uri)
+    protocol = match.group(2)
+    if protocol is not None:
+        protocol = "prpl-" + protocol
+    command = match.group(5)
+    paramstring = match.group(7) 
+    params = {}
+    if paramstring is not None:
+        for param in paramstring.split("&"):
+            key, value = extendlist(param.split("=",1), 2, "")
+            params[key] = urllib.unquote(value)
+
+    accountname = params.get("account", "")
+
+    if command == "goim":
+        account = cgaim.GaimAccountsFindConnected(accountname, protocol)
+        conversation = cgaim.GaimConversationNew(1, account, params["screenname"])
+        if "message" in params:
+            im = cgaim.GaimConversationGetImData(conversation)
+            gaim.GaimConvImSend(im, params["message"])
+        return None
+
+    elif command == "gochat":
+        account = cgaim.GaimAccountsFindConnected(accountname, protocol)
+        connection = cgaim.GaimAccountGetConnection(account)
+        return gaim.ServJoinChat(connection, params)
+
+    elif command == "addbuddy":
+        account = cgaim.GaimAccountsFindConnected(accountname, protocol)
+        return cgaim.GaimBlistRequestAddBuddy(account, params["screenname"],
+                                              params.get("group", ""), "")
+
+    elif command == "setstatus":
+        if "account" in params:
+            accounts = [cgaim.GaimAccountsFindConnected(accountname, protocol)]
+        else:
+            accounts = gaim.GaimAccountsGetAllActive()
+
+        for account in accounts:
+            status = gaim.GaimAccountGetStatus(account, params["status"])
+            for key, value in params.items():
+                if key not in ["state", "account"]:
+                    gaim.GaimStatusSetAttrString(status, key, value)
+            gaim.GaimAccountSetStatusVargs(account, params["status"], 1)
+        return None
+
+    elif command == "quit":
+        return gaim.GaimCoreQuit()
+
+    elif command == "uri":
+        return None
+
+    else:
+        match = re.match(r"(\w+)\s*\(([^)]*)\)", command)
+        if match is not None:
+            name = match.group(1)
+            argstr = match.group(2)
+            if argstr == "":
+                args = []
+            else:
+                args = argstr.split(",")
+            fargs = []
+            for arg in args:
+                fargs.append(convert(arg.strip()))
+            return gaim.__getattr__(name)(*fargs)
+        else:
+            # introspect the object to get parameter names and types
+            # this is slow because the entire introspection info must be downloaded
+            data = dbus.Interface(obj, "org.freedesktop.DBus.Introspectable").\
+                   Introspect()
+            introspect = xml.dom.minidom.parseString(data).documentElement
+            for method in introspect.all("method"):
+                if command == method.getAttribute("name"):
+                    methodparams = []
+                    for arg in method.all("arg"):
+                        if arg.getAttribute("direction") == "in":
+                            value = params[arg.getAttribute("name")]
+                            type = arg.getAttribute("type")
+                            if type == "s":
+                                methodparams.append(value)
+                            elif type == "i":
+                                methodparams.append(int(value))
+                            else:
+                                raise "Don't know how to handle type \"%s\"" % type
+                            return gaim.__getattr__(command)(*methodparams)
+            raise "Unknown command: %s" % command
+
+def example_code_do_not_call():
+    execute("jabber:addbuddy?screenname=friend")
+    execute("setstatus?status=away&message=don't disturb")
+
+    account = execute("GaimAccountsFindConnected?name=&protocol=")
+    execute("GaimConversationNew?type=1&account=%i&name=testone@localhost" % account)
+
+    execute("jabber:addbuddy?screenname=friend")
+    execute("jabber:goim?screenname=testone@localhost&message=hi")
+
+    execute("jabber:gochat?room=TestRoom&server=conference.localhost")
+    execute("jabber:goim?screenname=testone@localhost&message=hi")
+
+
+
+
+
+for arg in sys.argv[1:]:
+    print execute(arg)
+    
+    
--- a/src/status.c	Wed Aug 03 22:58:06 2005 +0000
+++ b/src/status.c	Wed Aug 03 23:54:37 2005 +0000
@@ -26,6 +26,7 @@
 
 #include "blist.h"
 #include "core.h"
+#include "dbus-maybe.h"
 #include "debug.h"
 #include "notify.h"
 #include "prefs.h"
@@ -221,6 +222,7 @@
 	g_return_val_if_fail(name      != NULL,              NULL);
 
 	status_type = g_new0(GaimStatusType, 1);
+	GAIM_DBUS_REGISTER_POINTER(status_type, GaimStatusType);
 
 	status_type->primitive     = primitive;
 	status_type->id            = g_strdup(id);
@@ -296,6 +298,7 @@
 		g_list_free(status_type->attrs);
 	}
 
+	GAIM_DBUS_UNREGISTER_POINTER(status_type);
 	g_free(status_type);
 }
 
@@ -504,6 +507,7 @@
 	g_return_val_if_fail(value_type != NULL, NULL);
 
 	attr = g_new0(GaimStatusAttr, 1);
+	GAIM_DBUS_REGISTER_POINTER(attr, GaimStatusAttr);
 
 	attr->id         = g_strdup(id);
 	attr->name       = g_strdup(name);
@@ -522,6 +526,7 @@
 
 	gaim_value_destroy(attr->value_type);
 
+	GAIM_DBUS_UNREGISTER_POINTER(attr);
 	g_free(attr);
 }
 
@@ -563,6 +568,7 @@
 	g_return_val_if_fail(presence    != NULL, NULL);
 
 	status = g_new0(GaimStatus, 1);
+	GAIM_DBUS_REGISTER_POINTER(status, GaimStatus);
 
 	status->type     = status_type;
 	status->presence = presence;
@@ -599,6 +605,7 @@
 
 	g_hash_table_destroy(status->attr_values);
 
+	GAIM_DBUS_UNREGISTER_POINTER(status);
 	g_free(status);
 }
 
@@ -1066,6 +1073,7 @@
 	g_return_val_if_fail(context != GAIM_PRESENCE_CONTEXT_UNSET, NULL);
 
 	presence = g_new0(GaimPresence, 1);
+	GAIM_DBUS_REGISTER_POINTER(presence, GaimPresence);
 
 	presence->context = context;
 
@@ -1174,6 +1182,7 @@
 
 	g_hash_table_destroy(presence->status_table);
 
+	GAIM_DBUS_UNREGISTER_POINTER(presence);
 	g_free(presence);
 }