From 0b0bb0f621d8e1cda1508d9062a279459fc3b955 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 30 Aug 2007 16:49:52 +0000 Subject: [PATCH] Completely reworked ContactList API. Fixes bug #471611, bug #467280, bug #459540 and bug #462907. svn path=/trunk/; revision=280 --- ChangeLog | 258 +- configure.ac | 100 +- .../tmpl/empathy-contact-list-store.sgml | 19 - .../tmpl/empathy-contact-list-view.sgml | 36 - doc/libempathy-gtk/tmpl/empathy-images.sgml | 7 - .../tmpl/empathy-preferences.sgml | 7 - doc/libempathy/libempathy.types | 4 +- doc/libempathy/tmpl/empathy-avatar.sgml | 8 - doc/libempathy/tmpl/empathy-contact-list.sgml | 88 +- .../tmpl/empathy-contact-manager.sgml | 40 - doc/libempathy/tmpl/empathy-contact.sgml | 92 - .../tmpl/empathy-tp-contact-list.sgml | 58 - doc/libempathy/tmpl/empathy-tp-group.sgml | 68 +- libempathy-gtk/empathy-chat-window.c | 35 +- libempathy-gtk/empathy-contact-dialogs.c | 12 +- libempathy-gtk/empathy-contact-list-store.c | 373 ++- libempathy-gtk/empathy-contact-list-store.h | 5 - libempathy-gtk/empathy-contact-list-view.c | 346 +-- libempathy-gtk/empathy-contact-list-view.h | 25 +- libempathy-gtk/empathy-contact-widget.c | 114 +- libempathy-gtk/empathy-group-chat.c | 49 +- libempathy-gtk/empathy-images.h | 2 +- libempathy-gtk/empathy-main-window.c | 1 - libempathy-gtk/empathy-private-chat.c | 40 +- libempathy-gtk/empathy-status-icon.c | 49 +- libempathy-gtk/empathy-ui-utils.c | 10 +- libempathy/Makefile.am | 6 +- libempathy/empathy-avatar.c | 2 +- libempathy/empathy-avatar.h | 4 +- libempathy/empathy-contact-factory.c | 1102 ++++++++ libempathy/empathy-contact-factory.h | 72 + libempathy/empathy-contact-list.c | 147 +- libempathy/empathy-contact-list.h | 79 +- libempathy/empathy-contact-manager.c | 684 ++--- libempathy/empathy-contact-manager.h | 17 +- libempathy/empathy-contact.c | 367 +-- libempathy/empathy-contact.h | 89 +- libempathy/empathy-log-manager.c | 18 +- libempathy/empathy-marshal.list | 12 +- libempathy/empathy-tp-chat.c | 39 +- libempathy/empathy-tp-chatroom.c | 164 +- libempathy/empathy-tp-contact-list.c | 2323 +++++------------ libempathy/empathy-tp-contact-list.h | 17 +- libempathy/empathy-tp-group.c | 864 ++++-- libempathy/empathy-tp-group.h | 71 +- python/README | 19 + python/pyempathy/pyempathy.defs | 819 +++--- python/pyempathy/pyempathy.override | 30 +- python/pyempathygtk/pyempathygtk.defs | 51 +- 49 files changed, 4145 insertions(+), 4697 deletions(-) create mode 100644 libempathy/empathy-contact-factory.c create mode 100644 libempathy/empathy-contact-factory.h create mode 100644 python/README diff --git a/ChangeLog b/ChangeLog index fdb0c4d9..976db9eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,23 +1,69 @@ -2007-08-24 Xavier Claessens +2007-08-30 Xavier Claessens + + * python/pyempathy/pyempathy.defs: + * python/pyempathy/pyempathy.override: + * python/pyempathygtk/pyempathygtk.defs: Updated for new API. + * python/README: Explain how to update python binding. + + * libempathy-gtk/empathy-images.h: + * libempathy-gtk/empathy-private-chat.c: + * libempathy-gtk/empathy-main-window.c: + * libempathy-gtk/empathy-status-icon.c: + * libempathy-gtk/empathy-group-chat.c: + * libempathy-gtk/empathy-ui-utils.c: + * libempathy-gtk/empathy-contact-dialogs.c: + * libempathy-gtk/empathy-contact-list-view.c: + * libempathy-gtk/empathy-contact-list-view.h: + * libempathy-gtk/empathy-contact-widget.c: + * libempathy-gtk/empathy-contact-list-store.c: + * libempathy-gtk/empathy-contact-list-store.h: + * libempathy-gtk/empathy-chat-window.c: Updated to use new libempathy + API. + + * libempathy/empathy-log-manager.c: + * libempathy/empathy-contact.c: + * libempathy/empathy-contact.h: + * libempathy/empathy-tp-chat.c: + * libempathy/empathy-contact-manager.c: + * libempathy/empathy-contact-manager.h: + * libempathy/empathy-avatar.c: + * libempathy/empathy-avatar.h: + * libempathy/empathy-tp-contact-list.c: + * libempathy/empathy-tp-contact-list.h: + * libempathy/empathy-tp-chatroom.c: + * libempathy/empathy-contact-factory.c: + * libempathy/empathy-contact-factory.h: + * libempathy/empathy-contact-list.c: + * libempathy/empathy-contact-list.h: + * libempathy/empathy-tp-group.c: + * libempathy/empathy-marshal.list: + * libempathy/empathy-tp-group.h: + * libempathy/Makefile.am: + * configure.ac: Completely reworked ContactList API. Fixes bug #471611, + bug #467280, bug #459540 and bug #462907. + + * doc/*: Updated. + +2007-08-24 Xavier Claessens * python/pyempathy/Makefile.am: * python/pyempathygtk/Makefile.am: * configure.ac: Make use of AM_PATH_PYTHON to get python variables. Fixes bug #470642 (Daniel Gryniewicz). -2007-08-24 Xavier Claessens +2007-08-24 Xavier Claessens * configure.ac: Bump version to 0.13. * NEWS: Last NEWS entry is for version 0.12 and not 0.11. -2007-08-24 Xavier Claessens +2007-08-24 Xavier Claessens * configure.ac: * doc/libempathy-gtk/tmpl/empathy-preferences.sgml: * NEWS: * po/POTFILES.in: Updated. -2007-08-24 Xavier Claessens +2007-08-24 Xavier Claessens * libempathy-gtk/empathy-new-chatroom-dialog.c: * libempathy-gtk/empathy-contact-widget.c: @@ -26,12 +72,12 @@ * data/salut.profile: Salut's protocol name is going to change to local-xmpp. Fixes bug #469638 (Sjoerd Simons) -2007-08-24 Xavier Claessens +2007-08-24 Xavier Claessens * src/empathy.c: Check if there is already a Salut account before creating a new one and add more debug messages. -2007-08-24 Xavier Claessens +2007-08-24 Xavier Claessens * configure.ac: * data/22x22/Makefile.am: @@ -52,7 +98,7 @@ * data/Makefile.am: Change jabber icon. Fixes bug #466377 (Björn Martensen). -2007-08-23 Xavier Claessens +2007-08-23 Xavier Claessens * libempathy-gtk/empathy-account-widget-salut.glade: * libempathy-gtk/empathy-account-widget-salut.c: @@ -67,14 +113,14 @@ salut CM installed using gnome-about-me information. Fixes bug #447467 (Cosimo Cecchi, Xavier Claessens). -2007-08-19 Xavier Claessens +2007-08-19 Xavier Claessens * python/pyempathy/Makefile.am: * python/pyempathy/pyempathy.override: * python/pyempathygtk/Makefile.am: Fix build system, make distcheck now works. -2007-08-19 Xavier Claessens +2007-08-19 Xavier Claessens * python/pyempathy/pyempathy.defs: * python/pyempathy/pyempathymodule.c: @@ -89,12 +135,12 @@ * configure.ac: * Makefile.am: Add python binding. Fixes bug #457660 (Michael Sheldon). -2007-08-19 Xavier Claessens +2007-08-19 Xavier Claessens * libempathy-gtk/empathy-main-window.glade: Edit menu should be second from the left. Fixes bug #467827 (Cosimo Cecchi). -2007-08-13 Xavier Claessens +2007-08-13 Xavier Claessens * libempathy-gtk/empathy-group-chat.c: Only update the topic of it has really be changed, avoid diplaying many times "Topic set to:" message. @@ -104,11 +150,11 @@ if we already logged them last time we joined that room. Previous workaround prevented Empathy to log offline messages. -2007-08-12 Xavier Claessens +2007-08-12 Xavier Claessens * configure.ac: Bump version to 0.12. -2007-08-12 Xavier Claessens +2007-08-12 Xavier Claessens * configure.ac: Update libtool version. @@ -116,33 +162,33 @@ * doc/libempathy-gtk/tmpl/empathy-status-presets.sgml: * NEWS: Updated. -2007-08-12 Xavier Claessens +2007-08-12 Xavier Claessens * data/irc.profile: Removed spaces in the SupportedPresences key to workaround a MC warning SF bug 1772539. -2007-08-11 Xavier Claessens +2007-08-11 Xavier Claessens * libempathy-gtk/empathy-accounts-dialog.c: Make "Add account" button insensitive when we are creating one. Fixes bug #459170 (Jaap A. Haitsma). -2007-08-11 Xavier Claessens +2007-08-11 Xavier Claessens * libempathy/empathy-tp-contact-list.c: s/Local Network/People nearby/ (Sjoerd Simons) -2007-08-10 Xavier Claessens +2007-08-10 Xavier Claessens * libempathy-gtk/empathy-accounts-dialog.c: Unselect accounts when clicking on "add" button. Fixes bug #459173 (Cosimo Cecchi). -2007-08-10 Xavier Claessens +2007-08-10 Xavier Claessens * libempathy-gtk/empathy-presence-chooser.glade: add some spacing in "Custom message" dialog. Fixes bug #465360 (Frederic Peters). -2007-08-10 Xavier Claessens +2007-08-10 Xavier Claessens * libempathy-gtk/empathy-images.h: * libempathy-gtk/empathy-presence-chooser.c: @@ -156,7 +202,7 @@ * data/irc.profile: * data/msn.profile: Updated to use SupportedPresences field. -2007-08-09 Xavier Claessens +2007-08-09 Xavier Claessens * libempathy-gtk/empathy-presence-chooser.glade: * libempathy-gtk/empathy-presence-chooser.c: @@ -169,24 +215,24 @@ messages. Make easier to add other states to the list if needed. Fixes bug #460678. -2007-08-09 Xavier Claessens +2007-08-09 Xavier Claessens * libempathy/empathy-presence.c: * libempathy/empathy-idle.c: * configure.ac: Remove workaround for mc-enum-types.h not being installed by MC and bump MC minimal version to 4.33. -2007-08-09 Xavier Claessens +2007-08-09 Xavier Claessens * libempathy-gtk/empathy-preferences.c: * libempathy-gtk/empathy-preferences.glade: Useless spell checker option. Fixes bug #459164 (Cosimo Cecchi). -2007-08-08 Xavier Claessens +2007-08-08 Xavier Claessens * autogen.sh: Requier automake 1.9. Fixes bug #464822 (Cosimo Cecchi). -2007-08-08 Xavier Claessens +2007-08-08 Xavier Claessens * MAINTAINERS: Updated the MAINTAINERS file to match new syntax. @@ -217,12 +263,12 @@ empathy_contact_list_store_sort_get_type() as it's now auto-generated by glib-mkenums. -2007-08-06 Xavier Claessens +2007-08-06 Xavier Claessens * libempathy-gtk/empathy-main-window.glade: Change main window's title to "Contact list". -2007-08-06 Xavier Claessens +2007-08-06 Xavier Claessens * libempathy/empathy-tp-chat.c: Don't forget to reverse the glist of pending messages. @@ -230,7 +276,7 @@ * libempathy/empathy-tp-roomlist.c: Fix wrong room list names when listing them. -2007-08-06 Xavier Claessens +2007-08-06 Xavier Claessens * libempathy-gtk/empathy-account-widget-msn.glade: * libempathy-gtk/empathy-account-widget-msn.c: Add an Advanced section @@ -239,18 +285,18 @@ * README: Use ./autogen.sh instead of gnome-autogen.sh. -2007-08-02 Xavier Claessens +2007-08-02 Xavier Claessens * libempathy-gtk/empathy-accounts-dialog.glade: * libempathy-gtk/empathy-accounts-dialog.c: Click on the treeview to edit the name of an account. Fixes bug #459166. -2007-08-02 Xavier Claessens +2007-08-02 Xavier Claessens * libempathy-gtk/empathy-account-widget-jabber.c: Do not try to guess the Jabber server from the jid, gabble does that for us. -2007-08-02 Xavier Claessens +2007-08-02 Xavier Claessens * doc/libempathy-gtk/tmpl/empathy-account-chooser.sgml: * doc/libempathy-gtk/tmpl/empathy-ui-utils.sgml: @@ -258,18 +304,18 @@ * doc/libempathy/tmpl/empathy-message.sgml: * doc/libempathy/tmpl/empathy-utils.sgml: Update doc. -2007-08-02 Xavier Claessens +2007-08-02 Xavier Claessens * libempathy-gtk/empathy-profile-chooser.c: Do not list profiles that don't have the corresponding CM installed when creating a new account. This is a workaround for MC bug: SF #1688779. -2007-08-02 Xavier Claessens +2007-08-02 Xavier Claessens * libempathy-gtk/empathy-account-widget-generic.c: Remove size_group. Fixes bug #462792. -2007-08-02 Xavier Claessens +2007-08-02 Xavier Claessens * libempathy-gtk/empathy-accounts-dialog.c: * libempathy/empathy-utils.c: @@ -277,31 +323,31 @@ telepathy-glib. It check if strings are != NULL before using strcmp. Using that API to fix bug #461886. Should be used in more places. -2007-08-02 Xavier Claessens +2007-08-02 Xavier Claessens * libempathy-gtk/empathy-status-icon.c: Click on the tray icon shows the window if it's not active and hide if it is. Fixes bug #462057 (Olivier Valentin). -2007-08-02 Xavier Claessens +2007-08-02 Xavier Claessens * libempathy-gtk/empathy-group-chat.c: don't display "Topic set to: (null)". Fixes bug #460205 (Michael Scherer). -2007-07-30 Xavier Claessens +2007-07-30 Xavier Claessens * autogen.sh: Added back, it calls gnome-autogen.sh. -2007-07-29 Xavier Claessens +2007-07-29 Xavier Claessens * libempathy-gtk/empathy-profile-chooser.c: * libempathy/empathy-message.c: Add missing include string.h. -2007-07-29 Xavier Claessens +2007-07-29 Xavier Claessens * configure.ac: Bump version to 0.11. -2007-07-29 Xavier Claessens +2007-07-29 Xavier Claessens * libempathy-gtk/empathy-account-widget-generic.c: * libempathy-gtk/empathy-account-widget-generic.h: Align param names @@ -313,36 +359,36 @@ * configure.ac: Set Collabora Ltd. in the Copyright. -2007-07-28 Xavier Claessens +2007-07-28 Xavier Claessens * libempathy-gtk/empathy-profile-chooser.c: Makes easier to change to profile order. -2007-07-28 Xavier Claessens +2007-07-28 Xavier Claessens * libempathy-gtk/empathy-account-widget-jabber.c: Try to guess the server from the jid only if we are using the jabber profile. When we guessed a server don't forget to set the "server" McAccount param, setting the entry's text is not enough. -2007-07-28 Xavier Claessens +2007-07-28 Xavier Claessens * libempathy-gtk/empathy-profile-chooser.c: Improve the sort function a bit to have Jabber before GTalk. -2007-07-28 Xavier Claessens +2007-07-28 Xavier Claessens * libempathy-gtk/empathy-accounts-dialog.glade: * libempathy-gtk/empathy-accounts-dialog.c: Update the Enable/Disable button even if there is no account selected. Set it insensitive if no account is selected. Fixes bug #459012. -2007-07-27 Xavier Claessens +2007-07-27 Xavier Claessens * libempathy-gtk/empathy-profile-chooser.c: Sort profiles to have free protocols first. Fixes bug #460605. -2007-07-27 Xavier Claessens +2007-07-27 Xavier Claessens * libempathy/empathy-message.c: * libempathy/empathy-message.h: @@ -351,38 +397,38 @@ * doc/*: Updated. -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * po/POTFILES.in: Add missing file libempathy-gtk/empathy-account-widget-msn.glade. -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * libempathy-gtk/empathy-account-widget-jabber.glade: * libempathy-gtk/empathy-account-widget-jabber.c: Hide "advanced options" for jabber in a GtkExpander. Fixes bug #459168 (Guillaume Desmottes). -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * libempathy-gtk/empathy-new-chatroom-dialog.c: * libempathy/empathy-tp-roomlist.c: Fix Room listing. Fixes bug #460416 (Sjoerd Simons). -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * libempathy-gtk/Makefile.am: * libempathy/Makefile.am: * configure.ac: Use libtool -version-info. Fixes bug #460579 (Laurent Bigonville). -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * README: * autogen.sh: Remove the autogen.sh script and use gnome-autogen.sh instead. Fixes bug #460590. -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * libempathy-gtk/empathy-account-chooser.c: * libempathy-gtk/empathy-new-chatroom-dialog.c: @@ -396,32 +442,32 @@ a bit EmpathyContactWidget. Fixes bug #459100 (Guillaume Desmottes, Xavier Claessens). -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * libempathy-gtk/empathy-accounts-dialog.c: add contact frame is not hidden after cancelling. Fixes bug #458997 (Frederic Peters). -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * libempathy/empathy-idle.c: Fix problems when NM is not running. Fixes bug #460419. * doc/*: Updated documentation. -2007-07-26 Xavier Claessens +2007-07-26 Xavier Claessens * configure.ac: Bump version to 0.10 -2007-07-25 Xavier Claessens +2007-07-25 Xavier Claessens * libempathy/empathy-filter.c: Adding more debug output. -2007-07-25 Xavier Claessens +2007-07-25 Xavier Claessens * libempathy/empathy-tp-contact-list.c: Add a check to be sure the new channel is valid in the NewChannel cb. Fixes bug #451564. -2007-07-20 Xavier Claessens +2007-07-20 Xavier Claessens * libempathy/Makefile.am: * libempathy/empathy-tp-roomlist.h: @@ -468,22 +514,22 @@ * data/empathy.desktop.in.in: Change application description (Jaap A. Haitsma). -2007-07-14 Xavier Claessens +2007-07-14 Xavier Claessens * libempathy-gtk/empathy-contact-list-store.c: Show avatars by default. -2007-07-13 Xavier Claessens +2007-07-13 Xavier Claessens * libempathy-gtk/empathy-status-icon.c: If there is no pending msg when a text channel should be filtered wait for the first message instead of not dispatching the channel which may cause messages to be lost. -2007-07-13 Xavier Claessens +2007-07-13 Xavier Claessens * libempathy/empathy-tp-contact-list.c: Fix avatar request queue. -2007-07-13 Xavier Claessens +2007-07-13 Xavier Claessens * libempathy-gtk/empathy-new-chatroom-dialog.c: * libempathy-gtk/empathy-new-chatroom-dialog.glade: Remove unused @@ -499,7 +545,7 @@ * libempathy/empathy-tp-contact-list.c: Add more debug msg for avatar handling. -2007-07-12 Xavier Claessens +2007-07-12 Xavier Claessens * libempathy-gtk/Makefile.am: Fix missing header for EmpathyAccountWidgetMSN. @@ -508,26 +554,26 @@ * autogen.sh: run gtkdocize if needed. -2007-07-12 Xavier Claessens +2007-07-12 Xavier Claessens * configure.ac: * doc/*: * Makefile.am: Adding initial API documentation using gtk-doc. -2007-07-12 Xavier Claessens +2007-07-12 Xavier Claessens * libempathy/empathy-tp-contact-list.c: Auto-accept to publish presence to contacts that are in our subscribe list. When accepting a pending contact add it to publish and subscribe list. -2007-07-09 Xavier Claessens +2007-07-09 Xavier Claessens * src/empathy.c: * libempathy/empathy-debug.c: * libempathy/empathy-debug.h: Add EMPATHY_LOGFILE env variable. Fixes bug #455240 (Guillaume Desmottes). -2007-07-09 Xavier Claessens +2007-07-09 Xavier Claessens * libempathy-gtk/empathy-account-widget-msn.glade: * libempathy-gtk/empathy-account-widget-msn.c: @@ -541,18 +587,18 @@ * libempathy/empathy-log-manager.h: Add needed API to show chat logs in Tracker. Fixes bug #452536. -2007-07-07 Xavier Claessens +2007-07-07 Xavier Claessens * libempathy-gtk/empathy-account-widget-generic.c: Workaround to fix a commonly reported crash. Fixes bug #454277 * libempathy/empathy-tp-group.c: Add a missing check. -2007-06-30 Xavier Claessens +2007-06-30 Xavier Claessens * configure.ac: Bump MC version required to 4.27. * TODO: Updated. -2007-06-30 Xavier Claessens +2007-06-30 Xavier Claessens * libempathy-gtk/empathy-account-widget-generic.c: Fix a leaked ref. @@ -575,7 +621,7 @@ status icon flash when there we receive a new message. Dispatch the channel only when we get a message and the user click on the icon. -2007-06-22 Xavier Claessens +2007-06-22 Xavier Claessens * libempathy-gtk/libempathy-gtk.pc.in: * libempathy-gtk/Makefile.am: @@ -584,11 +630,11 @@ * configure.ac: Install libempathy and libempathy-gtk and make their API public. -2007-06-22 Xavier Claessens +2007-06-22 Xavier Claessens * po/POTFILES.in: s/gossip/empathy/ -2007-06-22 Xavier Claessens +2007-06-22 Xavier Claessens * libempathy/*.[ch]: * libempathy-gtk/*.[ch]: @@ -596,15 +642,15 @@ change namespace of all gossip_*() functions to empathy_*(). Fixes bug #444490 (Mario Danic, Xavier Claessens). -2007-06-21 Xavier Claessens +2007-06-21 Xavier Claessens * configure.ac: Bump version to 0.9 -2007-06-21 Xavier Claessens +2007-06-21 Xavier Claessens * libempathy/empathy-tp-contact-list.c: Fix typo causing warnings. -2007-06-21 Xavier Claessens +2007-06-21 Xavier Claessens * libempathy-gtk/empathy-contact-dialogs.c: * libempathy-gtk/gossip-contact-list-store.c: @@ -618,12 +664,12 @@ only add/remove from subscribe list. Accept/Reject a contact in local-pending of publish list is done using _process_pending(). -2007-06-15 Xavier Claessens +2007-06-15 Xavier Claessens * src/empathy.c: * libempathy/empathy-idle.c: Adding NetworkManager support. -2007-06-15 Xavier Claessens +2007-06-15 Xavier Claessens * libempathy-gtk/empathy-status-icon.c: * libempathy-gtk/gossip-presence-chooser.c: @@ -632,7 +678,7 @@ * libempathy/empathy-idle.h: Prepare for slack time when coming back from auto away. Not yet fully implemented. -2007-06-14 Xavier Claessens +2007-06-14 Xavier Claessens * libempathy-gtk/empathy-images.h: * libempathy-gtk/gossip-chat.c: Use gtk-info for contact informaiton. @@ -645,12 +691,12 @@ * data/scalable/Makefile.am: * data/salut.profile: Add salut icon. Fixes bug #447659 (Michael Monreal). -2007-06-14 Xavier Claessens +2007-06-14 Xavier Claessens * libempathy-gtk/gossip-contact-list-view.c: Show logs when right click on a contact in the roster. -2007-06-14 Xavier Claessens +2007-06-14 Xavier Claessens * src/org.gnome.Empathy.Chat.service.in: * src/empathy-accounts.c: @@ -664,22 +710,22 @@ debugging more difficult when emmpathy-chat crashes. It's also more optimised like that since contact objects can be shared. -2007-06-14 Xavier Claessens +2007-06-14 Xavier Claessens * libempathy-gtk/gossip-chat-window.c: Disconnect signals from chatroom_manager. Fixes bug #447178. -2007-06-14 Xavier Claessens +2007-06-14 Xavier Claessens * po/POTFILES.in: * po/POTFILES.skip: Get strings in empathy.desktop.in.in and skip empathy.desktop.in. Fixes bug #446161. -2007-06-14 Xavier Claessens +2007-06-14 Xavier Claessens * po/POTFILES.in: Adding missing files. -2007-06-14 Xavier Claessens +2007-06-14 Xavier Claessens * libempathy-gtk/gossip-log-window.c: * libempathy-gtk/gossip-chat-window.c: @@ -688,7 +734,7 @@ chat if there is no messages to put in. Show logs and information for the contact we are speaking with in the chat window menu. -2007-06-13 Xavier Claessens +2007-06-13 Xavier Claessens * libempathy-gtk/Makefile.am: * libempathy-gtk/gossip-log-window.glade: @@ -723,7 +769,7 @@ * libempathy/gossip-message.c: Add a "receiver" property like that we have our self contact for nick highlight. -2007-06-10 Xavier Claessens +2007-06-10 Xavier Claessens * libempathy-gtk/gossip-spell-dialog.glade: * libempathy-gtk/gossip-spell-dialog.c: @@ -735,22 +781,22 @@ * libempathy-gtk/gossip-spell.c: * libempathy/gossip-conf.c: Remove useless debug messages. -2007-06-10 Xavier Claessens +2007-06-10 Xavier Claessens * libempathy-gtk/gossip-chat-view.c: Smooth scrolling. Fixes bug #445859 (Raphael Slinckx). -2007-06-09 Xavier Claessens +2007-06-09 Xavier Claessens * libempathy/gossip-contact.c: Emit notify signal only if the property value effectively changed. -2007-06-09 Xavier Claessens +2007-06-09 Xavier Claessens * libempathy-gtk/gossip-contact-list-view.c: Fix warning for DnD. patch imported from gossip. -2007-06-09 Xavier Claessens +2007-06-09 Xavier Claessens * configure.ac: Bump version to 0.8 @@ -762,11 +808,11 @@ * data/msn.profile: Add VCardField and VCardDefault to profiles for eds-sync support. -2007-06-09 Xavier Claessens +2007-06-09 Xavier Claessens * libempathy-gtk/empathy-contact-widget.c: Fix a warning. -2007-06-09 Xavier Claessens +2007-06-09 Xavier Claessens * libempathy-gtk/empathy-main-window.c: * libempathy-gtk/empathy-contact-widget.glade: @@ -779,12 +825,12 @@ * libempathy/empathy-tp-contact-list.c: Fix a refcount bug. -2007-06-08 Xavier Claessens +2007-06-08 Xavier Claessens * libempathy/gossip-chatroom-manager.c: Checks if the chatroom has an account and a room. Fixes bug #444135. -2007-06-08 Xavier Claessens +2007-06-08 Xavier Claessens * libempathy-gtk/empathy-contact-dialogs.c: * libempathy-gtk/empathy-contact-widget.c: @@ -797,18 +843,18 @@ gossip_contact_add/remove_group(). This fixes leaks when a contact is added/removed from a group. -2007-06-08 Xavier Claessens +2007-06-08 Xavier Claessens * libempathy-gtk/gossip-chat.c: Fix build on 64bits arch. Fixes bug #444680 (Matej Cepl). -2007-06-06 Xavier Claessens +2007-06-06 Xavier Claessens * libempathy-gtk/empathy-contact-dialogs.glade: * libempathy-gtk/empathy-contact-dialogs.c: Fix response and action buttons. -2007-06-06 Xavier Claessens +2007-06-06 Xavier Claessens * libempathy-gtk/empathy-contact-dialogs.glade: * libempathy-gtk/empathy-contact-widget.glade: @@ -825,7 +871,7 @@ * libempathy-gtk/empathy-subscription-dialog.h: Implement editing and viewing contact information with right click on the roster. -2007-06-06 Xavier Claessens +2007-06-06 Xavier Claessens * libempathy-gtk/empathy-contact-widget.glade: * libempathy-gtk/empathy-contact-widget.c: @@ -833,11 +879,11 @@ * libempathy-gtk/empathy-subscription-dialog.c: EmpatchContactWidget has 2 modes: editable or not. -2007-06-06 Xavier Claessens +2007-06-06 Xavier Claessens * po/POTFILES.in: Updated with new files. -2007-06-06 Xavier Claessens +2007-06-06 Xavier Claessens * libempathy-gtk/empathy-status-icon.c: * libempathy-gtk/empathy-subscription-dialog.glade: @@ -852,7 +898,7 @@ dialog appears when clicking on the status icon when it blinks. You can also remove contacts when right-click on it in the roster. -2007-06-06 Xavier Claessens +2007-06-06 Xavier Claessens * libempathy-gtk/empathy-status-icon.c: * libempathy-gtk/empathy-contact-widget.glade: @@ -870,7 +916,7 @@ gossip_presence_state_get_default_status (MC_PRESENCE_OFFLINE) when there is no presence. -2007-06-06 Xavier Claessens +2007-06-06 Xavier Claessens * libempathy-gtk/empathy-status-icon.c: Add support for blinking when there is an event. Make use of EmpathyIdle for presence handling. Add @@ -893,7 +939,7 @@ * TODO: Updated. -2007-06-03 Xavier Claessens +2007-06-03 Xavier Claessens * libempathy-gtk/gossip-accounts-dialog.glade: Set use_stock for button_connect to False, to avoid a crasher when opening the accounts @@ -901,7 +947,7 @@ * libempathy-gtk/gossip-chat.c: Do not add backlog for chatrooms and do not log backlog from jabber server. -2007-06-03 Xavier Claessens +2007-06-03 Xavier Claessens * libempathy-gtk/gossip-ui-utils.c * libempathy-gtk/gossip-accounts-dialog.c @@ -920,13 +966,13 @@ * libempathy/gossip-paths.h: Remove unused code and append DATADIR to dirs where GTK should search icons. -2007-06-03 Xavier Claessens +2007-06-03 Xavier Claessens * po/POTFILES.in: * po/POTFILES.skip: Add missing files that have strings for translation. Skip empathy-desktop.in.in. (Olivier Crete) -2007-06-03 Xavier Claessens +2007-06-03 Xavier Claessens * libempathy-gtk/gossip-group-chat.c: * libempathy-gtk/gossip-private-chat.c: diff --git a/configure.ac b/configure.ac index c31afd82..49a09b7b 100644 --- a/configure.ac +++ b/configure.ac @@ -155,62 +155,58 @@ AC_ARG_ENABLE(python, [build python bindings to libempathy and libempathy-gtk]), , enable_python=auto) -PKG_CHECK_MODULES(PYTHON_BINDING, -[ - pygtk-2.0, - glib-2.0 >= $GLIB_REQUIRED - gobject-2.0 - gconf-2.0 >= $GCONF_REQUIRED - libxml-2.0 - gnome-vfs-2.0 - libtelepathy >= $TELEPATHY_REQUIRED - libmissioncontrol >= $MISSION_CONTROL_REQUIRED - gtk+-2.0 >= $GTK_REQUIRED - libglade-2.0 >= $LIBGLADE_REQUIRED - libgnomeui-2.0 -], have_python="yes", have_python="no") - -if test "x$have_python" = "xno"; then - if test "x$enable_python" = "xyes"; then - AC_MSG_ERROR([Could not find python dependencies]) - fi - enable_python="no (missing dependencies)" +if test "x$enable_python" != "xno"; then + AM_PATH_PYTHON + if test -z "$PYTHON" ; then + have_python="no" + else + PKG_CHECK_MODULES(PYTHON_BINDING, + [ + pygtk-2.0, + glib-2.0 >= $GLIB_REQUIRED + gobject-2.0 + gconf-2.0 >= $GCONF_REQUIRED + libxml-2.0 + gnome-vfs-2.0 + libtelepathy >= $TELEPATHY_REQUIRED + libmissioncontrol >= $MISSION_CONTROL_REQUIRED + gtk+-2.0 >= $GTK_REQUIRED + libglade-2.0 >= $LIBGLADE_REQUIRED + libgnomeui-2.0 + ], have_python="yes", have_python="no") + fi else - if test "x$enable_python" != "xno"; then - AM_PATH_PYTHON - if test -z "$PYTHON" ; then - enable_python="no" - else - enable_python="yes" - fi - else - enable_python="no (disabled)" - fi + have_python=no +fi + +if test "x$enable_python" = "xyes" -a "x$have_python" != "xyes"; then + AC_MSG_ERROR([Couldn't find python.]) fi -AM_CONDITIONAL(HAVE_PYTHON, test x$enable_python = xyes) + +AM_CONDITIONAL(HAVE_PYTHON, test "x$have_python" = "xyes") dnl ----------------------------------------------------------- AC_OUTPUT([ - Makefile - data/Makefile - data/empathy.desktop.in - data/16x16/Makefile - data/22x22/Makefile - data/24x24/Makefile - data/32x32/Makefile - data/48x48/Makefile - data/scalable/Makefile - po/Makefile.in - libempathy/Makefile - libempathy/libempathy.pc - libempathy-gtk/Makefile - libempathy-gtk/libempathy-gtk.pc - src/Makefile - doc/Makefile - doc/libempathy/Makefile - doc/libempathy-gtk/Makefile - python/Makefile - python/pyempathy/Makefile - python/pyempathygtk/Makefile + Makefile + data/Makefile + data/empathy.desktop.in + data/16x16/Makefile + data/22x22/Makefile + data/24x24/Makefile + data/32x32/Makefile + data/48x48/Makefile + data/scalable/Makefile + po/Makefile.in + libempathy/Makefile + libempathy/libempathy.pc + libempathy-gtk/Makefile + libempathy-gtk/libempathy-gtk.pc + src/Makefile + doc/Makefile + doc/libempathy/Makefile + doc/libempathy-gtk/Makefile + python/Makefile + python/pyempathy/Makefile + python/pyempathygtk/Makefile ]) diff --git a/doc/libempathy-gtk/tmpl/empathy-contact-list-store.sgml b/doc/libempathy-gtk/tmpl/empathy-contact-list-store.sgml index a4430da4..cc74feef 100644 --- a/doc/libempathy-gtk/tmpl/empathy-contact-list-store.sgml +++ b/doc/libempathy-gtk/tmpl/empathy-contact-list-store.sgml @@ -173,22 +173,3 @@ EmpathyContactListStore @Returns: - - - - - -@store: -@func: -@user_data: - - - - - - - -@store: -@contact: - - diff --git a/doc/libempathy-gtk/tmpl/empathy-contact-list-view.sgml b/doc/libempathy-gtk/tmpl/empathy-contact-list-view.sgml index ad7a1ff7..188033eb 100644 --- a/doc/libempathy-gtk/tmpl/empathy-contact-list-view.sgml +++ b/doc/libempathy-gtk/tmpl/empathy-contact-list-view.sgml @@ -39,23 +39,6 @@ EmpathyContactListView @arg2: @arg3: - - - - - - - - - - -@contact: -@action: -@old_group: -@new_group: -@user_data: - - @@ -102,22 +85,3 @@ EmpathyContactListView @Returns: - - - - - -@view: -@filter: - - - - - - - -@view: -@func: -@user_data: - - diff --git a/doc/libempathy-gtk/tmpl/empathy-images.sgml b/doc/libempathy-gtk/tmpl/empathy-images.sgml index c55b21f1..5b8c6541 100644 --- a/doc/libempathy-gtk/tmpl/empathy-images.sgml +++ b/doc/libempathy-gtk/tmpl/empathy-images.sgml @@ -59,13 +59,6 @@ empathy-images - - - - - - - diff --git a/doc/libempathy-gtk/tmpl/empathy-preferences.sgml b/doc/libempathy-gtk/tmpl/empathy-preferences.sgml index d97f5b57..0b7a7d27 100644 --- a/doc/libempathy-gtk/tmpl/empathy-preferences.sgml +++ b/doc/libempathy-gtk/tmpl/empathy-preferences.sgml @@ -143,13 +143,6 @@ empathy-preferences - - - - - - - diff --git a/doc/libempathy/libempathy.types b/doc/libempathy/libempathy.types index 0211e40b..15955d12 100644 --- a/doc/libempathy/libempathy.types +++ b/doc/libempathy/libempathy.types @@ -16,7 +16,7 @@ #include #include -empathy_avatar_get_gtype +empathy_avatar_get_type empathy_chatroom_manager_get_type empathy_contact_manager_get_type empathy_idle_get_type @@ -26,7 +26,7 @@ empathy_conf_get_type empathy_log_manager_get_type empathy_tp_group_get_type empathy_chandler_get_type -empathy_contact_get_gtype +empathy_contact_get_type empathy_tp_chat_get_type empathy_chatroom_get_type empathy_contact_list_get_type diff --git a/doc/libempathy/tmpl/empathy-avatar.sgml b/doc/libempathy/tmpl/empathy-avatar.sgml index 44035517..3f71285c 100644 --- a/doc/libempathy/tmpl/empathy-avatar.sgml +++ b/doc/libempathy/tmpl/empathy-avatar.sgml @@ -34,14 +34,6 @@ empathy-avatar @format: @refcount: - - - - - -@Returns: - - diff --git a/doc/libempathy/tmpl/empathy-contact-list.sgml b/doc/libempathy/tmpl/empathy-contact-list.sgml index 1a2839fc..a84646a8 100644 --- a/doc/libempathy/tmpl/empathy-contact-list.sgml +++ b/doc/libempathy/tmpl/empathy-contact-list.sgml @@ -23,23 +23,29 @@ empathy-contact-list - + @empathycontactlist: the object which received the signal. @arg1: +@arg2: +@arg3: - + @empathycontactlist: the object which received the signal. @arg1: +@arg2: +@arg3: +@arg4: +@arg5: - + @@ -47,6 +53,9 @@ empathy-contact-list @empathycontactlist: the object which received the signal. @arg1: @arg2: +@arg3: +@arg4: +@arg5: @@ -54,57 +63,15 @@ empathy-contact-list @base_iface: -@setup: -@find: @add: @remove: @get_members: -@get_local_pending: -@process_pending: - - - - - - -@contact: -@message: - - - - - - -@contact: -@message: -@Returns: - - - - - - - -@info: - - - - - - - -@list: - - - - - - - -@list: -@id: -@Returns: - +@get_pendings: +@get_all_groups: +@get_groups: +@add_to_group: +@remove_from_group: +@rename_group: @@ -135,22 +102,3 @@ empathy-contact-list @Returns: - - - - - -@list: -@Returns: - - - - - - - -@list: -@contact: -@accept: - - diff --git a/doc/libempathy/tmpl/empathy-contact-manager.sgml b/doc/libempathy/tmpl/empathy-contact-manager.sgml index 0defe484..fe25eb7e 100644 --- a/doc/libempathy/tmpl/empathy-contact-manager.sgml +++ b/doc/libempathy/tmpl/empathy-contact-manager.sgml @@ -47,43 +47,3 @@ EmpathyContactManager @Returns: - - - - - -@manager: -@account: -@Returns: - - - - - - - -@manager: -@account: -@id: -@Returns: - - - - - - - -@manager: -@old_group: -@new_group: - - - - - - - -@manager: -@Returns: - - diff --git a/doc/libempathy/tmpl/empathy-contact.sgml b/doc/libempathy/tmpl/empathy-contact.sgml index 1ab2321a..861151fb 100644 --- a/doc/libempathy/tmpl/empathy-contact.sgml +++ b/doc/libempathy/tmpl/empathy-contact.sgml @@ -33,11 +33,6 @@ EmpathyContact - - - - - @@ -63,29 +58,6 @@ EmpathyContact - - - - - - - - - - -@EMPATHY_SUBSCRIPTION_NONE: -@EMPATHY_SUBSCRIPTION_TO: -@EMPATHY_SUBSCRIPTION_FROM: -@EMPATHY_SUBSCRIPTION_BOTH: - - - - - - -@Returns: - - @@ -151,24 +123,6 @@ EmpathyContact @Returns: - - - - - -@contact: -@Returns: - - - - - - - -@contact: -@Returns: - - @@ -232,24 +186,6 @@ EmpathyContact @presence: - - - - - -@contact: -@categories: - - - - - - - -@contact: -@subscription: - - @@ -268,24 +204,6 @@ EmpathyContact @is_user: - - - - - -@contact: -@group: - - - - - - - -@contact: -@group: - - @@ -295,16 +213,6 @@ EmpathyContact @Returns: - - - - - -@contact: -@group: -@Returns: - - diff --git a/doc/libempathy/tmpl/empathy-tp-contact-list.sgml b/doc/libempathy/tmpl/empathy-tp-contact-list.sgml index 3420151d..a3ff09ef 100644 --- a/doc/libempathy/tmpl/empathy-tp-contact-list.sgml +++ b/doc/libempathy/tmpl/empathy-tp-contact-list.sgml @@ -54,61 +54,3 @@ EmpathyTpContactList @Returns: - - - - - -@list: -@Returns: - - - - - - - -@list: -@id: -@Returns: - - - - - - - -@list: -@handle: -@Returns: - - - - - - - -@list: -@handles: -@Returns: - - - - - - - -@list: -@old_group: -@new_group: - - - - - - - -@list: -@Returns: - - diff --git a/doc/libempathy/tmpl/empathy-tp-group.sgml b/doc/libempathy/tmpl/empathy-tp-group.sgml index 988b5d8f..6ea6206e 100644 --- a/doc/libempathy/tmpl/empathy-tp-group.sgml +++ b/doc/libempathy/tmpl/empathy-tp-group.sgml @@ -29,6 +29,13 @@ EmpathyTpGroup + + + + + +@empathytpgroup: the object which received the signal. + @@ -40,7 +47,7 @@ EmpathyTpGroup @arg3: @arg4: - + @@ -51,7 +58,7 @@ EmpathyTpGroup @arg3: @arg4: - + @@ -73,16 +80,6 @@ EmpathyTpGroup @arg3: @arg4: - - - - - -@member: -@actor: -@reason: -@message: - @@ -99,7 +96,7 @@ EmpathyTpGroup @group: -@handles: +@contacts: @message: @@ -109,7 +106,7 @@ EmpathyTpGroup @group: -@handle: +@contact: @message: @@ -119,7 +116,7 @@ EmpathyTpGroup @group: -@handle: +@contacts: @message: @@ -129,7 +126,7 @@ EmpathyTpGroup @group: -@handle: +@contact: @message: @@ -142,34 +139,6 @@ EmpathyTpGroup @Returns: - - - - - -@group: -@members: -@local_pending: -@remote_pending: - - - - - - - -@group: -@Returns: - - - - - - - -@infos: - - @@ -179,15 +148,6 @@ EmpathyTpGroup @Returns: - - - - - -@group: -@Returns: - - @@ -203,7 +163,7 @@ EmpathyTpGroup @group: -@handle: +@contact: @Returns: diff --git a/libempathy-gtk/empathy-chat-window.c b/libempathy-gtk/empathy-chat-window.c index 7d48abf8..c1df38b1 100644 --- a/libempathy-gtk/empathy-chat-window.c +++ b/libempathy-gtk/empathy-chat-window.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include @@ -823,17 +823,20 @@ chat_window_update_menu (EmpathyChatWindow *window) window); } else { EmpathyPrivateChat *chat; - EmpathySubscription subscription; EmpathyContact *contact; + EmpathyPresence *presence; chat = EMPATHY_PRIVATE_CHAT (priv->current_chat); /* Show / Hide widgets */ gtk_widget_hide (priv->menu_room); + /* presence==NULL means this contact refuses to send us his + * presence. By adding the contact we ask the contact to accept + * to send his presence. */ contact = empathy_private_chat_get_contact (chat); - subscription = empathy_contact_get_subscription (contact); - if (!(subscription & EMPATHY_SUBSCRIPTION_FROM)) { + presence = empathy_contact_get_presence (contact); + if (!presence) { gtk_widget_show (priv->menu_conv_add_contact); } else { gtk_widget_hide (priv->menu_conv_add_contact); @@ -1583,12 +1586,13 @@ chat_window_drag_data_received (GtkWidget *widget, { /* FIXME: DnD of contact do not seems to work... */ if (info == DND_DRAG_TYPE_CONTACT_ID) { - EmpathyContactManager *manager; - EmpathyContact *contact; - EmpathyChat *chat; - EmpathyChatWindow *old_window; + EmpathyContactFactory *factory; + EmpathyContact *contact = NULL; + EmpathyChat *chat; + EmpathyChatWindow *old_window; McAccount *account; const gchar *id = NULL; + gchar **strv; if (selection) { id = (const gchar*) selection->data; @@ -1596,9 +1600,18 @@ chat_window_drag_data_received (GtkWidget *widget, empathy_debug (DEBUG_DOMAIN, "DND contact from roster with id:'%s'", id); - manager = empathy_contact_manager_new (); - contact = empathy_contact_list_find (EMPATHY_CONTACT_LIST (manager), id); - g_object_unref (manager); + strv = g_strsplit (id, "/", 2); + factory = empathy_contact_factory_new (); + account = mc_account_lookup (strv[0]); + if (account) { + contact = empathy_contact_factory_get_from_id (factory, + account, + strv[1]); + g_object_unref (account); + } + g_object_unref (factory); + g_object_unref (account); + g_strfreev (strv); if (!contact) { empathy_debug (DEBUG_DOMAIN, "DND contact from roster not found"); diff --git a/libempathy-gtk/empathy-contact-dialogs.c b/libempathy-gtk/empathy-contact-dialogs.c index 437e255f..553f85bc 100644 --- a/libempathy-gtk/empathy-contact-dialogs.c +++ b/libempathy-gtk/empathy-contact-dialogs.c @@ -42,7 +42,7 @@ static GtkWidget *new_contact_dialog = NULL; static gint -contact_dialogs_find (GtkDialog *dialog, +contact_dialogs_find (GtkDialog *dialog, EmpathyContact *contact) { GtkWidget *contact_widget; @@ -64,18 +64,18 @@ subscription_dialog_response_cb (GtkDialog *dialog, GtkWidget *contact_widget) { EmpathyContactManager *manager; - EmpathyContact *contact; + EmpathyContact *contact; manager = empathy_contact_manager_new (); contact = empathy_contact_widget_get_contact (contact_widget); if (response == GTK_RESPONSE_YES) { - empathy_contact_list_process_pending (EMPATHY_CONTACT_LIST (manager), - contact, TRUE); + empathy_contact_list_add (EMPATHY_CONTACT_LIST (manager), + contact, ""); } else if (response == GTK_RESPONSE_NO) { - empathy_contact_list_process_pending (EMPATHY_CONTACT_LIST (manager), - contact, FALSE); + empathy_contact_list_remove (EMPATHY_CONTACT_LIST (manager), + contact, ""); } subscription_dialogs = g_list_remove (subscription_dialogs, dialog); diff --git a/libempathy-gtk/empathy-contact-list-store.c b/libempathy-gtk/empathy-contact-list-store.c index ac2fa62c..9cf03bfe 100644 --- a/libempathy-gtk/empathy-contact-list-store.c +++ b/libempathy-gtk/empathy-contact-list-store.c @@ -57,10 +57,10 @@ struct _EmpathyContactListStorePriv { gboolean show_avatars; gboolean is_compact; gboolean show_active; - EmpathyContactListStoreSort sort_criterium; + EmpathyContactListStoreSort sort_criterium; guint inhibit_active; - EmpathyContactGroupsFunc get_contact_groups; + EmpathyContactGroupsFunc get_contact_groups; gpointer get_contact_groups_data; }; @@ -84,71 +84,74 @@ typedef struct { static void empathy_contact_list_store_class_init (EmpathyContactListStoreClass *klass); static void empathy_contact_list_store_init (EmpathyContactListStore *list); -static void contact_list_store_finalize (GObject *object); -static void contact_list_store_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void contact_list_store_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void contact_list_store_setup (EmpathyContactListStore *store); -static gboolean contact_list_store_inibit_active_cb (EmpathyContactListStore *store); -static void contact_list_store_contact_added_cb (EmpathyContactList *list_iface, - EmpathyContact *contact, - EmpathyContactListStore *store); -static void contact_list_store_add_contact (EmpathyContactListStore *store, - EmpathyContact *contact); -static void contact_list_store_contact_removed_cb (EmpathyContactList *list_iface, - EmpathyContact *contact, - EmpathyContactListStore *store); -static void contact_list_store_remove_contact (EmpathyContactListStore *store, - EmpathyContact *contact); -static void contact_list_store_contact_update (EmpathyContactListStore *store, - EmpathyContact *contact); -static void contact_list_store_contact_groups_updated_cb (EmpathyContact *contact, - GParamSpec *param, - EmpathyContactListStore *store); -static void contact_list_store_contact_updated_cb (EmpathyContact *contact, - GParamSpec *param, - EmpathyContactListStore *store); -static void contact_list_store_contact_set_active (EmpathyContactListStore *store, - EmpathyContact *contact, - gboolean active, - gboolean set_changed); -static ShowActiveData * contact_list_store_contact_active_new (EmpathyContactListStore *store, - EmpathyContact *contact, - gboolean remove); -static void contact_list_store_contact_active_free (ShowActiveData *data); -static gboolean contact_list_store_contact_active_cb (ShowActiveData *data); -static gboolean contact_list_store_get_group_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindGroup *fg); -static void contact_list_store_get_group (EmpathyContactListStore *store, - const gchar *name, - GtkTreeIter *iter_group_to_set, - GtkTreeIter *iter_separator_to_set, - gboolean *created); -static gint contact_list_store_state_sort_func (GtkTreeModel *model, - GtkTreeIter *iter_a, - GtkTreeIter *iter_b, - gpointer user_data); -static gint contact_list_store_name_sort_func (GtkTreeModel *model, - GtkTreeIter *iter_a, - GtkTreeIter *iter_b, - gpointer user_data); -static gboolean contact_list_store_find_contact_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindContact *fc); -static GList * contact_list_store_find_contact (EmpathyContactListStore *store, - EmpathyContact *contact); -static gboolean contact_list_store_update_list_mode_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - EmpathyContactListStore *store); +static void contact_list_store_finalize (GObject *object); +static void contact_list_store_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void contact_list_store_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void contact_list_store_setup (EmpathyContactListStore *store); +static gboolean contact_list_store_inibit_active_cb (EmpathyContactListStore *store); +static void contact_list_store_members_changed_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_member, + EmpathyContactListStore *store); +static void contact_list_store_groups_changed_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + gchar *group, + gboolean is_member, + EmpathyContactListStore *store); +static void contact_list_store_add_contact (EmpathyContactListStore *store, + EmpathyContact *contact); +static void contact_list_store_remove_contact (EmpathyContactListStore *store, + EmpathyContact *contact); +static void contact_list_store_contact_update (EmpathyContactListStore *store, + EmpathyContact *contact); +static void contact_list_store_contact_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyContactListStore *store); +static void contact_list_store_contact_set_active (EmpathyContactListStore *store, + EmpathyContact *contact, + gboolean active, + gboolean set_changed); +static ShowActiveData * contact_list_store_contact_active_new (EmpathyContactListStore *store, + EmpathyContact *contact, + gboolean remove); +static void contact_list_store_contact_active_free (ShowActiveData *data); +static gboolean contact_list_store_contact_active_cb (ShowActiveData *data); +static gboolean contact_list_store_get_group_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + FindGroup *fg); +static void contact_list_store_get_group (EmpathyContactListStore *store, + const gchar *name, + GtkTreeIter *iter_group_to_set, + GtkTreeIter *iter_separator_to_set, + gboolean *created); +static gint contact_list_store_state_sort_func (GtkTreeModel *model, + GtkTreeIter *iter_a, + GtkTreeIter *iter_b, + gpointer user_data); +static gint contact_list_store_name_sort_func (GtkTreeModel *model, + GtkTreeIter *iter_a, + GtkTreeIter *iter_b, + gpointer user_data); +static gboolean contact_list_store_find_contact_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + FindContact *fc); +static GList * contact_list_store_find_contact (EmpathyContactListStore *store, + EmpathyContact *contact); +static gboolean contact_list_store_update_list_mode_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyContactListStore *store); enum { PROP_0, @@ -317,24 +320,23 @@ empathy_contact_list_store_new (EmpathyContactList *list_iface) /* Signal connection. */ g_signal_connect (priv->list, - "contact-added", - G_CALLBACK (contact_list_store_contact_added_cb), + "members-changed", + G_CALLBACK (contact_list_store_members_changed_cb), store); g_signal_connect (priv->list, - "contact-removed", - G_CALLBACK (contact_list_store_contact_removed_cb), + "groups-changed", + G_CALLBACK (contact_list_store_groups_changed_cb), store); /* Add contacts already created. */ contacts = empathy_contact_list_get_members (priv->list); for (l = contacts; l; l = l->next) { - EmpathyContact *contact; + contact_list_store_members_changed_cb (priv->list, l->data, + NULL, 0, NULL, + TRUE, + store); - contact = l->data; - - contact_list_store_contact_added_cb (priv->list, contact, store); - - g_object_unref (contact); + g_object_unref (l->data); } g_list_free (contacts); @@ -385,13 +387,9 @@ empathy_contact_list_store_set_show_offline (EmpathyContactListStore *store, contacts = empathy_contact_list_get_members (priv->list); for (l = contacts; l; l = l->next) { - EmpathyContact *contact; - - contact = EMPATHY_CONTACT (l->data); - - contact_list_store_contact_update (store, contact); + contact_list_store_contact_update (store, l->data); - g_object_unref (contact); + g_object_unref (l->data); } g_list_free (contacts); @@ -611,80 +609,6 @@ empathy_contact_list_store_search_equal_func (GtkTreeModel *model, return ret; } -void -empathy_contact_list_store_set_contact_groups_func (EmpathyContactListStore *store, - EmpathyContactGroupsFunc func, - gpointer user_data) -{ - EmpathyContactListStorePriv *priv; - GList *contacts, *l; - - g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store)); - - priv = GET_PRIV (store); - - if (func) { - priv->get_contact_groups = func; - priv->get_contact_groups_data = user_data; - } else { - priv->get_contact_groups = NULL; - priv->get_contact_groups_data = NULL; - } - - /* If we set a custom function to get contacts groups we have to - * disconnect our default notify::groups signal and wait for the user - * to call himself empathy_contact_list_store_update_contact_groups () - * when needed. If func is NULL we come back to default. - */ - contacts = empathy_contact_list_get_members (priv->list); - for (l = contacts; l; l = l->next) { - EmpathyContact *contact; - - contact = l->data; - - if (func) { - g_signal_handlers_disconnect_by_func (contact, - G_CALLBACK (contact_list_store_contact_groups_updated_cb), - store); - } else { - g_signal_connect (contact, "notify::groups", - G_CALLBACK (contact_list_store_contact_groups_updated_cb), - store); - } - - empathy_contact_list_store_update_contact_groups (store, contact); - - g_object_unref (contact); - } - g_list_free (contacts); -} - -void -empathy_contact_list_store_update_contact_groups (EmpathyContactListStore *store, - EmpathyContact *contact) -{ - EmpathyContactListStorePriv *priv; - gboolean show_active; - - g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store)); - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - priv = GET_PRIV (store); - - empathy_debug (DEBUG_DOMAIN, "Contact:'%s' updating groups", - empathy_contact_get_name (contact)); - - /* We do this to make sure the groups are correct, if not, we - * would have to check the groups already set up for each - * contact and then see what has been updated. - */ - show_active = priv->show_active; - priv->show_active = FALSE; - contact_list_store_remove_contact (store, contact); - contact_list_store_add_contact (store, contact); - priv->show_active = show_active; -} - static void contact_list_store_setup (EmpathyContactListStore *store) { @@ -733,37 +657,73 @@ contact_list_store_inibit_active_cb (EmpathyContactListStore *store) } static void -contact_list_store_contact_added_cb (EmpathyContactList *list_iface, - EmpathyContact *contact, - EmpathyContactListStore *store) +contact_list_store_members_changed_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_member, + EmpathyContactListStore *store) { EmpathyContactListStorePriv *priv; priv = GET_PRIV (store); empathy_debug (DEBUG_DOMAIN, - "Contact:'%s' added", - empathy_contact_get_name (contact)); - - if (!priv->get_contact_groups) { - g_signal_connect (contact, "notify::groups", - G_CALLBACK (contact_list_store_contact_groups_updated_cb), + "Contact %s (%d) %s", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + is_member ? "added" : "removed"); + + if (is_member) { + g_signal_connect (contact, "notify::presence", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::name", + G_CALLBACK (contact_list_store_contact_updated_cb), store); + g_signal_connect (contact, "notify::avatar", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::type", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + + contact_list_store_add_contact (store, contact); + } else { + g_signal_handlers_disconnect_by_func (contact, + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + + contact_list_store_remove_contact (store, contact); } - g_signal_connect (contact, "notify::presence", - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - g_signal_connect (contact, "notify::name", - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - g_signal_connect (contact, "notify::avatar", - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - g_signal_connect (contact, "notify::type", - G_CALLBACK (contact_list_store_contact_updated_cb), - store); +} +static void +contact_list_store_groups_changed_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + gchar *group, + gboolean is_member, + EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + gboolean show_active; + + priv = GET_PRIV (store); + + empathy_debug (DEBUG_DOMAIN, "Updating groups for contact %s (%d)", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact)); + + /* We do this to make sure the groups are correct, if not, we + * would have to check the groups already set up for each + * contact and then see what has been updated. + */ + show_active = priv->show_active; + priv->show_active = FALSE; + contact_list_store_remove_contact (store, contact); contact_list_store_add_contact (store, contact); + priv->show_active = show_active; } static void @@ -780,14 +740,9 @@ contact_list_store_add_contact (EmpathyContactListStore *store, return; } - /* If no groups just add it at the top level. */ - if (priv->get_contact_groups) { - groups = priv->get_contact_groups (contact, - priv->get_contact_groups_data); - } else { - groups = empathy_contact_get_groups (contact); - } + groups = empathy_contact_list_get_groups (priv->list, contact); + /* If no groups just add it at the top level. */ if (!groups) { gtk_tree_store_append (GTK_TREE_STORE (store), &iter, NULL); gtk_tree_store_set (GTK_TREE_STORE (store), &iter, @@ -800,15 +755,9 @@ contact_list_store_add_contact (EmpathyContactListStore *store, /* Else add to each group. */ for (l = groups; l; l = l->next) { - GtkTreeIter iter_group; - const gchar *name; - - name = l->data; - if (!name) { - continue; - } + GtkTreeIter iter_group; - contact_list_store_get_group (store, name, &iter_group, NULL, NULL); + contact_list_store_get_group (store, l->data, &iter_group, NULL, NULL); gtk_tree_store_insert_after (GTK_TREE_STORE (store), &iter, &iter_group, NULL); @@ -818,28 +767,12 @@ contact_list_store_add_contact (EmpathyContactListStore *store, COL_IS_GROUP, FALSE, COL_IS_SEPARATOR, FALSE, -1); + g_free (l->data); } + g_list_free (groups); contact_list_store_contact_update (store, contact); -} - -static void -contact_list_store_contact_removed_cb (EmpathyContactList *list_iface, - EmpathyContact *contact, - EmpathyContactListStore *store) -{ - empathy_debug (DEBUG_DOMAIN, "Contact:'%s' removed", - empathy_contact_get_name (contact)); - - /* Disconnect signals */ - g_signal_handlers_disconnect_by_func (contact, - G_CALLBACK (contact_list_store_contact_groups_updated_cb), - store); - g_signal_handlers_disconnect_by_func (contact, - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - contact_list_store_remove_contact (store, contact); } static void @@ -1028,17 +961,9 @@ contact_list_store_contact_update (EmpathyContactListStore *store, g_list_free (iters); } -static void -contact_list_store_contact_groups_updated_cb (EmpathyContact *contact, - GParamSpec *param, - EmpathyContactListStore *store) -{ - empathy_contact_list_store_update_contact_groups (store, contact); -} - static void contact_list_store_contact_updated_cb (EmpathyContact *contact, - GParamSpec *param, + GParamSpec *param, EmpathyContactListStore *store) { empathy_debug (DEBUG_DOMAIN, @@ -1180,10 +1105,10 @@ contact_list_store_get_group (EmpathyContactListStore *store, gboolean *created) { EmpathyContactListStorePriv *priv; - GtkTreeModel *model; - GtkTreeIter iter_group; - GtkTreeIter iter_separator; - FindGroup fg; + GtkTreeModel *model; + GtkTreeIter iter_group; + GtkTreeIter iter_separator; + FindGroup fg; priv = GET_PRIV (store); diff --git a/libempathy-gtk/empathy-contact-list-store.h b/libempathy-gtk/empathy-contact-list-store.h index d7c9635f..d096daaf 100644 --- a/libempathy-gtk/empathy-contact-list-store.h +++ b/libempathy-gtk/empathy-contact-list-store.h @@ -106,11 +106,6 @@ gboolean empathy_contact_list_store_search_equal_func (GtkTre const gchar *key, GtkTreeIter *iter, gpointer search_data); -void empathy_contact_list_store_set_contact_groups_func (EmpathyContactListStore*store, - EmpathyContactGroupsFunc func, - gpointer user_data); -void empathy_contact_list_store_update_contact_groups (EmpathyContactListStore *store, - EmpathyContact *contact); G_END_DECLS diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c index 2a5cf340..5b3f0de0 100644 --- a/libempathy-gtk/empathy-contact-list-view.c +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include @@ -66,13 +66,8 @@ struct _EmpathyContactListViewPriv { EmpathyContactListStore *store; - GtkUIManager *ui; - GtkTreeRowReference *drag_row; - GtkTreeModel *filter; - gchar *filter_text; - - EmpathyContactListViewDragReceivedFunc drag_received; - gpointer drag_received_data; + GtkUIManager *ui; + GtkTreeRowReference *drag_row; }; typedef struct { @@ -103,11 +98,6 @@ static void contact_list_view_row_has_child_toggled_cb (GtkTreeModel GtkTreePath *path, GtkTreeIter *iter, EmpathyContactListView *view); -static void contact_list_view_contact_received (EmpathyContactListView *view, - EmpathyContact *contact, - GdkDragAction action, - const gchar *old_group, - const gchar *new_group); static void contact_list_view_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, @@ -173,14 +163,6 @@ static void contact_list_view_row_expand_or_collapse_cb (EmpathyContactLi GtkTreeIter *iter, GtkTreePath *path, gpointer user_data); -static gboolean contact_list_view_filter_show_contact (EmpathyContact *contact, - const gchar *filter); -static gboolean contact_list_view_filter_show_group (EmpathyContactListView *view, - const gchar *group, - const gchar *filter); -static gboolean contact_list_view_filter_func (GtkTreeModel *model, - GtkTreeIter *iter, - EmpathyContactListView *view); static void contact_list_view_action_cb (GtkAction *action, EmpathyContactListView *view); static void contact_list_view_action_activated (EmpathyContactListView *view, @@ -188,7 +170,6 @@ static void contact_list_view_action_activated (EmpathyContactLi enum { PROP_0, - PROP_FILTER, }; static const GtkActionEntry entries[] = { @@ -315,14 +296,6 @@ empathy_contact_list_view_class_init (EmpathyContactListViewClass *klass) G_TYPE_NONE, 3, EMPATHY_TYPE_CONTACT, G_TYPE_STRING, G_TYPE_STRING); - g_object_class_install_property (object_class, - PROP_FILTER, - g_param_spec_string ("filter", - "Filter", - "The text to use to filter the contact list", - NULL, - G_PARAM_READWRITE)); - g_type_class_add_private (object_class, sizeof (EmpathyContactListViewPriv)); } @@ -389,10 +362,6 @@ contact_list_view_finalize (GObject *object) if (priv->store) { g_object_unref (priv->store); } - if (priv->filter) { - g_object_unref (priv->filter); - } - g_free (priv->filter_text); G_OBJECT_CLASS (empathy_contact_list_view_parent_class)->finalize (object); } @@ -408,9 +377,6 @@ contact_list_view_get_property (GObject *object, priv = GET_PRIV (object); switch (param_id) { - case PROP_FILTER: - g_value_set_string (value, priv->filter_text); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -428,10 +394,6 @@ contact_list_view_set_property (GObject *object, priv = GET_PRIV (object); switch (param_id) { - case PROP_FILTER: - empathy_contact_list_view_set_filter (EMPATHY_CONTACT_LIST_VIEW (object), - g_value_get_string (value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -547,47 +509,6 @@ empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view, can_show_log); } -void -empathy_contact_list_view_set_filter (EmpathyContactListView *view, - const gchar *filter) -{ - EmpathyContactListViewPriv *priv; - - g_return_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view)); - - priv = GET_PRIV (view); - - g_free (priv->filter_text); - if (filter) { - priv->filter_text = g_utf8_casefold (filter, -1); - } else { - priv->filter_text = NULL; - } - - empathy_debug (DEBUG_DOMAIN, "Refiltering with filter:'%s' (case folded)", filter); - gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter)); -} - -void -empathy_contact_list_view_set_drag_received_func (EmpathyContactListView *view, - EmpathyContactListViewDragReceivedFunc func, - gpointer user_data) -{ - EmpathyContactListViewPriv *priv; - - g_return_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view)); - - priv = GET_PRIV (view); - - if (func) { - priv->drag_received = func; - priv->drag_received_data = user_data; - } else { - priv->drag_received = NULL; - priv->drag_received_data = NULL; - } -} - static void contact_list_view_setup (EmpathyContactListView *view) { @@ -598,21 +519,11 @@ contact_list_view_setup (EmpathyContactListView *view) priv = GET_PRIV (view); - /* Create filter */ - priv->filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), NULL); - - gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter), - (GtkTreeModelFilterVisibleFunc) - contact_list_view_filter_func, - view, NULL); - gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view), - empathy_contact_list_store_search_equal_func, - view, NULL); - g_signal_connect (priv->filter, "row-has-child-toggled", + g_signal_connect (priv->store, "row-has-child-toggled", G_CALLBACK (contact_list_view_row_has_child_toggled_cb), view); - gtk_tree_view_set_model (GTK_TREE_VIEW (view), priv->filter); - + gtk_tree_view_set_model (GTK_TREE_VIEW (view), + GTK_TREE_MODEL (priv->store)); /* Setup view */ g_object_set (view, @@ -697,13 +608,13 @@ contact_list_view_setup (EmpathyContactListView *view) GDK_BUTTON1_MASK, drag_types_source, G_N_ELEMENTS (drag_types_source), - GDK_ACTION_MOVE); + GDK_ACTION_MOVE | GDK_ACTION_COPY); gtk_drag_dest_set (GTK_WIDGET (view), GTK_DEST_DEFAULT_ALL, drag_types_dest, G_N_ELEMENTS (drag_types_dest), - GDK_ACTION_MOVE | GDK_ACTION_LINK); + GDK_ACTION_MOVE | GDK_ACTION_COPY); } static void @@ -746,46 +657,6 @@ contact_list_view_row_has_child_toggled_cb (GtkTreeModel *model, g_free (name); } -static void -contact_list_view_contact_received (EmpathyContactListView *view, - EmpathyContact *contact, - GdkDragAction action, - const gchar *old_group, - const gchar *new_group) -{ - EmpathyContactListViewPriv *priv; - GList *groups, *l; - GList *new_groups_list = NULL; - - priv = GET_PRIV (view); - - groups = empathy_contact_get_groups (contact); - for (l = groups; l; l = l->next) { - gchar *str; - - str = l->data; - - if (action == GDK_ACTION_MOVE && - old_group != NULL && - strcmp (str, old_group) == 0) { - continue; - } - - if (new_group && strcmp (str, new_group) == 0) { - /* Otherwise we set it twice */ - continue; - } - - new_groups_list = g_list_prepend (new_groups_list, g_strdup (str)); - } - - if (new_group) { - new_groups_list = g_list_prepend (new_groups_list, g_strdup (new_group)); - } - - empathy_contact_set_groups (contact, new_groups_list); -} - static void contact_list_view_drag_data_received (GtkWidget *widget, GdkDragContext *context, @@ -796,15 +667,18 @@ contact_list_view_drag_data_received (GtkWidget *widget, guint time) { EmpathyContactListViewPriv *priv; - EmpathyContactList *list; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeViewDropPosition position; - EmpathyContact *contact; - const gchar *id; - gchar *new_group = NULL; - gchar *old_group = NULL; - gboolean is_row; + EmpathyContactList *list; + EmpathyContactFactory *factory; + McAccount *account; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeViewDropPosition position; + EmpathyContact *contact = NULL; + const gchar *id; + gchar **strv; + gchar *new_group = NULL; + gchar *old_group = NULL; + gboolean is_row; priv = GET_PRIV (widget); @@ -814,9 +688,18 @@ contact_list_view_drag_data_received (GtkWidget *widget, context->action == GDK_ACTION_COPY ? "copy" : "", id); - /* FIXME: This is ambigous, an id can come from multiple accounts */ - list = empathy_contact_list_store_get_list_iface (priv->store); - contact = empathy_contact_list_find (list, id); + strv = g_strsplit (id, "/", 2); + factory = empathy_contact_factory_new (); + account = mc_account_lookup (strv[0]); + if (account) { + contact = empathy_contact_factory_get_from_id (factory, + account, + strv[1]); + g_object_unref (account); + } + g_object_unref (factory); + g_object_unref (account); + g_strfreev (strv); if (!contact) { empathy_debug (DEBUG_DOMAIN, "No contact found associated with drag & drop"); @@ -847,22 +730,17 @@ contact_list_view_drag_data_received (GtkWidget *widget, } empathy_debug (DEBUG_DOMAIN, - "contact '%s' dragged from '%s' to '%s'", - empathy_contact_get_name (contact), + "contact %s (%d) dragged from '%s' to '%s'", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), old_group, new_group); - if (priv->drag_received) { - priv->drag_received (contact, - context->action, - old_group, - new_group, - priv->drag_received_data); - } else { - contact_list_view_contact_received (EMPATHY_CONTACT_LIST_VIEW (widget), - contact, - context->action, - old_group, - new_group); + list = empathy_contact_list_store_get_list_iface (priv->store); + if (new_group) { + empathy_contact_list_add_to_group (list, contact, new_group); + } + if (old_group && context->action == GDK_ACTION_MOVE) { + empathy_contact_list_remove_from_group (list, contact, old_group); } g_free (old_group); @@ -976,11 +854,15 @@ contact_list_view_drag_data_get (GtkWidget *widget, guint time) { EmpathyContactListViewPriv *priv; - GtkTreePath *src_path; - GtkTreeIter iter; - GtkTreeModel *model; + GtkTreePath *src_path; + GtkTreeIter iter; + GtkTreeModel *model; EmpathyContact *contact; - const gchar *id; + McAccount *account; + const gchar *contact_id; + const gchar *account_id; + gchar *str; + priv = GET_PRIV (widget); @@ -1006,18 +888,20 @@ contact_list_view_drag_data_get (GtkWidget *widget, return; } - id = empathy_contact_get_id (contact); + account = empathy_contact_get_account (contact); + account_id = mc_account_get_unique_name (account); + contact_id = empathy_contact_get_id (contact); g_object_unref (contact); + str = g_strconcat (account_id, "/", contact_id, NULL); switch (info) { case DND_DRAG_TYPE_CONTACT_ID: gtk_selection_data_set (selection, drag_atoms_source[info], 8, - (guchar*)id, strlen (id) + 1); + (guchar*)str, strlen (str) + 1); break; - - default: - return; } + + g_free (str); } static void @@ -1329,124 +1213,6 @@ contact_list_view_row_expand_or_collapse_cb (EmpathyContactListView *view, g_free (name); } -static gboolean -contact_list_view_filter_show_contact (EmpathyContact *contact, - const gchar *filter) -{ - gchar *str; - gboolean visible; - - /* Check contact id */ - str = g_utf8_casefold (empathy_contact_get_id (contact), -1); - visible = G_STR_EMPTY (str) || strstr (str, filter); - g_free (str); - - if (visible) { - return TRUE; - } - - /* Check contact name */ - str = g_utf8_casefold (empathy_contact_get_name (contact), -1); - visible = G_STR_EMPTY (str) || strstr (str, filter); - g_free (str); - - return visible; -} - -static gboolean -contact_list_view_filter_show_group (EmpathyContactListView *view, - const gchar *group, - const gchar *filter) -{ - EmpathyContactListViewPriv *priv; - EmpathyContactList *list; - GList *contacts, *l; - gchar *str; - gboolean show_group = FALSE; - - priv = GET_PRIV (view); - - str = g_utf8_casefold (group, -1); - if (!str) { - return FALSE; - } - - /* If the filter is the partially the group name, we show the - * whole group. - */ - if (strstr (str, filter)) { - g_free (str); - return TRUE; - } - - /* At this point, we need to check in advance if this - * group should be shown because a contact we want to - * show exists in it. - */ - list = empathy_contact_list_store_get_list_iface (priv->store); - contacts = empathy_contact_list_get_members (list); - for (l = contacts; l && !show_group; l = l->next) { - if (!empathy_contact_is_in_group (l->data, group)) { - g_object_unref (l->data); - continue; - } - - if (contact_list_view_filter_show_contact (l->data, filter)) { - show_group = TRUE; - } - g_object_unref (l->data); - } - g_list_free (contacts); - g_free (str); - - return show_group; -} - -static gboolean -contact_list_view_filter_func (GtkTreeModel *model, - GtkTreeIter *iter, - EmpathyContactListView *view) -{ - EmpathyContactListViewPriv *priv; - gboolean is_group; - gboolean is_separator; - gboolean visible = TRUE; - - priv = GET_PRIV (view); - - if (G_STR_EMPTY (priv->filter_text)) { - return TRUE; - } - - /* Check to see if iter matches any group names */ - gtk_tree_model_get (model, iter, - COL_IS_GROUP, &is_group, - COL_IS_SEPARATOR, &is_separator, - -1); - - if (is_group) { - gchar *name; - - gtk_tree_model_get (model, iter, COL_NAME, &name, -1); - visible &= contact_list_view_filter_show_group (view, - name, - priv->filter_text); - g_free (name); - } else if (is_separator) { - /* Do nothing here */ - } else { - EmpathyContact *contact; - - /* Check contact id */ - gtk_tree_model_get (model, iter, COL_CONTACT, &contact, -1); - visible &= contact_list_view_filter_show_contact (contact, - priv->filter_text); - g_object_unref (contact); - } - - return visible; -} - static void contact_list_view_action_cb (GtkAction *action, EmpathyContactListView *view) diff --git a/libempathy-gtk/empathy-contact-list-view.h b/libempathy-gtk/empathy-contact-list-view.h index 4d7cf1cb..b9de2435 100644 --- a/libempathy-gtk/empathy-contact-list-view.h +++ b/libempathy-gtk/empathy-contact-list-view.h @@ -53,24 +53,13 @@ struct _EmpathyContactListViewClass { GtkTreeViewClass parent_class; }; -typedef void (*EmpathyContactListViewDragReceivedFunc) (EmpathyContact *contact, - GdkDragAction action, - const gchar *old_group, - const gchar *new_group, - gpointer user_data); - -GType empathy_contact_list_view_get_type (void) G_GNUC_CONST; -EmpathyContactListView *empathy_contact_list_view_new (EmpathyContactListStore *store); -EmpathyContact * empathy_contact_list_view_get_selected (EmpathyContactListView *view); -gchar * empathy_contact_list_view_get_selected_group (EmpathyContactListView *view); -GtkWidget * empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view, - EmpathyContact *contact); -GtkWidget * empathy_contact_list_view_get_group_menu (EmpathyContactListView *view); -void empathy_contact_list_view_set_filter (EmpathyContactListView *view, - const gchar *filter); -void empathy_contact_list_view_set_drag_received_func (EmpathyContactListView *view, - EmpathyContactListViewDragReceivedFunc func, - gpointer user_data); +GType empathy_contact_list_view_get_type (void) G_GNUC_CONST; +EmpathyContactListView *empathy_contact_list_view_new (EmpathyContactListStore *store); +EmpathyContact * empathy_contact_list_view_get_selected (EmpathyContactListView *view); +gchar * empathy_contact_list_view_get_selected_group (EmpathyContactListView *view); +GtkWidget * empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view, + EmpathyContact *contact); +GtkWidget * empathy_contact_list_view_get_group_menu (EmpathyContactListView *view); G_END_DECLS diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index 5c8f6d3d..b3081b13 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -31,7 +31,9 @@ #include +#include #include +#include #include #include "empathy-contact-widget.h" @@ -42,44 +44,45 @@ #define ID_CHANGED_TIMEOUT 500 typedef struct { - EmpathyContact *contact; - gboolean is_user; - EmpathyContactWidgetType type; - GtkCellRenderer *renderer; - guint widget_id_timeout; + EmpathyContactFactory *factory; + EmpathyContactManager *manager; + EmpathyContact *contact; + gboolean is_user; + EmpathyContactWidgetType type; + GtkCellRenderer *renderer; + guint widget_id_timeout; - GtkWidget *vbox_contact_widget; + GtkWidget *vbox_contact_widget; /* Contact */ - GtkWidget *vbox_contact; - GtkWidget *widget_avatar; - GtkWidget *widget_account; - GtkWidget *widget_id; - GtkWidget *widget_alias; - GtkWidget *label_alias; - GtkWidget *entry_alias; - GtkWidget *hbox_presence; - GtkWidget *image_state; - GtkWidget *label_status; - GtkWidget *table_contact; - GtkWidget *hbox_contact; + GtkWidget *vbox_contact; + GtkWidget *widget_avatar; + GtkWidget *widget_account; + GtkWidget *widget_id; + GtkWidget *widget_alias; + GtkWidget *label_alias; + GtkWidget *entry_alias; + GtkWidget *hbox_presence; + GtkWidget *image_state; + GtkWidget *label_status; + GtkWidget *table_contact; + GtkWidget *hbox_contact; /* Groups */ - GtkWidget *vbox_groups; - GtkWidget *entry_group; - GtkWidget *button_group; - GtkWidget *treeview_groups; + GtkWidget *vbox_groups; + GtkWidget *entry_group; + GtkWidget *button_group; + GtkWidget *treeview_groups; /* Details */ - GtkWidget *vbox_details; - GtkWidget *table_details; - GtkWidget *hbox_details_requested; + GtkWidget *vbox_details; + GtkWidget *table_details; + GtkWidget *hbox_details_requested; /* Client */ - GtkWidget *vbox_client; - GtkWidget *table_client; - GtkWidget *hbow_client_requested; - + GtkWidget *vbox_client; + GtkWidget *table_client; + GtkWidget *hbow_client_requested; } EmpathyContactWidget; typedef struct { @@ -151,6 +154,7 @@ empathy_contact_widget_new (EmpathyContact *contact, information = g_slice_new0 (EmpathyContactWidget); information->type = type; + information->factory = empathy_contact_factory_new (); if (contact) { information->is_user = empathy_contact_is_user (contact); } else { @@ -231,6 +235,12 @@ contact_widget_destroy_cb (GtkWidget *widget, if (information->widget_id_timeout != 0) { g_source_remove (information->widget_id_timeout); } + if (information->factory) { + g_object_unref (information->factory); + } + if (information->manager) { + g_object_unref (information->manager); + } g_slice_free (EmpathyContactWidget, information); } @@ -467,17 +477,15 @@ contact_widget_update_contact (EmpathyContactWidget *information) id = gtk_entry_get_text (GTK_ENTRY (information->widget_id)); if (account && !G_STR_EMPTY (id)) { - EmpathyContactManager *manager; - EmpathyContact *contact; + EmpathyContact *contact; - manager = empathy_contact_manager_new (); - contact = empathy_contact_manager_create (manager, account, id); + contact = empathy_contact_factory_get_from_id (information->factory, + account, id); contact_widget_set_contact (information, contact); if (contact) { g_object_unref (contact); } - g_object_unref (manager); } return FALSE; @@ -508,7 +516,9 @@ contact_widget_entry_alias_focus_event_cb (GtkEditable *editable, const gchar *name; name = gtk_entry_get_text (GTK_ENTRY (editable)); - empathy_contact_set_name (information->contact, name); + empathy_contact_factory_set_name (information->factory, + information->contact, + name); } return FALSE; @@ -559,6 +569,7 @@ static void contact_widget_groups_setup (EmpathyContactWidget *information) { if (information->type > CONTACT_WIDGET_TYPE_SHOW) { + information->manager = empathy_contact_manager_new (); contact_widget_model_setup (information); } } @@ -657,21 +668,19 @@ contact_widget_model_populate_columns (EmpathyContactWidget *information) static void contact_widget_groups_populate_data (EmpathyContactWidget *information) { - EmpathyContactManager *manager; - GtkTreeView *view; - GtkListStore *store; - GtkTreeIter iter; - GList *my_groups, *l; - GList *all_groups; + GtkTreeView *view; + GtkListStore *store; + GtkTreeIter iter; + GList *my_groups, *l; + GList *all_groups; view = GTK_TREE_VIEW (information->treeview_groups); store = GTK_LIST_STORE (gtk_tree_view_get_model (view)); gtk_list_store_clear (store); - manager = empathy_contact_manager_new (); - all_groups = empathy_contact_manager_get_groups (manager); - my_groups = empathy_contact_get_groups (information->contact); - g_object_unref (manager); + all_groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (information->manager)); + my_groups = empathy_contact_list_get_groups (EMPATHY_CONTACT_LIST (information->manager), + information->contact); for (l = all_groups; l; l = l->next) { const gchar *group_str; @@ -691,7 +700,10 @@ contact_widget_groups_populate_data (EmpathyContactWidget *information) -1); } + g_list_foreach (all_groups, (GFunc) g_free, NULL); + g_list_foreach (my_groups, (GFunc) g_free, NULL); g_list_free (all_groups); + g_list_free (my_groups); } static void @@ -792,9 +804,13 @@ contact_widget_cell_toggled (GtkCellRendererToggle *cell, if (group) { if (enabled) { - empathy_contact_remove_group (information->contact, group); + empathy_contact_list_remove_from_group (EMPATHY_CONTACT_LIST (information->manager), + information->contact, + group); } else { - empathy_contact_add_group (information->contact, group); + empathy_contact_list_add_to_group (EMPATHY_CONTACT_LIST (information->manager), + information->contact, + group); } g_free (group); @@ -846,7 +862,9 @@ contact_widget_button_group_clicked_cb (GtkButton *button, COL_ENABLED, TRUE, -1); - empathy_contact_add_group (information->contact, group); + empathy_contact_list_add_to_group (EMPATHY_CONTACT_LIST (information->manager), + information->contact, + group); } static void diff --git a/libempathy-gtk/empathy-group-chat.c b/libempathy-gtk/empathy-group-chat.c index ca046a3d..48439302 100644 --- a/libempathy-gtk/empathy-group-chat.c +++ b/libempathy-gtk/empathy-group-chat.c @@ -78,11 +78,12 @@ static void group_chat_finalize (GObject *obj static void group_chat_create_ui (EmpathyGroupChat *chat); static void group_chat_widget_destroy_cb (GtkWidget *widget, EmpathyGroupChat *chat); -static void group_chat_contact_added_cb (EmpathyTpChatroom *tp_chat, - EmpathyContact *contact, - EmpathyGroupChat *chat); -static void group_chat_contact_removed_cb (EmpathyTpChatroom *tp_chat, +static void group_chat_members_changed_cb (EmpathyTpChatroom *tp_chat, EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_member, EmpathyGroupChat *chat); static void group_chat_topic_entry_activate_cb (GtkWidget *entry, GtkDialog *dialog); @@ -348,33 +349,26 @@ group_chat_widget_destroy_cb (GtkWidget *widget, } static void -group_chat_contact_added_cb (EmpathyTpChatroom *tp_chat, - EmpathyContact *contact, - EmpathyGroupChat *chat) -{ - EmpathyGroupChatPriv *priv; - gchar *str; - - priv = GET_PRIV (chat); - - str = g_strdup_printf (_("%s has joined the room"), - empathy_contact_get_name (contact)); - empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, str); - g_free (str); -} - -static void -group_chat_contact_removed_cb (EmpathyTpChatroom *tp_chat, +group_chat_members_changed_cb (EmpathyTpChatroom *tp_chat, EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_member, EmpathyGroupChat *chat) { EmpathyGroupChatPriv *priv; - gchar *str; + gchar *str; priv = GET_PRIV (chat); - str = g_strdup_printf (_("%s has left the room"), - empathy_contact_get_name (contact)); + if (is_member) { + str = g_strdup_printf (_("%s has joined the room"), + empathy_contact_get_name (contact)); + } else { + str = g_strdup_printf (_("%s has left the room"), + empathy_contact_get_name (contact)); + } empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, str); g_free (str); } @@ -540,11 +534,8 @@ group_chat_set_tp_chat (EmpathyChat *chat, gtk_widget_show (GTK_WIDGET (priv->view)); /* Connect signals */ - g_signal_connect (priv->tp_chat, "contact-added", - G_CALLBACK (group_chat_contact_added_cb), - chat); - g_signal_connect (priv->tp_chat, "contact-removed", - G_CALLBACK (group_chat_contact_removed_cb), + g_signal_connect (priv->tp_chat, "members-changed", + G_CALLBACK (group_chat_members_changed_cb), chat); g_signal_connect (priv->tp_chat, "notify::subject", G_CALLBACK (group_chat_subject_notify_cb), diff --git a/libempathy-gtk/empathy-images.h b/libempathy-gtk/empathy-images.h index 227ebe59..ad6d43b2 100644 --- a/libempathy-gtk/empathy-images.h +++ b/libempathy-gtk/empathy-images.h @@ -31,7 +31,7 @@ G_BEGIN_DECLS #define EMPATHY_IMAGE_BUSY "empathy-busy" #define EMPATHY_IMAGE_AWAY "empathy-away" #define EMPATHY_IMAGE_EXT_AWAY "empathy-extended-away" -#define EMPATHY_IMAGE_PENDING "empathy-pending" +#define EMPATHY_IMAGE_UNKNOWN "empathy-pending" #define EMPATHY_IMAGE_MESSAGE "empathy-message" #define EMPATHY_IMAGE_NEW_MESSAGE "empathy-new-message" diff --git a/libempathy-gtk/empathy-main-window.c b/libempathy-gtk/empathy-main-window.c index 13c578d8..4b89c4e6 100644 --- a/libempathy-gtk/empathy-main-window.c +++ b/libempathy-gtk/empathy-main-window.c @@ -288,7 +288,6 @@ empathy_main_window_show (void) empathy_status_presets_get_all (); list_iface = EMPATHY_CONTACT_LIST (empathy_contact_manager_new ()); - empathy_contact_list_setup (list_iface); window->list_store = empathy_contact_list_store_new (list_iface); window->list_view = empathy_contact_list_view_new (window->list_store); g_object_unref (list_iface); diff --git a/libempathy-gtk/empathy-private-chat.c b/libempathy-gtk/empathy-private-chat.c index 81f93c02..b187e98c 100644 --- a/libempathy-gtk/empathy-private-chat.c +++ b/libempathy-gtk/empathy-private-chat.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include "empathy-private-chat.h" #include "empathy-chat-view.h" @@ -51,11 +51,12 @@ #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_PRIVATE_CHAT, EmpathyPrivateChatPriv)) struct _EmpathyPrivateChatPriv { - EmpathyContact *contact; - gchar *name; - gboolean is_online; - GtkWidget *widget; - GtkWidget *text_view_sw; + EmpathyContactFactory *factory; + EmpathyContact *contact; + gchar *name; + gboolean is_online; + GtkWidget *widget; + GtkWidget *text_view_sw; }; static void empathy_private_chat_class_init (EmpathyPrivateChatClass *klass); @@ -125,7 +126,9 @@ private_chat_finalize (GObject *object) if (priv->contact) { g_object_unref (priv->contact); } - + if (priv->factory) { + g_object_unref (priv->factory); + } g_free (priv->name); G_OBJECT_CLASS (empathy_private_chat_parent_class)->finalize (object); @@ -327,27 +330,30 @@ EmpathyPrivateChat * empathy_private_chat_new (McAccount *account, TpChan *tp_chan) { - EmpathyPrivateChat *chat; - EmpathyTpChat *tp_chat; - EmpathyContactManager *manager; - EmpathyTpContactList *list; - EmpathyContact *contact; + EmpathyPrivateChat *chat; + EmpathyPrivateChatPriv *priv; + EmpathyTpChat *tp_chat; + EmpathyContactFactory *factory; + EmpathyContact *contact; g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); - manager = empathy_contact_manager_new (); - list = empathy_contact_manager_get_list (manager, account); - contact = empathy_tp_contact_list_get_from_handle (list, tp_chan->handle); + factory = empathy_contact_factory_new (); + contact = empathy_contact_factory_get_from_handle (factory, + account, + tp_chan->handle); chat = g_object_new (EMPATHY_TYPE_PRIVATE_CHAT, NULL); - tp_chat = empathy_tp_chat_new (account, tp_chan); + priv = GET_PRIV (chat); + priv->factory = factory; + tp_chat = empathy_tp_chat_new (account, tp_chan); private_chat_setup (chat, contact, tp_chat); g_object_unref (tp_chat); g_object_unref (contact); - g_object_unref (manager); + g_object_unref (factory); return chat; } diff --git a/libempathy-gtk/empathy-status-icon.c b/libempathy-gtk/empathy-status-icon.c index 1ec1a21a..1fdc0095 100644 --- a/libempathy-gtk/empathy-status-icon.c +++ b/libempathy-gtk/empathy-status-icon.c @@ -117,9 +117,12 @@ static void status_icon_quit_cb (GtkWidget *windo EmpathyStatusIcon *icon); static void status_icon_show_hide_window_cb (GtkWidget *widget, EmpathyStatusIcon *icon); -static void status_icon_local_pending_cb (EmpathyContactManager *manager, - EmpathyContact *contact, +static void status_icon_pendings_changed_cb (EmpathyContactManager *manager, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, gchar *message, + gboolean is_pending, EmpathyStatusIcon *icon); static void status_icon_event_subscribe_cb (StatusIconEvent *event); static void status_icon_event_flash_state_cb (StatusIconEvent *event); @@ -148,7 +151,7 @@ static void empathy_status_icon_init (EmpathyStatusIcon *icon) { EmpathyStatusIconPriv *priv; - GList *pending, *l; + GList *pendings, *l; priv = GET_PRIV (icon); @@ -177,21 +180,25 @@ empathy_status_icon_init (EmpathyStatusIcon *icon) g_signal_connect (priv->icon, "popup-menu", G_CALLBACK (status_icon_popup_menu_cb), icon); - g_signal_connect (priv->manager, "local-pending", - G_CALLBACK (status_icon_local_pending_cb), + g_signal_connect (priv->manager, "pendings-changed", + G_CALLBACK (status_icon_pendings_changed_cb), icon); - pending = empathy_contact_list_get_local_pending (EMPATHY_CONTACT_LIST (priv->manager)); - for (l = pending; l; l = l->next) { - EmpathyContactListInfo *info; + pendings = empathy_contact_list_get_pendings (EMPATHY_CONTACT_LIST (priv->manager)); + for (l = pendings; l; l = l->next) { + EmpathyPendingInfo *info; info = l->data; - status_icon_local_pending_cb (priv->manager, - info->contact, - info->message, - icon); + status_icon_pendings_changed_cb (priv->manager, + info->member, + info->actor, + 0, + info->message, + TRUE, + icon); + empathy_pending_info_free (info); } - g_list_free (pending); + g_list_free (pendings); } static void @@ -533,10 +540,13 @@ status_icon_show_hide_window_cb (GtkWidget *widget, } static void -status_icon_local_pending_cb (EmpathyContactManager *manager, - EmpathyContact *contact, - gchar *message, - EmpathyStatusIcon *icon) +status_icon_pendings_changed_cb (EmpathyContactManager *manager, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_pending, + EmpathyStatusIcon *icon) { EmpathyStatusIconPriv *priv; StatusIconEvent *event; @@ -545,6 +555,11 @@ status_icon_local_pending_cb (EmpathyContactManager *manager, priv = GET_PRIV (icon); + if (!is_pending) { + /* FIXME: We should remove the event */ + return; + } + for (l = priv->events; l; l = l->next) { if (empathy_contact_equal (contact, ((StatusIconEvent*)l->data)->user_data)) { return; diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index fb491cc5..aedacb08 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -378,8 +378,7 @@ empathy_icon_name_for_presence (EmpathyPresence *presence) const gchar * empathy_icon_name_for_contact (EmpathyContact *contact) { - EmpathyPresence *presence; - EmpathySubscription subscription; + EmpathyPresence *presence; g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), EMPATHY_IMAGE_OFFLINE); @@ -389,12 +388,7 @@ empathy_icon_name_for_contact (EmpathyContact *contact) return empathy_icon_name_for_presence (presence); } - subscription = empathy_contact_get_subscription (contact); - if (!(subscription & EMPATHY_SUBSCRIPTION_FROM)) { - return EMPATHY_IMAGE_PENDING; - } - - return EMPATHY_IMAGE_OFFLINE; + return EMPATHY_IMAGE_UNKNOWN; } static void diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index 39dfa9b6..c24a16f2 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -17,7 +17,6 @@ lib_LTLIBRARIES = libempathy.la libempathy_la_SOURCES = \ empathy-conf.c \ - empathy-contact.c \ empathy-avatar.c \ empathy-time.c \ empathy-presence.c \ @@ -26,8 +25,10 @@ libempathy_la_SOURCES = \ empathy-message.c \ empathy-chatroom-manager.c \ empathy-chatroom.c \ + empathy-contact.c \ empathy-contact-list.c \ empathy-contact-manager.c \ + empathy-contact-factory.c \ empathy-tp-group.c \ empathy-tp-contact-list.c \ empathy-tp-chat.c \ @@ -50,7 +51,6 @@ libempathy_la_LDFLAGS = \ libempathy_headers = \ empathy-conf.h \ - empathy-contact.h \ empathy-avatar.h \ empathy-time.h \ empathy-presence.h \ @@ -59,8 +59,10 @@ libempathy_headers = \ empathy-message.h \ empathy-chatroom-manager.h \ empathy-chatroom.h \ + empathy-contact.h \ empathy-contact-list.h \ empathy-contact-manager.h \ + empathy-contact-factory.h \ empathy-tp-group.h \ empathy-tp-contact-list.h \ empathy-tp-chat.h \ diff --git a/libempathy/empathy-avatar.c b/libempathy/empathy-avatar.c index e5a2a73a..425f23f5 100644 --- a/libempathy/empathy-avatar.c +++ b/libempathy/empathy-avatar.c @@ -28,7 +28,7 @@ #define DEBUG_DOMAIN "Avatar" GType -empathy_avatar_get_gtype (void) +empathy_avatar_get_type (void) { static GType type_id = 0; diff --git a/libempathy/empathy-avatar.h b/libempathy/empathy-avatar.h index 73d69cf7..6b28e8e7 100644 --- a/libempathy/empathy-avatar.h +++ b/libempathy/empathy-avatar.h @@ -25,7 +25,7 @@ G_BEGIN_DECLS -#define EMPATHY_TYPE_AVATAR (empathy_avatar_get_gtype ()) +#define EMPATHY_TYPE_AVATAR (empathy_avatar_get_type ()) typedef struct _EmpathyAvatar EmpathyAvatar; @@ -36,7 +36,7 @@ struct _EmpathyAvatar { guint refcount; }; -GType empathy_avatar_get_gtype (void) G_GNUC_CONST; +GType empathy_avatar_get_type (void) G_GNUC_CONST; EmpathyAvatar * empathy_avatar_new (guchar *avatar, gsize len, gchar *format); diff --git a/libempathy/empathy-contact-factory.c b/libempathy/empathy-contact-factory.c new file mode 100644 index 00000000..1c91a65b --- /dev/null +++ b/libempathy/empathy-contact-factory.c @@ -0,0 +1,1102 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "empathy-contact-factory.h" +#include "empathy-utils.h" +#include "empathy-debug.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryPriv)) + +#define DEBUG_DOMAIN "ContactFactory" + +struct _EmpathyContactFactoryPriv { + MissionControl *mc; + GHashTable *accounts; +}; + +typedef struct { + EmpathyContactFactory *factory; + McAccount *account; + guint nb_pending_calls; + + TpConn *tp_conn; + DBusGProxy *aliasing_iface; + DBusGProxy *avatars_iface; + DBusGProxy *presence_iface; + + GList *contacts; + guint self_handle; +} ContactFactoryAccountData; + +typedef struct { + ContactFactoryAccountData *account_data; + GList *contacts; +} RequestHandlesData; + +typedef struct { + ContactFactoryAccountData *account_data; + guint *handles; +} RequestAliasesData; + +typedef struct { + ContactFactoryAccountData *account_data; + EmpathyContact *contact; +} RequestAvatarData; + +static void empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass); +static void empathy_contact_factory_init (EmpathyContactFactory *factory); + +G_DEFINE_TYPE (EmpathyContactFactory, empathy_contact_factory, G_TYPE_OBJECT); + +static gint +contact_factory_find_by_handle (gconstpointer a, + gconstpointer b) +{ + EmpathyContact *contact; + guint handle; + + contact = EMPATHY_CONTACT (a); + handle = GPOINTER_TO_UINT (b); + + return handle - empathy_contact_get_handle (contact); +} + +static EmpathyContact * +contact_factory_account_data_find_by_handle (ContactFactoryAccountData *account_data, + guint handle) +{ + GList *l; + + l = g_list_find_custom (account_data->contacts, + GUINT_TO_POINTER (handle), + contact_factory_find_by_handle); + + return l ? l->data : NULL; +} + +static gint +contact_factory_find_by_id (gconstpointer a, + gconstpointer b) +{ + EmpathyContact *contact; + const gchar *id = b; + + contact = EMPATHY_CONTACT (a); + + return strcmp (id, empathy_contact_get_id (contact)); +} + +static EmpathyContact * +contact_factory_account_data_find_by_id (ContactFactoryAccountData *account_data, + const gchar *id) +{ + GList *l; + + l = g_list_find_custom (account_data->contacts, + id, + contact_factory_find_by_id); + + return l ? l->data : NULL; +} + +static void contact_factory_account_data_free (gpointer data); + +static void +contact_factory_account_data_return_call (ContactFactoryAccountData *account_data) +{ + if (--account_data->nb_pending_calls == 0 && + account_data->contacts == NULL) { + contact_factory_account_data_free (account_data); + } +} + +static void +contact_factory_presences_table_foreach (const gchar *state_str, + GHashTable *presences_table, + EmpathyPresence **presence) +{ + McPresence state; + const GValue *message; + + state = empathy_presence_state_from_str (state_str); + if (state == MC_PRESENCE_UNSET) { + return; + } + + if (*presence) { + g_object_unref (*presence); + *presence = NULL; + } + + *presence = empathy_presence_new (); + empathy_presence_set_state (*presence, state); + + message = g_hash_table_lookup (presences_table, "message"); + if (message != NULL) { + empathy_presence_set_status (*presence, + g_value_get_string (message)); + } +} + +static void +contact_factory_parse_presence_foreach (guint handle, + GValueArray *presence_struct, + ContactFactoryAccountData *account_data) +{ + GHashTable *presences_table; + EmpathyContact *contact; + EmpathyPresence *presence = NULL; + + contact = contact_factory_account_data_find_by_handle (account_data, + handle); + if (!contact) { + return; + } + + presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1)); + + g_hash_table_foreach (presences_table, + (GHFunc) contact_factory_presences_table_foreach, + &presence); + + empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)", + empathy_contact_get_id (contact), + handle, + presence ? empathy_presence_get_status (presence) : "unset", + presence ? empathy_presence_get_state (presence) : MC_PRESENCE_UNSET); + + empathy_contact_set_presence (contact, presence); +} + +static void +contact_factory_get_presence_cb (DBusGProxy *proxy, + GHashTable *handle_table, + GError *error, + gpointer user_data) +{ + ContactFactoryAccountData *account_data = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s", + error->message); + goto OUT; + } + + g_hash_table_foreach (handle_table, + (GHFunc) contact_factory_parse_presence_foreach, + account_data); +OUT: + contact_factory_account_data_return_call (account_data); +} + +static void +contact_factory_presence_update_cb (DBusGProxy *proxy, + GHashTable *handle_table, + ContactFactoryAccountData *account_data) +{ + g_hash_table_foreach (handle_table, + (GHFunc) contact_factory_parse_presence_foreach, + account_data); +} + +static void +contact_factory_set_aliases_cb (DBusGProxy *proxy, + GError *error, + gpointer user_data) +{ + ContactFactoryAccountData *account_data = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s", + error->message); + } + + contact_factory_account_data_return_call (account_data); +} + +static void +contact_factory_request_aliases_cb (DBusGProxy *proxy, + gchar **contact_names, + GError *error, + gpointer user_data) +{ + RequestAliasesData *data = user_data; + guint i = 0; + gchar **name; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s", + error->message); + goto OUT; + } + + for (name = contact_names; *name; name++) { + EmpathyContact *contact; + + contact = contact_factory_account_data_find_by_handle (data->account_data, + data->handles[i]); + if (!contact) { + continue; + } + + empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (request cb)", + empathy_contact_get_id (contact), + data->handles[i], *name); + + empathy_contact_set_name (contact, *name); + + i++; + } + +OUT: + contact_factory_account_data_return_call (data->account_data); + g_free (data->handles); + g_slice_free (RequestAliasesData, data); +} + +static void +contact_factory_aliases_changed_cb (DBusGProxy *proxy, + GPtrArray *renamed_handlers, + gpointer user_data) +{ + ContactFactoryAccountData *account_data = user_data; + guint i; + + for (i = 0; renamed_handlers->len > i; i++) { + guint handle; + const gchar *alias; + GValueArray *renamed_struct; + EmpathyContact *contact; + + renamed_struct = g_ptr_array_index (renamed_handlers, i); + handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0)); + alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1)); + contact = contact_factory_account_data_find_by_handle (account_data, handle); + + if (!contact) { + /* We don't know this contact, skip */ + continue; + } + + if (G_STR_EMPTY (alias)) { + alias = NULL; + } + + empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)", + empathy_contact_get_id (contact), + handle, alias); + + empathy_contact_set_name (contact, alias); + } +} + +static void +contact_factory_request_avatars_cb (DBusGProxy *proxy, + GError *error, + gpointer user_data) +{ + ContactFactoryAccountData *account_data = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s", + error->message); + } + + contact_factory_account_data_return_call (account_data); +} + +static void +contact_factory_request_avatar_cb (DBusGProxy *proxy, + GArray *avatar_data, + gchar *mime_type, + GError *error, + gpointer user_data) +{ + RequestAvatarData *data = user_data; + EmpathyAvatar *avatar; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error requesting avatar: %s", + error->message); + goto OUT; + } + + empathy_debug (DEBUG_DOMAIN, "Avatar received for %s (%d)", + empathy_contact_get_id (data->contact), + empathy_contact_get_handle (data->contact)); + + avatar = empathy_avatar_new (avatar_data->data, + avatar_data->len, + mime_type); + empathy_contact_set_avatar (data->contact, avatar); + empathy_avatar_unref (avatar); + +OUT: + g_object_unref (data->contact); + contact_factory_account_data_return_call (data->account_data); + g_slice_free (RequestAvatarData, data); +} + +static void +contact_factory_avatar_updated_cb (DBusGProxy *proxy, + guint handle, + gchar *new_token, + gpointer user_data) +{ + ContactFactoryAccountData *account_data = user_data; + RequestAvatarData *data; + EmpathyContact *contact; + + contact = contact_factory_account_data_find_by_handle (account_data, + handle); + if (!contact) { + return; + } + + account_data->nb_pending_calls++; + data = g_slice_new0 (RequestAvatarData); + data->account_data = account_data; + data->contact = g_object_ref (contact); + tp_conn_iface_avatars_request_avatar_async (account_data->avatars_iface, + handle, + contact_factory_request_avatar_cb, + data); +} + +static void +contact_factory_avatar_retrieved_cb (DBusGProxy *proxy, + guint handle, + gchar *token, + GArray *avatar_data, + gchar *mime_type, + gpointer user_data) +{ + ContactFactoryAccountData *account_data = user_data; + EmpathyContact *contact; + EmpathyAvatar *avatar; + + contact = contact_factory_account_data_find_by_handle (account_data, + handle); + if (!contact) { + return; + } + + avatar = empathy_avatar_new (avatar_data->data, + avatar_data->len, + mime_type); + empathy_contact_set_avatar (contact, avatar); + empathy_avatar_unref (avatar); +} + +static void +contact_factory_request_everything (ContactFactoryAccountData *account_data, + GArray *handles) +{ + if (account_data->presence_iface) { + account_data->nb_pending_calls++; + tp_conn_iface_presence_get_presence_async (account_data->presence_iface, + handles, + contact_factory_get_presence_cb, + account_data); + } + + if (account_data->aliasing_iface) { + RequestAliasesData *data; + + account_data->nb_pending_calls++; + data = g_slice_new (RequestAliasesData); + data->account_data = account_data; + data->handles = g_memdup (handles->data, handles->len * sizeof (guint)); + + tp_conn_iface_aliasing_request_aliases_async (account_data->aliasing_iface, + handles, + contact_factory_request_aliases_cb, + data); + } + + if (account_data->avatars_iface) { + account_data->nb_pending_calls++; + tp_conn_iface_avatars_request_avatars_async (account_data->avatars_iface, + handles, + contact_factory_request_avatars_cb, + account_data); + } +} + +static void +contact_factory_request_handles_cb (DBusGProxy *proxy, + GArray *handles, + GError *error, + gpointer user_data) +{ + RequestHandlesData *data = user_data; + GList *l; + guint i = 0; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s", + error->message); + goto OUT; + } + + for (l = data->contacts; l; l = l->next) { + guint handle; + + handle = g_array_index (handles, guint, i); + empathy_contact_set_handle (l->data, handle); + if (handle == data->account_data->self_handle) { + empathy_contact_set_is_user (l->data, TRUE); + } + + i++; + } + + contact_factory_request_everything (data->account_data, handles); + +OUT: + g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL); + g_list_free (data->contacts); + contact_factory_account_data_return_call (data->account_data); + g_slice_free (RequestHandlesData, data); +} + +static void +contact_factory_disconnect_contact_foreach (gpointer data, + gpointer user_data) +{ + EmpathyContact *contact = data; + + empathy_contact_set_presence (contact, NULL); + empathy_contact_set_handle (contact, 0); +} + +static void +contact_factory_destroy_cb (TpConn *tp_conn, + ContactFactoryAccountData *account_data) +{ + empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed"); + + g_object_unref (account_data->tp_conn); + account_data->tp_conn = NULL; + account_data->aliasing_iface = NULL; + account_data->avatars_iface = NULL; + account_data->presence_iface = NULL; + + g_list_foreach (account_data->contacts, + contact_factory_disconnect_contact_foreach, + account_data); +} + +static void +contact_factory_account_data_disconnect (ContactFactoryAccountData *account_data) +{ + if (account_data->aliasing_iface) { + dbus_g_proxy_disconnect_signal (account_data->aliasing_iface, + "AliasesChanged", + G_CALLBACK (contact_factory_aliases_changed_cb), + account_data); + } + if (account_data->avatars_iface) { + dbus_g_proxy_disconnect_signal (account_data->avatars_iface, + "AvatarUpdated", + G_CALLBACK (contact_factory_avatar_updated_cb), + account_data); + dbus_g_proxy_disconnect_signal (account_data->avatars_iface, + "AvatarRetrieved", + G_CALLBACK (contact_factory_avatar_retrieved_cb), + account_data); + } + if (account_data->presence_iface) { + dbus_g_proxy_disconnect_signal (account_data->presence_iface, + "PresenceUpdate", + G_CALLBACK (contact_factory_presence_update_cb), + account_data); + } + if (account_data->tp_conn) { + g_signal_handlers_disconnect_by_func (account_data->tp_conn, + contact_factory_destroy_cb, + account_data); + } +} + +static void +contact_factory_account_data_update (ContactFactoryAccountData *account_data) +{ + EmpathyContactFactory *factory = account_data->factory; + EmpathyContactFactoryPriv *priv = GET_PRIV (factory); + McAccount *account = account_data->account; + TpConn *tp_conn = NULL; + RequestHandlesData *data; + const gchar **contact_ids; + guint i; + GList *l; + GError *error; + + if (account_data->account) { + guint status; + + /* status == 0 means the status is CONNECTED */ + status = mission_control_get_connection_status (priv->mc, + account, NULL); + if (status == 0) { + tp_conn = mission_control_get_connection (priv->mc, + account, NULL); + } + } + + if (!tp_conn) { + /* We are not connected anymore, remove the old connection */ + contact_factory_account_data_disconnect (account_data); + if (account_data->tp_conn) { + contact_factory_destroy_cb (account_data->tp_conn, + account_data); + } + return; + } + else if (account_data->tp_conn) { + /* We were connected and we still are connected, nothing + * changed so nothing to do. */ + g_object_unref (tp_conn); + return; + } + + /* We got a new connection */ + account_data->tp_conn = tp_conn; + account_data->aliasing_iface = tp_conn_get_interface (tp_conn, + TELEPATHY_CONN_IFACE_ALIASING_QUARK); + account_data->avatars_iface = tp_conn_get_interface (tp_conn, + TELEPATHY_CONN_IFACE_AVATARS_QUARK); + account_data->presence_iface = tp_conn_get_interface (tp_conn, + TELEPATHY_CONN_IFACE_PRESENCE_QUARK); + + /* Connect signals */ + if (account_data->aliasing_iface) { + dbus_g_proxy_connect_signal (account_data->aliasing_iface, + "AliasesChanged", + G_CALLBACK (contact_factory_aliases_changed_cb), + account_data, NULL); + } + if (account_data->avatars_iface) { + dbus_g_proxy_connect_signal (account_data->avatars_iface, + "AvatarUpdated", + G_CALLBACK (contact_factory_avatar_updated_cb), + account_data, NULL); + dbus_g_proxy_connect_signal (account_data->avatars_iface, + "AvatarRetrieved", + G_CALLBACK (contact_factory_avatar_retrieved_cb), + account_data, NULL); + } + if (account_data->presence_iface) { + dbus_g_proxy_connect_signal (account_data->presence_iface, + "PresenceUpdate", + G_CALLBACK (contact_factory_presence_update_cb), + account_data, NULL); + } + g_signal_connect (tp_conn, "destroy", + G_CALLBACK (contact_factory_destroy_cb), + account_data); + + /* Get our own handle */ + if (!tp_conn_get_self_handle (DBUS_G_PROXY (account_data->tp_conn), + &account_data->self_handle, + &error)) { + empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + } + + /* Request new handles for all contacts */ + if (account_data->contacts) { + data = g_slice_new (RequestHandlesData); + data->account_data = account_data; + data->contacts = g_list_copy (account_data->contacts); + g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL); + + i = g_list_length (data->contacts); + contact_ids = g_new0 (const gchar*, i + 1); + i = 0; + for (l = data->contacts; l; l = l->next) { + contact_ids[i] = empathy_contact_get_id (l->data); + i++; + } + + account_data->nb_pending_calls++; + tp_conn_request_handles_async (DBUS_G_PROXY (account_data->tp_conn), + TP_HANDLE_TYPE_CONTACT, + contact_ids, + contact_factory_request_handles_cb, + data); + g_free (contact_ids); + } +} + +static void +contact_factory_weak_notify (gpointer data, + GObject *where_the_object_was) +{ + ContactFactoryAccountData *account_data = data; + + empathy_debug (DEBUG_DOMAIN, "Remove finalized contact %p", + where_the_object_was); + + account_data->contacts = g_list_remove (account_data->contacts, + where_the_object_was); + if (!account_data->contacts) { + EmpathyContactFactoryPriv *priv; + + priv = GET_PRIV (account_data->factory); + + g_hash_table_remove (priv->accounts, account_data->account); + } +} + +static void +contact_factory_remove_foreach (gpointer data, + gpointer user_data) +{ + ContactFactoryAccountData *account_data = user_data; + EmpathyContact *contact = data; + + g_object_weak_unref (G_OBJECT (contact), + contact_factory_weak_notify, + account_data); +} + +static ContactFactoryAccountData * +contact_factory_account_data_new (EmpathyContactFactory *factory, + McAccount *account) +{ + ContactFactoryAccountData *account_data; + + account_data = g_slice_new0 (ContactFactoryAccountData); + account_data->factory = factory; + account_data->account = g_object_ref (account); + + contact_factory_account_data_update (account_data); + + return account_data; +} + +static void +contact_factory_account_data_free (gpointer data) +{ + ContactFactoryAccountData *account_data = data; + + contact_factory_account_data_disconnect (account_data); + + if (account_data->contacts) { + g_list_foreach (account_data->contacts, + contact_factory_remove_foreach, + account_data); + g_list_free (account_data->contacts); + account_data->contacts = NULL; + } + + if (account_data->account) { + g_object_unref (account_data->account); + account_data->account = NULL; + } + + if (account_data->tp_conn) { + g_object_unref (account_data->tp_conn); + account_data->tp_conn = NULL; + account_data->aliasing_iface = NULL; + account_data->avatars_iface = NULL; + account_data->presence_iface = NULL; + } + + /* Keep the struct alive if we have calls in flight, it will be + * destroyed once all calls returned. */ + if (account_data->nb_pending_calls == 0) { + g_slice_free (ContactFactoryAccountData, account_data); + } +} + +static void +contact_factory_status_changed_cb (MissionControl *mc, + TelepathyConnectionStatus status, + McPresence presence, + TelepathyConnectionStatusReason reason, + const gchar *unique_name, + EmpathyContactFactory *factory) +{ + EmpathyContactFactoryPriv *priv = GET_PRIV (factory); + ContactFactoryAccountData *account_data; + McAccount *account; + + account = mc_account_lookup (unique_name); + account_data = g_hash_table_lookup (priv->accounts, account); + if (account_data) { + contact_factory_account_data_update (account_data); + } + g_object_unref (account); +} + +static ContactFactoryAccountData * +contact_factory_account_data_get (EmpathyContactFactory *factory, + McAccount *account) +{ + EmpathyContactFactoryPriv *priv = GET_PRIV (factory); + ContactFactoryAccountData *account_data; + + account_data = g_hash_table_lookup (priv->accounts, account); + if (!account_data) { + account_data = contact_factory_account_data_new (factory, account); + g_hash_table_insert (priv->accounts, + g_object_ref (account), + account_data); + } + + return account_data; +} + +static void +contact_factory_account_data_add_contact (ContactFactoryAccountData *account_data, + EmpathyContact *contact) +{ + g_object_weak_ref (G_OBJECT (contact), + contact_factory_weak_notify, + account_data); + account_data->contacts = g_list_prepend (account_data->contacts, contact); + + if (!account_data->presence_iface) { + EmpathyPresence *presence; + + /* We have no presence iface, set default presence + * to available */ + presence = empathy_presence_new_full (MC_PRESENCE_AVAILABLE, + NULL); + + empathy_contact_set_presence (contact, presence); + g_object_unref (presence); + } + + empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact)); +} + +static void +contact_factory_hold_handles_cb (DBusGProxy *proxy, + GError *error, + gpointer userdata) +{ + if (error) { + empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s", + error->message); + } +} + +EmpathyContact * +empathy_contact_factory_get_user (EmpathyContactFactory *factory, + McAccount *account) +{ + ContactFactoryAccountData *account_data; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + + account_data = contact_factory_account_data_get (factory, account); + + return empathy_contact_factory_get_from_handle (factory, account, + account_data->self_handle); +} + +EmpathyContact * +empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, + McAccount *account, + const gchar *id) +{ + ContactFactoryAccountData *account_data; + EmpathyContact *contact; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (id != NULL, NULL); + + /* Check if the contact already exists */ + account_data = contact_factory_account_data_get (factory, account); + contact = contact_factory_account_data_find_by_id (account_data, id); + if (contact) { + return g_object_ref (contact); + } + + /* Create new contact */ + contact = g_object_new (EMPATHY_TYPE_CONTACT, + "account", account, + "id", id, + NULL); + contact_factory_account_data_add_contact (account_data, contact); + + /* If the account is connected, request contact's handle */ + if (account_data->tp_conn) { + RequestHandlesData *data; + const gchar *contact_ids[] = {id, NULL}; + + account_data->nb_pending_calls++; + data = g_slice_new (RequestHandlesData); + data->account_data = account_data; + data->contacts = g_list_prepend (NULL, g_object_ref (contact)); + tp_conn_request_handles_async (DBUS_G_PROXY (account_data->tp_conn), + TP_HANDLE_TYPE_CONTACT, + contact_ids, + contact_factory_request_handles_cb, + data); + } + + return contact; +} + +EmpathyContact * +empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, + McAccount *account, + guint handle) +{ + EmpathyContact *contact; + GArray *handles; + GList *contacts; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + + handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_array_append_val (handles, handle); + + contacts = empathy_contact_factory_get_from_handles (factory, account, handles); + g_array_free (handles, TRUE); + + contact = contacts ? contacts->data : NULL; + g_list_free (contacts); + + return contact; +} + +GList * +empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, + McAccount *account, + GArray *handles) +{ + ContactFactoryAccountData *account_data; + GList *contacts = NULL; + GArray *new_handles; + gchar **handles_names; + guint i; + GError *error = NULL; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (handles != NULL, NULL); + + /* Search all contacts we already have */ + account_data = contact_factory_account_data_get (factory, account); + new_handles = g_array_new (FALSE, FALSE, sizeof (guint)); + for (i = 0; i < handles->len; i++) { + EmpathyContact *contact; + guint handle; + + handle = g_array_index (handles, guint, i); + if (handle == 0) { + continue; + } + + contact = contact_factory_account_data_find_by_handle (account_data, handle); + if (contact) { + contacts = g_list_prepend (contacts, g_object_ref (contact)); + } else { + g_array_append_val (new_handles, handle); + } + } + + if (new_handles->len == 0) { + g_array_free (new_handles, TRUE); + return contacts; + } + + /* Get the IDs of all new handles */ + if (!tp_conn_inspect_handles (DBUS_G_PROXY (account_data->tp_conn), + TP_HANDLE_TYPE_CONTACT, + new_handles, + &handles_names, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Couldn't inspect contact: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + g_array_free (new_handles, TRUE); + return contacts; + } + + /* Create new contacts */ + for (i = 0; i < new_handles->len; i++) { + EmpathyContact *contact; + gchar *id; + guint handle; + gboolean is_user; + + id = handles_names[i]; + handle = g_array_index (new_handles, guint, i); + + is_user = (handle == account_data->self_handle); + contact = g_object_new (EMPATHY_TYPE_CONTACT, + "account", account, + "handle", handle, + "id", id, + "is-user", is_user, + NULL); + contact_factory_account_data_add_contact (account_data, + contact); + contacts = g_list_prepend (contacts, contact); + g_free (id); + } + g_free (handles_names); + + /* Hold all new handles. */ + tp_conn_hold_handles_async (DBUS_G_PROXY (account_data->tp_conn), + TP_HANDLE_TYPE_CONTACT, + new_handles, + contact_factory_hold_handles_cb, + NULL); + + contact_factory_request_everything (account_data, new_handles); + + g_array_free (new_handles, TRUE); + + return contacts; +} + +void +empathy_contact_factory_set_name (EmpathyContactFactory *factory, + EmpathyContact *contact, + const gchar *name) +{ + ContactFactoryAccountData *account_data; + McAccount *account; + GHashTable *new_alias; + guint handle; + + g_return_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + account = empathy_contact_get_account (contact); + account_data = contact_factory_account_data_get (factory, account); + + if (!account_data->aliasing_iface) { + return; + } + + handle = empathy_contact_get_handle (contact); + + empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s", + empathy_contact_get_id (contact), + handle, name); + + new_alias = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + g_free); + + g_hash_table_insert (new_alias, + GUINT_TO_POINTER (handle), + g_strdup (name)); + + account_data->nb_pending_calls++; + tp_conn_iface_aliasing_set_aliases_async (account_data->aliasing_iface, + new_alias, + contact_factory_set_aliases_cb, + account_data); + + g_hash_table_destroy (new_alias); +} + +static void +contact_factory_finalize (GObject *object) +{ + EmpathyContactFactoryPriv *priv; + + priv = GET_PRIV (object); + + dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), + "AccountStatusChanged", + G_CALLBACK (contact_factory_status_changed_cb), + object); + + g_hash_table_destroy (priv->accounts); + g_object_unref (priv->mc); + + G_OBJECT_CLASS (empathy_contact_factory_parent_class)->finalize (object); +} + +static void +empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = contact_factory_finalize; + + g_type_class_add_private (object_class, sizeof (EmpathyContactFactoryPriv)); +} + +static void +empathy_contact_factory_init (EmpathyContactFactory *factory) +{ + EmpathyContactFactoryPriv *priv; + + priv = GET_PRIV (factory); + + priv->mc = empathy_mission_control_new (); + priv->accounts = g_hash_table_new_full (empathy_account_hash, + empathy_account_equal, + g_object_unref, + contact_factory_account_data_free); + + dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), + "AccountStatusChanged", + G_CALLBACK (contact_factory_status_changed_cb), + factory, NULL); +} + +EmpathyContactFactory * +empathy_contact_factory_new (void) +{ + static EmpathyContactFactory *factory = NULL; + + if (!factory) { + factory = g_object_new (EMPATHY_TYPE_CONTACT_FACTORY, NULL); + g_object_add_weak_pointer (G_OBJECT (factory), (gpointer) &factory); + } else { + g_object_ref (factory); + } + + return factory; +} + diff --git a/libempathy/empathy-contact-factory.h b/libempathy/empathy-contact-factory.h new file mode 100644 index 00000000..1379371a --- /dev/null +++ b/libempathy/empathy-contact-factory.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#ifndef __EMPATHY_CONTACT_FACTORY_H__ +#define __EMPATHY_CONTACT_FACTORY_H__ + +#include + +#include + +#include "empathy-contact.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CONTACT_FACTORY (empathy_contact_factory_get_type ()) +#define EMPATHY_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactory)) +#define EMPATHY_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryClass)) +#define EMPATHY_IS_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONTACT_FACTORY)) +#define EMPATHY_IS_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CONTACT_FACTORY)) +#define EMPATHY_CONTACT_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryClass)) + +typedef struct _EmpathyContactFactory EmpathyContactFactory; +typedef struct _EmpathyContactFactoryClass EmpathyContactFactoryClass; +typedef struct _EmpathyContactFactoryPriv EmpathyContactFactoryPriv; + +struct _EmpathyContactFactory { + GObject parent; +}; + +struct _EmpathyContactFactoryClass { + GObjectClass parent_class; +}; + +GType empathy_contact_factory_get_type (void) G_GNUC_CONST; +EmpathyContactFactory *empathy_contact_factory_new (void); +EmpathyContact * empathy_contact_factory_get_user (EmpathyContactFactory *factory, + McAccount *account); +EmpathyContact * empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, + McAccount *account, + const gchar *id); +EmpathyContact * empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, + McAccount *account, + guint handle); +GList * empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, + McAccount *account, + GArray *handles); +void empathy_contact_factory_set_name (EmpathyContactFactory *factory, + EmpathyContact *contact, + const gchar *name); + +G_END_DECLS + +#endif /* __EMPATHY_CONTACT_FACTORY_H__ */ diff --git a/libempathy/empathy-contact-list.c b/libempathy/empathy-contact-list.c index cc388d7e..80308314 100644 --- a/libempathy/empathy-contact-list.c +++ b/libempathy/empathy-contact-list.c @@ -53,149 +53,154 @@ contact_list_base_init (gpointer klass) static gboolean initialized = FALSE; if (!initialized) { - g_signal_new ("contact-added", + g_signal_new ("members-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, + empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING_BOOLEAN, G_TYPE_NONE, - 1, EMPATHY_TYPE_CONTACT); + 5, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, + G_TYPE_UINT, G_TYPE_STRING, G_TYPE_BOOLEAN); - g_signal_new ("contact-removed", + g_signal_new ("pendings-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, + empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING_BOOLEAN, G_TYPE_NONE, - 1, EMPATHY_TYPE_CONTACT); + 5, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, + G_TYPE_UINT, G_TYPE_STRING, G_TYPE_BOOLEAN); - g_signal_new ("local-pending", + g_signal_new ("groups-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - empathy_marshal_VOID__OBJECT_STRING, + empathy_marshal_VOID__OBJECT_STRING_BOOLEAN, G_TYPE_NONE, - 2, EMPATHY_TYPE_CONTACT, G_TYPE_STRING); + 3, EMPATHY_TYPE_CONTACT, G_TYPE_STRING, G_TYPE_BOOLEAN); initialized = TRUE; } } -EmpathyContactListInfo * -empathy_contact_list_info_new (EmpathyContact *contact, - const gchar *message) -{ - EmpathyContactListInfo *info; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); - - info = g_slice_new0 (EmpathyContactListInfo); - info->contact = g_object_ref (contact); - info->message = g_strdup (message); - - return info; -} - void -empathy_contact_list_info_free (EmpathyContactListInfo *info) +empathy_contact_list_add (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message) { - if (!info) { - return; - } + g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - if (info->contact) { - g_object_unref (info->contact); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->add) { + EMPATHY_CONTACT_LIST_GET_IFACE (list)->add (list, contact, message); } - g_free (info->message); - - g_slice_free (EmpathyContactListInfo, info); } void -empathy_contact_list_setup (EmpathyContactList *list) +empathy_contact_list_remove (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message) { g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->setup) { - EMPATHY_CONTACT_LIST_GET_IFACE (list)->setup (list); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->remove) { + EMPATHY_CONTACT_LIST_GET_IFACE (list)->remove (list, contact, message); } } -EmpathyContact * -empathy_contact_list_find (EmpathyContactList *list, - const gchar *id) +GList * +empathy_contact_list_get_members (EmpathyContactList *list) { g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list), NULL); - if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->find) { - return EMPATHY_CONTACT_LIST_GET_IFACE (list)->find (list, id); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_members) { + return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_members (list); } return NULL; } -void -empathy_contact_list_add (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message) +GList * +empathy_contact_list_get_pendings (EmpathyContactList *list) { - g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list), NULL); - if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->add) { - EMPATHY_CONTACT_LIST_GET_IFACE (list)->add (list, contact, message); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_pendings) { + return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_pendings (list); } + + return NULL; } -void -empathy_contact_list_remove (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message) +GList * +empathy_contact_list_get_all_groups (EmpathyContactList *list) { - g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list), NULL); - if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->remove) { - EMPATHY_CONTACT_LIST_GET_IFACE (list)->remove (list, contact, message); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_all_groups) { + return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_all_groups (list); } + + return NULL; } GList * -empathy_contact_list_get_members (EmpathyContactList *list) +empathy_contact_list_get_groups (EmpathyContactList *list, + EmpathyContact *contact) { g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list), NULL); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); - if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_members) { - return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_members (list); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_groups) { + return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_groups (list, contact); } return NULL; } -GList * -empathy_contact_list_get_local_pending (EmpathyContactList *list) +void +empathy_contact_list_add_to_group (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *group) { - g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list), NULL); + g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (group != NULL); - if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_local_pending) { - return EMPATHY_CONTACT_LIST_GET_IFACE (list)->get_local_pending (list); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->add_to_group) { + EMPATHY_CONTACT_LIST_GET_IFACE (list)->add_to_group (list, contact, group); } +} - return NULL; +void +empathy_contact_list_remove_from_group (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *group) +{ + g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (group != NULL); + + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->remove_from_group) { + EMPATHY_CONTACT_LIST_GET_IFACE (list)->remove_from_group (list, contact, group); + } } void -empathy_contact_list_process_pending (EmpathyContactList *list, - EmpathyContact *contact, - gboolean accept) +empathy_contact_list_rename_group (EmpathyContactList *list, + const gchar *old_group, + const gchar *new_group) { g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); + g_return_if_fail (old_group != NULL); + g_return_if_fail (new_group != NULL); - if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->process_pending) { - EMPATHY_CONTACT_LIST_GET_IFACE (list)->process_pending (list, - contact, - accept); + if (EMPATHY_CONTACT_LIST_GET_IFACE (list)->rename_group) { + EMPATHY_CONTACT_LIST_GET_IFACE (list)->rename_group (list, old_group, new_group); } } diff --git a/libempathy/empathy-contact-list.h b/libempathy/empathy-contact-list.h index 959f5c51..4b027f08 100644 --- a/libempathy/empathy-contact-list.h +++ b/libempathy/empathy-contact-list.h @@ -26,6 +26,7 @@ #include #include "empathy-contact.h" +#include "empathy-tp-group.h" G_BEGIN_DECLS @@ -37,49 +38,53 @@ G_BEGIN_DECLS typedef struct _EmpathyContactList EmpathyContactList; typedef struct _EmpathyContactListIface EmpathyContactListIface; -typedef struct { - EmpathyContact *contact; - gchar *message; -} EmpathyContactListInfo; - struct _EmpathyContactListIface { GTypeInterface base_iface; /* VTabled */ - void (*setup) (EmpathyContactList *list); - EmpathyContact * (*find) (EmpathyContactList *list, - const gchar *id); - void (*add) (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message); - void (*remove) (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message); - GList * (*get_members) (EmpathyContactList *list); - GList * (*get_local_pending) (EmpathyContactList *list); - void (*process_pending) (EmpathyContactList *list, - EmpathyContact *contact, - gboolean accept); + void (*add) (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message); + void (*remove) (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message); + GList * (*get_members) (EmpathyContactList *list); + GList * (*get_pendings) (EmpathyContactList *list); + GList * (*get_all_groups) (EmpathyContactList *list); + GList * (*get_groups) (EmpathyContactList *list, + EmpathyContact *contact); + void (*add_to_group) (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *group); + void (*remove_from_group) (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *group); + void (*rename_group) (EmpathyContactList *list, + const gchar *old_group, + const gchar *new_group); }; -GType empathy_contact_list_get_type (void) G_GNUC_CONST; -EmpathyContactListInfo *empathy_contact_list_info_new (EmpathyContact *contact, - const gchar *message); -void empathy_contact_list_info_free (EmpathyContactListInfo *info); -void empathy_contact_list_setup (EmpathyContactList *list); -EmpathyContact * empathy_contact_list_find (EmpathyContactList *list, - const gchar *id); -void empathy_contact_list_add (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message); -void empathy_contact_list_remove (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message); -GList * empathy_contact_list_get_members (EmpathyContactList *list); -GList * empathy_contact_list_get_local_pending (EmpathyContactList *list); -void empathy_contact_list_process_pending (EmpathyContactList *list, - EmpathyContact *contact, - gboolean accept); +GType empathy_contact_list_get_type (void) G_GNUC_CONST; +void empathy_contact_list_add (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message); +void empathy_contact_list_remove (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message); +GList * empathy_contact_list_get_members (EmpathyContactList *list); +GList * empathy_contact_list_get_pendings (EmpathyContactList *list); +GList * empathy_contact_list_get_all_groups (EmpathyContactList *list); +GList * empathy_contact_list_get_groups (EmpathyContactList *list, + EmpathyContact *contact); +void empathy_contact_list_add_to_group (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *group); +void empathy_contact_list_remove_from_group (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *group); +void empathy_contact_list_rename_group (EmpathyContactList *list, + const gchar *old_group, + const gchar *new_group); G_END_DECLS diff --git a/libempathy/empathy-contact-manager.c b/libempathy/empathy-contact-manager.c index cc00108c..575814fa 100644 --- a/libempathy/empathy-contact-manager.c +++ b/libempathy/empathy-contact-manager.c @@ -39,100 +39,171 @@ struct _EmpathyContactManagerPriv { GHashTable *lists; MissionControl *mc; - gboolean setup; }; -typedef struct { - const gchar *old_group; - const gchar *new_group; -} ContactManagerRenameGroupData; - -typedef struct { - EmpathyContact *contact; - const gchar *id; -} ContactManagerFindData; - -static void empathy_contact_manager_class_init (EmpathyContactManagerClass *klass); -static void contact_manager_iface_init (EmpathyContactListIface *iface); -static void empathy_contact_manager_init (EmpathyContactManager *manager); -static void contact_manager_finalize (GObject *object); -static void contact_manager_setup (EmpathyContactList *manager); -static EmpathyContact *contact_manager_find (EmpathyContactList *manager, - const gchar *id); -static void contact_manager_add (EmpathyContactList *manager, - EmpathyContact *contact, - const gchar *message); -static void contact_manager_remove (EmpathyContactList *manager, - EmpathyContact *contact, - const gchar *message); -static GList * contact_manager_get_members (EmpathyContactList *manager); -static GList * contact_manager_get_local_pending (EmpathyContactList *manager); -static void contact_manager_process_pending (EmpathyContactList *manager, - EmpathyContact *contact, - gboolean accept); -static void contact_manager_setup_foreach (McAccount *account, - EmpathyTpContactList *list, - EmpathyContactManager *manager); -static gboolean contact_manager_find_foreach (McAccount *account, - EmpathyTpContactList *list, - ContactManagerFindData *data); -static void contact_manager_add_account (EmpathyContactManager *manager, - McAccount *account); -static void contact_manager_added_cb (EmpathyTpContactList *list, - EmpathyContact *contact, - EmpathyContactManager *manager); -static void contact_manager_removed_cb (EmpathyTpContactList *list, - EmpathyContact *contact, - EmpathyContactManager *manager); -static void contact_manager_local_pending_cb (EmpathyTpContactList *list, - EmpathyContact *contact, - const gchar *message, - EmpathyContactManager *manager); -static void contact_manager_destroy_cb (EmpathyTpContactList *list, - EmpathyContactManager *manager); -static void contact_manager_rename_group_foreach (McAccount *account, - EmpathyTpContactList *list, - ContactManagerRenameGroupData *data); -static void contact_manager_get_groups_foreach (McAccount *account, - EmpathyTpContactList *list, - GList **all_groups); -static void contact_manager_get_members_foreach (McAccount *account, - EmpathyTpContactList *list, - GList **contacts); -static void contact_manager_get_local_pending_foreach (McAccount *account, - EmpathyTpContactList *list, - GList **contacts); -static void contact_manager_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - EmpathyContactManager *manager); +static void empathy_contact_manager_class_init (EmpathyContactManagerClass *klass); +static void empathy_contact_manager_init (EmpathyContactManager *manager); +static void contact_manager_iface_init (EmpathyContactListIface *iface); G_DEFINE_TYPE_WITH_CODE (EmpathyContactManager, empathy_contact_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST, contact_manager_iface_init)); static void -empathy_contact_manager_class_init (EmpathyContactManagerClass *klass) +contact_manager_members_changed_cb (EmpathyTpContactList *list, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_member, + EmpathyContactManager *manager) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + g_signal_emit_by_name (manager, "members-changed", + contact, actor, reason, message, is_member); +} - object_class->finalize = contact_manager_finalize; +static void +contact_manager_pendings_changed_cb (EmpathyTpContactList *list, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_pending, + EmpathyContactManager *manager) +{ + g_signal_emit_by_name (manager, "pendings-changed", + contact, actor, reason, message, is_pending); +} - g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv)); +static void +contact_manager_groups_changed_cb (EmpathyTpContactList *list, + EmpathyContact *contact, + gchar *group, + gboolean is_member, + EmpathyContactManager *manager) +{ + g_signal_emit_by_name (manager, "groups-changed", + contact, group, is_member); } +static void contact_manager_destroy_cb (EmpathyTpContactList *list, + EmpathyContactManager *manager); + static void -contact_manager_iface_init (EmpathyContactListIface *iface) +contact_manager_disconnect_foreach (gpointer key, + gpointer value, + gpointer user_data) { - iface->setup = contact_manager_setup; - iface->find = contact_manager_find; - iface->add = contact_manager_add; - iface->remove = contact_manager_remove; - iface->get_members = contact_manager_get_members; - iface->get_local_pending = contact_manager_get_local_pending; - iface->process_pending = contact_manager_process_pending; + EmpathyTpContactList *list = value; + EmpathyContactManager *manager = user_data; + + /* Disconnect signals from the list */ + g_signal_handlers_disconnect_by_func (list, + contact_manager_members_changed_cb, + manager); + g_signal_handlers_disconnect_by_func (list, + contact_manager_pendings_changed_cb, + manager); + g_signal_handlers_disconnect_by_func (list, + contact_manager_groups_changed_cb, + manager); + g_signal_handlers_disconnect_by_func (list, + contact_manager_destroy_cb, + manager); +} + +static void +contact_manager_destroy_cb (EmpathyTpContactList *list, + EmpathyContactManager *manager) +{ + EmpathyContactManagerPriv *priv = GET_PRIV (manager); + McAccount *account; + + account = empathy_tp_contact_list_get_account (list); + + empathy_debug (DEBUG_DOMAIN, "Removing account: %s", + mc_account_get_display_name (account)); + + contact_manager_disconnect_foreach (account, list, manager); + g_hash_table_remove (priv->lists, account); +} + +static void +contact_manager_add_account (EmpathyContactManager *manager, + McAccount *account) +{ + EmpathyContactManagerPriv *priv = GET_PRIV (manager); + EmpathyTpContactList *list; + + if (g_hash_table_lookup (priv->lists, account)) { + return; + } + + empathy_debug (DEBUG_DOMAIN, "Adding new account: %s", + mc_account_get_display_name (account)); + + list = empathy_tp_contact_list_new (account); + if (!list) { + return; + } + + g_hash_table_insert (priv->lists, g_object_ref (account), list); + + /* Connect signals */ + g_signal_connect (list, "members-changed", + G_CALLBACK (contact_manager_members_changed_cb), + manager); + g_signal_connect (list, "pendings-changed", + G_CALLBACK (contact_manager_pendings_changed_cb), + manager); + g_signal_connect (list, "groups-changed", + G_CALLBACK (contact_manager_groups_changed_cb), + manager); + g_signal_connect (list, "destroy", + G_CALLBACK (contact_manager_destroy_cb), + manager); +} + +static void +contact_manager_status_changed_cb (MissionControl *mc, + TelepathyConnectionStatus status, + McPresence presence, + TelepathyConnectionStatusReason reason, + const gchar *unique_name, + EmpathyContactManager *manager) +{ + McAccount *account; + + if (status != TP_CONN_STATUS_CONNECTED) { + /* We only care about newly connected accounts */ + return; + } + + account = mc_account_lookup (unique_name); + contact_manager_add_account (manager, account); + g_object_unref (account); +} + +static void +contact_manager_finalize (GObject *object) +{ + EmpathyContactManagerPriv *priv = GET_PRIV (object); + + g_hash_table_foreach (priv->lists, + contact_manager_disconnect_foreach, + object); + g_hash_table_destroy (priv->lists); + g_object_unref (priv->mc); +} + +static void +empathy_contact_manager_class_init (EmpathyContactManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = contact_manager_finalize; + + g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv)); } static void @@ -158,27 +229,12 @@ empathy_contact_manager_init (EmpathyContactManager *manager) /* Get ContactList for existing connections */ accounts = mission_control_get_online_connections (priv->mc, NULL); for (l = accounts; l; l = l->next) { - McAccount *account; - - account = l->data; - contact_manager_add_account (manager, account); - - g_object_unref (account); + contact_manager_add_account (manager, l->data); + g_object_unref (l->data); } g_slist_free (accounts); } -static void -contact_manager_finalize (GObject *object) -{ - EmpathyContactManagerPriv *priv; - - priv = GET_PRIV (object); - - g_hash_table_destroy (priv->lists); - g_object_unref (priv->mc); -} - EmpathyContactManager * empathy_contact_manager_new (void) { @@ -194,62 +250,28 @@ empathy_contact_manager_new (void) return manager; } -static void -contact_manager_setup (EmpathyContactList *manager) -{ - EmpathyContactManagerPriv *priv; - - g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - - priv = GET_PRIV (manager); - - if (priv->setup) { - /* Already done */ - return; - } - - g_hash_table_foreach (priv->lists, - (GHFunc) contact_manager_setup_foreach, - manager); - - priv->setup = TRUE; -} - -static EmpathyContact * -contact_manager_find (EmpathyContactList *manager, - const gchar *id) +EmpathyTpContactList * +empathy_contact_manager_get_list (EmpathyContactManager *manager, + McAccount *account) { - EmpathyContactManagerPriv *priv; - ContactManagerFindData data; + EmpathyContactManagerPriv *priv = GET_PRIV (manager); g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - g_return_val_if_fail (id != NULL, NULL); - - priv = GET_PRIV (manager); - - data.contact = NULL; - data.id = id; - - g_hash_table_find (priv->lists, - (GHRFunc) contact_manager_find_foreach, - &data); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - return data.contact; + return g_hash_table_lookup (priv->lists, account); } static void contact_manager_add (EmpathyContactList *manager, - EmpathyContact *contact, + EmpathyContact *contact, const gchar *message) { - EmpathyContactManagerPriv *priv; + EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; McAccount *account; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - priv = GET_PRIV (manager); account = empathy_contact_get_account (contact); list = g_hash_table_lookup (priv->lists, account); @@ -264,14 +286,11 @@ contact_manager_remove (EmpathyContactList *manager, EmpathyContact *contact, const gchar *message) { - EmpathyContactManagerPriv *priv; + EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; McAccount *account; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - priv = GET_PRIV (manager); account = empathy_contact_get_account (contact); list = g_hash_table_lookup (priv->lists, account); @@ -281,16 +300,25 @@ contact_manager_remove (EmpathyContactList *manager, } } +static void +contact_manager_get_members_foreach (McAccount *account, + EmpathyTpContactList *list, + GList **contacts) +{ + GList *l; + + l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list)); + *contacts = g_list_concat (*contacts, l); +} + static GList * contact_manager_get_members (EmpathyContactList *manager) { - EmpathyContactManagerPriv *priv; + EmpathyContactManagerPriv *priv = GET_PRIV (manager); GList *contacts = NULL; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - priv = GET_PRIV (manager); - g_hash_table_foreach (priv->lists, (GHFunc) contact_manager_get_members_foreach, &contacts); @@ -298,337 +326,169 @@ contact_manager_get_members (EmpathyContactList *manager) return contacts; } -static GList * -contact_manager_get_local_pending (EmpathyContactList *manager) -{ - EmpathyContactManagerPriv *priv; - GList *pending = NULL; - - g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - - priv = GET_PRIV (manager); - - g_hash_table_foreach (priv->lists, - (GHFunc) contact_manager_get_local_pending_foreach, - &pending); - - return pending; -} - static void -contact_manager_process_pending (EmpathyContactList *manager, - EmpathyContact *contact, - gboolean accept) +contact_manager_get_pendings_foreach (McAccount *account, + EmpathyTpContactList *list, + GList **contacts) { - EmpathyContactManagerPriv *priv; - EmpathyContactList *list; - McAccount *account; - - g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - priv = GET_PRIV (manager); - - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); - - if (list) { - empathy_contact_list_process_pending (list, contact, accept); - } -} - -EmpathyTpContactList * -empathy_contact_manager_get_list (EmpathyContactManager *manager, - McAccount *account) -{ - EmpathyContactManagerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - - priv = GET_PRIV (manager); + GList *l; - return g_hash_table_lookup (priv->lists, account); + l = empathy_contact_list_get_pendings (EMPATHY_CONTACT_LIST (list)); + *contacts = g_list_concat (*contacts, l); } -EmpathyContact * -empathy_contact_manager_get_user (EmpathyContactManager *manager, - McAccount *account) +static GList * +contact_manager_get_pendings (EmpathyContactList *manager) { - EmpathyContactManagerPriv *priv; - EmpathyTpContactList *list; + EmpathyContactManagerPriv *priv = GET_PRIV (manager); + GList *contacts = NULL; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - - priv = GET_PRIV (manager); - list = g_hash_table_lookup (priv->lists, account); - - if (!list) { - return NULL; - } + g_hash_table_foreach (priv->lists, + (GHFunc) contact_manager_get_pendings_foreach, + &contacts); - return empathy_tp_contact_list_get_user (list); + return contacts; } -EmpathyContact * -empathy_contact_manager_create (EmpathyContactManager *manager, - McAccount *account, - const gchar *id) +static void +contact_manager_get_all_groups_foreach (McAccount *account, + EmpathyTpContactList *list, + GList **all_groups) { - EmpathyContactManagerPriv *priv; - EmpathyTpContactList *list; - - g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (id != NULL, NULL); - - priv = GET_PRIV (manager); + GList *groups, *l; - list = g_hash_table_lookup (priv->lists, account); - - if (!list) { - return NULL; + groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (list)); + for (l = groups; l; l = l->next) { + if (!g_list_find_custom (*all_groups, + l->data, + (GCompareFunc) strcmp)) { + *all_groups = g_list_prepend (*all_groups, l->data); + } else { + g_free (l->data); + } } - return empathy_tp_contact_list_get_from_id (list, id); -} - -void -empathy_contact_manager_rename_group (EmpathyContactManager *manager, - const gchar *old_group, - const gchar *new_group) -{ - EmpathyContactManagerPriv *priv; - ContactManagerRenameGroupData data; - - g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - g_return_if_fail (old_group != NULL); - g_return_if_fail (new_group != NULL); - - priv = GET_PRIV (manager); - - data.old_group = old_group; - data.new_group = new_group; - - g_hash_table_foreach (priv->lists, - (GHFunc) contact_manager_rename_group_foreach, - &data); + g_list_free (groups); } -GList * -empathy_contact_manager_get_groups (EmpathyContactManager *manager) +static GList * +contact_manager_get_all_groups (EmpathyContactList *manager) { - EmpathyContactManagerPriv *priv; + EmpathyContactManagerPriv *priv = GET_PRIV (manager); GList *groups = NULL; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - priv = GET_PRIV (manager); - g_hash_table_foreach (priv->lists, - (GHFunc) contact_manager_get_groups_foreach, + (GHFunc) contact_manager_get_all_groups_foreach, &groups); return groups; } -static void -contact_manager_setup_foreach (McAccount *account, - EmpathyTpContactList *list, - EmpathyContactManager *manager) +static GList * +contact_manager_get_groups (EmpathyContactList *manager, + EmpathyContact *contact) { - empathy_contact_list_setup (EMPATHY_CONTACT_LIST (list)); -} + EmpathyContactManagerPriv *priv = GET_PRIV (manager); + EmpathyContactList *list; + McAccount *account; -static gboolean -contact_manager_find_foreach (McAccount *account, - EmpathyTpContactList *list, - ContactManagerFindData *data) -{ - data->contact = empathy_contact_list_find (EMPATHY_CONTACT_LIST (list), - data->id); + g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); + + account = empathy_contact_get_account (contact); + list = g_hash_table_lookup (priv->lists, account); - if (data->contact) { - return TRUE; + if (list) { + return empathy_contact_list_get_groups (list, contact); } - return FALSE; + return NULL; } static void -contact_manager_add_account (EmpathyContactManager *manager, - McAccount *account) +contact_manager_add_to_group (EmpathyContactList *manager, + EmpathyContact *contact, + const gchar *group) { - EmpathyContactManagerPriv *priv; - EmpathyTpContactList *list; - - priv = GET_PRIV (manager); - - if (g_hash_table_lookup (priv->lists, account)) { - return; - } - - empathy_debug (DEBUG_DOMAIN, "Adding new account: %s", - mc_account_get_display_name (account)); - - list = empathy_tp_contact_list_new (account); - if (!list) { - return; - } + EmpathyContactManagerPriv *priv = GET_PRIV (manager); + EmpathyContactList *list; + McAccount *account; - g_hash_table_insert (priv->lists, g_object_ref (account), list); + g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - /* Connect signals */ - g_signal_connect (list, "contact-added", - G_CALLBACK (contact_manager_added_cb), - manager); - g_signal_connect (list, "contact-removed", - G_CALLBACK (contact_manager_removed_cb), - manager); - g_signal_connect (list, "local-pending", - G_CALLBACK (contact_manager_local_pending_cb), - manager); - g_signal_connect (list, "destroy", - G_CALLBACK (contact_manager_destroy_cb), - manager); + account = empathy_contact_get_account (contact); + list = g_hash_table_lookup (priv->lists, account); - if (priv->setup) { - empathy_contact_list_setup (EMPATHY_CONTACT_LIST (list)); + if (list) { + empathy_contact_list_add_to_group (list, contact, group); } } static void -contact_manager_added_cb (EmpathyTpContactList *list, - EmpathyContact *contact, - EmpathyContactManager *manager) +contact_manager_remove_from_group (EmpathyContactList *manager, + EmpathyContact *contact, + const gchar *group) { - g_signal_emit_by_name (manager, "contact-added", contact); -} - -static void -contact_manager_removed_cb (EmpathyTpContactList *list, - EmpathyContact *contact, - EmpathyContactManager *manager) -{ - g_signal_emit_by_name (manager, "contact-removed", contact); -} - -static void -contact_manager_local_pending_cb (EmpathyTpContactList *list, - EmpathyContact *contact, - const gchar *message, - EmpathyContactManager *manager) -{ - g_signal_emit_by_name (manager, "local-pending", contact, message); -} - -static void -contact_manager_destroy_cb (EmpathyTpContactList *list, - EmpathyContactManager *manager) -{ - EmpathyContactManagerPriv *priv; + EmpathyContactManagerPriv *priv = GET_PRIV (manager); + EmpathyContactList *list; McAccount *account; - priv = GET_PRIV (manager); - - account = empathy_tp_contact_list_get_account (list); - - empathy_debug (DEBUG_DOMAIN, "Removing account: %s", - mc_account_get_display_name (account)); + g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - /* Disconnect signals from the list */ - g_signal_handlers_disconnect_by_func (list, - contact_manager_added_cb, - manager); - g_signal_handlers_disconnect_by_func (list, - contact_manager_removed_cb, - manager); - g_signal_handlers_disconnect_by_func (list, - contact_manager_local_pending_cb, - manager); - g_signal_handlers_disconnect_by_func (list, - contact_manager_destroy_cb, - manager); + account = empathy_contact_get_account (contact); + list = g_hash_table_lookup (priv->lists, account); - g_hash_table_remove (priv->lists, account); + if (list) { + empathy_contact_list_remove_from_group (list, contact, group); + } } -static void -contact_manager_rename_group_foreach (McAccount *account, - EmpathyTpContactList *list, - ContactManagerRenameGroupData *data) -{ - empathy_tp_contact_list_rename_group (list, - data->old_group, - data->new_group); -} +typedef struct { + const gchar *old_group; + const gchar *new_group; +} RenameGroupData; static void -contact_manager_get_groups_foreach (McAccount *account, - EmpathyTpContactList *list, - GList **all_groups) +contact_manager_rename_group_foreach (McAccount *account, + EmpathyTpContactList *list, + RenameGroupData *data) { - GList *groups, *l; - - groups = empathy_tp_contact_list_get_groups (list); - for (l = groups; l; l = l->next) { - if (!g_list_find_custom (*all_groups, - l->data, - (GCompareFunc) strcmp)) { - *all_groups = g_list_append (*all_groups, - g_strdup (l->data)); - } - g_free (l->data); - } - - g_list_free (groups); + empathy_contact_list_rename_group (EMPATHY_CONTACT_LIST (list), + data->old_group, + data->new_group); } static void -contact_manager_get_members_foreach (McAccount *account, - EmpathyTpContactList *list, - GList **contacts) +contact_manager_rename_group (EmpathyContactList *manager, + const gchar *old_group, + const gchar *new_group) { - GList *l; - - l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list)); - *contacts = g_list_concat (*contacts, l); -} + EmpathyContactManagerPriv *priv = GET_PRIV (manager); + RenameGroupData data; -static void -contact_manager_get_local_pending_foreach (McAccount *account, - EmpathyTpContactList *list, - GList **contacts) -{ - GList *l; + g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - l = empathy_contact_list_get_local_pending (EMPATHY_CONTACT_LIST (list)); - *contacts = g_list_concat (*contacts, l); + data.old_group = old_group; + data.new_group = new_group; + g_hash_table_foreach (priv->lists, + (GHFunc) contact_manager_rename_group_foreach, + &data); } static void -contact_manager_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - EmpathyContactManager *manager) +contact_manager_iface_init (EmpathyContactListIface *iface) { - EmpathyContactManagerPriv *priv; - McAccount *account; - - priv = GET_PRIV (manager); - - if (status != TP_CONN_STATUS_CONNECTED) { - /* We only care about newly connected accounts */ - return; - } - - account = mc_account_lookup (unique_name); - contact_manager_add_account (manager, account); - - g_object_unref (account); + iface->add = contact_manager_add; + iface->remove = contact_manager_remove; + iface->get_members = contact_manager_get_members; + iface->get_pendings = contact_manager_get_pendings; + iface->get_all_groups = contact_manager_get_all_groups; + iface->get_groups = contact_manager_get_groups; + iface->add_to_group = contact_manager_add_to_group; + iface->remove_from_group = contact_manager_remove_from_group; + iface->rename_group = contact_manager_rename_group; } diff --git a/libempathy/empathy-contact-manager.h b/libempathy/empathy-contact-manager.h index 768301ae..41144cf4 100644 --- a/libempathy/empathy-contact-manager.h +++ b/libempathy/empathy-contact-manager.h @@ -51,19 +51,10 @@ struct _EmpathyContactManagerClass { GObjectClass parent_class; }; -GType empathy_contact_manager_get_type (void) G_GNUC_CONST; -EmpathyContactManager *empathy_contact_manager_new (void); -EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, - McAccount *account); -EmpathyContact * empathy_contact_manager_get_user (EmpathyContactManager *manager, - McAccount *account); -EmpathyContact * empathy_contact_manager_create (EmpathyContactManager *manager, - McAccount *account, - const gchar *id); -void empathy_contact_manager_rename_group (EmpathyContactManager *manager, - const gchar *old_group, - const gchar *new_group); -GList * empathy_contact_manager_get_groups (EmpathyContactManager *manager); +GType empathy_contact_manager_get_type (void) G_GNUC_CONST; +EmpathyContactManager *empathy_contact_manager_new (void); +EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, + McAccount *account); G_END_DECLS diff --git a/libempathy/empathy-contact.c b/libempathy/empathy-contact.c index d3935ad6..505e190c 100644 --- a/libempathy/empathy-contact.c +++ b/libempathy/empathy-contact.c @@ -1,6 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2004-2007 Imendio AB + * Copyright (C) 2004 Imendio AB + * Copyright (C) 2007 Collabora Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,6 +20,7 @@ * * Authors: Mikael Hallendal * Martyn Russell + * Xavier Claessens */ #include "config.h" @@ -41,26 +43,26 @@ typedef struct _EmpathyContactPriv EmpathyContactPriv; struct _EmpathyContactPriv { gchar *id; gchar *name; - EmpathyAvatar *avatar; + EmpathyAvatar *avatar; McAccount *account; - EmpathyPresence *presence; - GList *groups; - EmpathySubscription subscription; + EmpathyPresence *presence; guint handle; gboolean is_user; }; -static void contact_class_init (EmpathyContactClass *class); -static void contact_init (EmpathyContact *contact); -static void contact_finalize (GObject *object); -static void contact_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void contact_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); +static void empathy_contact_class_init (EmpathyContactClass *class); +static void empathy_contact_init (EmpathyContact *contact); +static void contact_finalize (GObject *object); +static void contact_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void contact_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); + +G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT); enum { PROP_0, @@ -75,41 +77,12 @@ enum { PROP_IS_USER }; -static gpointer parent_class = NULL; - -GType -empathy_contact_get_gtype (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (EmpathyContactClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) contact_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EmpathyContact), - 0, /* n_preallocs */ - (GInstanceInitFunc) contact_init - }; - - type = g_type_register_static (G_TYPE_OBJECT, - "EmpathyContact", - &info, 0); - } - - return type; -} - static void -contact_class_init (EmpathyContactClass *class) +empathy_contact_class_init (EmpathyContactClass *class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (class); - parent_class = g_type_class_peek_parent (class); object_class->finalize = contact_finalize; object_class->get_property = contact_get_property; @@ -155,23 +128,6 @@ contact_class_init (EmpathyContactClass *class) EMPATHY_TYPE_PRESENCE, G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_GROUPS, - g_param_spec_pointer ("groups", - "Contact groups", - "Groups of contact", - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SUBSCRIPTION, - g_param_spec_flags ("subscription", - "Contact Subscription", - "The subscription status of the contact", - EMPATHY_TYPE_SUBSCRIPTION, - EMPATHY_SUBSCRIPTION_NONE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_HANDLE, g_param_spec_uint ("handle", @@ -193,7 +149,7 @@ contact_class_init (EmpathyContactClass *class) } static void -contact_init (EmpathyContact *contact) +empathy_contact_init (EmpathyContact *contact) { } @@ -217,16 +173,11 @@ contact_finalize (GObject *object) g_object_unref (priv->presence); } - if (priv->groups) { - g_list_foreach (priv->groups, (GFunc) g_free, NULL); - g_list_free (priv->groups); - } - if (priv->account) { g_object_unref (priv->account); } - (G_OBJECT_CLASS (parent_class)->finalize) (object); + G_OBJECT_CLASS (empathy_contact_parent_class)->finalize (object); } static void @@ -257,12 +208,6 @@ contact_get_property (GObject *object, case PROP_PRESENCE: g_value_set_object (value, priv->presence); break; - case PROP_GROUPS: - g_value_set_pointer (value, priv->groups); - break; - case PROP_SUBSCRIPTION: - g_value_set_flags (value, priv->subscription); - break; case PROP_HANDLE: g_value_set_uint (value, priv->handle); break; @@ -306,14 +251,6 @@ contact_set_property (GObject *object, empathy_contact_set_presence (EMPATHY_CONTACT (object), EMPATHY_PRESENCE (g_value_get_object (value))); break; - case PROP_GROUPS: - empathy_contact_set_groups (EMPATHY_CONTACT (object), - g_value_get_pointer (value)); - break; - case PROP_SUBSCRIPTION: - empathy_contact_set_subscription (EMPATHY_CONTACT (object), - g_value_get_flags (value)); - break; case PROP_HANDLE: empathy_contact_set_handle (EMPATHY_CONTACT (object), g_value_get_uint (value)); @@ -338,8 +275,8 @@ empathy_contact_new (McAccount *account) EmpathyContact * empathy_contact_new_full (McAccount *account, - const gchar *id, - const gchar *name) + const gchar *id, + const gchar *name) { return g_object_new (EMPATHY_TYPE_CONTACT, "account", account, @@ -364,107 +301,6 @@ empathy_contact_get_id (EmpathyContact *contact) return ""; } -const gchar * -empathy_contact_get_name (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), ""); - - priv = GET_PRIV (contact); - - if (G_STR_EMPTY (priv->name)) { - return empathy_contact_get_id (contact); - } - - return priv->name; -} - -EmpathyAvatar * -empathy_contact_get_avatar (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); - - priv = GET_PRIV (contact); - - return priv->avatar; -} - -McAccount * -empathy_contact_get_account (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); - - priv = GET_PRIV (contact); - - return priv->account; -} - -EmpathyPresence * -empathy_contact_get_presence (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); - - priv = GET_PRIV (contact); - - return priv->presence; -} - -GList * -empathy_contact_get_groups (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); - - priv = GET_PRIV (contact); - - return priv->groups; -} - -EmpathySubscription -empathy_contact_get_subscription (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), - EMPATHY_SUBSCRIPTION_NONE); - - priv = GET_PRIV (contact); - - return priv->subscription; -} - -guint -empathy_contact_get_handle (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0); - - priv = GET_PRIV (contact); - - return priv->handle; -} - -gboolean -empathy_contact_is_user (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - - priv = GET_PRIV (contact); - - return priv->is_user; -} - void empathy_contact_set_id (EmpathyContact *contact, const gchar *id) @@ -486,6 +322,22 @@ empathy_contact_set_id (EmpathyContact *contact, g_object_notify (G_OBJECT (contact), "id"); } +const gchar * +empathy_contact_get_name (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), ""); + + priv = GET_PRIV (contact); + + if (G_STR_EMPTY (priv->name)) { + return empathy_contact_get_id (contact); + } + + return priv->name; +} + void empathy_contact_set_name (EmpathyContact *contact, const gchar *name) @@ -507,6 +359,18 @@ empathy_contact_set_name (EmpathyContact *contact, g_object_notify (G_OBJECT (contact), "name"); } +EmpathyAvatar * +empathy_contact_get_avatar (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->avatar; +} + void empathy_contact_set_avatar (EmpathyContact *contact, EmpathyAvatar *avatar) @@ -533,9 +397,21 @@ empathy_contact_set_avatar (EmpathyContact *contact, g_object_notify (G_OBJECT (contact), "avatar"); } +McAccount * +empathy_contact_get_account (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->account; +} + void empathy_contact_set_account (EmpathyContact *contact, - McAccount *account) + McAccount *account) { EmpathyContactPriv *priv; @@ -556,9 +432,21 @@ empathy_contact_set_account (EmpathyContact *contact, g_object_notify (G_OBJECT (contact), "account"); } +EmpathyPresence * +empathy_contact_get_presence (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->presence; +} + void empathy_contact_set_presence (EmpathyContact *contact, - EmpathyPresence *presence) + EmpathyPresence *presence) { EmpathyContactPriv *priv; @@ -582,34 +470,21 @@ empathy_contact_set_presence (EmpathyContact *contact, g_object_notify (G_OBJECT (contact), "presence"); } -void -empathy_contact_set_groups (EmpathyContact *contact, - GList *groups) +guint +empathy_contact_get_handle (EmpathyContact *contact) { EmpathyContactPriv *priv; - GList *old_groups, *l; - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0); priv = GET_PRIV (contact); - old_groups = priv->groups; - priv->groups = NULL; - - for (l = groups; l; l = l->next) { - priv->groups = g_list_append (priv->groups, - g_strdup (l->data)); - } - - g_list_foreach (old_groups, (GFunc) g_free, NULL); - g_list_free (old_groups); - - g_object_notify (G_OBJECT (contact), "groups"); + return priv->handle; } void -empathy_contact_set_subscription (EmpathyContact *contact, - EmpathySubscription subscription) +empathy_contact_set_handle (EmpathyContact *contact, + guint handle) { EmpathyContactPriv *priv; @@ -617,32 +492,25 @@ empathy_contact_set_subscription (EmpathyContact *contact, priv = GET_PRIV (contact); - if (priv->subscription == subscription) { + if (priv->handle == handle) { return; } - priv->subscription = subscription; + priv->handle = handle; - g_object_notify (G_OBJECT (contact), "subscription"); + g_object_notify (G_OBJECT (contact), "handle"); } -void -empathy_contact_set_handle (EmpathyContact *contact, - guint handle) +gboolean +empathy_contact_is_user (EmpathyContact *contact) { EmpathyContactPriv *priv; - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); priv = GET_PRIV (contact); - if (priv->handle == handle) { - return; - } - - priv->handle = handle; - - g_object_notify (G_OBJECT (contact), "handle"); + return priv->is_user; } void @@ -664,43 +532,6 @@ empathy_contact_set_is_user (EmpathyContact *contact, g_object_notify (G_OBJECT (contact), "is-user"); } -void -empathy_contact_add_group (EmpathyContact *contact, - const gchar *group) -{ - EmpathyContactPriv *priv; - - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - g_return_if_fail (group != NULL); - - priv = GET_PRIV (contact); - - if (!g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) { - priv->groups = g_list_prepend (priv->groups, g_strdup (group)); - g_object_notify (G_OBJECT (contact), "groups"); - } -} - -void -empathy_contact_remove_group (EmpathyContact *contact, - const gchar *group) -{ - EmpathyContactPriv *priv; - GList *l; - - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - g_return_if_fail (group != NULL); - - priv = GET_PRIV (contact); - - l = g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp); - if (l) { - g_free (l->data); - priv->groups = g_list_delete_link (priv->groups, l); - g_object_notify (G_OBJECT (contact), "groups"); - } -} - gboolean empathy_contact_is_online (EmpathyContact *contact) { @@ -717,24 +548,6 @@ empathy_contact_is_online (EmpathyContact *contact) return (empathy_presence_get_state (priv->presence) > MC_PRESENCE_OFFLINE); } -gboolean -empathy_contact_is_in_group (EmpathyContact *contact, - const gchar *group) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - g_return_val_if_fail (!G_STR_EMPTY (group), FALSE); - - priv = GET_PRIV (contact); - - if (g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) { - return TRUE; - } - - return FALSE; -} - const gchar * empathy_contact_get_status (EmpathyContact *contact) { diff --git a/libempathy/empathy-contact.h b/libempathy/empathy-contact.h index b32d451b..87a26f0d 100644 --- a/libempathy/empathy-contact.h +++ b/libempathy/empathy-contact.h @@ -1,6 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2004 Imendio AB + * Copyright (C) 2007 Collabora Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -16,6 +17,10 @@ * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Martyn Russell + * Xavier Claessens */ #ifndef __EMPATHY_CONTACT_H__ @@ -30,7 +35,7 @@ G_BEGIN_DECLS -#define EMPATHY_TYPE_CONTACT (empathy_contact_get_gtype ()) +#define EMPATHY_TYPE_CONTACT (empathy_contact_get_type ()) #define EMPATHY_CONTACT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONTACT, EmpathyContact)) #define EMPATHY_CONTACT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_CONTACT, EmpathyContactClass)) #define EMPATHY_IS_CONTACT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONTACT)) @@ -48,57 +53,37 @@ struct _EmpathyContactClass { GObjectClass parent_class; }; -typedef enum { - EMPATHY_SUBSCRIPTION_NONE = 0, - EMPATHY_SUBSCRIPTION_TO = 1 << 0, /* We send our presence to that contact */ - EMPATHY_SUBSCRIPTION_FROM = 1 << 1, /* That contact sends his presence to us */ - EMPATHY_SUBSCRIPTION_BOTH = EMPATHY_SUBSCRIPTION_TO | EMPATHY_SUBSCRIPTION_FROM -} EmpathySubscription; - -GType empathy_contact_get_gtype (void) G_GNUC_CONST; - -EmpathyContact * empathy_contact_new (McAccount *account); -EmpathyContact * empathy_contact_new_full (McAccount *account, - const gchar *id, - const gchar *name); -const gchar * empathy_contact_get_id (EmpathyContact *contact); -const gchar * empathy_contact_get_name (EmpathyContact *contact); -EmpathyAvatar * empathy_contact_get_avatar (EmpathyContact *contact); -McAccount * empathy_contact_get_account (EmpathyContact *contact); -EmpathyPresence * empathy_contact_get_presence (EmpathyContact *contact); -GList * empathy_contact_get_groups (EmpathyContact *contact); -EmpathySubscription empathy_contact_get_subscription (EmpathyContact *contact); -guint empathy_contact_get_handle (EmpathyContact *contact); -gboolean empathy_contact_is_user (EmpathyContact *contact); -void empathy_contact_set_id (EmpathyContact *contact, - const gchar *id); -void empathy_contact_set_name (EmpathyContact *contact, - const gchar *name); -void empathy_contact_set_avatar (EmpathyContact *contact, - EmpathyAvatar *avatar); -void empathy_contact_set_account (EmpathyContact *contact, - McAccount *account); -void empathy_contact_set_presence (EmpathyContact *contact, - EmpathyPresence *presence); -void empathy_contact_set_groups (EmpathyContact *contact, - GList *categories); -void empathy_contact_set_subscription (EmpathyContact *contact, - EmpathySubscription subscription); -void empathy_contact_set_handle (EmpathyContact *contact, - guint handle); -void empathy_contact_set_is_user (EmpathyContact *contact, - gboolean is_user); -void empathy_contact_add_group (EmpathyContact *contact, - const gchar *group); -void empathy_contact_remove_group (EmpathyContact *contact, - const gchar *group); -gboolean empathy_contact_is_online (EmpathyContact *contact); -gboolean empathy_contact_is_in_group (EmpathyContact *contact, - const gchar *group); -const gchar * empathy_contact_get_status (EmpathyContact *contact); -gboolean empathy_contact_equal (gconstpointer v1, - gconstpointer v2); -guint empathy_contact_hash (gconstpointer key); +GType empathy_contact_get_type (void) G_GNUC_CONST; +EmpathyContact * empathy_contact_new (McAccount *account); +EmpathyContact * empathy_contact_new_full (McAccount *account, + const gchar *id, + const gchar *name); +const gchar * empathy_contact_get_id (EmpathyContact *contact); +void empathy_contact_set_id (EmpathyContact *contact, + const gchar *id); +const gchar * empathy_contact_get_name (EmpathyContact *contact); +void empathy_contact_set_name (EmpathyContact *contact, + const gchar *name); +EmpathyAvatar * empathy_contact_get_avatar (EmpathyContact *contact); +void empathy_contact_set_avatar (EmpathyContact *contact, + EmpathyAvatar *avatar); +McAccount * empathy_contact_get_account (EmpathyContact *contact); +void empathy_contact_set_account (EmpathyContact *contact, + McAccount *account); +EmpathyPresence * empathy_contact_get_presence (EmpathyContact *contact); +void empathy_contact_set_presence (EmpathyContact *contact, + EmpathyPresence *presence); +guint empathy_contact_get_handle (EmpathyContact *contact); +void empathy_contact_set_handle (EmpathyContact *contact, + guint handle); +gboolean empathy_contact_is_user (EmpathyContact *contact); +void empathy_contact_set_is_user (EmpathyContact *contact, + gboolean is_user); +gboolean empathy_contact_is_online (EmpathyContact *contact); +const gchar * empathy_contact_get_status (EmpathyContact *contact); +gboolean empathy_contact_equal (gconstpointer v1, + gconstpointer v2); +guint empathy_contact_hash (gconstpointer key); G_END_DECLS diff --git a/libempathy/empathy-log-manager.c b/libempathy/empathy-log-manager.c index e234ec52..e47f50fb 100644 --- a/libempathy/empathy-log-manager.c +++ b/libempathy/empathy-log-manager.c @@ -634,24 +634,22 @@ log_manager_get_dir (EmpathyLogManager *manager, { const gchar *account_id; gchar *basedir; - gchar *str; account_id = mc_account_get_unique_name (account); - basedir = - str = g_build_path (G_DIR_SEPARATOR_S, - log_manager_get_basedir (manager), - account_id, - chat_id, - NULL); if (chatroom) { basedir = g_build_path (G_DIR_SEPARATOR_S, - str, + log_manager_get_basedir (manager), + account_id, LOG_DIR_CHATROOMS, + chat_id, NULL); - g_free (str); } else { - basedir = str; + basedir = g_build_path (G_DIR_SEPARATOR_S, + log_manager_get_basedir (manager), + account_id, + chat_id, + NULL); } return basedir; diff --git a/libempathy/empathy-marshal.list b/libempathy/empathy-marshal.list index 3b36b7be..383bfbbe 100644 --- a/libempathy/empathy-marshal.list +++ b/libempathy/empathy-marshal.list @@ -1,10 +1,14 @@ VOID:OBJECT,UINT -VOID:OBJECT,OBJECT -VOID:OBJECT,OBJECT,UINT VOID:OBJECT,BOOLEAN -VOID:OBJECT,STRING,STRING +VOID:OBJECT,POINTER VOID:OBJECT,STRING -VOID:POINTER,UINT,UINT,STRING +VOID:OBJECT,STRING,STRING +VOID:OBJECT,STRING,BOOLEAN +VOID:OBJECT,OBJECT +VOID:OBJECT,OBJECT,UINT +VOID:OBJECT,OBJECT,UINT,STRING +VOID:OBJECT,OBJECT,UINT,STRING,BOOLEAN +VOID:OBJECT,OBJECT,STRING VOID:INT,STRING VOID:UINT,BOOLEAN diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c index 077afe36..fc943f0c 100644 --- a/libempathy/empathy-tp-chat.c +++ b/libempathy/empathy-tp-chat.c @@ -31,8 +31,7 @@ #include #include "empathy-tp-chat.h" -#include "empathy-contact-manager.h" -#include "empathy-tp-contact-list.h" +#include "empathy-contact-factory.h" #include "empathy-marshal.h" #include "empathy-debug.h" #include "empathy-time.h" @@ -44,8 +43,8 @@ #define DEBUG_DOMAIN "TpChat" struct _EmpathyTpChatPriv { - EmpathyTpContactList *list; - EmpathyContactManager *manager; + EmpathyContactFactory *factory; + EmpathyContact *user; McAccount *account; gchar *id; MissionControl *mc; @@ -363,11 +362,11 @@ tp_chat_finalize (GObject *object) g_object_unref (priv->tp_chan); } - if (priv->manager) { - g_object_unref (priv->manager); + if (priv->factory) { + g_object_unref (priv->factory); } - if (priv->list) { - g_object_unref (priv->list); + if (priv->user) { + g_object_unref (priv->user); } if (priv->account) { g_object_unref (priv->account); @@ -392,10 +391,9 @@ tp_chat_constructor (GType type, priv = GET_PRIV (chat); - priv->manager = empathy_contact_manager_new (); - priv->list = empathy_contact_manager_get_list (priv->manager, priv->account); + priv->factory = empathy_contact_factory_new (); + priv->user = empathy_contact_factory_get_user (priv->factory, priv->account); priv->mc = empathy_mission_control_new (); - g_object_ref (priv->list); priv->text_iface = tp_chan_get_interface (priv->tp_chan, TELEPATHY_CHAN_IFACE_TEXT_QUARK); @@ -750,12 +748,10 @@ empathy_tp_chat_get_id (EmpathyTpChat *chat) priv = GET_PRIV (chat); - if (priv->id) { - return priv->id; + if (!priv->id) { + priv->id = empathy_inspect_channel (priv->account, priv->tp_chan); } - priv->id = empathy_inspect_channel (priv->account, priv->tp_chan); - return priv->id; } @@ -885,7 +881,9 @@ tp_chat_state_changed_cb (DBusGProxy *chat_state_iface, priv = GET_PRIV (chat); - contact = empathy_tp_contact_list_get_from_handle (priv->list, handle); + contact = empathy_contact_factory_get_from_handle (priv->factory, + priv->account, + handle); empathy_debug (DEBUG_DOMAIN, "Chat state changed for %s (%d): %d", empathy_contact_get_name (contact), @@ -906,22 +904,21 @@ tp_chat_build_message (EmpathyTpChat *chat, EmpathyTpChatPriv *priv; EmpathyMessage *message; EmpathyContact *sender; - EmpathyContact *receiver; priv = GET_PRIV (chat); - receiver = empathy_tp_contact_list_get_user (priv->list); if (from_handle == 0) { - sender = g_object_ref (receiver); + sender = g_object_ref (priv->user); } else { - sender = empathy_tp_contact_list_get_from_handle (priv->list, + sender = empathy_contact_factory_get_from_handle (priv->factory, + priv->account, from_handle); } message = empathy_message_new (message_body); empathy_message_set_type (message, type); empathy_message_set_sender (message, sender); - empathy_message_set_receiver (message, receiver); + empathy_message_set_receiver (message, priv->user); empathy_message_set_timestamp (message, (EmpathyTime) timestamp); g_object_unref (sender); diff --git a/libempathy/empathy-tp-chatroom.c b/libempathy/empathy-tp-chatroom.c index 32716865..72f08394 100644 --- a/libempathy/empathy-tp-chatroom.c +++ b/libempathy/empathy-tp-chatroom.c @@ -23,9 +23,8 @@ #include #include "empathy-tp-chatroom.h" -#include "empathy-tp-contact-list.h" #include "empathy-contact-list.h" -#include "empathy-contact-manager.h" +#include "empathy-contact-factory.h" #include "empathy-tp-group.h" #include "empathy-utils.h" #include "empathy-debug.h" @@ -36,8 +35,7 @@ #define DEBUG_DOMAIN "TpChatroom" struct _EmpathyTpChatroomPriv { - EmpathyContactManager *manager; - EmpathyTpContactList *list; + EmpathyContactFactory *factory; EmpathyTpGroup *group; gboolean is_invited; @@ -49,21 +47,18 @@ static void empathy_tp_chatroom_class_init (EmpathyTpChatroomClass * static void tp_chatroom_iface_init (EmpathyContactListIface *iface); static void empathy_tp_chatroom_init (EmpathyTpChatroom *chatroom); static void tp_chatroom_finalize (GObject *object); -static void tp_chatroom_members_added_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, +static void tp_chatroom_member_added_cb (EmpathyTpGroup *group, + EmpathyContact *contact, + EmpathyContact *actor, guint reason, const gchar *message, - EmpathyTpChatroom *list); -static void tp_chatroom_members_removed_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, + EmpathyTpChatroom *chatroom); +static void tp_chatroom_member_removed_cb (EmpathyTpGroup *group, + EmpathyContact *contact, + EmpathyContact *actor, guint reason, const gchar *message, - EmpathyTpChatroom *list); -static void tp_chatroom_setup (EmpathyContactList *list); -static EmpathyContact * tp_chatroom_find (EmpathyContactList *list, - const gchar *id); + EmpathyTpChatroom *chatroom); static void tp_chatroom_add (EmpathyContactList *list, EmpathyContact *contact, const gchar *message); @@ -89,8 +84,6 @@ empathy_tp_chatroom_class_init (EmpathyTpChatroomClass *klass) static void tp_chatroom_iface_init (EmpathyContactListIface *iface) { - iface->setup = tp_chatroom_setup; - iface->find = tp_chatroom_find; iface->add = tp_chatroom_add; iface->remove = tp_chatroom_remove; iface->get_members = tp_chatroom_get_members; @@ -111,7 +104,7 @@ tp_chatroom_finalize (GObject *object) priv = GET_PRIV (chatroom); g_object_unref (priv->group); - g_object_unref (priv->manager); + g_object_unref (priv->factory); if (priv->invitor) { g_object_unref (priv->invitor); @@ -129,7 +122,7 @@ empathy_tp_chatroom_new (McAccount *account, EmpathyTpChatroomPriv *priv; EmpathyTpChatroom *chatroom; GList *members, *l; - guint self_handle; + EmpathyContact *user; g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); @@ -141,40 +134,41 @@ empathy_tp_chatroom_new (McAccount *account, priv = GET_PRIV (chatroom); - priv->manager = empathy_contact_manager_new (); - priv->list = empathy_contact_manager_get_list (priv->manager, account); + priv->factory = empathy_contact_factory_new (); priv->group = empathy_tp_group_new (account, tp_chan); - g_signal_connect (priv->group, "members-added", - G_CALLBACK (tp_chatroom_members_added_cb), + g_signal_connect (priv->group, "member-added", + G_CALLBACK (tp_chatroom_member_added_cb), chatroom); - g_signal_connect (priv->group, "members-removed", - G_CALLBACK (tp_chatroom_members_removed_cb), + g_signal_connect (priv->group, "member-removed", + G_CALLBACK (tp_chatroom_member_removed_cb), chatroom); /* Check if we are invited to join the chat */ - self_handle = empathy_tp_group_get_self_handle (priv->group); - members = empathy_tp_group_get_local_pending_members_with_info (priv->group); + user = empathy_tp_group_get_self_contact (priv->group); + members = empathy_tp_group_get_local_pendings (priv->group); for (l = members; l; l = l->next) { - EmpathyTpGroupInfo *info; + EmpathyPendingInfo *info; info = l->data; - if (info->member != self_handle) { + if (!empathy_contact_equal (user, info->member)) { continue; } - priv->invitor = empathy_tp_contact_list_get_from_handle (priv->list, - info->actor); + priv->invitor = g_object_ref (info->actor); priv->invit_message = g_strdup (info->message); priv->is_invited = TRUE; - empathy_debug (DEBUG_DOMAIN, "We are invited to join by %s: %s", - empathy_contact_get_name (priv->invitor), - priv->invit_message); + empathy_debug (DEBUG_DOMAIN, "We are invited to join by %s (%d): %s", + empathy_contact_get_id (priv->invitor), + empathy_contact_get_handle (priv->invitor), + priv->invit_message); } - empathy_tp_group_info_list_free (members); + g_list_foreach (members, (GFunc) empathy_pending_info_free, NULL); + g_list_free (members); + g_object_unref (user); return chatroom; } @@ -204,7 +198,7 @@ void empathy_tp_chatroom_accept_invitation (EmpathyTpChatroom *chatroom) { EmpathyTpChatroomPriv *priv; - guint self_handle; + EmpathyContact *user; g_return_if_fail (EMPATHY_IS_TP_CHATROOM (chatroom)); @@ -220,80 +214,42 @@ empathy_tp_chatroom_accept_invitation (EmpathyTpChatroom *chatroom) priv->invit_message = NULL; /* Add ourself in the members of the room */ - self_handle = empathy_tp_group_get_self_handle (priv->group); - empathy_tp_group_add_member (priv->group, self_handle, - "Just for fun"); + user = empathy_tp_group_get_self_contact (priv->group); + empathy_tp_group_add_member (priv->group, user, ""); + g_object_unref (user); } void empathy_tp_chatroom_set_topic (EmpathyTpChatroom *chatroom, const gchar *topic) { + /* FIXME: not implemented */ } static void -tp_chatroom_members_added_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpChatroom *chatroom) +tp_chatroom_member_added_cb (EmpathyTpGroup *group, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + const gchar *message, + EmpathyTpChatroom *chatroom) { - EmpathyTpChatroomPriv *priv; - GList *contacts, *l; - - priv = GET_PRIV (chatroom); - - contacts = empathy_tp_contact_list_get_from_handles (priv->list, handles); - for (l = contacts; l; l = l->next) { - EmpathyContact *contact; - - contact = l->data; - - g_signal_emit_by_name (chatroom, "contact-added", contact); - - g_object_unref (contact); - } - g_list_free (contacts); -} - -static void -tp_chatroom_members_removed_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpChatroom *chatroom) -{ - EmpathyTpChatroomPriv *priv; - GList *contacts, *l; - - priv = GET_PRIV (chatroom); - - contacts = empathy_tp_contact_list_get_from_handles (priv->list, handles); - for (l = contacts; l; l = l->next) { - EmpathyContact *contact; - - contact = l->data; - - g_signal_emit_by_name (chatroom, "contact-removed", contact); - - g_object_unref (contact); - } - g_list_free (contacts); + g_signal_emit_by_name (chatroom, "members-changed", + contact, actor, reason, message, + TRUE); } static void -tp_chatroom_setup (EmpathyContactList *list) -{ - /* Nothing to do */ -} - -static EmpathyContact * -tp_chatroom_find (EmpathyContactList *list, - const gchar *id) +tp_chatroom_member_removed_cb (EmpathyTpGroup *group, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + const gchar *message, + EmpathyTpChatroom *chatroom) { - return NULL; + g_signal_emit_by_name (chatroom, "members-changed", + contact, actor, reason, message, + FALSE); } static void @@ -308,9 +264,7 @@ tp_chatroom_add (EmpathyContactList *list, priv = GET_PRIV (list); - empathy_tp_group_add_member (priv->group, - empathy_contact_get_handle (contact), - message); + empathy_tp_group_add_member (priv->group, contact, message); } static void @@ -325,26 +279,18 @@ tp_chatroom_remove (EmpathyContactList *list, priv = GET_PRIV (list); - empathy_tp_group_remove_member (priv->group, - empathy_contact_get_handle (contact), - message); + empathy_tp_group_remove_member (priv->group, contact, message); } static GList * tp_chatroom_get_members (EmpathyContactList *list) { EmpathyTpChatroomPriv *priv; - GArray *members; - GList *contacts; g_return_val_if_fail (EMPATHY_IS_TP_CHATROOM (list), NULL); priv = GET_PRIV (list); - members = empathy_tp_group_get_members (priv->group); - contacts = empathy_tp_contact_list_get_from_handles (priv->list, members); - g_array_free (members, TRUE); - - return contacts; + return empathy_tp_group_get_members (priv->group); } diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c index a5c54b74..16ecad80 100644 --- a/libempathy/empathy-tp-contact-list.c +++ b/libempathy/empathy-tp-contact-list.c @@ -30,9 +30,6 @@ #include #include #include -#include -#include -#include #include "empathy-tp-contact-list.h" #include "empathy-contact-list.h" @@ -44,1065 +41,140 @@ EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv)) #define DEBUG_DOMAIN "TpContactList" -#define MAX_AVATAR_REQUESTS 10 struct _EmpathyTpContactListPriv { TpConn *tp_conn; McAccount *account; MissionControl *mc; - EmpathyContact *user_contact; - gboolean setup; const gchar *protocol_group; EmpathyTpGroup *publish; EmpathyTpGroup *subscribe; - - GHashTable *groups; - GHashTable *contacts; GList *members; - GList *local_pending; + GList *pendings; - DBusGProxy *aliasing_iface; - DBusGProxy *avatars_iface; - DBusGProxy *presence_iface; + GList *groups; + GHashTable *contacts_groups; }; typedef enum { TP_CONTACT_LIST_TYPE_PUBLISH, TP_CONTACT_LIST_TYPE_SUBSCRIBE, - TP_CONTACT_LIST_TYPE_UNKNOWN, - TP_CONTACT_LIST_TYPE_COUNT + TP_CONTACT_LIST_TYPE_UNKNOWN } TpContactListType; -typedef struct { - guint handle; - GList *new_groups; -} TpContactListData; - -typedef struct { - EmpathyTpContactList *list; - guint handle; -} TpContactListAvatarRequestData; - -typedef struct { - EmpathyTpContactList *list; - guint *handles; -} TpContactListAliasesRequestData; - -static void empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass); -static void tp_contact_list_iface_init (EmpathyContactListIface *iface); -static void empathy_tp_contact_list_init (EmpathyTpContactList *list); -static void tp_contact_list_finalize (GObject *object); -static void tp_contact_list_finalize_proxies (EmpathyTpContactList *list); -static void tp_contact_list_setup (EmpathyContactList *list); -static EmpathyContact * tp_contact_list_find (EmpathyContactList *list, - const gchar *id); -static void tp_contact_list_add (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message); -static void tp_contact_list_remove (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message); -static GList * tp_contact_list_get_members (EmpathyContactList *list); -static GList * tp_contact_list_get_local_pending (EmpathyContactList *list); -static void tp_contact_list_process_pending (EmpathyContactList *list, - EmpathyContact *contact, - gboolean accept); -static void tp_contact_list_remove_local_pending (EmpathyTpContactList *list, - EmpathyContact *contact); -static void tp_contact_list_contact_removed_foreach (guint handle, - EmpathyContact *contact, - EmpathyTpContactList *list); -static void tp_contact_list_destroy_cb (DBusGProxy *proxy, - EmpathyTpContactList *list); -static gboolean tp_contact_list_find_foreach (guint handle, - EmpathyContact *contact, - gchar *id); -static void tp_contact_list_newchannel_cb (DBusGProxy *proxy, - const gchar *object_path, - const gchar *channel_type, - TelepathyHandleType handle_type, - guint channel_handle, - gboolean suppress_handle, - EmpathyTpContactList *list); -static TpContactListType tp_contact_list_get_type (EmpathyTpContactList *list, - EmpathyTpGroup *group); -static void tp_contact_list_added_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_removed_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_pending_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_groups_updated_cb (EmpathyContact *contact, - GParamSpec *param, - EmpathyTpContactList *list); -static void tp_contact_list_name_updated_cb (EmpathyContact *contact, - GParamSpec *param, - EmpathyTpContactList *list); -static void tp_contact_list_update_groups_foreach (gchar *object_path, - EmpathyTpGroup *group, - TpContactListData *data); -static EmpathyTpGroup * tp_contact_list_get_group (EmpathyTpContactList *list, - const gchar *name); -static gboolean tp_contact_list_find_group (gchar *key, - EmpathyTpGroup *group, - gchar *group_name); -static void tp_contact_list_get_groups_foreach (gchar *key, - EmpathyTpGroup *group, - GList **groups); -static void tp_contact_list_group_channel_closed_cb (TpChan *channel, - EmpathyTpContactList *list); -static void tp_contact_list_group_members_added_cb (EmpathyTpGroup *group, - GArray *members, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_group_members_removed_cb (EmpathyTpGroup *group, - GArray *members, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_get_info (EmpathyTpContactList *list, - GArray *handles); -static void tp_contact_list_request_avatar (EmpathyTpContactList *list, - guint handle); -static void tp_contact_list_start_avatar_requests (void); -static void tp_contact_list_avatar_update_cb (DBusGProxy *proxy, - guint handle, - gchar *new_token, - EmpathyTpContactList *list); -static void tp_contact_list_request_avatar_cb (DBusGProxy *proxy, - GArray *avatar_data, - gchar *mime_type, - GError *error, - TpContactListAvatarRequestData *data); -static void tp_contact_list_aliases_update_cb (DBusGProxy *proxy, - GPtrArray *handlers, - EmpathyTpContactList *list); -static void tp_contact_list_request_aliases_cb (DBusGProxy *proxy, - gchar **contact_names, - GError *error, - TpContactListAliasesRequestData *data); -static void tp_contact_list_presence_update_cb (DBusGProxy *proxy, - GHashTable *handle_table, - EmpathyTpContactList *list); -static void tp_contact_list_parse_presence_foreach (guint handle, - GValueArray *presence_struct, - EmpathyTpContactList *list); -static void tp_contact_list_presences_table_foreach (const gchar *state_str, - GHashTable *presences_table, - EmpathyPresence **presence); -static void tp_contact_list_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - EmpathyTpContactList *list); - -enum { - DESTROY, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; -GList *avatar_requests_queue = NULL; -guint n_avatar_requests = 0; - -G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST, - tp_contact_list_iface_init)); - -static void -empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = tp_contact_list_finalize; - - signals[DESTROY] = - g_signal_new ("destroy", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv)); -} - -static void -tp_contact_list_iface_init (EmpathyContactListIface *iface) -{ - iface->setup = tp_contact_list_setup; - iface->find = tp_contact_list_find; - iface->add = tp_contact_list_add; - iface->remove = tp_contact_list_remove; - iface->get_members = tp_contact_list_get_members; - iface->get_local_pending = tp_contact_list_get_local_pending; - iface->process_pending = tp_contact_list_process_pending; -} - -static void -empathy_tp_contact_list_init (EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - - priv = GET_PRIV (list); - - priv->groups = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); - priv->contacts = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, - (GDestroyNotify) g_object_unref); -} - -static void -tp_contact_list_finalize (GObject *object) -{ - EmpathyTpContactListPriv *priv; - EmpathyTpContactList *list; - - list = EMPATHY_TP_CONTACT_LIST (object); - priv = GET_PRIV (list); - - empathy_debug (DEBUG_DOMAIN, "finalize: %p", object); - - dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), - "AccountStatusChanged", - G_CALLBACK (tp_contact_list_status_changed_cb), - list); - - tp_contact_list_finalize_proxies (list); - - if (priv->tp_conn) { - g_object_unref (priv->tp_conn); - } - if (priv->subscribe) { - g_object_unref (priv->subscribe); - } - if (priv->publish) { - g_object_unref (priv->publish); - } - - g_object_unref (priv->account); - g_object_unref (priv->user_contact); - g_object_unref (priv->mc); - g_hash_table_destroy (priv->groups); - g_hash_table_destroy (priv->contacts); - - g_list_foreach (priv->local_pending, (GFunc) empathy_contact_list_info_free, NULL); - g_list_free (priv->local_pending); - - g_list_foreach (priv->members, (GFunc) g_object_unref, NULL); - g_list_free (priv->members); - - G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object); -} - -EmpathyTpContactList * -empathy_tp_contact_list_new (McAccount *account) -{ - EmpathyTpContactListPriv *priv; - EmpathyTpContactList *list; - MissionControl *mc; - McProfile *profile; - const gchar *protocol_name; - guint handle; - GError *error = NULL; - - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - - mc = empathy_mission_control_new (); - - if (mission_control_get_connection_status (mc, account, NULL) != 0) { - /* The account is not connected, nothing to do. */ - return NULL; - } - - list = g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, NULL); - priv = GET_PRIV (list); - - priv->tp_conn = mission_control_get_connection (mc, account, NULL); - priv->account = g_object_ref (account); - priv->mc = mc; - - /* Check for protocols that does not support contact groups. We can - * put all contacts into a special group in that case. - * FIXME: Default group should be an information in the profile */ - profile = mc_account_get_profile (account); - protocol_name = mc_profile_get_protocol_name (profile); - if (strcmp (protocol_name, "local-xmpp") == 0) { - priv->protocol_group = _("People nearby"); - } - g_object_unref (profile); - - g_signal_connect (priv->tp_conn, "destroy", - G_CALLBACK (tp_contact_list_destroy_cb), - list); - dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), - "AccountStatusChanged", - G_CALLBACK (tp_contact_list_status_changed_cb), - list, NULL); - - priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn, - TELEPATHY_CONN_IFACE_ALIASING_QUARK); - priv->avatars_iface = tp_conn_get_interface (priv->tp_conn, - TELEPATHY_CONN_IFACE_AVATARS_QUARK); - priv->presence_iface = tp_conn_get_interface (priv->tp_conn, - TELEPATHY_CONN_IFACE_PRESENCE_QUARK); - - if (priv->aliasing_iface) { - dbus_g_proxy_connect_signal (priv->aliasing_iface, - "AliasesChanged", - G_CALLBACK (tp_contact_list_aliases_update_cb), - list, NULL); - } - - if (priv->avatars_iface) { - dbus_g_proxy_connect_signal (priv->avatars_iface, - "AvatarUpdated", - G_CALLBACK (tp_contact_list_avatar_update_cb), - list, NULL); - } - - if (priv->presence_iface) { - dbus_g_proxy_connect_signal (priv->presence_iface, - "PresenceUpdate", - G_CALLBACK (tp_contact_list_presence_update_cb), - list, NULL); - } - - /* Get our own handle and contact */ - if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn), - &handle, &error)) { - empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } else { - priv->user_contact = empathy_tp_contact_list_get_from_handle (list, handle); - empathy_contact_set_is_user (priv->user_contact, TRUE); - } - - return list; -} - -static void -tp_contact_list_setup (EmpathyContactList *list) -{ - EmpathyTpContactListPriv *priv; - GPtrArray *channels; - GError *error = NULL; - guint i; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - - priv = GET_PRIV (list); - - empathy_debug (DEBUG_DOMAIN, "setup contact list: %p", list); - - priv->setup = TRUE; - dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel", - G_CALLBACK (tp_contact_list_newchannel_cb), - list, NULL); - - /* Get existing channels */ - if (!tp_conn_list_channels (DBUS_G_PROXY (priv->tp_conn), - &channels, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Failed to get list of open channels: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return; - } - - for (i = 0; channels->len > i; i++) { - GValueArray *chan_struct; - const gchar *object_path; - const gchar *chan_iface; - TelepathyHandleType handle_type; - guint handle; - - chan_struct = g_ptr_array_index (channels, i); - object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0)); - chan_iface = g_value_get_string (g_value_array_get_nth (chan_struct, 1)); - handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2)); - handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3)); - - tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn), - object_path, chan_iface, - handle_type, handle, - FALSE, - EMPATHY_TP_CONTACT_LIST (list)); - - g_value_array_free (chan_struct); - } - - g_ptr_array_free (channels, TRUE); -} - -static EmpathyContact * -tp_contact_list_find (EmpathyContactList *list, - const gchar *id) -{ - EmpathyTpContactListPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - priv = GET_PRIV (list); - - return g_hash_table_find (priv->contacts, - (GHRFunc) tp_contact_list_find_foreach, - (gchar*) id); -} - -static void -tp_contact_list_add (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message) -{ - EmpathyTpContactListPriv *priv; - guint handle; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - - priv = GET_PRIV (list); - - handle = empathy_contact_get_handle (contact); - empathy_tp_group_add_member (priv->subscribe, handle, message); -} - -static void -tp_contact_list_remove (EmpathyContactList *list, - EmpathyContact *contact, - const gchar *message) -{ - EmpathyTpContactListPriv *priv; - guint handle; +static void empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass); +static void empathy_tp_contact_list_init (EmpathyTpContactList *list); +static void tp_contact_list_iface_init (EmpathyContactListIface *iface); - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - - priv = GET_PRIV (list); - - handle = empathy_contact_get_handle (contact); - empathy_tp_group_remove_member (priv->subscribe, handle, message); -} - -static GList * -tp_contact_list_get_members (EmpathyContactList *list) -{ - EmpathyTpContactListPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - priv = GET_PRIV (list); - - g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); - return g_list_copy (priv->members); -} - -static GList * -tp_contact_list_get_local_pending (EmpathyContactList *list) -{ - EmpathyTpContactListPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - priv = GET_PRIV (list); - - return g_list_copy (priv->local_pending); -} - -static void -tp_contact_list_process_pending (EmpathyContactList *list, - EmpathyContact *contact, - gboolean accept) -{ - EmpathyTpContactListPriv *priv; - guint handle; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - priv = GET_PRIV (list); - - handle = empathy_contact_get_handle (contact); - if (accept) { - empathy_tp_group_add_member (priv->publish, handle, NULL); - empathy_tp_group_add_member (priv->subscribe, handle, NULL); - } else { - empathy_tp_group_remove_member (priv->publish, handle, NULL); - } -} - -McAccount * -empathy_tp_contact_list_get_account (EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - priv = GET_PRIV (list); - - return priv->account; -} - -EmpathyContact * -empathy_tp_contact_list_get_user (EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - priv = GET_PRIV (list); - - return priv->user_contact; -} - -EmpathyContact * -empathy_tp_contact_list_get_from_id (EmpathyTpContactList *list, - const gchar *id) -{ - EmpathyTpContactListPriv *priv; - EmpathyContact *contact; - const gchar *contact_ids[] = {id, NULL}; - GArray *handles; - guint handle; - GError *error = NULL; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - g_return_val_if_fail (id != NULL, NULL); - - priv = GET_PRIV (list); - - contact = tp_contact_list_find (EMPATHY_CONTACT_LIST (list), id); - if (contact) { - return g_object_ref (contact); - } - - /* The id is unknown, requests a new handle */ - if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn), - TP_HANDLE_TYPE_CONTACT, - contact_ids, - &handles, &error)) { - empathy_debug (DEBUG_DOMAIN, - "RequestHandle for %s failed: %s", id, - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - - handle = g_array_index(handles, guint, 0); - g_array_free (handles, TRUE); - - return empathy_tp_contact_list_get_from_handle (list, handle); -} - -EmpathyContact * -empathy_tp_contact_list_get_from_handle (EmpathyTpContactList *list, - guint handle) -{ - EmpathyContact *contact; - GArray *handles; - GList *contacts; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, handle); - - contacts = empathy_tp_contact_list_get_from_handles (list, handles); - g_array_free (handles, TRUE); - - if (!contacts) { - return NULL; - } - - contact = contacts->data; - g_list_free (contacts); - - return contact; -} - -GList * -empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list, - GArray *handles) -{ - EmpathyTpContactListPriv *priv; - gchar **handles_names; - gchar **id; - GArray *new_handles; - GList *contacts = NULL; - guint i; - GError *error = NULL; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - g_return_val_if_fail (handles != NULL, NULL); - - priv = GET_PRIV (list); - - /* Search all handles we already have */ - new_handles = g_array_new (FALSE, FALSE, sizeof (guint)); - for (i = 0; i < handles->len; i++) { - EmpathyContact *contact; - guint handle; - - handle = g_array_index (handles, guint, i); - - if (handle == 0) { - continue; - } - - contact = g_hash_table_lookup (priv->contacts, - GUINT_TO_POINTER (handle)); - - if (contact) { - contacts = g_list_prepend (contacts, - g_object_ref (contact)); - } else { - g_array_append_val (new_handles, handle); - } - } - - if (new_handles->len == 0) { - g_array_free (new_handles, TRUE); - return contacts; - } - - /* Holds all handles we don't have yet. - * FIXME: We should release them at some point. */ - if (!tp_conn_hold_handles (DBUS_G_PROXY (priv->tp_conn), - TP_HANDLE_TYPE_CONTACT, - new_handles, &error)) { - empathy_debug (DEBUG_DOMAIN, - "HoldHandles Error: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - g_array_free (new_handles, TRUE); - return contacts; - } - - /* Get the IDs of all new handles */ - if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn), - TP_HANDLE_TYPE_CONTACT, - new_handles, - &handles_names, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "InspectHandle Error: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - g_array_free (new_handles, TRUE); - return contacts; - } - - /* Create contact objects */ - for (i = 0, id = handles_names; *id && i < new_handles->len; id++, i++) { - EmpathyContact *contact; - guint handle; - - handle = g_array_index (new_handles, guint, i); - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", priv->account, - "id", *id, - "handle", handle, - NULL); - - if (priv->protocol_group) { - empathy_contact_add_group (contact, priv->protocol_group); - } - - if (!priv->presence_iface) { - EmpathyPresence *presence; - - /* We have no presence iface, set default presence - * to available */ - presence = empathy_presence_new_full (MC_PRESENCE_AVAILABLE, - NULL); - - empathy_contact_set_presence (contact, presence); - g_object_unref (presence); - } - - g_signal_connect (contact, "notify::groups", - G_CALLBACK (tp_contact_list_groups_updated_cb), - list); - g_signal_connect (contact, "notify::name", - G_CALLBACK (tp_contact_list_name_updated_cb), - list); - - empathy_debug (DEBUG_DOMAIN, "new contact created: %s (%d)", - *id, handle); - - g_hash_table_insert (priv->contacts, - GUINT_TO_POINTER (handle), - contact); - - contacts = g_list_prepend (contacts, g_object_ref (contact)); - } - - tp_contact_list_get_info (list, new_handles); - - g_array_free (new_handles, TRUE); - g_strfreev (handles_names); - - return contacts; -} - -void -empathy_tp_contact_list_rename_group (EmpathyTpContactList *list, - const gchar *old_group, - const gchar *new_group) -{ - EmpathyTpContactListPriv *priv; - EmpathyTpGroup *group; - GArray *members; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - g_return_if_fail (old_group != NULL); - g_return_if_fail (new_group != NULL); - - priv = GET_PRIV (list); - - group = g_hash_table_find (priv->groups, - (GHRFunc) tp_contact_list_find_group, - (gchar*) old_group); - if (!group) { - /* The group doesn't exists on this account */ - return; - } - - empathy_debug (DEBUG_DOMAIN, "rename group %s to %s", group, new_group); - - /* Remove all members from the old group */ - members = empathy_tp_group_get_members (group); - empathy_tp_group_remove_members (group, members, ""); - tp_contact_list_group_members_removed_cb (group, members, - 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE, - NULL, list); - g_hash_table_remove (priv->groups, - empathy_tp_group_get_object_path (group)); - - /* Add all members to the new group */ - group = tp_contact_list_get_group (list, new_group); - if (group) { - empathy_tp_group_add_members (group, members, ""); - } -} - -GList * -empathy_tp_contact_list_get_groups (EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - GList *groups = NULL; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - priv = GET_PRIV (list); - - g_hash_table_foreach (priv->groups, - (GHFunc) tp_contact_list_get_groups_foreach, - &groups); - - groups = g_list_sort (groups, (GCompareFunc) strcmp); - - return groups; -} - -static void -tp_contact_list_finalize_proxies (EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - - priv = GET_PRIV (list); - - if (priv->tp_conn) { - g_signal_handlers_disconnect_by_func (priv->tp_conn, - tp_contact_list_destroy_cb, - list); - dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel", - G_CALLBACK (tp_contact_list_newchannel_cb), - list); - } - - if (priv->aliasing_iface) { - dbus_g_proxy_disconnect_signal (priv->aliasing_iface, - "AliasesChanged", - G_CALLBACK (tp_contact_list_aliases_update_cb), - list); - } - - if (priv->avatars_iface) { - dbus_g_proxy_disconnect_signal (priv->avatars_iface, - "AvatarUpdated", - G_CALLBACK (tp_contact_list_avatar_update_cb), - list); - } - - if (priv->presence_iface) { - dbus_g_proxy_disconnect_signal (priv->presence_iface, - "PresenceUpdate", - G_CALLBACK (tp_contact_list_presence_update_cb), - list); - } -} - -static void -tp_contact_list_destroy_cb (DBusGProxy *proxy, - EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - - priv = GET_PRIV (list); - - empathy_debug (DEBUG_DOMAIN, "Connection destroyed... " - "Account disconnected or CM crashed"); - - /* DBus proxies should NOT be used anymore */ - g_object_unref (priv->tp_conn); - priv->tp_conn = NULL; - priv->aliasing_iface = NULL; - priv->avatars_iface = NULL; - priv->presence_iface = NULL; - - /* Remove all contacts */ - g_hash_table_foreach (priv->contacts, - (GHFunc) tp_contact_list_contact_removed_foreach, - list); - g_hash_table_remove_all (priv->contacts); - - /* Tell the world to not use us anymore */ - g_signal_emit (list, signals[DESTROY], 0); -} - -static void -tp_contact_list_contact_removed_foreach (guint handle, - EmpathyContact *contact, - EmpathyTpContactList *list) -{ - g_signal_handlers_disconnect_by_func (contact, - tp_contact_list_groups_updated_cb, - list); - g_signal_handlers_disconnect_by_func (contact, - tp_contact_list_name_updated_cb, - list); - - g_signal_emit_by_name (list, "contact-removed", contact); -} - -static void -tp_contact_list_block_contact (EmpathyTpContactList *list, - EmpathyContact *contact) -{ - g_signal_handlers_block_by_func (contact, - tp_contact_list_groups_updated_cb, - list); - g_signal_handlers_block_by_func (contact, - tp_contact_list_name_updated_cb, - list); -} - -static void -tp_contact_list_unblock_contact (EmpathyTpContactList *list, - EmpathyContact *contact) -{ - g_signal_handlers_unblock_by_func (contact, - tp_contact_list_groups_updated_cb, - list); - g_signal_handlers_unblock_by_func (contact, - tp_contact_list_name_updated_cb, - list); -} - -static gboolean -tp_contact_list_find_foreach (guint handle, - EmpathyContact *contact, - gchar *id) -{ - if (strcmp (empathy_contact_get_id (contact), id) == 0) { - return TRUE; - } - - return FALSE; -} - -static void -tp_contact_list_newchannel_cb (DBusGProxy *proxy, - const gchar *object_path, - const gchar *channel_type, - TelepathyHandleType handle_type, - guint channel_handle, - gboolean suppress_handle, - EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - EmpathyTpGroup *group; - TpChan *new_chan; - const gchar *bus_name; - GArray *members; - - priv = GET_PRIV (list); - - if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 || - suppress_handle || - !priv->setup) { - return; - } - - bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn)); - new_chan = tp_chan_new (tp_get_bus (), - bus_name, - object_path, - channel_type, handle_type, channel_handle); - g_return_if_fail (TELEPATHY_IS_CHAN (new_chan)); - - if (handle_type == TP_HANDLE_TYPE_LIST) { - TpContactListType list_type; - - group = empathy_tp_group_new (priv->account, new_chan); - - list_type = tp_contact_list_get_type (list, group); - if (list_type == TP_CONTACT_LIST_TYPE_UNKNOWN) { - empathy_debug (DEBUG_DOMAIN, - "Type of contact list channel unknown: %s", - empathy_tp_group_get_name (group)); - - g_object_unref (new_chan); - g_object_unref (group); - return; - } else { - empathy_debug (DEBUG_DOMAIN, - "New contact list channel of type: %d", - list_type); - } - - g_signal_connect (group, "members-added", - G_CALLBACK (tp_contact_list_added_cb), - list); - g_signal_connect (group, "members-removed", - G_CALLBACK (tp_contact_list_removed_cb), - list); +enum { + DESTROY, + LAST_SIGNAL +}; - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { - GList *pendings, *l; +static guint signals[LAST_SIGNAL]; - if (priv->publish) { - g_object_unref (priv->publish); - } - priv->publish = group; +G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST, + tp_contact_list_iface_init)); - /* Makes no sense to be in remote-pending */ - g_signal_connect (group, "local-pending", - G_CALLBACK (tp_contact_list_pending_cb), - list); +static void +tp_contact_list_group_destroy_cb (EmpathyTpGroup *group, + EmpathyTpContactList *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); - pendings = empathy_tp_group_get_local_pending_members_with_info (group); - if (pendings) { - GArray *pending; - - pending = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - for (l = pendings; l; l = l->next) { - EmpathyTpGroupInfo *info; - - info = l->data; - - g_array_insert_val (pending, 0, info->member); - tp_contact_list_pending_cb (group, pending, - info->actor, - info->reason, - info->message, - list); - } - g_array_free (pending, TRUE); - empathy_tp_group_info_list_free (pendings); - } - } - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - GArray *remote_pendings = NULL; + empathy_debug (DEBUG_DOMAIN, "Group destroyed: %s", + empathy_tp_group_get_name (group)); - if (priv->subscribe) { - g_object_unref (priv->subscribe); - } - priv->subscribe = group; + priv->groups = g_list_remove (priv->groups, group); + g_object_unref (group); +} - /* Makes no sense to be in local-pending */ - g_signal_connect (group, "remote-pending", - G_CALLBACK (tp_contact_list_pending_cb), - list); - empathy_tp_group_get_all_members (group, - &members, - NULL, - &remote_pendings); - - tp_contact_list_pending_cb (group, remote_pendings, 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE, - NULL, - list); - g_array_free (remote_pendings, TRUE); - } else { - members = empathy_tp_group_get_members (group); - } +static void +tp_contact_list_group_member_added_cb (EmpathyTpGroup *group, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + const gchar *message, + EmpathyTpContactList *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + const gchar *group_name; + GList **groups; - tp_contact_list_added_cb (group, members, 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE, - NULL, list); - g_array_free (members, TRUE); + if (!g_list_find (priv->members, contact)) { + return; } - else if (handle_type == TP_HANDLE_TYPE_GROUP) { - const gchar *object_path; - object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (new_chan)); - if (g_hash_table_lookup (priv->groups, object_path)) { - g_object_unref (new_chan); - return; - } + groups = g_hash_table_lookup (priv->contacts_groups, contact); + if (!groups) { + groups = g_slice_new0 (GList*); + g_hash_table_insert (priv->contacts_groups, + g_object_ref (contact), + groups); + } - group = empathy_tp_group_new (priv->account, new_chan); + group_name = empathy_tp_group_get_name (group); + if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) { + empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to group %s", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + group_name); + *groups = g_list_prepend (*groups, g_strdup (group_name)); + g_signal_emit_by_name (list, "groups-changed", contact, + group_name, + TRUE); + } +} - empathy_debug (DEBUG_DOMAIN, "New server-side group channel: %s", - empathy_tp_group_get_name (group)); +static void +tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + const gchar *message, + EmpathyTpContactList *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + const gchar *group_name; + GList **groups, *l; - dbus_g_proxy_connect_signal (DBUS_G_PROXY (new_chan), "Closed", - G_CALLBACK - (tp_contact_list_group_channel_closed_cb), - list, NULL); + if (!g_list_find (priv->members, contact)) { + return; + } - g_hash_table_insert (priv->groups, g_strdup (object_path), group); - g_signal_connect (group, "members-added", - G_CALLBACK (tp_contact_list_group_members_added_cb), - list); - g_signal_connect (group, "members-removed", - G_CALLBACK (tp_contact_list_group_members_removed_cb), - list); + groups = g_hash_table_lookup (priv->contacts_groups, contact); + if (!groups) { + return; + } - members = empathy_tp_group_get_members (group); - tp_contact_list_group_members_added_cb (group, members, 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE, - NULL, list); - g_array_free (members, TRUE); + group_name = empathy_tp_group_get_name (group); + if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) { + empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from group %s", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + group_name); + *groups = g_list_delete_link (*groups, l); + g_signal_emit_by_name (list, "groups-changed", contact, + group_name, + FALSE); } +} - g_object_unref (new_chan); +static EmpathyTpGroup * +tp_contact_list_find_group (EmpathyTpContactList *list, + const gchar *group) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *l; + + for (l = priv->groups; l; l = l->next) { + if (strcmp (group, empathy_tp_group_get_name (l->data)) == 0) { + return l->data; + } + } + return NULL; } static TpContactListType @@ -1127,808 +199,795 @@ tp_contact_list_get_type (EmpathyTpContactList *list, return list_type; } +static void +tp_contact_list_add_member (EmpathyTpContactList *list, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + const gchar *message) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *l; + + /* Add to the list and emit signal */ + priv->members = g_list_prepend (priv->members, g_object_ref (contact)); + g_signal_emit_by_name (list, "members-changed", + contact, actor, reason, message, + TRUE); + + /* This contact is now member, implicitly accept pending. */ + if (g_list_find (priv->pendings, contact)) { + empathy_tp_group_add_member (priv->publish, contact, ""); + } + + /* Update groups of the contact */ + for (l = priv->groups; l; l = l->next) { + if (empathy_tp_group_is_member (l->data, contact)) { + tp_contact_list_group_member_added_cb (l->data, contact, + NULL, 0, NULL, + list); + } + } +} + static void tp_contact_list_added_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, + EmpathyContact *contact, + EmpathyContact *actor, guint reason, const gchar *message, EmpathyTpContactList *list) { - EmpathyTpContactListPriv *priv; - GList *added_list, *l; + EmpathyTpContactListPriv *priv = GET_PRIV (list); TpContactListType list_type; - priv = GET_PRIV (list); - list_type = tp_contact_list_get_type (list, group); - - added_list = empathy_tp_contact_list_get_from_handles (list, handles); - for (l = added_list; l; l = l->next) { - EmpathyContact *contact; - EmpathySubscription subscription; - - contact = EMPATHY_CONTACT (l->data); - - empathy_debug (DEBUG_DOMAIN, "Contact '%s' added to list type %d", - empathy_contact_get_name (contact), - list_type); - - subscription = empathy_contact_get_subscription (contact); - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - subscription |= EMPATHY_SUBSCRIPTION_FROM; - } - else if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { - subscription |= EMPATHY_SUBSCRIPTION_TO; - tp_contact_list_remove_local_pending (list, contact); - } - - tp_contact_list_block_contact (list, contact); - empathy_contact_set_subscription (contact, subscription); - tp_contact_list_unblock_contact (list, contact); - - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - if (!g_list_find (priv->members, contact)) { - priv->members = g_list_prepend (priv->members, - g_object_ref (contact)); - g_signal_emit_by_name (list, "contact-added", contact); - } - } - + empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to list type %d", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + list_type); + + /* We now get the presence of that contact, add it to members */ + if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && + !g_list_find (priv->members, contact)) { + tp_contact_list_add_member (list, contact, actor, reason, message); + } + + /* We now send our presence to that contact, remove it from pendings */ + if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && + g_list_find (priv->pendings, contact)) { + g_signal_emit_by_name (list, "pendings-changed", + contact, actor, reason, message, + FALSE); + priv->pendings = g_list_remove (priv->pendings, contact); g_object_unref (contact); } - - g_list_free (added_list); } static void tp_contact_list_removed_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, + EmpathyContact *contact, + EmpathyContact *actor, guint reason, const gchar *message, EmpathyTpContactList *list) { - EmpathyTpContactListPriv *priv; - GList *removed_list, *l; + EmpathyTpContactListPriv *priv = GET_PRIV (list); TpContactListType list_type; - priv = GET_PRIV (list); - list_type = tp_contact_list_get_type (list, group); - - removed_list = empathy_tp_contact_list_get_from_handles (list, handles); - for (l = removed_list; l; l = l->next) { - EmpathyContact *contact; - EmpathySubscription subscription; - - contact = EMPATHY_CONTACT (l->data); - - empathy_debug (DEBUG_DOMAIN, "Contact '%s' removed from list type %d", - empathy_contact_get_name (contact), - list_type); - - subscription = empathy_contact_get_subscription (contact); - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - subscription &= !EMPATHY_SUBSCRIPTION_FROM; - } - else if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { - subscription &= !EMPATHY_SUBSCRIPTION_TO; - tp_contact_list_remove_local_pending (list, contact); - } - - tp_contact_list_block_contact (list, contact); - empathy_contact_set_subscription (contact, subscription); - tp_contact_list_unblock_contact (list, contact); - - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - GList *l; - - if ((l = g_list_find (priv->members, contact))) { - g_signal_emit_by_name (list, "contact-removed", contact); - priv->members = g_list_delete_link (priv->members, l); - g_object_unref (contact); - } - } + empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from list type %d", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + list_type); + + /* This contact refuses to send us his presence, remove from members. */ + if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && + g_list_find (priv->members, contact)) { + g_signal_emit_by_name (list, "members-changed", + contact, actor, reason, message, + FALSE); + priv->members = g_list_remove (priv->members, contact); g_object_unref (contact); } - g_list_free (removed_list); + /* We refuse to send our presence to that contact, remove from pendings */ + if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && + g_list_find (priv->pendings, contact)) { + g_signal_emit_by_name (list, "pendings-changed", + contact, actor, reason, message, + FALSE); + priv->pendings = g_list_remove (priv->pendings, contact); + g_object_unref (contact); + } } static void tp_contact_list_pending_cb (EmpathyTpGroup *group, - GArray *handles, - guint actor_handle, + EmpathyContact *contact, + EmpathyContact *actor, guint reason, const gchar *message, EmpathyTpContactList *list) { - EmpathyTpContactListPriv *priv; - GList *pending_list, *l; + EmpathyTpContactListPriv *priv = GET_PRIV (list); TpContactListType list_type; - priv = GET_PRIV (list); - list_type = tp_contact_list_get_type (list, group); - - pending_list = empathy_tp_contact_list_get_from_handles (list, handles); - for (l = pending_list; l; l = l->next) { - EmpathyContact *contact; - - contact = EMPATHY_CONTACT (l->data); - - empathy_debug (DEBUG_DOMAIN, "Contact '%s' pending in list type %d", - empathy_contact_get_name (contact), - list_type); - - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { - if (!g_list_find (priv->members, contact)) { - EmpathyContactListInfo *info; - - info = empathy_contact_list_info_new (contact, message); - priv->local_pending = g_list_prepend (priv->local_pending, - info); - - g_signal_emit_by_name (list, "local-pending", - contact, message); - } else { - guint handle; - - /* That contact wants our presence and he is - * in our roster. Accept to publish our presence - * without asking the user. */ - handle = empathy_contact_get_handle (contact); - empathy_tp_group_add_member (priv->publish, - handle, ""); - } - } - else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - if (!g_list_find (priv->members, contact)) { - priv->members = g_list_prepend (priv->members, - g_object_ref (contact)); - g_signal_emit_by_name (list, "contact-added", contact); - } + empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) pending in list type %d", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + list_type); + + /* We want this contact in our contact list but we don't get its + * presence yet. Add to members anyway. */ + if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && + !g_list_find (priv->members, contact)) { + tp_contact_list_add_member (list, contact, actor, reason, message); + } + + /* This contact wants our presence, auto accept if he is member, + * otherwise he is pending. */ + if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && + !g_list_find (priv->pendings, contact)) { + if (g_list_find (priv->members, contact)) { + empathy_tp_group_add_member (priv->publish, contact, ""); + } else { + priv->pendings = g_list_prepend (priv->pendings, + g_object_ref (contact)); + g_signal_emit_by_name (list, "pendings-changed", + contact, actor, reason, message, + TRUE); } - - g_object_unref (contact); } - - g_list_free (pending_list); } static void -tp_contact_list_remove_local_pending (EmpathyTpContactList *list, - EmpathyContact *contact) +tp_contact_list_newchannel_cb (DBusGProxy *proxy, + const gchar *object_path, + const gchar *channel_type, + TelepathyHandleType handle_type, + guint channel_handle, + gboolean suppress_handle, + EmpathyTpContactList *list) { - EmpathyTpContactListPriv *priv; - GList *l; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + EmpathyTpGroup *group; + TpChan *new_chan; + const gchar *bus_name; - priv = GET_PRIV (list); + if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 || + suppress_handle) { + return; + } - for (l = priv->local_pending; l; l = l->next) { - EmpathyContactListInfo *info; + bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn)); + new_chan = tp_chan_new (tp_get_bus (), + bus_name, + object_path, + channel_type, + handle_type, + channel_handle); + g_return_if_fail (TELEPATHY_IS_CHAN (new_chan)); - info = l->data; - if (empathy_contact_equal (contact, info->contact)) { - empathy_debug (DEBUG_DOMAIN, "Contact no more local-pending: %s", - empathy_contact_get_name (contact)); + group = empathy_tp_group_new (priv->account, new_chan); + g_object_unref (new_chan); - priv->local_pending = g_list_delete_link (priv->local_pending, l); - empathy_contact_list_info_free (info); - break; - } - } -} + if (handle_type == TP_HANDLE_TYPE_LIST) { + TpContactListType list_type; + GList *contacts, *l; -static void -tp_contact_list_groups_updated_cb (EmpathyContact *contact, - GParamSpec *param, - EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - TpContactListData data; - GList *groups, *l; + list_type = tp_contact_list_get_type (list, group); + if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) { + priv->publish = group; - priv = GET_PRIV (list); + /* Publish is the list of contacts to who we send our + * presence. Makes no sense to be in remote-pending */ + g_signal_connect (group, "local-pending", + G_CALLBACK (tp_contact_list_pending_cb), + list); - /* Make sure all groups are created */ - groups = empathy_contact_get_groups (contact); - for (l = groups; l; l = l->next) { - tp_contact_list_get_group (list, l->data); - } + contacts = empathy_tp_group_get_local_pendings (group); + for (l = contacts; l; l = l->next) { + EmpathyPendingInfo *info = l->data; + + tp_contact_list_pending_cb (group, + info->member, + info->actor, + 0, + info->message, + list); + empathy_pending_info_free (info); + } + g_list_free (contacts); + } + else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) { + priv->subscribe = group; - data.handle = empathy_contact_get_handle (contact); - data.new_groups = groups; + /* Subscribe is the list of contacts from who we + * receive presence. Makes no sense to be in + * local-pending */ + g_signal_connect (group, "remote-pending", + G_CALLBACK (tp_contact_list_pending_cb), + list); - g_hash_table_foreach (priv->groups, - (GHFunc) tp_contact_list_update_groups_foreach, - &data); -} + contacts = empathy_tp_group_get_remote_pendings (group); + for (l = contacts; l; l = l->next) { + tp_contact_list_pending_cb (group, + l->data, + NULL, 0, + NULL, list); + g_object_unref (l->data); + } + g_list_free (contacts); + } else { + empathy_debug (DEBUG_DOMAIN, + "Type of contact list channel unknown " + "or aleady have that list: %s", + empathy_tp_group_get_name (group)); + g_object_unref (group); + return; + } + empathy_debug (DEBUG_DOMAIN, + "New contact list channel of type: %d", + list_type); -static void -tp_contact_list_name_updated_cb (EmpathyContact *contact, - GParamSpec *param, - EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - GHashTable *new_alias; - const gchar *new_name; - guint handle; - GError *error = NULL; + g_signal_connect (group, "member-added", + G_CALLBACK (tp_contact_list_added_cb), + list); + g_signal_connect (group, "member-removed", + G_CALLBACK (tp_contact_list_removed_cb), + list); - priv = GET_PRIV (list); - - if (!priv->aliasing_iface) { - return; + contacts = empathy_tp_group_get_members (group); + for (l = contacts; l; l = l->next) { + tp_contact_list_added_cb (group, + l->data, + NULL, 0, NULL, + list); + g_object_unref (l->data); + } + g_list_free (contacts); } + else if (handle_type == TP_HANDLE_TYPE_GROUP) { + const gchar *group_name; + GList *contacts, *l; - handle = empathy_contact_get_handle (contact); - new_name = empathy_contact_get_name (contact); + /* Check if already exists */ + group_name = empathy_tp_group_get_name (group); + if (tp_contact_list_find_group (list, group_name)) { + g_object_unref (group); + return; + } - empathy_debug (DEBUG_DOMAIN, "renaming handle %d to %s", - handle, new_name); + empathy_debug (DEBUG_DOMAIN, "New server-side group channel: %s", + group_name); - new_alias = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, - g_free); + priv->groups = g_list_prepend (priv->groups, group); - g_hash_table_insert (new_alias, - GUINT_TO_POINTER (handle), - g_strdup (new_name)); + g_signal_connect (group, "member-added", + G_CALLBACK (tp_contact_list_group_member_added_cb), + list); + g_signal_connect (group, "member-removed", + G_CALLBACK (tp_contact_list_group_member_removed_cb), + list); + g_signal_connect (group, "destroy", + G_CALLBACK (tp_contact_list_group_destroy_cb), + list); - if (!tp_conn_iface_aliasing_set_aliases (priv->aliasing_iface, - new_alias, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Couldn't rename contact: %s", - error ? error->message : "No error given"); - g_clear_error (&error); + contacts = empathy_tp_group_get_members (group); + for (l = contacts; l; l = l->next) { + tp_contact_list_group_member_added_cb (group, l->data, + NULL, 0, NULL, + list); + g_object_unref (l->data); + } + g_list_free (contacts); + } else { + empathy_debug (DEBUG_DOMAIN, + "Unknown handle type (%d) for contact list channel", + handle_type); + g_object_unref (group); } - - g_hash_table_destroy (new_alias); } static void -tp_contact_list_update_groups_foreach (gchar *object_path, - EmpathyTpGroup *group, - TpContactListData *data) +tp_contact_list_remove_all (EmpathyTpContactList *list) { - gboolean is_member; - gboolean found = FALSE; - const gchar *group_name; - GList *l; - - is_member = empathy_tp_group_is_member (group, data->handle); - group_name = empathy_tp_group_get_name (group); + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *l; - for (l = data->new_groups; l; l = l->next) { - if (strcmp (group_name, l->data) == 0) { - found = TRUE; - break; - } + for (l = priv->members; l; l = l->next) { + g_signal_emit_by_name (list, "members-changed", l->data, + NULL, 0, NULL, + FALSE); + g_object_unref (l->data); } - - if (is_member && !found) { - /* We are no longer member of this group */ - empathy_debug (DEBUG_DOMAIN, "Contact %d removed from group '%s'", - data->handle, group_name); - empathy_tp_group_remove_member (group, data->handle, ""); + for (l = priv->pendings; l; l = l->next) { + g_signal_emit_by_name (list, "pendings-changed", l->data, + NULL, 0, NULL, + FALSE); + g_object_unref (l->data); } - if (!is_member && found) { - /* We are now member of this group */ - empathy_debug (DEBUG_DOMAIN, "Contact %d added to group '%s'", - data->handle, group_name); - empathy_tp_group_add_member (group, data->handle, ""); - } + g_list_free (priv->members); + g_list_free (priv->pendings); + priv->members = NULL; + priv->pendings = NULL; } -static EmpathyTpGroup * -tp_contact_list_get_group (EmpathyTpContactList *list, - const gchar *name) +static void +tp_contact_list_destroy_cb (TpConn *tp_conn, + EmpathyTpContactList *list) { - EmpathyTpContactListPriv *priv; - EmpathyTpGroup *group; - TpChan *group_channel; - GArray *handles; - guint group_handle; - char *group_object_path; - const char *names[2] = {name, NULL}; - GError *error = NULL; + EmpathyTpContactListPriv *priv = GET_PRIV (list); - priv = GET_PRIV (list); - - group = g_hash_table_find (priv->groups, - (GHRFunc) tp_contact_list_find_group, - (gchar*) name); - if (group) { - return group; - } + empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed"); - empathy_debug (DEBUG_DOMAIN, "creating new group: %s", name); + /* DBus proxie should NOT be used anymore */ + g_object_unref (priv->tp_conn); + priv->tp_conn = NULL; - if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn), - TP_HANDLE_TYPE_GROUP, - names, - &handles, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Couldn't request the creation of a new handle for group: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - group_handle = g_array_index (handles, guint, 0); - g_array_free (handles, TRUE); + tp_contact_list_remove_all (list); - if (!tp_conn_request_channel (DBUS_G_PROXY (priv->tp_conn), - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_GROUP, - group_handle, - FALSE, - &group_object_path, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Couldn't request the creation of a new group channel: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } + /* Tell the world to not use us anymore */ + g_signal_emit (list, signals[DESTROY], 0); +} - group_channel = tp_chan_new (tp_get_bus (), - dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn)), - group_object_path, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_GROUP, - group_handle); - - dbus_g_proxy_connect_signal (DBUS_G_PROXY (group_channel), - "Closed", - G_CALLBACK - (tp_contact_list_group_channel_closed_cb), - list, - NULL); - - group = empathy_tp_group_new (priv->account, group_channel); - g_hash_table_insert (priv->groups, group_object_path, group); - g_signal_connect (group, "members-added", - G_CALLBACK (tp_contact_list_group_members_added_cb), - list); - g_signal_connect (group, "members-removed", - G_CALLBACK (tp_contact_list_group_members_removed_cb), - list); +static void +tp_contact_list_disconnect (EmpathyTpContactList *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); - return group; + if (priv->tp_conn) { + g_signal_handlers_disconnect_by_func (priv->tp_conn, + tp_contact_list_destroy_cb, + list); + dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel", + G_CALLBACK (tp_contact_list_newchannel_cb), + list); + } } -static gboolean -tp_contact_list_find_group (gchar *key, - EmpathyTpGroup *group, - gchar *group_name) +static void +tp_contact_list_status_changed_cb (MissionControl *mc, + TelepathyConnectionStatus status, + McPresence presence, + TelepathyConnectionStatusReason reason, + const gchar *unique_name, + EmpathyTpContactList *list) { - if (strcmp (group_name, empathy_tp_group_get_name (group)) == 0) { - return TRUE; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + McAccount *account; + + account = mc_account_lookup (unique_name); + if (status != TP_CONN_STATUS_CONNECTED && + empathy_account_equal (account, priv->account)) { + /* We are disconnected */ + tp_contact_list_disconnect (list); + tp_contact_list_destroy_cb (priv->tp_conn, list); } - return FALSE; + g_object_unref (account); } static void -tp_contact_list_get_groups_foreach (gchar *key, - EmpathyTpGroup *group, - GList **groups) +tp_contact_list_group_list_free (GList **groups) { - const gchar *name; - - name = empathy_tp_group_get_name (group); - *groups = g_list_append (*groups, g_strdup (name)); + g_list_foreach (*groups, (GFunc) g_free, NULL); + g_list_free (*groups); + g_slice_free (GList*, groups); } static void -tp_contact_list_group_channel_closed_cb (TpChan *channel, - EmpathyTpContactList *list) +tp_contact_list_finalize (GObject *object) { EmpathyTpContactListPriv *priv; + EmpathyTpContactList *list; + list = EMPATHY_TP_CONTACT_LIST (object); priv = GET_PRIV (list); - g_hash_table_remove (priv->groups, - dbus_g_proxy_get_path (DBUS_G_PROXY (channel))); -} + empathy_debug (DEBUG_DOMAIN, "finalize: %p", object); -static void -tp_contact_list_group_members_added_cb (EmpathyTpGroup *group, - GArray *members, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list) -{ - EmpathyTpContactListPriv *priv; - GList *added_list, *l; - const gchar *group_name; + tp_contact_list_disconnect (list); + tp_contact_list_remove_all (list); - priv = GET_PRIV (list); + if (priv->mc) { + dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), + "AccountStatusChanged", + G_CALLBACK (tp_contact_list_status_changed_cb), + list); + g_object_unref (priv->mc); + } - group_name = empathy_tp_group_get_name (group); - added_list = empathy_tp_contact_list_get_from_handles (list, members); + if (priv->subscribe) { + g_object_unref (priv->subscribe); + } + if (priv->publish) { + g_object_unref (priv->publish); + } + if (priv->account) { + g_object_unref (priv->account); + } + if (priv->tp_conn) { + g_object_unref (priv->tp_conn); + } + + g_hash_table_destroy (priv->contacts_groups); + g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL); + g_list_free (priv->groups); + + G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object); +} - for (l = added_list; l; l = l->next) { - EmpathyContact *contact; +static void +empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); - contact = EMPATHY_CONTACT (l->data); + object_class->finalize = tp_contact_list_finalize; - tp_contact_list_block_contact (list, contact); - empathy_contact_add_group (contact, group_name); - tp_contact_list_unblock_contact (list, contact); + signals[DESTROY] = + g_signal_new ("destroy", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); - g_object_unref (contact); - } + g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv)); +} - g_list_free (added_list); +static void +empathy_tp_contact_list_init (EmpathyTpContactList *list) +{ } static void -tp_contact_list_group_members_removed_cb (EmpathyTpGroup *group, - GArray *members, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_setup (EmpathyTpContactList *list) { - EmpathyTpContactListPriv *priv; - GList *removed_list, *l; - const gchar *group_name; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GPtrArray *channels; + guint i; + GError *error = NULL; - priv = GET_PRIV (list); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - group_name = empathy_tp_group_get_name (group); - removed_list = empathy_tp_contact_list_get_from_handles (list, members); + /* Get existing channels */ + if (!tp_conn_list_channels (DBUS_G_PROXY (priv->tp_conn), + &channels, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Failed to get list of open channels: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + return; + } - for (l = removed_list; l; l = l->next) { - EmpathyContact *contact; + for (i = 0; i < channels->len; i++) { + GValueArray *chan_struct; + const gchar *object_path; + const gchar *chan_iface; + TelepathyHandleType handle_type; + guint handle; - contact = l->data; + chan_struct = g_ptr_array_index (channels, i); + object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0)); + chan_iface = g_value_get_string (g_value_array_get_nth (chan_struct, 1)); + handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2)); + handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3)); - tp_contact_list_block_contact (list, contact); - empathy_contact_remove_group (contact, group_name); - tp_contact_list_unblock_contact (list, contact); + tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn), + object_path, chan_iface, + handle_type, handle, + FALSE, + list); - g_object_unref (contact); + g_value_array_free (chan_struct); } - - g_list_free (removed_list); + g_ptr_array_free (channels, TRUE); } -static void -tp_contact_list_get_info (EmpathyTpContactList *list, - GArray *handles) +EmpathyTpContactList * +empathy_tp_contact_list_new (McAccount *account) { EmpathyTpContactListPriv *priv; - GError *error = NULL; + EmpathyTpContactList *list; + MissionControl *mc; + TpConn *tp_conn = NULL; + McProfile *profile; + const gchar *protocol_name; - priv = GET_PRIV (list); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - if (priv->presence_iface) { - /* FIXME: We should use GetPresence instead */ - if (!tp_conn_iface_presence_request_presence (priv->presence_iface, - handles, &error)) { - empathy_debug (DEBUG_DOMAIN, - "Could not request presences: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } + mc = empathy_mission_control_new (); + + /* status==0 means CONNECTED */ + if (mission_control_get_connection_status (mc, account, NULL) == 0) { + tp_conn = mission_control_get_connection (mc, account, NULL); + } + if (!tp_conn) { + /* The account is not connected, nothing to do. */ + g_object_unref (mc); + return NULL; } - if (priv->aliasing_iface) { - TpContactListAliasesRequestData *data; + list = g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, NULL); + priv = GET_PRIV (list); - data = g_slice_new (TpContactListAliasesRequestData); - data->list = list; - data->handles = g_memdup (handles->data, handles->len * sizeof (guint)); + priv->tp_conn = tp_conn; + priv->account = g_object_ref (account); + priv->mc = mc; + priv->contacts_groups = g_hash_table_new_full (empathy_contact_hash, + empathy_contact_equal, + (GDestroyNotify) g_object_unref, + (GDestroyNotify) tp_contact_list_group_list_free); - tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface, - handles, - (tp_conn_iface_aliasing_request_aliases_reply) - tp_contact_list_request_aliases_cb, - data); + /* Check for protocols that does not support contact groups. We can + * put all contacts into a special group in that case. + * FIXME: Default group should be an information in the profile */ + profile = mc_account_get_profile (account); + protocol_name = mc_profile_get_protocol_name (profile); + if (strcmp (protocol_name, "local-xmpp") == 0) { + priv->protocol_group = _("People nearby"); } + g_object_unref (profile); - if (priv->avatars_iface) { - guint i; + /* Connect signals */ + dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), + "AccountStatusChanged", + G_CALLBACK (tp_contact_list_status_changed_cb), + list, NULL); + dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel", + G_CALLBACK (tp_contact_list_newchannel_cb), + list, NULL); + g_signal_connect (priv->tp_conn, "destroy", + G_CALLBACK (tp_contact_list_destroy_cb), + list); - for (i = 0; i < handles->len; i++) { - guint handle; + tp_contact_list_setup (list); - handle = g_array_index (handles, gint, i); - tp_contact_list_request_avatar (list, handle); - } - } + return list; } -static void -tp_contact_list_request_avatar (EmpathyTpContactList *list, - guint handle) +McAccount * +empathy_tp_contact_list_get_account (EmpathyTpContactList *list) { - EmpathyTpContactListPriv *priv; - TpContactListAvatarRequestData *data; + EmpathyTpContactListPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); priv = GET_PRIV (list); - - /* We queue avatar requests to not send too many dbus async - * calls at once. If we don't we reach the dbus's limit of - * pending calls */ - data = g_slice_new (TpContactListAvatarRequestData); - data->list = g_object_ref (list); - data->handle = handle; - avatar_requests_queue = g_list_append (avatar_requests_queue, data); - tp_contact_list_start_avatar_requests (); + + return priv->account; } static void -tp_contact_list_start_avatar_requests (void) +tp_contact_list_add (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message) { - empathy_debug (DEBUG_DOMAIN, "Start avatar requests, pending calls: %d", - n_avatar_requests); - - while (n_avatar_requests < MAX_AVATAR_REQUESTS && avatar_requests_queue) { - EmpathyTpContactListPriv *priv; - TpContactListAvatarRequestData *data; - - data = avatar_requests_queue->data; - priv = GET_PRIV (data->list); - - n_avatar_requests++; - avatar_requests_queue = g_list_delete_link (avatar_requests_queue, - avatar_requests_queue); - - empathy_debug (DEBUG_DOMAIN, "Calling RequestAvatar async"); - tp_conn_iface_avatars_request_avatar_async (priv->avatars_iface, - data->handle, - (tp_conn_iface_avatars_request_avatar_reply) - tp_contact_list_request_avatar_cb, - data); + EmpathyTpContactListPriv *priv = GET_PRIV (list); + + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + + empathy_tp_group_add_member (priv->subscribe, contact, message); + if (g_list_find (priv->pendings, contact)) { + empathy_tp_group_add_member (priv->publish, contact, message); } } static void -tp_contact_list_avatar_update_cb (DBusGProxy *proxy, - guint handle, - gchar *new_token, - EmpathyTpContactList *list) +tp_contact_list_remove (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message) { - EmpathyTpContactListPriv *priv; - - priv = GET_PRIV (list); - - if (!g_hash_table_lookup (priv->contacts, GUINT_TO_POINTER (handle))) { - /* We don't know this contact, skip */ - return; - } + EmpathyTpContactListPriv *priv = GET_PRIV (list); - empathy_debug (DEBUG_DOMAIN, "Changing avatar for %d to %s", - handle, new_token); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - tp_contact_list_request_avatar (list, handle); + empathy_tp_group_remove_member (priv->subscribe, contact, message); + empathy_tp_group_remove_member (priv->publish, contact, message); } -static void -tp_contact_list_request_avatar_cb (DBusGProxy *proxy, - GArray *avatar_data, - gchar *mime_type, - GError *error, - TpContactListAvatarRequestData *data) +static GList * +tp_contact_list_get_members (EmpathyContactList *list) { - EmpathyContact *contact; + EmpathyTpContactListPriv *priv = GET_PRIV (list); - contact = empathy_tp_contact_list_get_from_handle (data->list, data->handle); + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error requesting avatar for %s: %s", - empathy_contact_get_name (contact), - error ? error->message : "No error given"); - } else { - EmpathyAvatar *avatar; + g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); + return g_list_copy (priv->members); +} - empathy_debug (DEBUG_DOMAIN, "Avatar received for %s (%d)", - empathy_contact_get_id (contact), - data->handle); - - avatar = empathy_avatar_new (avatar_data->data, - avatar_data->len, - mime_type); - tp_contact_list_block_contact (data->list, contact); - empathy_contact_set_avatar (contact, avatar); - tp_contact_list_unblock_contact (data->list, contact); - empathy_avatar_unref (avatar); - } +static GList * +tp_contact_list_get_pendings (EmpathyContactList *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); - n_avatar_requests--; - tp_contact_list_start_avatar_requests (); + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - g_object_unref (contact); - g_object_unref (data->list); - g_slice_free (TpContactListAvatarRequestData, data); + g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL); + return g_list_copy (priv->pendings); } -static void -tp_contact_list_aliases_update_cb (DBusGProxy *proxy, - GPtrArray *renamed_handlers, - EmpathyTpContactList *list) +static GList * +tp_contact_list_get_all_groups (EmpathyContactList *list) { - EmpathyTpContactListPriv *priv; - guint i; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *groups = NULL, *l; - priv = GET_PRIV (list); + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - for (i = 0; renamed_handlers->len > i; i++) { - guint handle; - const gchar *alias; - GValueArray *renamed_struct; - EmpathyContact *contact; + for (l = priv->groups; l; l = l->next) { + const gchar *name; - renamed_struct = g_ptr_array_index (renamed_handlers, i); - handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0)); - alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1)); + name = empathy_tp_group_get_name (l->data); + groups = g_list_prepend (groups, g_strdup (name)); + } - if (!g_hash_table_lookup (priv->contacts, GUINT_TO_POINTER (handle))) { - /* We don't know this contact, skip */ - continue; - } + return groups; +} - if (G_STR_EMPTY (alias)) { - alias = NULL; - } +static GList * +tp_contact_list_get_groups (EmpathyContactList *list, + EmpathyContact *contact) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList **groups; + GList *ret = NULL, *l; - contact = empathy_tp_contact_list_get_from_handle (list, handle); - tp_contact_list_block_contact (list, contact); - empathy_contact_set_name (contact, alias); - tp_contact_list_unblock_contact (list, contact); - g_object_unref (contact); + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); + + groups = g_hash_table_lookup (priv->contacts_groups, contact); + if (!groups) { + return NULL; + } - empathy_debug (DEBUG_DOMAIN, "contact %d renamed to %s (update cb)", - handle, alias); + for (l = *groups; l; l = l->next) { + ret = g_list_prepend (ret, g_strdup (l->data)); } + + return ret; } -static void -tp_contact_list_request_aliases_cb (DBusGProxy *proxy, - gchar **contact_names, - GError *error, - TpContactListAliasesRequestData *data) +static EmpathyTpGroup * +tp_contact_list_get_group (EmpathyTpContactList *list, + const gchar *group) { - guint i = 0; - gchar **name; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + EmpathyTpGroup *tp_group; + gchar *object_path; + guint handle; + GArray *handles; + const char *names[2] = {group, NULL}; + GError *error = NULL; - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s", - error->message); + tp_group = tp_contact_list_find_group (list, group); + if (tp_group) { + return tp_group; } - for (name = contact_names; *name && !error; name++) { - EmpathyContact *contact; + empathy_debug (DEBUG_DOMAIN, "creating new group: %s", group); - contact = empathy_tp_contact_list_get_from_handle (data->list, - data->handles[i]); - tp_contact_list_block_contact (data->list, contact); - empathy_contact_set_name (contact, *name); - tp_contact_list_unblock_contact (data->list, contact); - g_object_unref (contact); - - empathy_debug (DEBUG_DOMAIN, "contact %d renamed to %s (request cb)", - data->handles[i], *name); + if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn), + TP_HANDLE_TYPE_GROUP, + names, + &handles, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Failed to RequestHandles: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + return NULL; + } + handle = g_array_index (handles, guint, 0); + g_array_free (handles, TRUE); - i++; + if (!tp_conn_request_channel (DBUS_G_PROXY (priv->tp_conn), + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_GROUP, + handle, + FALSE, + &object_path, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Failed to RequestChannel: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + return NULL; } - g_free (data->handles); - g_slice_free (TpContactListAliasesRequestData, data); -} + tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn), + object_path, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_GROUP, + handle, FALSE, + list); + g_free (object_path); -static void -tp_contact_list_presence_update_cb (DBusGProxy *proxy, - GHashTable *handle_table, - EmpathyTpContactList *list) -{ - g_hash_table_foreach (handle_table, - (GHFunc) tp_contact_list_parse_presence_foreach, - list); + return tp_contact_list_find_group (list, group); } static void -tp_contact_list_parse_presence_foreach (guint handle, - GValueArray *presence_struct, - EmpathyTpContactList *list) +tp_contact_list_add_to_group (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *group) { - EmpathyTpContactListPriv *priv; - GHashTable *presences_table; - EmpathyContact *contact; - EmpathyPresence *presence = NULL; - - priv = GET_PRIV (list); - - if (!g_hash_table_lookup (priv->contacts, GUINT_TO_POINTER (handle))) { - /* We don't know this contact, skip */ - return; - } - - contact = empathy_tp_contact_list_get_from_handle (list, handle); - presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1)); + EmpathyTpGroup *tp_group; - g_hash_table_foreach (presences_table, - (GHFunc) tp_contact_list_presences_table_foreach, - &presence); - - empathy_debug (DEBUG_DOMAIN, "Presence changed for %s (%d) to %s (%d)", - empathy_contact_get_name (contact), - handle, - presence ? empathy_presence_get_status (presence) : "unset", - presence ? empathy_presence_get_state (presence) : MC_PRESENCE_UNSET); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - tp_contact_list_block_contact (list, contact); - empathy_contact_set_presence (contact, presence); - tp_contact_list_unblock_contact (list, contact); + tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list), + group); - g_object_unref (contact); + empathy_tp_group_add_member (tp_group, contact, ""); } static void -tp_contact_list_presences_table_foreach (const gchar *state_str, - GHashTable *presences_table, - EmpathyPresence **presence) +tp_contact_list_remove_from_group (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *group) { - McPresence state; - const GValue *message; - - state = empathy_presence_state_from_str (state_str); - if ((state == MC_PRESENCE_UNSET) || (state == MC_PRESENCE_OFFLINE)) { - return; - } + EmpathyTpGroup *tp_group; - if (*presence) { - g_object_unref (*presence); - *presence = NULL; - } + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - *presence = empathy_presence_new (); - empathy_presence_set_state (*presence, state); + tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), + group); - message = g_hash_table_lookup (presences_table, "message"); - if (message != NULL) { - empathy_presence_set_status (*presence, - g_value_get_string (message)); + if (tp_group) { + empathy_tp_group_remove_member (tp_group, contact, ""); } } static void -tp_contact_list_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - EmpathyTpContactList *list) +tp_contact_list_rename_group (EmpathyContactList *list, + const gchar *old_group, + const gchar *new_group) { - EmpathyTpContactListPriv *priv; - McAccount *account; + EmpathyTpGroup *tp_group; + GList *members; - priv = GET_PRIV (list); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - account = mc_account_lookup (unique_name); - if (status != TP_CONN_STATUS_DISCONNECTED || - !empathy_account_equal (account, priv->account) || - !priv->tp_conn) { - g_object_unref (account); + tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), + old_group); + if (!tp_group) { return; } - /* We are disconnected, do just like if the connection was destroyed */ - g_signal_handlers_disconnect_by_func (priv->tp_conn, - tp_contact_list_destroy_cb, - list); - tp_contact_list_destroy_cb (DBUS_G_PROXY (priv->tp_conn), list); + empathy_debug (DEBUG_DOMAIN, "rename group %s to %s", old_group, new_group); - g_object_unref (account); + /* Remove all members from the old group */ + members = empathy_tp_group_get_members (tp_group); + empathy_tp_group_remove_members (tp_group, members, ""); + empathy_tp_group_close (tp_group); + + /* Add all members to the new group */ + tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list), + new_group); + empathy_tp_group_add_members (tp_group, members, ""); + + g_list_foreach (members, (GFunc) g_object_unref, NULL); + g_list_free (members); +} + +static void +tp_contact_list_iface_init (EmpathyContactListIface *iface) +{ + iface->add = tp_contact_list_add; + iface->remove = tp_contact_list_remove; + iface->get_members = tp_contact_list_get_members; + iface->get_pendings = tp_contact_list_get_pendings; + iface->get_all_groups = tp_contact_list_get_all_groups; + iface->get_groups = tp_contact_list_get_groups; + iface->add_to_group = tp_contact_list_add_to_group; + iface->remove_from_group = tp_contact_list_remove_from_group; + iface->rename_group = tp_contact_list_rename_group; } diff --git a/libempathy/empathy-tp-contact-list.h b/libempathy/empathy-tp-contact-list.h index f0eccb37..6ac4662f 100644 --- a/libempathy/empathy-tp-contact-list.h +++ b/libempathy/empathy-tp-contact-list.h @@ -50,20 +50,9 @@ struct _EmpathyTpContactListClass { GObjectClass parent_class; }; -GType empathy_tp_contact_list_get_type (void) G_GNUC_CONST; -EmpathyTpContactList * empathy_tp_contact_list_new (McAccount *account); -McAccount * empathy_tp_contact_list_get_account (EmpathyTpContactList *list); -EmpathyContact * empathy_tp_contact_list_get_user (EmpathyTpContactList *list); -EmpathyContact * empathy_tp_contact_list_get_from_id (EmpathyTpContactList *list, - const gchar *id); -EmpathyContact * empathy_tp_contact_list_get_from_handle (EmpathyTpContactList *list, - guint handle); -GList * empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list, - GArray *handles); -void empathy_tp_contact_list_rename_group (EmpathyTpContactList *list, - const gchar *old_group, - const gchar *new_group); -GList * empathy_tp_contact_list_get_groups (EmpathyTpContactList *list); +GType empathy_tp_contact_list_get_type (void) G_GNUC_CONST; +EmpathyTpContactList * empathy_tp_contact_list_new (McAccount *account); +McAccount * empathy_tp_contact_list_get_account (EmpathyTpContactList *list); G_END_DECLS diff --git a/libempathy/empathy-tp-group.c b/libempathy/empathy-tp-group.c index b86a00e2..1ffab9ec 100644 --- a/libempathy/empathy-tp-group.c +++ b/libempathy/empathy-tp-group.c @@ -1,6 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2006 Xavier Claessens + * Copyright (C) 2007 Collabora Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -16,18 +17,22 @@ * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens */ #include #include #include +#include #include #include #include -#include "empathy-debug.h" #include "empathy-tp-group.h" +#include "empathy-contact-factory.h" +#include "empathy-debug.h" #include "empathy-utils.h" #include "empathy-marshal.h" @@ -37,32 +42,27 @@ #define DEBUG_DOMAIN "TpGroup" struct _EmpathyTpGroupPriv { - McAccount *account; - DBusGProxy *group_iface; - TpChan *tp_chan; - gchar *group_name; + EmpathyContactFactory *factory; + McAccount *account; + DBusGProxy *group_iface; + TpChan *tp_chan; + gchar *group_name; + guint self_handle; + + GList *members; + GList *local_pendings; + GList *remote_pendings; }; static void empathy_tp_group_class_init (EmpathyTpGroupClass *klass); static void empathy_tp_group_init (EmpathyTpGroup *group); -static void tp_group_finalize (GObject *object); -static void tp_group_destroy_cb (DBusGProxy *proxy, - EmpathyTpGroup *group); -static void tp_group_members_changed_cb (DBusGProxy *group_iface, - gchar *message, - GArray *added, - GArray *removed, - GArray *local_pending, - GArray *remote_pending, - guint actor, - guint reason, - EmpathyTpGroup *group); enum { - MEMBERS_ADDED, - MEMBERS_REMOVED, + MEMBER_ADDED, + MEMBER_REMOVED, LOCAL_PENDING, REMOTE_PENDING, + DESTROY, LAST_SIGNAL }; @@ -70,6 +70,409 @@ static guint signals[LAST_SIGNAL]; G_DEFINE_TYPE (EmpathyTpGroup, empathy_tp_group, G_TYPE_OBJECT); +static EmpathyContact * +tp_group_get_contact (EmpathyTpGroup *group, + guint handle) +{ + EmpathyTpGroupPriv *priv = GET_PRIV (group); + EmpathyContact *contact = NULL; + + if (handle != 0) { + contact = empathy_contact_factory_get_from_handle (priv->factory, + priv->account, + handle); + } + + if (contact && empathy_contact_get_handle (contact) == priv->self_handle) { + empathy_contact_set_is_user (contact, TRUE); + } + + return contact; +} + +static GList * +tp_group_get_contacts (EmpathyTpGroup *group, + GArray *handles) +{ + EmpathyTpGroupPriv *priv = GET_PRIV (group); + GList *contacts, *l; + + if (!handles) { + return NULL; + } + + contacts = empathy_contact_factory_get_from_handles (priv->factory, + priv->account, + handles); + + /* FIXME: Only useful if the group has a different self handle than + * the connection, otherwise the contact factory already set that + * property. That can be known using group flags. */ + for (l = contacts; l; l = l->next) { + if (empathy_contact_get_handle (l->data) == priv->self_handle) { + empathy_contact_set_is_user (l->data, TRUE); + } + } + + return contacts; +} + +EmpathyPendingInfo * +empathy_pending_info_new (EmpathyContact *member, + EmpathyContact *actor, + const gchar *message) +{ + EmpathyPendingInfo *info; + + info = g_slice_new0 (EmpathyPendingInfo); + + if (member) { + info->member = g_object_ref (member); + } + if (actor) { + info->actor = g_object_ref (actor); + } + if (message) { + info->message = g_strdup (message); + } + + return info; +} + +void +empathy_pending_info_free (EmpathyPendingInfo *info) +{ + if (!info) { + return; + } + + if (info->member) { + g_object_unref (info->member); + } + if (info->actor) { + g_object_unref (info->actor); + } + g_free (info->message); + + g_slice_free (EmpathyPendingInfo, info); +} + +static gint +tp_group_local_pending_find (gconstpointer a, + gconstpointer b) +{ + const EmpathyPendingInfo *info = a; + + return (info->member != b); +} + +static void +tp_group_remove_from_pendings (EmpathyTpGroup *group, + EmpathyContact *contact) +{ + EmpathyTpGroupPriv *priv = GET_PRIV (group); + GList *l; + + /* local pending */ + l = g_list_find_custom (priv->local_pendings, + contact, + tp_group_local_pending_find); + if (l) { + empathy_pending_info_free (l->data); + priv->local_pendings = g_list_delete_link (priv->local_pendings, l); + } + + /* remote pending */ + l = g_list_find (priv->remote_pendings, contact); + if (l) { + g_object_unref (l->data); + priv->remote_pendings = g_list_delete_link (priv->remote_pendings, l); + } +} + +static void +tp_group_members_changed_cb (DBusGProxy *group_iface, + const gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv = GET_PRIV (group); + EmpathyContact *actor_contact = NULL; + GList *contacts, *l, *ll; + + actor_contact = tp_group_get_contact (group, actor); + + empathy_debug (DEBUG_DOMAIN, "Members changed for list %s:\n" + " added-len=%d, current-len=%d\n" + " removed-len=%d\n" + " local-pending-len=%d, current-len=%d\n" + " remote-pending-len=%d, current-len=%d", + empathy_tp_group_get_name (group), + added ? added->len : 0, g_list_length (priv->members), + removed ? removed->len : 0, + local_pending ? local_pending->len : 0, + g_list_length (priv->local_pendings), + remote_pending ? remote_pending->len : 0, + g_list_length (priv->remote_pendings)); + + /* Contacts added */ + contacts = tp_group_get_contacts (group, added); + for (l = contacts; l; l = l->next) { + tp_group_remove_from_pendings (group, l->data); + + /* If the contact is not yet member, add it and emit signal */ + if (!g_list_find (priv->members, l->data)) { + priv->members = g_list_prepend (priv->members, + g_object_ref (l->data)); + g_signal_emit (group, signals[MEMBER_ADDED], 0, + l->data, actor_contact, reason, message); + } + g_object_unref (l->data); + } + g_list_free (contacts); + + /* Contacts removed */ + contacts = tp_group_get_contacts (group, removed); + for (l = contacts; l; l = l->next) { + tp_group_remove_from_pendings (group, l->data); + + /* If the contact is member, remove it and emit signal */ + if ((ll = g_list_find (priv->members, l->data))) { + g_object_unref (ll->data); + priv->members = g_list_delete_link (priv->members, ll); + g_signal_emit (group, signals[MEMBER_REMOVED], 0, + l->data, actor_contact, reason, message); + } + g_object_unref (l->data); + } + g_list_free (contacts); + + /* Contacts local pending */ + contacts = tp_group_get_contacts (group, local_pending); + for (l = contacts; l; l = l->next) { + /* If the contact is not yet local-pending, add it and emit signal */ + if (!g_list_find_custom (priv->members, l->data, + tp_group_local_pending_find)) { + EmpathyPendingInfo *info; + + info = empathy_pending_info_new (l->data, + actor_contact, + message); + + priv->local_pendings = g_list_prepend (priv->local_pendings, info); + g_signal_emit (group, signals[LOCAL_PENDING], 0, + l->data, actor_contact, reason, message); + } + g_object_unref (l->data); + } + g_list_free (contacts); + + /* Contacts remote pending */ + contacts = tp_group_get_contacts (group, remote_pending); + for (l = contacts; l; l = l->next) { + /* If the contact is not yet remote-pending, add it and emit signal */ + if (!g_list_find (priv->remote_pendings, l->data)) { + priv->remote_pendings = g_list_prepend (priv->remote_pendings, + g_object_ref (l->data)); + g_signal_emit (group, signals[REMOTE_PENDING], 0, + l->data, actor_contact, reason, message); + } + g_object_unref (l->data); + } + g_list_free (contacts); + + if (actor_contact) { + g_object_unref (actor_contact); + } + + empathy_debug (DEBUG_DOMAIN, "Members changed done for list %s:\n" + " members-len=%d\n" + " local-pendings-len=%d\n" + " remote-pendings-len=%d", + empathy_tp_group_get_name (group), + g_list_length (priv->members), + g_list_length (priv->local_pendings), + g_list_length (priv->remote_pendings)); +} + +static void +tp_group_destroy_cb (TpChan *tp_chan, + EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv = GET_PRIV (group); + + empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed"); + + g_object_unref (priv->tp_chan); + priv->group_iface = NULL; + priv->tp_chan = NULL; + + g_signal_emit (group, signals[DESTROY], 0); +} + +static void tp_group_closed_cb (DBusGProxy *proxy, + EmpathyTpGroup *group); + +static void +tp_group_disconnect (EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv = GET_PRIV (group); + + if (priv->group_iface) { + dbus_g_proxy_disconnect_signal (priv->group_iface, "MembersChanged", + G_CALLBACK (tp_group_members_changed_cb), + group); + } + if (priv->tp_chan) { + g_signal_handlers_disconnect_by_func (priv->tp_chan, + tp_group_destroy_cb, + group); + dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_chan), "Closed", + G_CALLBACK (tp_group_closed_cb), + group); + } +} + +static void +tp_group_closed_cb (DBusGProxy *proxy, + EmpathyTpGroup *group) +{ + tp_group_disconnect (group); + tp_group_destroy_cb (TELEPATHY_CHAN (proxy), group); +} + +static void +tp_group_get_members_cb (DBusGProxy *proxy, + GArray *handles, + GError *error, + gpointer user_data) +{ + EmpathyTpGroup *group = user_data; + EmpathyTpGroupPriv *priv = GET_PRIV (group); + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Failed to get members: %s", + error->message); + return; + } + + tp_group_members_changed_cb (priv->group_iface, + NULL, /* message */ + handles, /* added */ + NULL, /* removed */ + NULL, /* local_pending */ + NULL, /* remote_pending */ + 0, /* actor */ + 0, /* reason */ + group); +} + +static void +tp_group_get_local_pending_cb (DBusGProxy *proxy, + GPtrArray *array, + GError *error, + gpointer user_data) +{ + EmpathyTpGroup *group = user_data; + EmpathyTpGroupPriv *priv = GET_PRIV (group); + GArray *handles; + guint i; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Failed to get local pendings: %s", + error->message); + return; + } + + handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); + for (i = 0; array->len > i; i++) { + GValueArray *pending_struct; + const gchar *message; + guint member_handle; + guint actor_handle; + guint reason; + + pending_struct = g_ptr_array_index (array, i); + member_handle = g_value_get_uint (g_value_array_get_nth (pending_struct, 0)); + actor_handle = g_value_get_uint (g_value_array_get_nth (pending_struct, 1)); + reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2)); + message = g_value_get_string (g_value_array_get_nth (pending_struct, 3)); + + g_array_insert_val (handles, 0, member_handle); + tp_group_members_changed_cb (priv->group_iface, + message, /* message */ + NULL, /* added */ + NULL, /* removed */ + handles, /* local_pending */ + NULL, /* remote_pending */ + actor_handle, /* actor */ + reason, /* reason */ + group); + } + g_array_free (handles, TRUE); +} + +static void +tp_group_get_remote_pending_cb (DBusGProxy *proxy, + GArray *handles, + GError *error, + gpointer user_data) +{ + EmpathyTpGroup *group = user_data; + EmpathyTpGroupPriv *priv = GET_PRIV (group); + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Failed to get remote pendings: %s", + error->message); + return; + } + + tp_group_members_changed_cb (priv->group_iface, + NULL, /* message */ + NULL, /* added */ + NULL, /* removed */ + NULL, /* local_pending */ + handles, /* remote_pending */ + 0, /* actor */ + 0, /* reason */ + group); +} + +static void +tp_group_finalize (GObject *object) +{ + EmpathyTpGroupPriv *priv = GET_PRIV (object); + + tp_group_disconnect (EMPATHY_TP_GROUP (object)); + + if (priv->tp_chan) { + g_object_unref (priv->tp_chan); + } + if (priv->account) { + g_object_unref (priv->account); + } + if (priv->factory) { + g_object_unref (priv->factory); + } + g_free (priv->group_name); + + g_list_foreach (priv->members, (GFunc) g_object_unref, NULL); + g_list_free (priv->members); + + g_list_foreach (priv->local_pendings, (GFunc) empathy_pending_info_free, NULL); + g_list_free (priv->local_pendings); + + g_list_foreach (priv->remote_pendings, (GFunc) g_object_unref, NULL); + g_list_free (priv->remote_pendings); + + G_OBJECT_CLASS (empathy_tp_group_parent_class)->finalize (object); +} + static void empathy_tp_group_class_init (EmpathyTpGroupClass *klass) { @@ -77,25 +480,25 @@ empathy_tp_group_class_init (EmpathyTpGroupClass *klass) object_class->finalize = tp_group_finalize; - signals[MEMBERS_ADDED] = - g_signal_new ("members-added", + signals[MEMBER_ADDED] = + g_signal_new ("member-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - empathy_marshal_VOID__POINTER_UINT_UINT_STRING, + empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, G_TYPE_NONE, - 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - signals[MEMBERS_REMOVED] = - g_signal_new ("members-removed", + signals[MEMBER_REMOVED] = + g_signal_new ("member-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - empathy_marshal_VOID__POINTER_UINT_UINT_STRING, + empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, G_TYPE_NONE, - 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); signals[LOCAL_PENDING] = g_signal_new ("local-pending", @@ -103,9 +506,9 @@ empathy_tp_group_class_init (EmpathyTpGroupClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, - empathy_marshal_VOID__POINTER_UINT_UINT_STRING, + empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, G_TYPE_NONE, - 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); signals[REMOTE_PENDING] = g_signal_new ("remote-pending", @@ -113,9 +516,19 @@ empathy_tp_group_class_init (EmpathyTpGroupClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, - empathy_marshal_VOID__POINTER_UINT_UINT_STRING, + empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, G_TYPE_NONE, - 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); + + signals[DESTROY] = + g_signal_new ("destroy", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); g_type_class_add_private (object_class, sizeof (EmpathyTpGroupPriv)); } @@ -125,36 +538,6 @@ empathy_tp_group_init (EmpathyTpGroup *group) { } -static void -tp_group_finalize (GObject *object) -{ - EmpathyTpGroupPriv *priv; - - priv = GET_PRIV (object); - - if (priv->group_iface) { - g_signal_handlers_disconnect_by_func (priv->group_iface, - tp_group_destroy_cb, - object); - dbus_g_proxy_disconnect_signal (priv->group_iface, "MembersChanged", - G_CALLBACK (tp_group_members_changed_cb), - object); - g_object_unref (priv->group_iface); - } - - if (priv->account) { - g_object_unref (priv->account); - } - - if (priv->tp_chan) { - g_object_unref (priv->tp_chan); - } - - g_free (priv->group_name); - - G_OBJECT_CLASS (empathy_tp_group_parent_class)->finalize (object); -} - EmpathyTpGroup * empathy_tp_group_new (McAccount *account, TpChan *tp_chan) @@ -162,6 +545,7 @@ empathy_tp_group_new (McAccount *account, EmpathyTpGroup *group; EmpathyTpGroupPriv *priv; DBusGProxy *group_iface; + GError *error; g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); @@ -175,262 +559,205 @@ empathy_tp_group_new (McAccount *account, priv->account = g_object_ref (account); priv->tp_chan = g_object_ref (tp_chan); - priv->group_iface = g_object_ref (group_iface); + priv->group_iface = group_iface; + priv->factory = empathy_contact_factory_new (); + + if (!tp_chan_iface_group_get_self_handle (priv->group_iface, + &priv->self_handle, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Failed to get self handle: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + } dbus_g_proxy_connect_signal (priv->group_iface, "MembersChanged", G_CALLBACK (tp_group_members_changed_cb), group, NULL); - g_signal_connect (group_iface, "destroy", + dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_chan), "Closed", + G_CALLBACK (tp_group_closed_cb), + group, NULL); + g_signal_connect (priv->tp_chan, "destroy", G_CALLBACK (tp_group_destroy_cb), group); + tp_chan_iface_group_get_members_async (priv->group_iface, + tp_group_get_members_cb, + group); + tp_chan_iface_group_get_local_pending_members_with_info_async (priv->group_iface, + tp_group_get_local_pending_cb, + group); + tp_chan_iface_group_get_remote_pending_members_async (priv->group_iface, + tp_group_get_remote_pending_cb, + group); + return group; } +static void +tp_group_async_cb (DBusGProxy *proxy, GError *error, gpointer user_data) +{ + const gchar *msg = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "%s: %s", msg, error->message); + } +} + +void +empathy_tp_group_close (EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv = GET_PRIV (group); + + tp_chan_close_async (DBUS_G_PROXY (priv->tp_chan), + tp_group_async_cb, + "Failed to close"); +} + +static GArray * +tp_group_get_handles (GList *contacts) +{ + GArray *handles; + guint length; + GList *l; + + length = g_list_length (contacts); + handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), length); + + for (l = contacts; l; l = l->next) { + guint handle; + + handle = empathy_contact_get_handle (l->data); + g_array_append_val (handles, handle); + } + + return handles; +} + void empathy_tp_group_add_members (EmpathyTpGroup *group, - GArray *handles, + GList *contacts, const gchar *message) { - EmpathyTpGroupPriv *priv; - GError *error = NULL; + EmpathyTpGroupPriv *priv = GET_PRIV (group); + GArray *handles; g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (handles != NULL); + g_return_if_fail (contacts != NULL); - priv = GET_PRIV (group); + handles = tp_group_get_handles (contacts); + tp_chan_iface_group_add_members_async (priv->group_iface, + handles, + message, + tp_group_async_cb, + "Failed to add members"); - if (!tp_chan_iface_group_add_members (priv->group_iface, - handles, - message, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Failed to add members: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } + g_array_free (handles, TRUE); } void empathy_tp_group_add_member (EmpathyTpGroup *group, - guint handle, + EmpathyContact *contact, const gchar *message) { - GArray *handles; + EmpathyTpGroupPriv *priv = GET_PRIV (group); + GArray *handles; + guint handle; + handle = empathy_contact_get_handle (contact); handles = g_array_new (FALSE, FALSE, sizeof (guint)); g_array_append_val (handles, handle); - empathy_tp_group_add_members (group, handles, message); + tp_chan_iface_group_add_members_async (priv->group_iface, + handles, + message, + tp_group_async_cb, + "Failed to add member"); g_array_free (handles, TRUE); } void empathy_tp_group_remove_members (EmpathyTpGroup *group, - GArray *handles, + GList *contacts, const gchar *message) { - EmpathyTpGroupPriv *priv; - GError *error = NULL; + EmpathyTpGroupPriv *priv = GET_PRIV (group); + GArray *handles; g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); + g_return_if_fail (contacts != NULL); - priv = GET_PRIV (group); + handles = tp_group_get_handles (contacts); + tp_chan_iface_group_remove_members_async (priv->group_iface, + handles, + message, + tp_group_async_cb, + "Failed to remove members"); - if (!tp_chan_iface_group_remove_members (priv->group_iface, - handles, - message, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Failed to remove members: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } + g_array_free (handles, TRUE); } void empathy_tp_group_remove_member (EmpathyTpGroup *group, - guint handle, + EmpathyContact *contact, const gchar *message) { - GArray *handles; - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); + EmpathyTpGroupPriv *priv = GET_PRIV (group); + GArray *handles; + guint handle; + handle = empathy_contact_get_handle (contact); handles = g_array_new (FALSE, FALSE, sizeof (guint)); g_array_append_val (handles, handle); - empathy_tp_group_remove_members (group, handles, message); + tp_chan_iface_group_remove_members_async (priv->group_iface, + handles, + message, + tp_group_async_cb, + "Failed to remove member"); g_array_free (handles, TRUE); } -GArray * +GList * empathy_tp_group_get_members (EmpathyTpGroup *group) { - EmpathyTpGroupPriv *priv; - GArray *members; - GError *error = NULL; + EmpathyTpGroupPriv *priv = GET_PRIV (group); - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); + g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_get_members (priv->group_iface, - &members, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Couldn't get members: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - - return members; -} - -void -empathy_tp_group_get_all_members (EmpathyTpGroup *group, - GArray **members, - GArray **local_pending, - GArray **remote_pending) -{ - EmpathyTpGroupPriv *priv; - GError *error = NULL; - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_get_all_members (priv->group_iface, - members, - local_pending, - remote_pending, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Couldn't get all members: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } + return g_list_copy (priv->members); } GList * -empathy_tp_group_get_local_pending_members_with_info (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv; - GPtrArray *array; - guint i; - GList *infos = NULL; - GError *error = NULL; - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_get_local_pending_members_with_info (priv->group_iface, - &array, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "GetLocalPendingMembersWithInfo failed: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - - return NULL; - } - - if (!array) { - /* This happens with butterfly because - * GetLocalPendingMembersWithInfo is not - * implemented */ - return NULL; - } - - for (i = 0; array->len > i; i++) { - GValueArray *pending_struct; - EmpathyTpGroupInfo *info; - const gchar *message; - - info = g_slice_new (EmpathyTpGroupInfo); - - pending_struct = g_ptr_array_index (array, i); - info->member = g_value_get_uint (g_value_array_get_nth (pending_struct, 0)); - info->actor = g_value_get_uint (g_value_array_get_nth (pending_struct, 1)); - info->reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2)); - message = g_value_get_string (g_value_array_get_nth (pending_struct, 3)); - info->message = g_strdup (message); - g_value_array_free (pending_struct); - - infos = g_list_prepend (infos, info); - } - g_ptr_array_free (array, TRUE); - - return infos; -} - -void -empathy_tp_group_info_list_free (GList *infos) +empathy_tp_group_get_local_pendings (EmpathyTpGroup *group) { - GList *l; + EmpathyTpGroupPriv *priv = GET_PRIV (group); + GList *pendings = NULL, *l; - for (l = infos; l; l = l->next) { - EmpathyTpGroupInfo *info; + for (l = priv->local_pendings; l; l = l->next) { + EmpathyPendingInfo *info; + EmpathyPendingInfo *new_info; info = l->data; - - g_free (info->message); - g_slice_free (EmpathyTpGroupInfo, info); + new_info = empathy_pending_info_new (info->member, + info->actor, + info->message); + pendings = g_list_prepend (pendings, new_info); } - g_list_free (infos); -} - -static void -tp_group_destroy_cb (DBusGProxy *proxy, - EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv; - - priv = GET_PRIV (group); - - g_object_unref (priv->group_iface); - g_object_unref (priv->tp_chan); - priv->group_iface = NULL; - priv->tp_chan = NULL; + return pendings; } -static void -tp_group_members_changed_cb (DBusGProxy *group_iface, - gchar *message, - GArray *added, - GArray *removed, - GArray *local_pending, - GArray *remote_pending, - guint actor, - guint reason, - EmpathyTpGroup *group) +GList * +empathy_tp_group_get_remote_pendings (EmpathyTpGroup *group) { - EmpathyTpGroupPriv *priv; + EmpathyTpGroupPriv *priv = GET_PRIV (group); - priv = GET_PRIV (group); + g_list_foreach (priv->remote_pendings, (GFunc) g_object_ref, NULL); - /* emit signals */ - if (added->len > 0) { - g_signal_emit (group, signals[MEMBERS_ADDED], 0, - added, actor, reason, message); - } - if (removed->len > 0) { - g_signal_emit (group, signals[MEMBERS_REMOVED], 0, - removed, actor, reason, message); - } - if (local_pending->len > 0) { - g_signal_emit (group, signals[LOCAL_PENDING], 0, - local_pending, actor, reason, message); - } - if (remote_pending->len > 0) { - g_signal_emit (group, signals[REMOTE_PENDING], 0, - remote_pending, actor, reason, message); - } + return g_list_copy (priv->remote_pendings); } const gchar * @@ -443,35 +770,21 @@ empathy_tp_group_get_name (EmpathyTpGroup *group) priv = GET_PRIV (group); /* Lazy initialisation */ - if (priv->group_name) { - return priv->group_name; + if (!priv->group_name) { + priv->group_name = empathy_inspect_channel (priv->account, priv->tp_chan); } - priv->group_name = empathy_inspect_channel (priv->account, priv->tp_chan); - return priv->group_name; } -guint -empathy_tp_group_get_self_handle (EmpathyTpGroup *group) +EmpathyContact * +empathy_tp_group_get_self_contact (EmpathyTpGroup *group) { - EmpathyTpGroupPriv *priv; - guint handle; - GError *error = NULL; - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), 0 ); - - priv = GET_PRIV (group); + EmpathyTpGroupPriv *priv = GET_PRIV (group); - if (!tp_chan_iface_group_get_self_handle (priv->group_iface, &handle, &error)) { - empathy_debug (DEBUG_DOMAIN, - "Failed to get self handle: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return 0; - } + g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - return handle; + return tp_group_get_contact (group, priv->self_handle); } const gchar * @@ -488,21 +801,10 @@ empathy_tp_group_get_object_path (EmpathyTpGroup *group) gboolean empathy_tp_group_is_member (EmpathyTpGroup *group, - guint handle) + EmpathyContact *contact) { - GArray *members; - guint i; - gboolean found = FALSE; - - members = empathy_tp_group_get_members (group); - for (i = 0; i < members->len; i++) { - if (g_array_index (members, guint, i) == handle) { - found = TRUE; - break; - } - } - g_array_free (members, TRUE); - - return found; + EmpathyTpGroupPriv *priv = GET_PRIV (group); + + return g_list_find (priv->members, contact) != NULL; } diff --git a/libempathy/empathy-tp-group.h b/libempathy/empathy-tp-group.h index 5ea7bfc7..14cbd464 100644 --- a/libempathy/empathy-tp-group.h +++ b/libempathy/empathy-tp-group.h @@ -1,6 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2006 Xavier Claessens + * Copyright (C) 2007 Collabora Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -16,6 +17,8 @@ * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens */ #ifndef __EMPATHY_TP_GROUP_H__ @@ -24,8 +27,11 @@ #include #include +#include #include +#include "empathy-contact.h" + G_BEGIN_DECLS #define EMPATHY_TYPE_TP_GROUP (empathy_tp_group_get_type ()) @@ -48,39 +54,40 @@ struct _EmpathyTpGroupClass { }; typedef struct { - guint member; - guint actor; - guint reason; - gchar *message; -} EmpathyTpGroupInfo; + EmpathyContact *member; + EmpathyContact *actor; + gchar *message; + guint reason; +} EmpathyPendingInfo; -GType empathy_tp_group_get_type (void) G_GNUC_CONST; -EmpathyTpGroup * empathy_tp_group_new (McAccount *account, - TpChan *tp_chan); -void empathy_tp_group_add_members (EmpathyTpGroup *group, - GArray *handles, - const gchar *message); -void empathy_tp_group_add_member (EmpathyTpGroup *group, - guint handle, - const gchar *message); -void empathy_tp_group_remove_members (EmpathyTpGroup *group, - GArray *handle, - const gchar *message); -void empathy_tp_group_remove_member (EmpathyTpGroup *group, - guint handle, - const gchar *message); -GArray * empathy_tp_group_get_members (EmpathyTpGroup *group); -void empathy_tp_group_get_all_members (EmpathyTpGroup *group, - GArray **members, - GArray **local_pending, - GArray **remote_pending); -GList * empathy_tp_group_get_local_pending_members_with_info (EmpathyTpGroup *group); -void empathy_tp_group_info_list_free (GList *infos); -const gchar * empathy_tp_group_get_name (EmpathyTpGroup *group); -guint empathy_tp_group_get_self_handle (EmpathyTpGroup *group); -const gchar * empathy_tp_group_get_object_path (EmpathyTpGroup *group); -gboolean empathy_tp_group_is_member (EmpathyTpGroup *group, - guint handle); +GType empathy_tp_group_get_type (void) G_GNUC_CONST; +EmpathyTpGroup * empathy_tp_group_new (McAccount *account, + TpChan *tp_chan); +void empathy_tp_group_close (EmpathyTpGroup *group); +void empathy_tp_group_add_members (EmpathyTpGroup *group, + GList *contacts, + const gchar *message); +void empathy_tp_group_add_member (EmpathyTpGroup *group, + EmpathyContact *contact, + const gchar *message); +void empathy_tp_group_remove_members (EmpathyTpGroup *group, + GList *contacts, + const gchar *message); +void empathy_tp_group_remove_member (EmpathyTpGroup *group, + EmpathyContact *contact, + const gchar *message); +GList * empathy_tp_group_get_members (EmpathyTpGroup *group); +GList * empathy_tp_group_get_local_pendings (EmpathyTpGroup *group); +GList * empathy_tp_group_get_remote_pendings (EmpathyTpGroup *group); +const gchar * empathy_tp_group_get_name (EmpathyTpGroup *group); +EmpathyContact * empathy_tp_group_get_self_contact (EmpathyTpGroup *group); +const gchar * empathy_tp_group_get_object_path (EmpathyTpGroup *group); +gboolean empathy_tp_group_is_member (EmpathyTpGroup *group, + EmpathyContact *contact); +EmpathyPendingInfo *empathy_pending_info_new (EmpathyContact *member, + EmpathyContact *actor, + const gchar *message); +void empathy_pending_info_free (EmpathyPendingInfo *info); G_END_DECLS diff --git a/python/README b/python/README new file mode 100644 index 00000000..f9c121b5 --- /dev/null +++ b/python/README @@ -0,0 +1,19 @@ +To update python binding: +1) + $ make distclean + $ python /usr/share/pygtk/2.0/codegen/h2def.py libempathy/*.h > python/pyempathy/pyempathy.defs + $ python /usr/share/pygtk/2.0/codegen/h2def.py libempathy-gtk/*.h > python/pyempathygtk/pyempathygtk.defs + +2) +Manually modify pyempathy.defs, ContactList is not an object but an interface: +(define-interface ContactList + (in-module "Empathy") + (c-name "EmpathyContactList") + (gtype-id "EMPATHY_TYPE_CONTACT_LIST") +) + +ContactManager, TpChatroom and TpContactList implements ContactList interface: + (implements "EmpathyContactList") + +3) +Manually update headers in pyempathy.override and pyempathygtk.override. diff --git a/python/pyempathy/pyempathy.defs b/python/pyempathy/pyempathy.defs index eea0b76d..97f7b6ac 100644 --- a/python/pyempathy/pyempathy.defs +++ b/python/pyempathy/pyempathy.defs @@ -43,6 +43,13 @@ (gtype-id "EMPATHY_TYPE_CONTACT") ) +(define-object ContactFactory + (in-module "Empathy") + (parent "GObject") + (c-name "EmpathyContactFactory") + (gtype-id "EMPATHY_TYPE_CONTACT_FACTORY") +) + (define-object ContactManager (in-module "Empathy") (parent "GObject") @@ -116,20 +123,15 @@ (gtype-id "EMPATHY_TYPE_TP_GROUP") ) -;; Enumerations and flags ... - -(define-flags Subscription +(define-object TpRoomlist (in-module "Empathy") - (c-name "EmpathySubscription") - (gtype-id "EMPATHY_TYPE_SUBSCRIPTION") - (values - '("none" "EMPATHY_SUBSCRIPTION_NONE") - '("to" "EMPATHY_SUBSCRIPTION_TO") - '("from" "EMPATHY_SUBSCRIPTION_FROM") - '("both" "EMPATHY_SUBSCRIPTION_BOTH") - ) + (parent "GObject") + (c-name "EmpathyTpRoomlist") + (gtype-id "EMPATHY_TYPE_TP_ROOMLIST") ) +;; Enumerations and flags ... + (define-enum MessageType (in-module "Empathy") (c-name "EmpathyMessageType") @@ -159,8 +161,8 @@ ;; From empathy-avatar.h -(define-function empathy_avatar_get_gtype - (c-name "empathy_avatar_get_gtype") +(define-function empathy_avatar_get_type + (c-name "empathy_avatar_get_type") (return-type "GType") ) @@ -189,23 +191,6 @@ -;; From empathy-chandler-glue.h - -(define-function dbus_glib_marshal_empathy_chandler_BOOLEAN__STRING_BOXED_STRING_BOXED_UINT_UINT_POINTER - (c-name "dbus_glib_marshal_empathy_chandler_BOOLEAN__STRING_BOXED_STRING_BOXED_UINT_UINT_POINTER") - (return-type "none") - (parameters - '("GClosure*" "closure") - '("GValue*" "return_value") - '("guint" "n_param_values") - '("const-GValue*" "param_values") - '("gpointer" "invocation_hint") - '("gpointer" "marshal_data") - ) -) - - - ;; From empathy-chandler.h (define-function empathy_chandler_get_type @@ -225,73 +210,6 @@ -;; From empathy-chatroom-manager.h - -(define-function empathy_chatroom_manager_get_type - (c-name "empathy_chatroom_manager_get_type") - (return-type "GType") -) - -(define-function empathy_chatroom_manager_new - (c-name "empathy_chatroom_manager_new") - (is-constructor-of "EmpathyChatroomManager") - (return-type "EmpathyChatroomManager*") -) - -(define-method add - (of-object "EmpathyChatroomManager") - (c-name "empathy_chatroom_manager_add") - (return-type "gboolean") - (parameters - '("EmpathyChatroom*" "chatroom") - ) -) - -(define-method remove - (of-object "EmpathyChatroomManager") - (c-name "empathy_chatroom_manager_remove") - (return-type "none") - (parameters - '("EmpathyChatroom*" "chatroom") - ) -) - -(define-method find - (of-object "EmpathyChatroomManager") - (c-name "empathy_chatroom_manager_find") - (return-type "EmpathyChatroom*") - (parameters - '("McAccount*" "account") - '("const-gchar*" "room") - ) -) - -(define-method get_chatrooms - (of-object "EmpathyChatroomManager") - (c-name "empathy_chatroom_manager_get_chatrooms") - (return-type "GList*") - (parameters - '("McAccount*" "account") - ) -) - -(define-method get_count - (of-object "EmpathyChatroomManager") - (c-name "empathy_chatroom_manager_get_count") - (return-type "guint") - (parameters - '("McAccount*" "account") - ) -) - -(define-method store - (of-object "EmpathyChatroomManager") - (c-name "empathy_chatroom_manager_store") - (return-type "none") -) - - - ;; From empathy-chatroom.h (define-function empathy_chatroom_get_type @@ -391,6 +309,73 @@ +;; From empathy-chatroom-manager.h + +(define-function empathy_chatroom_manager_get_type + (c-name "empathy_chatroom_manager_get_type") + (return-type "GType") +) + +(define-function empathy_chatroom_manager_new + (c-name "empathy_chatroom_manager_new") + (is-constructor-of "EmpathyChatroomManager") + (return-type "EmpathyChatroomManager*") +) + +(define-method add + (of-object "EmpathyChatroomManager") + (c-name "empathy_chatroom_manager_add") + (return-type "gboolean") + (parameters + '("EmpathyChatroom*" "chatroom") + ) +) + +(define-method remove + (of-object "EmpathyChatroomManager") + (c-name "empathy_chatroom_manager_remove") + (return-type "none") + (parameters + '("EmpathyChatroom*" "chatroom") + ) +) + +(define-method find + (of-object "EmpathyChatroomManager") + (c-name "empathy_chatroom_manager_find") + (return-type "EmpathyChatroom*") + (parameters + '("McAccount*" "account") + '("const-gchar*" "room") + ) +) + +(define-method get_chatrooms + (of-object "EmpathyChatroomManager") + (c-name "empathy_chatroom_manager_get_chatrooms") + (return-type "GList*") + (parameters + '("McAccount*" "account") + ) +) + +(define-method get_count + (of-object "EmpathyChatroomManager") + (c-name "empathy_chatroom_manager_get_count") + (return-type "guint") + (parameters + '("McAccount*" "account") + ) +) + +(define-method store + (of-object "EmpathyChatroomManager") + (c-name "empathy_chatroom_manager_store") + (return-type "none") +) + + + ;; From empathy-conf.h (define-function empathy_conf_get_type @@ -510,198 +495,74 @@ -;; From empathy-contact-list.h +;; From empathy-contact-factory.h -(define-function contact_list_get_type - (c-name "empathy_contact_list_get_type") +(define-function empathy_contact_factory_get_type + (c-name "empathy_contact_factory_get_type") (return-type "GType") ) -(define-method list_info_new - (of-object "EmpathyContact") - (c-name "empathy_contact_list_info_new") - (return-type "EmpathyContactListInfo*") - (parameters - '("const-gchar*" "message") - ) -) - -(define-method free - (of-object "EmpathyContactListInfo") - (c-name "empathy_contact_list_info_free") - (return-type "none") -) - -(define-method setup - (of-object "EmpathyContactList") - (c-name "empathy_contact_list_setup") - (return-type "none") +(define-function empathy_contact_factory_new + (c-name "empathy_contact_factory_new") + (is-constructor-of "EmpathyContactFactory") + (return-type "EmpathyContactFactory*") ) -(define-method find - (of-object "EmpathyContactList") - (c-name "empathy_contact_list_find") +(define-method get_user + (of-object "EmpathyContactFactory") + (c-name "empathy_contact_factory_get_user") (return-type "EmpathyContact*") (parameters - '("const-gchar*" "id") - ) -) - -(define-method add - (of-object "EmpathyContactList") - (c-name "empathy_contact_list_add") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "message") - ) -) - -(define-method remove - (of-object "EmpathyContactList") - (c-name "empathy_contact_list_remove") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "message") - ) -) - -(define-method get_members - (of-object "EmpathyContactList") - (c-name "empathy_contact_list_get_members") - (return-type "GList*") -) - -(define-method get_local_pending - (of-object "EmpathyContactList") - (c-name "empathy_contact_list_get_local_pending") - (return-type "GList*") -) - -(define-method process_pending - (of-object "EmpathyContactList") - (c-name "empathy_contact_list_process_pending") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("gboolean" "accept") + '("McAccount*" "account") ) ) -(define-virtual setup - (of-object "EmpathyContactList") - (return-type "none") -) - -(define-virtual find - (of-object "EmpathyContactList") +(define-method get_from_id + (of-object "EmpathyContactFactory") + (c-name "empathy_contact_factory_get_from_id") (return-type "EmpathyContact*") - (parameters - '("const-gchar*" "id") - ) -) - -(define-virtual add - (of-object "EmpathyContactList") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "message") - ) -) - -(define-virtual remove - (of-object "EmpathyContactList") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("const-gchar*" "message") - ) -) - -(define-virtual get_members - (of-object "EmpathyContactList") - (return-type "GList*") -) - -(define-virtual get_local_pending - (of-object "EmpathyContactList") - (return-type "GList*") -) - -(define-virtual process_pending - (of-object "EmpathyContactList") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - '("gboolean" "accept") - ) -) - -;; From empathy-contact-manager.h - -(define-function empathy_contact_manager_get_type - (c-name "empathy_contact_manager_get_type") - (return-type "GType") -) - -(define-function empathy_contact_manager_new - (c-name "empathy_contact_manager_new") - (is-constructor-of "EmpathyContactManager") - (return-type "EmpathyContactManager*") -) - -(define-method get_list - (of-object "EmpathyContactManager") - (c-name "empathy_contact_manager_get_list") - (return-type "EmpathyTpContactList*") (parameters '("McAccount*" "account") + '("const-gchar*" "id") ) ) -(define-method get_user - (of-object "EmpathyContactManager") - (c-name "empathy_contact_manager_get_user") +(define-method get_from_handle + (of-object "EmpathyContactFactory") + (c-name "empathy_contact_factory_get_from_handle") (return-type "EmpathyContact*") (parameters '("McAccount*" "account") + '("guint" "handle") ) ) -(define-method create - (of-object "EmpathyContactManager") - (c-name "empathy_contact_manager_create") - (return-type "EmpathyContact*") +(define-method get_from_handles + (of-object "EmpathyContactFactory") + (c-name "empathy_contact_factory_get_from_handles") + (return-type "GList*") (parameters '("McAccount*" "account") - '("const-gchar*" "id") + '("GArray*" "handles") ) ) -(define-method rename_group - (of-object "EmpathyContactManager") - (c-name "empathy_contact_manager_rename_group") +(define-method set_name + (of-object "EmpathyContactFactory") + (c-name "empathy_contact_factory_set_name") (return-type "none") (parameters - '("const-gchar*" "old_group") - '("const-gchar*" "new_group") + '("EmpathyContact*" "contact") + '("const-gchar*" "name") ) ) -(define-method get_groups - (of-object "EmpathyContactManager") - (c-name "empathy_contact_manager_get_groups") - (return-type "GList*") -) - ;; From empathy-contact.h -(define-function empathy_contact_get_gtype - (c-name "empathy_contact_get_gtype") +(define-function empathy_contact_get_type + (c-name "empathy_contact_get_type") (return-type "GType") ) @@ -730,40 +591,73 @@ (return-type "const-gchar*") ) +(define-method set_id + (of-object "EmpathyContact") + (c-name "empathy_contact_set_id") + (return-type "none") + (parameters + '("const-gchar*" "id") + ) +) + (define-method get_name (of-object "EmpathyContact") (c-name "empathy_contact_get_name") (return-type "const-gchar*") ) +(define-method set_name + (of-object "EmpathyContact") + (c-name "empathy_contact_set_name") + (return-type "none") + (parameters + '("const-gchar*" "name") + ) +) + (define-method get_avatar (of-object "EmpathyContact") (c-name "empathy_contact_get_avatar") (return-type "EmpathyAvatar*") ) +(define-method set_avatar + (of-object "EmpathyContact") + (c-name "empathy_contact_set_avatar") + (return-type "none") + (parameters + '("EmpathyAvatar*" "avatar") + ) +) + (define-method get_account (of-object "EmpathyContact") (c-name "empathy_contact_get_account") (return-type "McAccount*") ) -(define-method get_presence +(define-method set_account (of-object "EmpathyContact") - (c-name "empathy_contact_get_presence") - (return-type "EmpathyPresence*") + (c-name "empathy_contact_set_account") + (return-type "none") + (parameters + '("McAccount*" "account") + ) ) -(define-method get_groups +(define-method get_presence (of-object "EmpathyContact") - (c-name "empathy_contact_get_groups") - (return-type "GList*") + (c-name "empathy_contact_get_presence") + (return-type "EmpathyPresence*") ) -(define-method get_subscription +(define-method set_presence (of-object "EmpathyContact") - (c-name "empathy_contact_get_subscription") - (return-type "EmpathySubscription") + (c-name "empathy_contact_set_presence") + (return-type "none") + (parameters + '("EmpathyPresence*" "presence") + ) ) (define-method get_handle @@ -772,146 +666,166 @@ (return-type "guint") ) +(define-method set_handle + (of-object "EmpathyContact") + (c-name "empathy_contact_set_handle") + (return-type "none") + (parameters + '("guint" "handle") + ) +) + (define-method is_user (of-object "EmpathyContact") (c-name "empathy_contact_is_user") (return-type "gboolean") ) -(define-method set_id +(define-method set_is_user (of-object "EmpathyContact") - (c-name "empathy_contact_set_id") + (c-name "empathy_contact_set_is_user") (return-type "none") (parameters - '("const-gchar*" "id") + '("gboolean" "is_user") ) ) -(define-method set_name +(define-method is_online (of-object "EmpathyContact") - (c-name "empathy_contact_set_name") - (return-type "none") + (c-name "empathy_contact_is_online") + (return-type "gboolean") +) + +(define-method get_status + (of-object "EmpathyContact") + (c-name "empathy_contact_get_status") + (return-type "const-gchar*") +) + +(define-function empathy_contact_equal + (c-name "empathy_contact_equal") + (return-type "gboolean") (parameters - '("const-gchar*" "name") + '("gconstpointer" "v1") + '("gconstpointer" "v2") ) ) -(define-method set_avatar - (of-object "EmpathyContact") - (c-name "empathy_contact_set_avatar") - (return-type "none") +(define-function empathy_contact_hash + (c-name "empathy_contact_hash") + (return-type "guint") (parameters - '("EmpathyAvatar*" "avatar") + '("gconstpointer" "key") ) ) -(define-method set_account - (of-object "EmpathyContact") - (c-name "empathy_contact_set_account") - (return-type "none") - (parameters - '("McAccount*" "account") - ) + + +;; From empathy-contact-list.h + +(define-function empathy_contact_list_get_type + (c-name "empathy_contact_list_get_type") + (return-type "GType") ) -(define-method set_presence - (of-object "EmpathyContact") - (c-name "empathy_contact_set_presence") +(define-method add + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_add") (return-type "none") (parameters - '("EmpathyPresence*" "presence") + '("EmpathyContact*" "contact") + '("const-gchar*" "message") ) ) -(define-method set_groups - (of-object "EmpathyContact") - (c-name "empathy_contact_set_groups") +(define-method remove + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_remove") (return-type "none") (parameters - '("GList*" "categories") + '("EmpathyContact*" "contact") + '("const-gchar*" "message") ) ) -(define-method set_subscription - (of-object "EmpathyContact") - (c-name "empathy_contact_set_subscription") - (return-type "none") - (parameters - '("EmpathySubscription" "subscription") - ) +(define-method get_members + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_get_members") + (return-type "GList*") ) -(define-method set_handle - (of-object "EmpathyContact") - (c-name "empathy_contact_set_handle") - (return-type "none") - (parameters - '("guint" "handle") - ) +(define-method get_pendings + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_get_pendings") + (return-type "GList*") ) -(define-method set_is_user - (of-object "EmpathyContact") - (c-name "empathy_contact_set_is_user") - (return-type "none") +(define-method get_all_groups + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_get_all_groups") + (return-type "GList*") +) + +(define-method get_groups + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_get_groups") + (return-type "GList*") (parameters - '("gboolean" "is_user") + '("EmpathyContact*" "contact") ) ) -(define-method add_group - (of-object "EmpathyContact") - (c-name "empathy_contact_add_group") +(define-method add_to_group + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_add_to_group") (return-type "none") (parameters + '("EmpathyContact*" "contact") '("const-gchar*" "group") ) ) -(define-method remove_group - (of-object "EmpathyContact") - (c-name "empathy_contact_remove_group") +(define-method remove_from_group + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_remove_from_group") (return-type "none") (parameters + '("EmpathyContact*" "contact") '("const-gchar*" "group") ) ) -(define-method is_online - (of-object "EmpathyContact") - (c-name "empathy_contact_is_online") - (return-type "gboolean") -) - -(define-method is_in_group - (of-object "EmpathyContact") - (c-name "empathy_contact_is_in_group") - (return-type "gboolean") +(define-method rename_group + (of-object "EmpathyContactList") + (c-name "empathy_contact_list_rename_group") + (return-type "none") (parameters - '("const-gchar*" "group") + '("const-gchar*" "old_group") + '("const-gchar*" "new_group") ) ) -(define-method get_status - (of-object "EmpathyContact") - (c-name "empathy_contact_get_status") - (return-type "const-gchar*") + + +;; From empathy-contact-manager.h + +(define-function empathy_contact_manager_get_type + (c-name "empathy_contact_manager_get_type") + (return-type "GType") ) -(define-function empathy_contact_equal - (c-name "empathy_contact_equal") - (return-type "gboolean") - (parameters - '("gconstpointer" "v1") - '("gconstpointer" "v2") - ) +(define-function empathy_contact_manager_new + (c-name "empathy_contact_manager_new") + (is-constructor-of "EmpathyContactManager") + (return-type "EmpathyContactManager*") ) -(define-function empathy_contact_hash - (c-name "empathy_contact_hash") - (return-type "guint") +(define-method get_list + (of-object "EmpathyContactManager") + (c-name "empathy_contact_manager_get_list") + (return-type "EmpathyTpContactList*") (parameters - '("gconstpointer" "key") + '("McAccount*" "account") ) ) @@ -929,21 +843,9 @@ (varargs #t) ) - - -;; From empathy-filter-glue.h - -(define-function dbus_glib_marshal_empathy_filter_BOOLEAN__STRING_BOXED_STRING_BOXED_UINT_UINT_UINT_POINTER - (c-name "dbus_glib_marshal_empathy_filter_BOOLEAN__STRING_BOXED_STRING_BOXED_UINT_UINT_UINT_POINTER") +(define-function empathy_debug_set_log_file_from_env + (c-name "empathy_debug_set_log_file_from_env") (return-type "none") - (parameters - '("GClosure*" "closure") - '("GValue*" "return_value") - '("guint" "n_param_values") - '("const-GValue*" "param_values") - '("gpointer" "invocation_hint") - '("gpointer" "marshal_data") - ) ) @@ -1096,6 +998,15 @@ ) ) +(define-method get_messages_for_file + (of-object "EmpathyLogManager") + (c-name "empathy_log_manager_get_messages_for_file") + (return-type "GList*") + (parameters + '("const-gchar*" "filename") + ) +) + (define-method get_messages_for_date (of-object "EmpathyLogManager") (c-name "empathy_log_manager_get_messages_for_date") @@ -1119,6 +1030,15 @@ ) ) +(define-method get_messages_for_file + (of-object "EmpathyLogManager") + (c-name "empathy_log_manager_get_messages_for_file") + (return-type "GList*") + (parameters + '("const-gchar*" "filename") + ) +) + (define-method get_chats (of-object "EmpathyLogManager") (c-name "empathy_log_manager_get_chats") @@ -1155,10 +1075,6 @@ -;; From empathy-marshal.h - - - ;; From empathy-message.h (define-function empathy_message_get_gtype @@ -1250,6 +1166,20 @@ ) ) +(define-function empathy_message_type_from_str + (c-name "empathy_message_type_from_str") + (return-type "EmpathyMessageType") + (parameters + '("const-gchar*" "type_str") + ) +) + +(define-method to_str + (of-object "EmpathyMessageType") + (c-name "empathy_message_type_to_str") + (return-type "const-gchar*") +) + ;; From empathy-presence.h @@ -1535,55 +1465,6 @@ (return-type "McAccount*") ) -(define-method get_user - (of-object "EmpathyTpContactList") - (c-name "empathy_tp_contact_list_get_user") - (return-type "EmpathyContact*") -) - -(define-method get_from_id - (of-object "EmpathyTpContactList") - (c-name "empathy_tp_contact_list_get_from_id") - (return-type "EmpathyContact*") - (parameters - '("const-gchar*" "id") - ) -) - -(define-method get_from_handle - (of-object "EmpathyTpContactList") - (c-name "empathy_tp_contact_list_get_from_handle") - (return-type "EmpathyContact*") - (parameters - '("guint" "handle") - ) -) - -(define-method get_from_handles - (of-object "EmpathyTpContactList") - (c-name "empathy_tp_contact_list_get_from_handles") - (return-type "GList*") - (parameters - '("GArray*" "handles") - ) -) - -(define-method rename_group - (of-object "EmpathyTpContactList") - (c-name "empathy_tp_contact_list_rename_group") - (return-type "none") - (parameters - '("const-gchar*" "old_group") - '("const-gchar*" "new_group") - ) -) - -(define-method get_groups - (of-object "EmpathyTpContactList") - (c-name "empathy_tp_contact_list_get_groups") - (return-type "GList*") -) - ;; From empathy-tp-group.h @@ -1598,17 +1479,23 @@ (is-constructor-of "EmpathyTpGroup") (return-type "EmpathyTpGroup*") (parameters + '("McAccount*" "account") '("TpChan*" "tp_chan") - '("TpConn*" "tp_conn") ) ) +(define-method close + (of-object "EmpathyTpGroup") + (c-name "empathy_tp_group_close") + (return-type "none") +) + (define-method add_members (of-object "EmpathyTpGroup") (c-name "empathy_tp_group_add_members") (return-type "none") (parameters - '("GArray*" "handles") + '("GList*" "contacts") '("const-gchar*" "message") ) ) @@ -1618,7 +1505,7 @@ (c-name "empathy_tp_group_add_member") (return-type "none") (parameters - '("guint" "handle") + '("EmpathyContact*" "contact") '("const-gchar*" "message") ) ) @@ -1628,7 +1515,7 @@ (c-name "empathy_tp_group_remove_members") (return-type "none") (parameters - '("GArray*" "handle") + '("GList*" "contacts") '("const-gchar*" "message") ) ) @@ -1638,7 +1525,7 @@ (c-name "empathy_tp_group_remove_member") (return-type "none") (parameters - '("guint" "handle") + '("EmpathyContact*" "contact") '("const-gchar*" "message") ) ) @@ -1646,44 +1533,31 @@ (define-method get_members (of-object "EmpathyTpGroup") (c-name "empathy_tp_group_get_members") - (return-type "GArray*") + (return-type "GList*") ) -(define-method get_all_members +(define-method get_local_pendings (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_all_members") - (return-type "none") - (parameters - '("GArray**" "members") - '("GArray**" "local_pending") - '("GArray**" "remote_pending") - ) + (c-name "empathy_tp_group_get_local_pendings") + (return-type "GList*") ) -(define-method get_local_pending_members_with_info +(define-method get_remote_pendings (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_local_pending_members_with_info") + (c-name "empathy_tp_group_get_remote_pendings") (return-type "GList*") ) -(define-function empathy_tp_group_info_list_free - (c-name "empathy_tp_group_info_list_free") - (return-type "none") - (parameters - '("GList*" "infos") - ) -) - (define-method get_name (of-object "EmpathyTpGroup") (c-name "empathy_tp_group_get_name") (return-type "const-gchar*") ) -(define-method get_self_handle +(define-method get_self_contact (of-object "EmpathyTpGroup") - (c-name "empathy_tp_group_get_self_handle") - (return-type "guint") + (c-name "empathy_tp_group_get_self_contact") + (return-type "EmpathyContact*") ) (define-method get_object_path @@ -1697,10 +1571,63 @@ (c-name "empathy_tp_group_is_member") (return-type "gboolean") (parameters - '("guint" "handle") + '("EmpathyContact*" "contact") + ) +) + +(define-function empathy_pending_info_new + (c-name "empathy_pending_info_new") + (is-constructor-of "EmpathyPendingInfo") + (return-type "EmpathyPendingInfo*") + (parameters + '("EmpathyContact*" "member") + '("EmpathyContact*" "actor") + '("const-gchar*" "message") + ) +) + +(define-method free + (of-object "EmpathyPendingInfo") + (c-name "empathy_pending_info_free") + (return-type "none") +) + + + +;; From empathy-tp-roomlist.h + +(define-function empathy_tp_roomlist_get_type + (c-name "empathy_tp_roomlist_get_type") + (return-type "GType") +) + +(define-function empathy_tp_roomlist_new + (c-name "empathy_tp_roomlist_new") + (is-constructor-of "EmpathyTpRoomlist") + (return-type "EmpathyTpRoomlist*") + (parameters + '("McAccount*" "account") ) ) +(define-method is_listing + (of-object "EmpathyTpRoomlist") + (c-name "empathy_tp_roomlist_is_listing") + (return-type "gboolean") +) + +(define-method start + (of-object "EmpathyTpRoomlist") + (c-name "empathy_tp_roomlist_start") + (return-type "none") +) + +(define-method stop + (of-object "EmpathyTpRoomlist") + (c-name "empathy_tp_roomlist_stop") + (return-type "none") +) + ;; From empathy-utils.h @@ -1805,8 +1732,18 @@ (return-type "MissionControl*") ) -(define-function empathy_get_channel_id - (c-name "empathy_get_channel_id") +(define-function empathy_inspect_handle + (c-name "empathy_inspect_handle") + (return-type "gchar*") + (parameters + '("McAccount*" "account") + '("guint" "handle") + '("guint" "handle_type") + ) +) + +(define-function empathy_inspect_channel + (c-name "empathy_inspect_channel") (return-type "gchar*") (parameters '("McAccount*" "account") @@ -1814,3 +1751,13 @@ ) ) +(define-function empathy_strdiff + (c-name "empathy_strdiff") + (return-type "gboolean") + (parameters + '("const-gchar*" "left") + '("const-gchar*" "right") + ) +) + + diff --git a/python/pyempathy/pyempathy.override b/python/pyempathy/pyempathy.override index 607a9e52..dd816e23 100644 --- a/python/pyempathy/pyempathy.override +++ b/python/pyempathy/pyempathy.override @@ -21,15 +21,10 @@ headers #include "empathy-tp-chatroom.h" #include "empathy-tp-contact-list.h" #include "empathy-tp-group.h" +#include "empathy-tp-roomlist.h" #include "empathy-utils.h" - - -/* FIXME */ -#define MC_TYPE_PRESENCE 1 -#define EMPATHY_TYPE_SUBSCRIPTION 2 -#define EMPATHY_TYPE_MESSAGE_TYPE 3 -#define EMPATHY_TYPE_REG_EX_TYPE 4 - +#include "empathy-contact-factory.h" +#include "empathy-enum-types.h" void empathy_add_constants(PyObject *module, const gchar *strip_prefix); void empathy_register_classes(PyObject *d); @@ -62,22 +57,3 @@ _wrap_empathy_contact_list_get_members(PyGObject *self, PyObject *args, PyObject } %% -override empathy_contact_get_groups kwargs -static PyObject * -_wrap_empathy_contact_get_groups(PyGObject *self, PyObject *args, PyObject *kwargs) -{ - - GList *groups = empathy_contact_get_groups(EMPATHY_CONTACT(self->obj)); - PyObject *py_groups = PyList_New(0); - GList *l; - - for(l = groups; l; l = l->next) { - const gchar *group; - group = l->data; - PyList_Append(py_groups, PyString_FromString(group)); - } - - return py_groups; - -} -%% diff --git a/python/pyempathygtk/pyempathygtk.defs b/python/pyempathygtk/pyempathygtk.defs index c41ea45c..71a4437b 100644 --- a/python/pyempathygtk/pyempathygtk.defs +++ b/python/pyempathygtk/pyempathygtk.defs @@ -306,6 +306,19 @@ +;; From empathy-account-widget-salut.h + +(define-function empathy_account_widget_salut_new + (c-name "empathy_account_widget_salut_new") + (is-constructor-of "EmpathyAccountWidgetSalut") + (return-type "GtkWidget*") + (parameters + '("McAccount*" "account") + ) +) + + + ;; From empathy-cell-renderer-expander.h (define-function empathy_cell_renderer_expander_get_type @@ -957,25 +970,6 @@ ) ) -(define-method set_contact_groups_func - (of-object "EmpathyContactListStore") - (c-name "empathy_contact_list_store_set_contact_groups_func") - (return-type "none") - (parameters - '("EmpathyContactGroupsFunc" "func") - '("gpointer" "user_data") - ) -) - -(define-method update_contact_groups - (of-object "EmpathyContactListStore") - (c-name "empathy_contact_list_store_update_contact_groups") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - ) -) - ;; From empathy-contact-list-view.h @@ -1021,25 +1015,6 @@ (return-type "GtkWidget*") ) -(define-method set_filter - (of-object "EmpathyContactListView") - (c-name "empathy_contact_list_view_set_filter") - (return-type "none") - (parameters - '("const-gchar*" "filter") - ) -) - -(define-method set_drag_received_func - (of-object "EmpathyContactListView") - (c-name "empathy_contact_list_view_set_drag_received_func") - (return-type "none") - (parameters - '("EmpathyContactListViewDragReceivedFunc" "func") - '("gpointer" "user_data") - ) -) - ;; From empathy-contact-widget.h -- 2.39.2