Mercurial > pidgin
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 */