changeset 11146:1c5398ccbeb0

[gaim-migrate @ 13217] Gaim-DBUS signal export works with DBUS >= 0.35 Various gaim API functions available through DBUS committer: Tailor Script <tailor@pidgin.im>
author Piotr Zielinski <zielaj>
date Fri, 22 Jul 2005 19:47:29 +0000
parents dbc518c453f2
children 616feca04ada
files configure.ac plugins/perl/Makefile.am src/Makefile.am src/account.c src/account.h src/blist.c src/connection.c src/conversation.c src/dbus-analyze-functions.py src/dbus-analyze-types.py src/dbus-client-example.py src/dbus-define-api.h src/dbus-maybe.h src/dbus-server.c src/dbus-server.h src/dbus-service-end.xml src/dbus-service.xml src/dbus-useful.c src/dbus-useful.h src/signals.c
diffstat 20 files changed, 915 insertions(+), 707 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Fri Jul 22 07:11:08 2005 +0000
+++ b/configure.ac	Fri Jul 22 19:47:29 2005 +0000
@@ -310,12 +310,12 @@
 
 AC_ARG_ENABLE(dbus,     [  --enable-dbus           enable DBUS support],,enable_dbus=no)
 
-if test "x$enable_dbus" = "xyes"; then
+if test "x$enable_dbus" = "xyes" ; then
    AC_CHECK_PROG(enable_dbus, dbus-binding-tool, yes, no)
 fi
 
-if test "x$enable_dbus" = "xyes"; then
-   	PKG_CHECK_MODULES(DBUS, [dbus-1 >= 0.34 dbus-glib-1 >= 0.34],
+if test "x$enable_dbus" = "xyes" ; then
+   	PKG_CHECK_MODULES(DBUS, [dbus-1 >= 0.35 dbus-glib-1 >= 0.35],
 	[
 		AC_SUBST(DBUS_CFLAGS)
 		AC_SUBST(DBUS_LIBS)
@@ -331,7 +331,35 @@
 	fi
 fi
 
-if test "x$enable_dbus" = "xyes"; then
+dnl  Why do we need python?  
+
+dnl  Python scripts are used to auto-generate about 3000 lines of C
+dnl  and XML code that wraps (part of) the existing Gaim API so that
+dnl  it is now accessible through DBUS.
+
+dnl  Python is only required if --enable-dbus is used, and only for
+dnl  the build process to generate the code, not for running gaim.
+dnl  This autogenerated code is system-independent, so in principle we
+dnl  can generate all of it before shipping.  But I thought adding
+dnl  auto-generated stuff to the CVS is inelegant.  Alternatively,
+dnl  these python scripts could be rewritten in C (brrrr ...).
+
+if test "x$enable_dbus" = "xyes" ; then
+        AC_PATH_PROG([PYTHON], [python], [no])
+	if test "x$PYTHON" = "xno" ; then
+		AC_MSG_WARN([python interpreter not found in your path])
+		enable_dbus=no
+	fi
+fi
+
+if test "x$enable_dbus" = "xyes" ; then
+	if $PYTHON -c "import sys; sys.exit(sys.version[[:3]] >= '2.4')" ; then
+		AC_MSG_WARN([python version >= 2.4 required])
+		enable_dbus=no
+	fi	
+fi
+
+if test "x$enable_dbus" = "xyes" ; then
    	AC_DEFINE(HAVE_DBUS, 1, [Define if we're using DBUS.])
 	echo "Building with DBUS support"
 else
--- a/plugins/perl/Makefile.am	Fri Jul 22 07:11:08 2005 +0000
+++ b/plugins/perl/Makefile.am	Fri Jul 22 19:47:29 2005 +0000
@@ -129,7 +129,7 @@
 		$(MAKE) clean; \
 		cd ..; \
 	done
-	rm *.so
+	rm -f *.so
 
 distclean-generic:
 	@for dir in $(perl_dirs); do \
--- a/src/Makefile.am	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/Makefile.am	Fri Jul 22 19:47:29 2005 +0000
@@ -146,23 +146,37 @@
 
 if ENABLE_DBUS
 
-dbus_sources = dbus-server.c  
-dbus_headers  = dbus-server.h
+dbus_sources = dbus-server.c dbus-useful.c
+dbus_headers  = dbus-server.h dbus-useful.h dbus-maybe.h 
+dbus_exported_headers = dbus-useful.h dbus-define-api.h account.h blist.h connection.h conversation.h core.h roomlist.h
+
+CLEANFILES=dbus-auto-enum-types.h dbus-auto-enums.txt dbus-auto-structs.txt dbus-generated-code.c dbus-generated-code.xml dbus-service-all.xml dbus-server-bindings.c
 
-# do not use gaim-client, use gaim-send instead
-# bin_PROGRAMS      += gaim-client
-#gaim_client_SOURCES      = dbus-client.c
-#gaim_client_DEPENDENCIES = @LIBOBJS@
-#gaim_client_LDADD        = @LIBOBJS@ $(GLIB_LIBS) $(DBUS_LIBS) $(INTLLIBS)
+dbus-auto-structs.txt: dbus-analyze-types.py $(gaim_coreheaders)
+	cat $(gaim_coreheaders) | $(PYTHON) dbus-analyze-types.py --keyword=struct --list > $@
+
+dbus-auto-enums.txt: dbus-analyze-types.py $(gaim_coreheaders)
+	cat $(gaim_coreheaders) | $(PYTHON) dbus-analyze-types.py --keyword=enum --list > $@
+
+dbus-auto-enum-types.h: dbus-analyze-types.py $(gaim_coreheaders)
+	cat $(gaim_coreheaders) | $(PYTHON) dbus-analyze-types.py --keyword=struct --enum > $@
 
-dbus-client-bindings.c: dbus-service.xml
-	dbus-binding-tool --prefix=gaim_object --mode=glib-client --output=$@ $<
+dbus-generated-code.c: dbus-analyze-functions.py dbus-auto-structs.txt dbus-auto-enums.txt $(dbus_exported_headers)
+	cat $(dbus_exported_headers) | $(PYTHON) dbus-analyze-functions.py --mode=c > $@
+
+dbus-generated-code.xml: dbus-analyze-functions.py dbus-auto-structs.txt dbus-auto-enums.txt $(dbus_exported_headers)
+	cat $(dbus_exported_headers) | $(PYTHON) dbus-analyze-functions.py --mode=xml > $@
 
-dbus-server-bindings.c: dbus-service.xml
-	dbus-binding-tool --prefix=gaim_object --mode=glib-server --output=$@ $<
+dbus-service-all.xml: dbus-service.xml dbus-generated-code.xml dbus-service-end.xml
+	cat $^ > $@
 
-dbus-client.$(OBJEXT): dbus-client-bindings.c
-dbus-server.$(OBJEXT): dbus-server-bindings.c
+dbus-server-bindings.c: dbus-service-all.xml $(DBUS_BINDING_TOOL)
+	$(DBUS_BINDING_TOOL) --prefix=gaim_object --mode=glib-server --output=$@ $<
+
+
+$(gaim_OBJECTS): dbus-auto-enum-types.h
+
+dbus-server.$(OBJEXT): dbus-server-bindings.c dbus-generated-code.c
 
 endif
 
--- a/src/account.c	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/account.c	Fri Jul 22 19:47:29 2005 +0000
@@ -666,6 +666,7 @@
 		return account;
 
 	account = g_new0(GaimAccount, 1);
+	GAIM_DBUS_REGISTER_POINTER(account, GaimAccount);
 
 	gaim_account_set_username(account, username);
 
@@ -693,7 +694,6 @@
 
 	gaim_presence_set_status_active(account->presence, "offline", TRUE);
 
-	GAIM_DBUS_REGISTER_POINTER(account, DBUS_POINTER_ACCOUNT);
 	return account;
 }
 
--- a/src/account.h	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/account.h	Fri Jul 22 19:47:29 2005 +0000
@@ -267,6 +267,8 @@
  *
  * @param account  The account.
  * @param presence The presence.
+ *
+ * This function does not seem to be implemented anywhere ...
  */
 void gaim_account_set_presence(GaimAccount *account, GaimPresence *presence);
 
--- a/src/blist.c	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/blist.c	Fri Jul 22 19:47:29 2005 +0000
@@ -658,6 +658,7 @@
 GaimBuddyList *gaim_blist_new()
 {
 	GaimBuddyList *gbl = g_new0(GaimBuddyList, 1);
+	GAIM_DBUS_REGISTER_POINTER(gbl, GaimBuddyList);
 
 	gbl->ui_ops = gaim_blist_get_ui_ops();
 
@@ -1054,7 +1055,7 @@
 	if (ops != NULL && ops->new_node != NULL)
 		ops->new_node((GaimBlistNode *)chat);
 
-	GAIM_DBUS_REGISTER_POINTER(chat, DBUS_POINTER_CHAT);
+	GAIM_DBUS_REGISTER_POINTER(chat, GaimChat);
 	return chat;
 }
 
@@ -1080,7 +1081,7 @@
 	if (ops && ops->new_node)
 		ops->new_node((GaimBlistNode *)buddy);
 
-	GAIM_DBUS_REGISTER_POINTER(buddy, DBUS_POINTER_BUDDY);
+	GAIM_DBUS_REGISTER_POINTER(buddy, GaimBuddy);
 	return buddy;
 }
 
@@ -1352,7 +1353,7 @@
 	if (ops && ops->new_node)
 		ops->new_node((GaimBlistNode *)contact);
 
-	GAIM_DBUS_REGISTER_POINTER(contact, DBUS_POINTER_CONTACT);
+	GAIM_DBUS_REGISTER_POINTER(contact, GaimContact);
 	return contact;
 }
 
@@ -1432,7 +1433,7 @@
 	if (ops && ops->new_node)
 		ops->new_node((GaimBlistNode *)group);
 
-	GAIM_DBUS_REGISTER_POINTER(group, DBUS_POINTER_GROUP);
+	GAIM_DBUS_REGISTER_POINTER(group, GaimGroup);
 	return group;
 }
 
--- a/src/connection.c	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/connection.c	Fri Jul 22 19:47:29 2005 +0000
@@ -26,6 +26,7 @@
 #include "account.h"
 #include "blist.h"
 #include "connection.h"
+#include "dbus-maybe.h"
 #include "debug.h"
 #include "gaim.h"
 #include "log.h"
@@ -118,6 +119,9 @@
 	}
 
 	gc = g_new0(GaimConnection, 1);
+	GAIM_DBUS_REGISTER_POINTER(gc, GaimConnection);
+
+
 	gc->prpl = prpl;
 	if ((password != NULL) && (*password != '\0'))
 		gc->password = g_strdup(password);
@@ -230,6 +234,7 @@
 	if (gc->disconnect_timeout)
 		gaim_timeout_remove(gc->disconnect_timeout);
 
+	GAIM_DBUS_UNREGISTER_POINTER(gc);
 	g_free(gc);
 }
 
--- a/src/conversation.c	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/conversation.c	Fri Jul 22 19:47:29 2005 +0000
@@ -22,6 +22,7 @@
 #include "internal.h"
 #include "blist.h"
 #include "conversation.h"
+#include "dbus-maybe.h"
 #include "debug.h"
 #include "imgstore.h"
 #include "notify.h"
@@ -266,6 +267,7 @@
 	GaimConvWindow *win;
 
 	win = g_new0(GaimConvWindow, 1);
+	GAIM_DBUS_REGISTER_POINTER(win, GaimConvWindow);
 
 	windows = g_list_append(windows, win);
 
@@ -318,6 +320,7 @@
 
 		windows = g_list_remove(windows, win);
 
+		GAIM_DBUS_UNREGISTER_POINTER(win);
 		g_free(win);
 	}
 }
@@ -672,6 +675,7 @@
 	g_return_val_if_fail(gc != NULL, NULL);
 
 	conv = g_new0(GaimConversation, 1);
+	GAIM_DBUS_REGISTER_POINTER(conv, GaimConversation);
 
 	conv->type         = type;
 	conv->account      = account;
@@ -692,6 +696,7 @@
 		GaimBuddyIcon *icon;
 		conv->u.im = g_new0(GaimConvIm, 1);
 		conv->u.im->conv = conv;
+		GAIM_DBUS_REGISTER_POINTER(conv->u.im, GaimConvIm);
 
 		ims = g_list_append(ims, conv);
 		if ((icon = gaim_buddy_icons_find(account, name)))
@@ -706,6 +711,7 @@
 
 		conv->u.chat = g_new0(GaimConvChat, 1);
 		conv->u.chat->conv = conv;
+		GAIM_DBUS_REGISTER_POINTER(conv->u.chat, GaimConvChat);
 
 		chats = g_list_append(chats, conv);
 
@@ -905,6 +911,7 @@
 		if(conv->u.chat->nick)
 			g_free(conv->u.chat->nick);
 
+		GAIM_DBUS_UNREGISTER_POINTER(conv->u.chat);
 		g_free(conv->u.chat);
 		conv->u.chat = NULL;
 
@@ -922,6 +929,7 @@
 		ops->destroy_conversation(conv);
 
 	gaim_log_free(conv->log);
+	GAIM_DBUS_UNREGISTER_POINTER(conv);
 	g_free(conv);
 	conv = NULL;
 }
@@ -2338,6 +2346,7 @@
 	cb->name = g_strdup(name);
 	cb->flags = flags;
 
+	GAIM_DBUS_REGISTER_POINTER(cb, GaimConvChatBuddy);
 	return cb;
 }
 
@@ -2368,6 +2377,8 @@
 		g_free(cb->name);
 	cb->name = NULL;
 	cb->flags = 0;
+
+	GAIM_DBUS_UNREGISTER_POINTER(cb);
 	g_free(cb);
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus-analyze-functions.py	Fri Jul 22 19:47:29 2005 +0000
@@ -0,0 +1,292 @@
+# This programs takes a C header file as the input and produces:
+#
+# with option --mode=xml:  xml dbus specification 
+# with option --mode=c:    C wrappers 
+#
+
+
+
+import re
+import string
+import sys
+
+# mode: "c" or "xml"
+
+mode = None
+
+for arg in sys.argv[1:]:
+    if arg.startswith("--mode="):
+        mode = arg[len("--mode="):]
+
+# list of object types
+
+objecttypes = []
+
+for objecttype in file("dbus-auto-structs.txt"):
+    objecttypes.append(objecttype.strip())
+
+# a dictionary of simple types
+# each TYPE maps into a pair (dbus-type-name, compatible-c-type-name)
+# if compatible-c-type-name is None then it is the same as TYPE
+
+simpletypes = {
+    "int" : ("i", None),
+    "gint" : ("i", None),
+    "guint" : ("u", None),
+    "gboolean" : ("i", "int")
+    }
+
+for enum in file("dbus-auto-enums.txt"):
+    simpletypes[enum.strip()] = ("i", "int")
+
+# functions that shouldn't be exported 
+
+excluded = ["gaim_accounts_load", "gaim_account_set_presence"]
+
+pointer = "#pointer#"
+prefix = "gaim_object_"
+
+cparams = []
+cdecls  = []
+ccode  = []
+dargs  = []
+
+myexception = "My Exception"
+
+
+def ctopascal(name):
+    newname = ""
+    for word in name.split("_"):
+        newname += word.capitalize()
+    return newname
+
+def dbus_print(function):
+    print '<method name="%s">' % ctopascal(function)
+
+    for name, type, direction in dargs:
+        print '<arg type="%s" name="%s" direction="%s" />' % \
+              (type, name, direction)
+
+    print '</method>'
+    print 
+
+def dbus_clear():
+    global dargs
+    dargs = []
+
+def c_print(function):
+    print "static gboolean %s%s(GaimObject *gaim_object," % (prefix, function),
+
+    for param in cparams:
+        print "%s," % param,
+
+    print "GError **error) {"
+
+    for decl in cdecls:
+        print decl
+
+    for code in ccode:
+        print code
+
+    print "return TRUE;\n}\n"
+   
+def c_clear():
+    global cparams, cdecls, ccode
+    cparams = []
+    cdecls  = []
+    ccode  = []
+
+
+# processing an input parameter
+
+def inputvar(mytype, name):
+    global dargs, ccode, cparams, cdecls
+    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):
+        dbustype, ctype = simpletypes[mytype[0]]
+        dargs.append((name, dbustype, "in"))
+        if ctype is None:
+            cparams.append(mytype[0] + " " + name)
+        else:
+            cparams.append(ctype + " " + name + "_ORIG")
+            cdecls .append("%s %s;\n" % (mytype[0], name))
+            ccode  .append("%s = (%s) %s_ORIG;\n" % \
+                           (name, mytype[0], name))
+        return
+
+    # pointers ...
+
+    if (len(mytype) == 2) and (mytype[1] == pointer):
+        # strings
+        if mytype[0] == "char":
+            if const:
+                dargs  .append((name, "s", "in"))
+                cparams.append("const char *" + name)
+                ccode  .append("NULLIFY(%s);" % name)
+                return
+            else:
+                raise myexception
+
+        # known object types are transformed to integer handles
+        elif mytype[0] in objecttypes:
+            dargs  .append((name, "i", "in"))
+            cparams.append("int " + name + "_ID")
+            cdecls .append("%s *%s;" % (mytype[0], name))
+            ccode  .append("GAIM_DBUS_ID_TO_POINTER(%s, %s_ID, %s);"  % \
+                           (name, name, mytype[0]))
+            return
+
+        # unknown pointers are always replaced with NULL
+        else:
+            dargs  .append((name, "i", "in"))
+            cparams.append("int " + name + "_NULL")
+            cdecls .append("%s *%s;" % (mytype[0], name))
+            ccode  .append("%s = NULL;" % name)
+            return
+
+    raise myexception
+
+            
+
+# processing an output parameter
+
+def outputvar(mytype, name, call):
+    # 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]:
+        dargs  .append((name, "s", "out"))
+        cparams.append("char **%s" % name)
+        ccode  .append("*%s = g_strdup(null_to_empty(%s));" % (name, call))
+        return
+
+    # simple types (ints, booleans, enums, ...)
+    if (len(mytype) == 1) and (mytype[0] in simpletypes): 
+        dbustype, ctype = simpletypes[mytype[0]]
+
+        if ctype is None:
+            ctype = mytype[0]
+            
+        dargs  .append((name, dbustype, "out"))
+        ccode  .append("*%s = %s;" % (name, call))
+        cparams.append("%s *%s" % (ctype, name))
+        return
+            
+    # pointers ...
+    if (len(mytype) == 2) and (mytype[1] == pointer):
+
+        # handles
+        if mytype[0] in objecttypes:
+            dargs  .append((name, "i", "out"))
+            cparams.append("int *%s" % name)
+            ccode  .append("GAIM_DBUS_POINTER_TO_ID(*%s, %s);" % (name, call))
+            return
+
+        # GList*, GSList*, assume that list is a list of objects
+        # not a list of strings!!!
+        if mytype[0] in ["GList", "GSList"]:
+            dargs  .append((name, "ai", "out"))
+            cparams.append("GArray **%s" % name)
+            ccode  .append("*%s = gaim_dbusify_%s(%s, TRUE);" % \
+                           (name, mytype[0],call))
+            return
+
+    raise myexception
+
+
+
+def processfunction(functionparam, paramlist):
+    dbus_clear()
+    c_clear()
+
+    ftokens = functionparam.split()
+    functiontype, function = ftokens[:-1], ftokens[-1]
+
+    if function in excluded:
+        return
+
+    origfunction = function
+    function = function.lower()
+
+    names = []
+    for param in paramlist:
+        tokens = param.split()
+        if len(tokens) < 2:
+            raise myexception
+        type, name = tokens[:-1], tokens[-1]
+        inputvar(type, name)
+        names.append(name)
+
+    outputvar(functiontype, "RESULT",
+              "%s(%s)" % (origfunction, ", ".join(names)))
+
+    if mode == "c":
+        c_print(function)
+
+    if mode == "xml":
+        dbus_print(function)
+
+
+if mode == "c":
+    print "/* Generated by %s.  Do not edit! */" % sys.argv[0]
+
+if mode == "xml":
+    print "<!-- Generated by %s.  Do not edit! -->" % sys.argv[0]
+
+functionregexp = re.compile(r"^(\w[^()]*)\(([^()]*)\)\s*;\s*$")
+
+inputiter = iter(sys.stdin)
+
+for line in inputiter:
+        words = line.split()
+        if len(words) == 0:             # empty line
+            continue
+        if line[0] == "#":              # preprocessor directive
+            continue
+        if words[0] in ["typedef", "struct", "enum", "static"]:
+            continue
+
+        # accumulate lines until the parentheses are balance or an
+        # empty line has been encountered
+        myline = line.strip()
+        while myline.count("(") > myline.count(")"):
+            newline = inputiter.next().strip()
+            if len(newline) == 0:
+                break
+            myline += " " + newline
+
+        # is this a function declaration?
+        thematch = functionregexp.match(
+            myline.replace("*", " " + pointer + " "))
+
+        if thematch is None:
+            continue
+
+        function = thematch.group(1)
+        parameters = thematch.group(2).strip()
+
+        if (parameters == "void") or (parameters == ""):
+            paramlist = []
+        else:
+            paramlist = parameters.split(",")
+
+        try:
+            processfunction(function, paramlist)
+        except myexception:
+            sys.stderr.write(myline + "\n")
+        except:
+            sys.stderr.write(myline + "\n")
+            raise
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus-analyze-types.py	Fri Jul 22 19:47:29 2005 +0000
@@ -0,0 +1,79 @@
+# This program takes a C header/source as the input and produces
+#
+# with --keyword=enum: the list of all enums
+# with --keyword=struct: the list of all structs
+#
+# the output styles:
+#
+# --enum    DBUS_POINTER_NAME1,
+#           DBUS_POINTER_NAME2,
+#           DBUS_POINTER_NAME3, 
+# 
+# --list    NAME1
+#           NAME2
+#           NAME3
+# 
+
+
+import re
+import sys
+
+myinput = iter(sys.stdin)
+
+def outputenum(name):
+    print "DBUS_POINTER_%s," % name
+
+def outputdeclare(name):
+    print "DECLARE_TYPE(%s, NONE);" % name
+
+def outputtext(name):
+    print name
+
+myoutput = outputtext
+keyword = "struct"
+
+for arg in sys.argv[1:]:
+    if arg[0:2] == "--":
+        mylist = arg[2:].split("=")
+        command = mylist[0]
+        if len(mylist) > 1:
+            value = mylist[1]
+        else:
+            value = None
+            
+    if command == "enum":
+        myoutput = outputenum
+    if command == "declare":
+        myoutput = outputdeclare
+    if command == "list":
+        myoutput = outputtext
+    if command == "keyword":
+        keyword = value
+        
+
+structregexp1 = re.compile(r"^(typedef\s+)?%s\s+\w+\s+(\w+)\s*;" % keyword)
+structregexp2 = re.compile(r"^(typedef\s+)?%s" % keyword)
+structregexp3 = re.compile(r"^}\s+(\w+)\s*;")
+
+for line in myinput:
+    match = structregexp1.match(line)
+    if match is not None:
+        myoutput(match.group(2))        
+        continue
+
+    match = structregexp2.match(line)
+    if match is not None:
+        while True:
+            line = myinput.next()
+            match = structregexp3.match(line)
+            if match is not None:
+                myoutput(match.group(1))
+                break
+            if line[0] not in [" ", "\t", "{", "\n"]:
+                break
+        
+
+
+
+    
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus-client-example.py	Fri Jul 22 19:47:29 2005 +0000
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+
+# this is an example of a client that communicates with gaim using DBUS
+#
+# requires Python 2.4 and PyGTK bindings
+#
+# note that all function names are resolved dynamically, no
+# gaim-specific library is needed
+
+import dbus
+import dbus.glib
+import dbus.decorators
+import gobject
+import os
+
+def receivedimmsg(account, name, message, conversation, flags):
+    buddy = gaim.GaimFindBuddy(account, name)
+    if buddy != 0:
+        alias = gaim.GaimBuddyGetAlias(buddy)
+    else:
+        alias = name
+
+    text = "%s says %s" % (alias, message)
+    code = os.spawnlp(os.P_WAIT, "xmessage", "xmessage", "-buttons",
+                      "'So what?','Show me',Close,Abuse", text)
+
+    if code == 101:                     # so what?
+        pass
+    if code == 102:                     # show me
+        window = gaim.GaimConversationGetWindow(conversation)
+        gaim.GaimConvWindowRaise(window)
+    if code == 103:                     # close 
+        gaim.GaimConversationDestroy(conversation)
+    if code == 104:                     # abuse
+        im = gaim.GaimConversationGetImData(conversation)
+        gaim.GaimConvImSend(im, "Go away you f...")
+                                 
+        
+def buddysignedon(buddyid):
+    alias = gaim.GaimBuddyGetAlias(buddyid)
+    text = "%s is online" % alias
+
+    code = os.spawnlp(os.P_WAIT, "xmessage", "xmessage", "-buttons",
+                      "'So what?','Let's talk'", text)
+
+    if code == 101:                     # so what?
+        pass
+    if code == 102:                     # let's talk
+        name = gaim.GaimBuddyGetName(buddyid)
+        account = gaim.GaimBuddyGetAccount(buddyid)
+        gaim.GaimConversationNew(1, account, name)
+    
+
+def talkto(buddyname, accountname, protocolname):
+    account = gaim.GaimAccountsFindConnected(accountname, protocolname)
+    if account != 0:                    
+        gaim.GaimConversationNew(1, account, buddyname)
+    
+
+bus = dbus.SessionBus()
+obj = bus.get_object("org.gaim.GaimService", "/org/gaim/GaimObject")
+gaim = dbus.Interface(obj, "org.gaim.GaimInterface")
+
+bus.add_signal_receiver(receivedimmsg,
+                        dbus_interface = "org.gaim.GaimInterface",
+                        signal_name = "ReceivedImMsg")
+bus.add_signal_receiver(buddysignedon,
+                        dbus_interface = "org.gaim.GaimInterface",
+                        signal_name = "BuddySignedOn")
+
+
+# Tell the remote object to emit the signal
+
+talkto("testone@localhost", "", "prpl-jabber")
+
+loop = gobject.MainLoop()
+loop.run()
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus-define-api.h	Fri Jul 22 19:47:29 2005 +0000
@@ -0,0 +1,25 @@
+#error "This is file is not a valid C code"
+
+/* This file contains some of the macros from other header files as
+   function declarations.  This does not make sense in C, but it
+   provides type information for the dbus-analyze-functions.py
+   program, which makes these macros callable by DBUS.  */
+
+/* blist.h */
+gboolean GAIM_BLIST_NODE_IS_CHAT(GaimBlistNode *node);
+gboolean GAIM_BLIST_NODE_IS_BUDDY(GaimBlistNode *node);   
+gboolean GAIM_BLIST_NODE_IS_CONTACT(GaimBlistNode *node);
+gboolean GAIM_BLIST_NODE_IS_GROUP(GaimBlistNode *node);
+gboolean GAIM_BUDDY_IS_ONLINE(GaimBuddy *buddy); 
+gboolean GAIM_BLIST_NODE_HAS_FLAG(GaimBlistNode *node, int flags);
+gboolean GAIM_BLIST_NODE_SHOULD_SAVE(GaimBlistNode *node);
+
+/* connection.h */
+gboolean GAIM_CONNECTION_IS_CONNECTED(GaimConnection *connection);
+gboolean GAIM_CONNECTION_IS_VALID(GaimConnection *connection);
+
+/* conversation.h */
+GaimConvIm *GAIM_CONV_IM(const GaimConversation *conversation);
+GaimConvIm *GAIM_CONV_CHAT(const GaimConversation *conversation);
+
+
--- a/src/dbus-maybe.h	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/dbus-maybe.h	Fri Jul 22 19:47:29 2005 +0000
@@ -10,7 +10,11 @@
 
 #include "dbus-server.h"
 
-#define GAIM_DBUS_REGISTER_POINTER(ptr, type) gaim_dbus_register_pointer(ptr, type)
+/* this provides a type check */
+#define GAIM_DBUS_REGISTER_POINTER(ptr, type) { \
+    type *typed_ptr = ptr; \
+    gaim_dbus_register_pointer(typed_ptr, DBUS_POINTER_##type); \
+}
 #define GAIM_DBUS_UNREGISTER_POINTER(ptr) gaim_dbus_unregister_pointer(ptr)
 
 #else  /* !HAVE_DBUS */
--- a/src/dbus-server.c	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/dbus-server.c	Fri Jul 22 19:47:29 2005 +0000
@@ -21,7 +21,10 @@
  *
  */
 
+#define DBUS_API_SUBJECT_TO_CHANGE
+
 #include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
 #include <dbus/dbus-glib-bindings.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -36,12 +39,11 @@
 #include "conversation.h"
 #include "dbus-gaim.h"
 #include "dbus-server.h"
+#include "dbus-useful.h"
 #include "debug.h"
 #include "core.h"
 #include "value.h"
 
-static gint gaim_dbus_pointer_to_id(gpointer node);
-static gpointer gaim_dbus_id_to_pointer(gint id, GaimDBusPointerType type);
 
 
 /**************************************************************************/
@@ -51,9 +53,8 @@
 GType gaim_object_get_type(void);
 
 struct _GaimObject {
-	GObject parent;
-
-	int ping_signal_id;
+    GObject parent;
+    DBusGProxy *proxy;
 };
 
 typedef struct {
@@ -61,7 +62,6 @@
 } GaimObjectClass;
 
 
-
 #define GAIM_DBUS_TYPE_OBJECT              (gaim_object_get_type ())
 #define GAIM_DBUS_OBJECT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GAIM_DBUS_TYPE_OBJECT, GaimObject))
 #define GAIM_DBUS_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GAIM_DBUS_TYPE_OBJECT, GaimObjectClass))
@@ -74,6 +74,15 @@
 GaimObject *gaim_dbus_object;
 static GQuark gaim_object_error_quark;
 
+#define NULLIFY(id) id = empty_to_null(id)
+
+static const char* empty_to_null(const char *str) {
+    if (str == NULL || str[0] == 0)
+	return NULL;
+    else
+	return str;
+}
+
 static const char* null_to_empty(const char *s) {
 	if (s)
 		return s;
@@ -87,517 +96,39 @@
 { 
 }
 
-
-
-/**************************************************************************/
-/** @name Signals                                                         */
-/**************************************************************************/
-
-/* used in #gaim_values_to_gvalues, undefined afterwards */
-#define my_arg(type) (ptr != NULL ? * ((type *)ptr) : va_arg(data, type))
-
-/**
-   Converts from a list of data into an GValue array.
-
-   @param gvalus      Array of empty gvalues to be filled.
-   @param number      The number of data items.
-   @param gaim_value  Array of #number pointers to GaimValues.  
-                      The types of of these GaimValues determine the type
-		      of data items.  The values do not matter.
-   @param mainptr     A pointer to a single data item.  If this pointer is not #NULL,
-                      then #number must be 1.
-   @param data        A va_list containing data items.  If 		      
-
-   Exactly one of #mainptr and #data must be not #NULL.  If #mainptr
-   is not #NULL, then there is a single piece of data at the address
-   pointed at by #mainptr.  If #data is not #NULL, then there are
-   #number data items in the #va_list #data.
- */
-static void gaim_values_to_gvalues(GValue *gvalue, int number,  
-		       GaimValue **gaim_values, gpointer mainptr, va_list data) 
-{
-	int i;
-	gpointer ptr;
-
-	g_assert(mainptr == NULL || data == NULL);
-	g_assert(mainptr != NULL || data != NULL);
-	g_assert(number == 1 || data != NULL);
-
-	for(i=0; i<number; i++, gvalue++) {
-		ptr = mainptr;
-		if (gaim_value_is_outgoing(gaim_values[i])) {
-			ptr = my_arg(gpointer);
-			g_assert(ptr);
-		}
-
-		switch(gaim_values[i]->type) {
-		case  GAIM_TYPE_CHAR:  	
-			g_value_init(gvalue, G_TYPE_CHAR);
-			g_value_set_char(gvalue, (char) my_arg(int));
-			break;
-		case  GAIM_TYPE_INT:  
-			g_value_init(gvalue, G_TYPE_INT);
-			g_value_set_int(gvalue, my_arg(gint));
-			break;
-		case  GAIM_TYPE_UINT:  
-			g_value_init(gvalue, G_TYPE_UINT);
-			g_value_set_uint(gvalue, my_arg(guint));
-			break;
-		case  GAIM_TYPE_BOOLEAN:  
-			g_value_init(gvalue, G_TYPE_BOOLEAN);
-			g_value_set_boolean(gvalue, my_arg(gboolean));
-			break;
-		case GAIM_TYPE_STRING: 
-			g_value_init(gvalue, G_TYPE_STRING);
-			g_value_set_string(gvalue, null_to_empty(my_arg(char*)));
-			break;
-		case GAIM_TYPE_SUBTYPE: /* registered pointers only! */
-			g_value_init(gvalue, G_TYPE_INT);
-			g_value_set_int(gvalue, 
-					gaim_dbus_pointer_to_id(my_arg(gpointer)));
-			break;
-		case GAIM_TYPE_POINTER:
- 		case GAIM_TYPE_OBJECT: 
-		case GAIM_TYPE_BOXED:
-			my_arg(gpointer); /* cannot pass general pointers */
-			g_value_init(gvalue, G_TYPE_INT);
-			g_value_set_int(gvalue, 0);
-			break;
-		
-		default:		/* no conversion implemented */
-			g_assert_not_reached();
-		}
-	}
-
-	if (data) 
-		va_end(data);
-}
-
-#undef my_arg			/* my_arg was only used in gaim_values_to_gvalues  */
-
-
-
-/**
-   Converts from GaimTypes to GTypes.
-
-   @param type   A GaimType to be converted.
-   @result       The result of the conversion (GType).
-*/
-static GType gaim_type_to_g_type(GaimType type)
+static void gaim_object_init(GaimObject *object) 
 {
-	switch(type) {
-	case  GAIM_TYPE_CHAR: 
-		return G_TYPE_CHAR;
-	case  GAIM_TYPE_INT:  
-		return G_TYPE_INT;
-	case  GAIM_TYPE_UINT:  
-		return G_TYPE_UINT;
-	case  GAIM_TYPE_BOOLEAN:  
-		return G_TYPE_BOOLEAN;
-	case GAIM_TYPE_STRING: 
-		return G_TYPE_STRING;
-	case GAIM_TYPE_SUBTYPE:    /* registered pointers only! */
-		return G_TYPE_INT;
-	case GAIM_TYPE_POINTER:
-	case GAIM_TYPE_BOXED:
- 	case GAIM_TYPE_OBJECT: 
-		return G_TYPE_INT; /* always 0 */
-	default:		   /* no conversion implemented */
-		g_assert_not_reached();
-	}	
-}
-
-
-static const char *gaim_dbus_convert_signal_name(const char *gaim_name) 
-{
-	int gaim_index, g_index;
-	char *g_name = g_new(char, strlen(gaim_name)+1);
-	gboolean capitalize_next = TRUE;
-
-	for(gaim_index = g_index = 0; gaim_name[gaim_index]; gaim_index++)
-		if (gaim_name[gaim_index] != '-' && gaim_name[gaim_index] != '_') {
-			if (capitalize_next)
-				g_name[g_index++] = g_ascii_toupper(gaim_name[gaim_index]);
-			else
-				g_name[g_index++] = gaim_name[gaim_index];
-			capitalize_next = FALSE;
-		} else
-			capitalize_next = TRUE;
-	g_name[g_index] = 0;
-	
-	return g_name;
-}
-
-/* Public signal-related functions */
-
-
-void gaim_dbus_invalid_marshaller(GClosure *closure,
-				  GValue *return_value,
-				  guint n_param_values,
-				  const GValue *param_values,
-				  gpointer invocation_hint,
-				  gpointer marshal_data)
-{
-	g_assert_not_reached();
-}
-
-int gaim_dbus_signal_register(GaimObject *object, const char *name, 
-			      GSignalCMarshaller marshaller,
-			      int num_values, ...) 
-{
-	va_list args;
-
-	va_start(args, num_values);
-
-	return g_signal_new_valist(name, G_OBJECT_TYPE(object),
-				   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-				   NULL, NULL, NULL, marshaller,
-				   G_TYPE_NONE, num_values, args);
-}
-
-void gaim_dbus_signal_emit(GaimObject *object, int dbus_id, ...) {
-	va_list args;
-	
-	va_start(args, dbus_id);
-	
-	gaim_dbus_signal_emit_valist(object, dbus_id, args);
-}
-
-void gaim_dbus_signal_emit_valist(GaimObject *object, int dbus_id, va_list args) {
-	g_signal_emit_valist(object, dbus_id, 0, args);
-}
-
-int gaim_dbus_signal_register_gaim(GaimObject *object, const char *name, 
-				   GSignalCMarshaller marshaller, 
-				   int num_values, GaimValue **values)
-{
-	int i;
-	int dbus_id;
-	GType *types;
-	
-	types = g_new0(GType, num_values);
-
-	for(i=0; i<num_values; i++) 
-		types[i] = gaim_type_to_g_type(values[i]->type);
-		
-	dbus_id = 
-		g_signal_newv(gaim_dbus_convert_signal_name(name),
-			      G_OBJECT_TYPE(object),
-			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-			      NULL, NULL, NULL, marshaller,
-			      G_TYPE_NONE, num_values, types);
-
-	g_free(types);
-
-	return dbus_id;
-}
-
-
-void gaim_dbus_signal_emit_gaim(GaimObject *object, int dbus_id, int num_values, 
-				GaimValue **values, va_list vargs)
-{
-	GValue *args;
-	int i;
-
-	g_return_if_fail(dbus_id);
-
-	args = g_new0(GValue, num_values + 1);
-
-	g_value_init(args + 0, G_OBJECT_TYPE(object));
-	g_value_set_object(args + 0, object);
-
-	gaim_values_to_gvalues(args + 1, num_values, values, NULL, vargs);
-	
-	g_signal_emitv(args, dbus_id, 0, NULL);
-
-	for(i = 1; i <= num_values; i++)
-		g_value_unset(args + i);
-	
-	g_free(args);		
 }
 
-
-/**************************************************************************/
-/** @name Utility functions                                               */
-/**************************************************************************/
-
-#define error_unless_1(condition, str, parameter)		\
-	if (!(condition)) {					\
-		    g_set_error(error, gaim_object_error_quark,	\
-				DBUS_ERROR_NOT_FOUND,		\
-				str, parameter);		\
-		    return FALSE;				\
-	    }
-
-#define error_unless_2(condition, str, a,b)			\
-	if (!(condition)) {					\
-		    g_set_error(error, gaim_object_error_quark,	\
-				DBUS_ERROR_NOT_FOUND,		\
-				str, a,b);			\
-		    return FALSE;				\
-	    }
-
-typedef gboolean (*GaimNodeFilter)(GaimBlistNode *node, gpointer *user_data);
-
-static gboolean 
-filter_is_buddy(GaimBlistNode *node, gpointer *user_data) 
-{
-	return GAIM_BLIST_NODE_IS_BUDDY(node);
-}
-
-static gboolean 
-filter_is_online_buddy(GaimBlistNode *node, 
-		       gpointer *user_data) 
-{
-	return GAIM_BLIST_NODE_IS_BUDDY(node) && 
-	  GAIM_BUDDY_IS_ONLINE((GaimBuddy *)node);
-}
-
-
-static GList* 
-get_buddy_list (GList *created_list,		/**< can be NULL */
-		GaimBlistNode *gaim_buddy_list, /**< can be NULL */
-		GaimNodeFilter filter, 
-		gpointer user_data) 
-{
-	GaimBlistNode *node;
-
-	for(node = gaim_buddy_list; node; node = node->next) 
-	{
-		if ((*filter)(node, user_data)) 
-			created_list = g_list_prepend(created_list, node);
-
-		created_list = get_buddy_list(created_list, node->child,
-					      filter, user_data);
-	}
-	
-	return created_list;
-}
-
-
-
-/**************************************************************************/
-/** @name Implementations of remote DBUS calls                            */
-/**************************************************************************/
-
-static gboolean 
-gaim_object_ping(GaimObject *object, GError **error) 
-{
- 	gaim_dbus_signal_emit(object, object->ping_signal_id, "Ping Pong!"); 
-	return TRUE;
-}
-
-static gboolean 
-gaim_object_quit(GaimObject *obj, GError **error) 
-{
-	g_timeout_add(0, gaim_core_quit_cb, NULL);
-	return TRUE;
-}
-
-static gboolean
-gaim_object_connect_all(GaimObject *obj, GError **error)
-{
-	GList *cur;
-
-	for (cur = gaim_accounts_get_all(); cur != NULL; cur = cur->next) 
-		gaim_account_connect((GaimAccount*) cur->data);
-
-	return TRUE;
-}
-
-
-
-static gboolean
-gaim_object_get_buddy_list (GaimObject *obj, GArray **out_buddy_ids, 
-			    GError **error) 
-{
-	GList *node;
-	GList *buddy_list = get_buddy_list(NULL, gaim_get_blist()->root,
-					   &filter_is_buddy, NULL);
-	GArray *buddy_ids  = g_array_new(FALSE, TRUE, sizeof(gint32));;
-  	
-	buddy_list = g_list_reverse(buddy_list);
-
-	for (node = buddy_list; node; node = node->next) {
-		gint32 id = gaim_dbus_pointer_to_id(node->data);
-		g_array_append_val(buddy_ids, id);
-	}
-
-	g_list_free(buddy_list);
-	*out_buddy_ids = buddy_ids;
-
-	return TRUE;
-}
-
-
-
-
-
-static gboolean
-gaim_object_find_account(GaimObject *object, 
-			 const char *account_name, const char *protocol_name,
-			 gint *account_id, GError **error) 
-{
-	GaimAccount *account = gaim_accounts_find(account_name, protocol_name);
-	
-	error_unless_2(account, "Account '%s' with protocol '%s' not found", 
-			    account_name, protocol_name);
-
-	*account_id = gaim_dbus_pointer_to_id(account);
-	return TRUE;
-}
-
-static gboolean
-gaim_object_find_buddy(GaimObject *object, gint account_id, const char *buddy_name,
-		       gint *buddy_id, GError **error)
-{
-	GaimAccount *account;
-	GaimBuddy *buddy;
-
-	account = gaim_dbus_id_to_pointer(account_id, DBUS_POINTER_ACCOUNT);
-	error_unless_1(account, "Invalid account id: %i", account_id);	
-
-	buddy = gaim_find_buddy(account, buddy_name);
-	error_unless_1(account, "Buddy '%s' not found.", buddy_name);	
-
-	*buddy_id = gaim_dbus_pointer_to_id(buddy);
-	return TRUE;
-}
-
-static gboolean
-gaim_object_start_im_conversation (GaimObject *object, gint buddy_id, GError **error)
-{
-	GaimBuddy *buddy = (GaimBuddy*) gaim_dbus_id_to_pointer(buddy_id, 
-								DBUS_POINTER_BUDDY);
-	
-	error_unless_1(buddy, "Invalid buddy id: %i", buddy_id);
-
-	gaim_conversation_new(GAIM_CONV_IM, buddy->account, buddy->name);
-
-	return TRUE;
-}
-
-
-
-/**************************************************************************/
-/** @name Gaim DBUS property handling functions                           */
-/**************************************************************************/
-
-
-typedef struct _GaimDBusProperty {
-	char *name;
-	gint offset;
-	GaimType type;
-} GaimDBusProperty;
-
-/* change GAIM_TYPE into G_TYPE */
-	  
-static gboolean
-gaim_dbus_get_property(GaimDBusProperty *list, int list_len, 
-		       gpointer data, const char *name, 
-		       GValue *value, GError **error)
-{
-	int i;
-
-	for(i=0; i<list_len; i++) {
-		if (!strcmp(list[i].name, name)) {
-			gpointer ptr;
-			GaimValue gaim_value, *gaim_value_ptr;
-
-			ptr = G_STRUCT_MEMBER_P(data, list[i].offset);
-			gaim_value.type = list[i].type;
-			gaim_value.flags = 0;
-			gaim_value_ptr = &gaim_value;
-			
-			gaim_values_to_gvalues(value, 1, &gaim_value_ptr, 
-					       ptr, NULL);
-			return TRUE;
-		}
-	}
-
-	g_value_init(value, G_TYPE_INT);
-	g_value_set_int(value, 0);
-	error_unless_1(FALSE, "Invalid property '%s'", name);	
-}
-
-
-#define DECLARE_PROPERTY(maintype, name, type) {#name, G_STRUCT_OFFSET(maintype, name), type}
-
-GaimDBusProperty buddy_properties [] = {
-	DECLARE_PROPERTY(GaimBuddy, name, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimBuddy, alias, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimBuddy, server_alias, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimBuddy, account, GAIM_TYPE_SUBTYPE) 
-};
-
-GaimDBusProperty account_properties [] = {
-	DECLARE_PROPERTY(GaimAccount, username, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimAccount, alias, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimAccount, user_info, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimAccount, protocol_id, GAIM_TYPE_STRING),
-};
-
-GaimDBusProperty contact_properties [] = {
-	DECLARE_PROPERTY(GaimContact, alias, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimContact, totalsize, GAIM_TYPE_INT),
-	DECLARE_PROPERTY(GaimContact, currentsize, GAIM_TYPE_INT),
-	DECLARE_PROPERTY(GaimContact, online, GAIM_TYPE_INT),
-	DECLARE_PROPERTY(GaimContact, priority, GAIM_TYPE_SUBTYPE),
-	DECLARE_PROPERTY(GaimContact, priority_valid, GAIM_TYPE_BOOLEAN),
-};
-
-GaimDBusProperty group_properties [] = {
-	DECLARE_PROPERTY(GaimGroup, name, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimGroup, totalsize, GAIM_TYPE_INT),
-	DECLARE_PROPERTY(GaimGroup, currentsize, GAIM_TYPE_INT),
-	DECLARE_PROPERTY(GaimGroup, online, GAIM_TYPE_INT),
-};
-
-GaimDBusProperty chat_properties [] = {
-	DECLARE_PROPERTY(GaimChat, alias, GAIM_TYPE_STRING),
-	DECLARE_PROPERTY(GaimChat, account, GAIM_TYPE_SUBTYPE),
-};
-
-
-#define DECLARE_PROPERTY_HANDLER(type, gaim_type)			\
-	static gboolean							\
-	gaim_object_get_##type##_property (GaimObject *object,		\
-					   gint id, const char *property_name, \
-					   GValue *value, GError **error) \
-	{								\
-		gpointer ptr = gaim_dbus_id_to_pointer(id, gaim_type); \
-									\
-		error_unless_1(ptr, "Invalid " #type " id: %i", id);	\
-									\
-		return gaim_dbus_get_property(type##_properties,	\
-					      G_N_ELEMENTS(type##_properties), \
-					      ptr, property_name, value, error); \
-	}
-
-DECLARE_PROPERTY_HANDLER(buddy, DBUS_POINTER_BUDDY)
-DECLARE_PROPERTY_HANDLER(account, DBUS_POINTER_ACCOUNT)
-DECLARE_PROPERTY_HANDLER(contact, DBUS_POINTER_CONTACT)
-DECLARE_PROPERTY_HANDLER(group, DBUS_POINTER_GROUP)
-DECLARE_PROPERTY_HANDLER(chat, DBUS_POINTER_CHAT)
-
-#include "dbus-server-bindings.c"
-
-
-
 /**************************************************************************/
 /** @name Gaim DBUS pointer registration mechanism                        */
 /**************************************************************************/
 
+GaimDBusPointerType dbus_type_parent[DBUS_POINTER_LASTTYPE];
+
 static GHashTable *map_id_node; 
 static GHashTable *map_id_type; 
 static GHashTable *map_node_id; 
 
+
+#define DECLARE_TYPE(type, parent) \
+	dbus_type_parent[DBUS_POINTER_##type] = DBUS_POINTER_##parent
+
 void gaim_dbus_init_ids(void) {
-
+	int i;
 
 	map_id_node = g_hash_table_new (g_direct_hash, g_direct_equal);
 	map_id_type = g_hash_table_new (g_direct_hash, g_direct_equal);
 	map_node_id = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	for (i = 0; i < DBUS_POINTER_LASTTYPE; i++)
+		dbus_type_parent[i] = DBUS_POINTER_NONE;
+
+	/* some manual corrections */
+	DECLARE_TYPE(GaimBuddy, GaimBlistNode);
+	DECLARE_TYPE(GaimContact, GaimBlistNode);
+	DECLARE_TYPE(GaimChat, GaimBlistNode);
+	DECLARE_TYPE(GaimGroup, GaimBlistNode);
 }
 
 void gaim_dbus_register_pointer(gpointer node, GaimDBusPointerType type) 
@@ -625,20 +156,221 @@
 }
 
 static gint gaim_dbus_pointer_to_id(gpointer node) {
-	g_assert(map_node_id);
-
 	gint id = GPOINTER_TO_INT(g_hash_table_lookup(map_node_id, node));
 	g_return_val_if_fail(id, 0);
 	return id;
 }
 	
 static gpointer gaim_dbus_id_to_pointer(gint id, GaimDBusPointerType type) {
-	if (type != GPOINTER_TO_INT(g_hash_table_lookup(map_id_type, 
-							GINT_TO_POINTER(id))))
+	GaimDBusPointerType objtype = 
+		GPOINTER_TO_INT(g_hash_table_lookup(map_id_type, 
+						    GINT_TO_POINTER(id)));
+							    
+	while (objtype != type && objtype != DBUS_POINTER_NONE)
+		objtype = dbus_type_parent[objtype];
+
+	if (objtype == type)
+		return g_hash_table_lookup(map_id_node, GINT_TO_POINTER(id));
+	else
 		return NULL;
-	return g_hash_table_lookup(map_id_node, GINT_TO_POINTER(id));
 }
 	
+/**************************************************************************/
+/** @name Useful functions                                                */
+/**************************************************************************/
+
+
+#define error_unless_1(condition, str, parameter)		\
+	if (!(condition)) {					\
+		    g_set_error(error, gaim_object_error_quark,	\
+				DBUS_ERROR_NOT_FOUND,		\
+				str, parameter);		\
+		    return FALSE;				\
+	    }
+
+#define error_unless_2(condition, str, a,b)			\
+	if (!(condition)) {					\
+		    g_set_error(error, gaim_object_error_quark,	\
+				DBUS_ERROR_NOT_FOUND,		\
+				str, a,b);			\
+		    return FALSE;				\
+	    }
+
+#define GAIM_DBUS_ID_TO_POINTER(ptr, id, type)				\
+	G_STMT_START {							\
+		ptr = ((type*) gaim_dbus_id_to_pointer			\
+		       (id, DBUS_POINTER_##type));			\
+		error_unless_2(ptr != NULL || id == 0,			\
+			       "%s object with ID = %i not found",	\
+			       #type, id);				\
+	} G_STMT_END
+	       
+
+#define GAIM_DBUS_POINTER_TO_ID(id, ptr)				\
+	G_STMT_START {							\
+		gpointer _ptr = ptr;					\
+		id = gaim_dbus_pointer_to_id(_ptr);			\
+		error_unless_1(ptr == NULL || id != 0,			\
+			       "Result object not registered (%i)",	\
+			       id);					\
+	} G_STMT_END
+
+
+/**************************************************************************/
+/** @name Signals                                                         */
+/**************************************************************************/
+
+
+
+static  char *gaim_dbus_convert_signal_name(const char *gaim_name) 
+{
+	int gaim_index, g_index;
+	char *g_name = g_new(char, strlen(gaim_name)+1);
+	gboolean capitalize_next = TRUE;
+
+	for(gaim_index = g_index = 0; gaim_name[gaim_index]; gaim_index++)
+		if (gaim_name[gaim_index] != '-' && gaim_name[gaim_index] != '_') {
+			if (capitalize_next)
+				g_name[g_index++] = g_ascii_toupper(gaim_name[gaim_index]);
+			else
+				g_name[g_index++] = gaim_name[gaim_index];
+			capitalize_next = FALSE;
+		} else
+			capitalize_next = TRUE;
+	g_name[g_index] = 0;
+	
+	return g_name;
+}
+
+#define my_arg(type) (ptr != NULL ? * ((type *)ptr) : va_arg(data, type))
+
+static void gaim_dbus_message_append_gaim_values(DBusMessageIter *iter,
+						 int number,
+						 GaimValue **gaim_values, 
+						 va_list data) 
+{
+    int i;
+
+    for(i=0; i<number; i++) {
+	const char *str;
+	int id;
+	gint xint;
+	guint xuint;
+	gboolean xboolean;
+	gpointer ptr = NULL;
+	if (gaim_value_is_outgoing(gaim_values[i])) {
+	    ptr = my_arg(gpointer);
+	    g_assert(ptr);
+	}
+	
+	switch(gaim_values[i]->type) {
+	case  GAIM_TYPE_INT:  
+	    g_print("appending int\n");
+	    xint = my_arg(gint);
+	    dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &xint);
+	    break;
+	case  GAIM_TYPE_UINT:  
+	    xuint = my_arg(guint);
+	    g_print("appending uint\n");
+	    dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &xuint);
+	    break;
+	case  GAIM_TYPE_BOOLEAN:  
+	    g_print("appending boolean\n");
+	    xboolean = my_arg(gboolean);
+	    dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &xboolean);
+	    break;
+	case GAIM_TYPE_STRING: 
+	    g_print("appending string\n");
+	    str = null_to_empty(my_arg(char*));
+	    dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+	    break;
+	case GAIM_TYPE_SUBTYPE: /* registered pointers only! */
+	case GAIM_TYPE_POINTER:
+	case GAIM_TYPE_OBJECT: 
+	case GAIM_TYPE_BOXED:		
+	    g_print("appending obj\n");
+	    id = gaim_dbus_pointer_to_id(my_arg(gpointer));
+	    dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &id);
+	    break;
+	default:		/* no conversion implemented */
+	    g_assert_not_reached();
+	}
+    }
+}
+
+#undef my_arg
+
+void gaim_dbus_signal_emit_gaim(GaimObject *object, char *name, int num_values, 
+				GaimValue **values, va_list vargs)
+{
+	/* pass name */
+    DBusMessage *signal;
+    DBusMessageIter iter;
+    char *newname;
+
+    g_print("Emitting %s\n", name);    
+    g_return_if_fail(object->proxy);
+    
+    newname =  gaim_dbus_convert_signal_name(name);
+    signal = dbus_message_new_signal(DBUS_PATH_GAIM, DBUS_INTERFACE_GAIM, newname);
+    dbus_message_iter_init_append(signal, &iter);
+
+    gaim_dbus_message_append_gaim_values(&iter, num_values, values, vargs);
+
+    dbus_g_proxy_send(object->proxy, signal, NULL);
+
+    g_free(newname);
+    dbus_message_unref(signal);
+}
+
+
+/**************************************************************/
+/* DBus bindings ...                                          */
+/**************************************************************/
+
+
+
+GArray* gaim_dbusify_GList(GList *list, gboolean free_memory) {
+	GArray *array;
+	GList *elem;
+
+	array = g_array_new (FALSE, TRUE, sizeof (guint32));
+	for(elem = list; elem != NULL; elem = elem->next) {
+		int objectid;
+
+		objectid = gaim_dbus_pointer_to_id(elem->data);
+		g_array_append_val(array, objectid);
+	}
+
+	if (free_memory)
+		g_list_free(list);
+
+	return array;
+}
+
+GArray* gaim_dbusify_GSList(GSList *list, gboolean free_memory) {
+	GArray *array;
+	GSList *elem;
+
+	array = g_array_new (FALSE, TRUE, sizeof (guint32));
+	for(elem = list; elem != NULL; elem = elem->next) {
+		int objectid;
+
+		objectid = gaim_dbus_pointer_to_id(elem->data);
+		g_array_append_val(array, objectid);
+	}
+
+	if (free_memory)
+		g_slist_free(list);
+	return array;
+}
+
+#include "dbus-generated-code.c"
+
+#include "dbus-server-bindings.c"
+
+
+
 
 
 /**************************************************************************/
@@ -646,6 +378,8 @@
 /**************************************************************************/
 
 
+/* fixme: why do we need two functions here instead of one?  */
+
 gboolean gaim_dbus_connect(GaimObject *object) 
 {
 	DBusGConnection *connection;
@@ -653,10 +387,10 @@
 	DBusGProxy *driver_proxy;
 	guint32 request_name_ret;
 
-
 	gaim_debug_misc("dbus", "launching dbus server\n");
 					
-	/* Connect to the bus */
+	dbus_g_object_type_install_info (GAIM_DBUS_TYPE_OBJECT,
+					 &dbus_glib_gaim_object_object_info);	/* Connect to the bus */
 
 	error = NULL;
 	connection = dbus_g_bus_get(DBUS_BUS_STARTER, &error);
@@ -674,13 +408,6 @@
 
 
 
-	dbus_g_object_type_install_info (GAIM_DBUS_TYPE_OBJECT,
-					 &dbus_glib_gaim_object_object_info);
-
-	dbus_g_connection_register_g_object (connection, DBUS_PATH_GAIM,
-					     (GObject*) object);
-
-
 	/* Obtain a proxy for the DBus object  */
 
 	driver_proxy = dbus_g_proxy_new_for_name (connection,
@@ -710,29 +437,37 @@
 
 	gaim_debug_misc ("dbus", "GLib test service has name '%s'\n", 
 			 DBUS_SERVICE_GAIM);
+
+
+
+	dbus_g_connection_register_g_object (connection, DBUS_PATH_GAIM,
+					     (GObject*) object);
+
+	object->proxy = dbus_g_proxy_new_for_name (connection,
+						  DBUS_SERVICE_GAIM,
+						  DBUS_PATH_GAIM,
+						  DBUS_INTERFACE_GAIM);
+
 	gaim_debug_misc ("dbus", "GLib test service entering main loop\n");
 
 	return TRUE;
 }
 
 
-static void gaim_object_init(GaimObject *object) 
-{
-
-	object->ping_signal_id =
-		gaim_dbus_signal_register(object, "PingSignal", 
-					  g_cclosure_marshal_VOID__STRING,
-					  1, G_TYPE_STRING);
-}
 
 
 gboolean gaim_dbus_init(void) 
 {
-	gaim_dbus_init_ids();
-	gaim_object_error_quark =
-		g_quark_from_static_string("org.gaim.GaimError");
+    gaim_dbus_init_ids();
+    gaim_object_error_quark =
+	g_quark_from_static_string("org.gaim.GaimError");
+
+
 
 	gaim_dbus_object = GAIM_DBUS_OBJECT(g_object_new (GAIM_DBUS_TYPE_OBJECT, NULL));
 
+	gaim_dbus_object->proxy = NULL;
 	return TRUE;
 }
+
+
--- a/src/dbus-server.h	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/dbus-server.h	Fri Jul 22 19:47:29 2005 +0000
@@ -43,11 +43,9 @@
 /* Types of pointers that can be registered with the gaim dbus pointer
    registration engine.  See below */
 typedef enum {
-  DBUS_POINTER_GROUP,
-  DBUS_POINTER_CONTACT,
-  DBUS_POINTER_BUDDY,
-  DBUS_POINTER_CHAT,
-  DBUS_POINTER_ACCOUNT
+  DBUS_POINTER_NONE = 0,
+#include "dbus-auto-enum-types.h"
+  DBUS_POINTER_LASTTYPE
 } GaimDBusPointerType;
 
 typedef struct _GaimObject GaimObject;
@@ -110,31 +108,7 @@
  */
 void gaim_dbus_unregister_pointer(gpointer node);
 
-/**
-    Registers a gaim signal with a #GaimObject.  
 
-    @param object      The #GaimObject (usually #gaim_dbus_object)
-    @param name        Name of the signal
-    @param marshaller  Marshaller for the signal.
-    @param num_values  The number of parameters.
-    @param values      Array of pointers to #GaimValue objects representing
-                       the types of the parameters.
-    @result            The dbus id of the registered signal.
-
-    This function is intended to be used in signal.h, where it
-    automatically registers all gaim signals with dbus.  For your own
-    dbus signals, use #gaim_dbus_register.
-
-    The name of the signal, usually in the form "aaa-bbb-ccc", is
-    converted into DBus standard, "AaaBbbCcc", because "aaa-bbb-ccc"
-    doesn't work with DBus GObject binding version 0.34 (cvs version is ok).
-
-    The #marshaller can be set to gaim_dbus_invalid_marshaller because
-    DBus signals are never passed to any local handler.
-  */
-int gaim_dbus_signal_register_gaim(GaimObject *object, const char *name, 
-				   GSignalCMarshaller marshaller, 
-				   int num_values, GaimValue **values);
 
 /**
     Emits a dbus signal.
@@ -150,53 +124,10 @@
     automatically emits all gaim signals to dbus.  For your own dbus
     signals, use #gaim_dbus_emit.
   */
-void gaim_dbus_signal_emit_gaim(GaimObject *object, int dbus_id, 
-				int num_values, GaimValue **values, va_list vargs);
-
-/**
-    A marshaller that emits an "assertion failed" message if called.  
-
-    This marshaller is intended to use with signal that will never need to be marshalled.
-  */
-void gaim_dbus_invalid_marshaller(GClosure *closure,
-				  GValue *return_value,
-				  guint n_param_values,
-				  const GValue *param_values,
-				  gpointer invocation_hint,
-				  gpointer marshal_data);
-
-/**
-    Registers a gaim signal with a #GaimObject.  
-
-    @param object      The #GaimObject (usually #gaim_dbus_object)
-    @param name        Name of the signal
-    @param marshaller  Marshaller for the signal.
-    @param num_values  The number of parameters.
-    @param ...         List of GType of the parameter types.
+void gaim_dbus_signal_emit_gaim(GaimObject *object, char *name,
+				int num_values, GaimValue **values, 
+				va_list vargs);
 
-    @result            The dbus id of the registered signal.
-  */
-int gaim_dbus_signal_register(GaimObject *object, const char *name, 
-			      GSignalCMarshaller marshaller, 
-			      int num_values, ...);
-
-/**
-    Emits a dbus signal.
-
-    @param object      The #GaimObject (usually #gaim_dbus_object)
-    @param dbus_id     Id of the signal.
-    @param ...         Actual parameters.
-  */
-void gaim_dbus_signal_emit(GaimObject *object, int dbus_id, ...);
-
-/**
-    Emits a dbus signal.
-
-    @param object      The #GaimObject (usually #gaim_dbus_object)
-    @param dbus_id     Id of the signal.
-    @param args       A va_list containing the actual parameters.
-  */
-void gaim_dbus_signal_emit_valist(GaimObject *object, int dbus_id, va_list args);
 
 
 G_END_DECLS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus-service-end.xml	Fri Jul 22 19:47:29 2005 +0000
@@ -0,0 +1,18 @@
+
+  </interface>
+  
+
+  <interface name="org.freedesktop.DBus.Properties">
+    <!-- We implement properties ourselves rather than relying on
+	 GObject property access.  This is because currently in gaim
+	 we have one GObject that represents many dbus objects such as
+	 buddies, accounts, etc.  Not for long! -->
+
+<!--      <method name="Get"> > -->
+<!--        <arg type="s" name="interface_name" />  -->
+<!--        <arg type="s" name="property_name" />  -->
+<!--        <arg type="v" name="value" direction="out" />  -->
+<!--      </method>  -->
+   </interface> 
+</node>
+
--- a/src/dbus-service.xml	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/dbus-service.xml	Fri Jul 22 19:47:29 2005 +0000
@@ -1,74 +1,8 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 
+
 <node name="/org/gaim/GaimObject">
   <interface name="org.gaim.GaimInterface">
-    <method name="Ping">
-    </method>
-    <method name="Quit">
-    </method>
-    <method name="ConnectAll">
-    </method>
-
-    <method name="GetBuddyList">
-      <arg type="ai" name="buddy_ids" direction="out" />
-    </method>
-
+ 
+    <!-- autogenerated ... -->
 
-    <method name="GetBuddyProperty">
-      <arg type="i" name="buddy_id" />
-      <arg type="s" name="property_name" />
-      <arg type="v" name="value" direction="out"/>
-    </method>
-    <method name="GetAccountProperty">
-      <arg type="i" name="account_id" />
-      <arg type="s" name="property_name" />
-      <arg type="v" name="value" direction="out"/>
-    </method>
-    <method name="GetGroupProperty">
-      <arg type="i" name="group_id" />
-      <arg type="s" name="property_name" />
-      <arg type="v" name="value" direction="out"/>
-    </method>
-    <method name="GetContactProperty">
-      <arg type="i" name="contact_id" />
-      <arg type="s" name="property_name" />
-      <arg type="v" name="value" direction="out"/>
-    </method>
-    <method name="GetChatProperty">
-      <arg type="i" name="chat_id" />
-      <arg type="s" name="property_name" />
-      <arg type="v" name="value" direction="out"/>
-    </method>
-
-    <method name="StartIMConversation">
-      <arg type="i" name="buddy_id" />
-    </method>
-
-    <method name="FindAccount">
-      <arg type="s" name="account_name" />
-      <arg type="s" name="protocol_name" />
-      <arg type="i" name="account_id" direction="out"/>
-    </method>
-    <method name="FindBuddy">
-      <arg type="i" name="account_id" />
-      <arg type="s" name="buddy_name" />
-      <arg type="i" name="buddy_id" direction="out"/>
-    </method>
-
-  </interface>
-  
-
-  <interface name="org.freedesktop.DBus.Properties">
-    <!-- We implement properties ourselves rather than relying on
-	 GObject property access.  This is because currently in gaim
-	 we have one GObject that represents many dbus objects such as
-	 buddies, accounts, etc.  Not for long! -->
-
-<!--      <method name="Get"> > -->
-<!--        <arg type="s" name="interface_name" />  -->
-<!--        <arg type="s" name="property_name" />  -->
-<!--        <arg type="v" name="value" direction="out" />  -->
-<!--      </method>  -->
-   </interface> 
-</node>
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus-useful.c	Fri Jul 22 19:47:29 2005 +0000
@@ -0,0 +1,48 @@
+#include "conversation.h"
+
+
+GaimAccount *
+gaim_accounts_find_ext(const char *name, const char *protocol_id, 
+		       gboolean (*account_test)(const GaimAccount *account))
+{
+    GaimAccount *result = NULL;
+    GList *l;
+    char *who;
+    
+    if (name)
+	who = g_strdup(gaim_normalize(NULL, name));
+    else 
+	who = NULL;
+    
+    for (l = gaim_accounts_get_all(); l != NULL; l = l->next) {
+	GaimAccount *account = (GaimAccount *)l->data;
+	
+	if (who && strcmp(gaim_normalize(NULL, gaim_account_get_username(account)), who))
+	    continue;
+
+	if (protocol_id && strcmp(account->protocol_id, protocol_id))
+	    continue;
+
+	if (account_test && !account_test(account)) 
+	    continue;
+
+	result = account;
+	break;
+    }
+
+    g_free(who);
+
+    return result;
+}
+
+GaimAccount *gaim_accounts_find_any(const char *name, const char *protocol) 
+{
+    return gaim_accounts_find_ext(name, protocol, NULL);
+}
+
+GaimAccount *gaim_accounts_find_connected(const char *name, const char *protocol) 
+{
+    return gaim_accounts_find_ext(name, protocol, gaim_account_is_connected);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus-useful.h	Fri Jul 22 19:47:29 2005 +0000
@@ -0,0 +1,13 @@
+#include "conversation.h"
+
+GaimAccount *gaim_accounts_find_ext(const char *name, const char *protocol_id, 
+				    gboolean (*account_test)(const GaimAccount *account));
+
+GaimAccount *gaim_accounts_find_any(const char *name, const char *protocol);
+
+GaimAccount *gaim_accounts_find_connected(const char *name, const char *protocol);
+
+
+
+
+
--- a/src/signals.c	Fri Jul 22 07:11:08 2005 +0000
+++ b/src/signals.c	Fri Jul 22 19:47:29 2005 +0000
@@ -57,8 +57,6 @@
 	size_t handler_count;
 
 	gulong next_handler_id;
-
-	int dbus_id;
 } GaimSignalData;
 
 typedef struct
@@ -169,15 +167,6 @@
 	instance_data->next_signal_id++;
 	instance_data->signal_count++;
 
-#ifdef HAVE_DBUS
-	/* DBus messages are sent directly to the bus so the
-	   marshalling function is never called. */
-	signal_data->dbus_id = 
-		gaim_dbus_signal_register_gaim(gaim_dbus_object, signal,
-					       gaim_dbus_invalid_marshaller, 
-					       num_values, signal_data->values);
-#endif	/* HAVE_DBUS */
-
 	return signal_data->id;
 }
 
@@ -500,7 +489,7 @@
 	}
 
 #ifdef HAVE_DBUS
-	gaim_dbus_signal_emit_gaim(gaim_dbus_object, signal_data->dbus_id, 
+	gaim_dbus_signal_emit_gaim(gaim_dbus_object, signal, 
 				   signal_data->num_values, 
 				   signal_data->values, args);
 #endif	/* HAVE_DBUS */
@@ -552,7 +541,7 @@
 	}
 
 #ifdef HAVE_DBUS
-	gaim_dbus_signal_emit_gaim(gaim_dbus_object, signal_data->dbus_id, 
+	gaim_dbus_signal_emit_gaim(gaim_dbus_object, signal,
 				   signal_data->num_values, 
 				   signal_data->values, args);
 #endif	/* HAVE_DBUS */