Bug 29417

Summary: Add API to get a TpAccount from a TpContact and/or TpConnection
Product: Telepathy Reporter: Xavier Claessens <xclaesse>
Component: tp-glibAssignee: Telepathy bugs list <telepathy-bugs>
Status: RESOLVED FIXED QA Contact: Telepathy bugs list <telepathy-bugs>
Severity: enhancement    
Priority: medium CC: f.kaser, travis.reitter
Version: git master   
Hardware: Other   
OS: All   
URL: http://cgit.collabora.com/git/user/xclaesse/telepathy-glib.git/commit/?h=contact-list&id=e0ffadae465be3dad4125119f28cee096f14b2c5
Whiteboard:
i915 platform: i915 features:
Bug Depends on: 38142    
Bug Blocks:    

Description Xavier Claessens 2010-08-06 01:33:30 UTC
It is a common case to need to get the TpAccount object from a TpContact. The work flow is usually:

You have an object 'self' which needs to work with contacts:
1) Get a TpAccount
2) Gets its TpConnection, and wait for it to be ready. You have only one user_data so you give self
3) Get some TpContact from the connection
4) ... You need the TpAccount of that contact, but since the only user_data you had for step 2 is self, you "lost" the account pointer.

The usual solutions for that is to use g_object_set_data(connection, "account", account); or create a struct{self, account}; to pass as user_data. It is ugly and complex for a very common flow IMO.

So I suggest adding a TpConnection:account construct-only property. When TpAccount creates its own TpConnection object, that property is set. If the TpConnection is created manually, that property is defined as NULL. Like that we are sure to keep a 1:1 mapping TpAccount<>TpConnection.
Comment 1 Simon McVittie 2010-08-06 03:41:40 UTC
We've discussed this on IRC and not really come to a conclusion; there are some problems with a naive approach, like reference-counting cycles between the account and connection.

In Handlers and similar channel-oriented things, we shouldn't generally need this, because there'll usually be an object (e.g. an Empathy chat tab) that knows its own account, connection and channel.

The difficult case is when you have a contact but you're not account- or channel-specific, like the Empathy contact list owning TpContact objects, and wanting to know which account to pass to ChannelDispatcher.EnsureChannel when you click on a contact. The contact list is account-agnostic, although I think we can safely assume it has a ref to the TpAccountManager.

10:48 < Zdra> smcv, the use case is: "I have a TpContact and I want to request 
              a channel for it", the dispatcher needs the account
10:48 < smcv> devil's advocate: isn't that just an artefact of us not having 
              metacontacts yet?

Some possibilities:

What Zdra proposed in Comment #0
================================

10:50 < smcv> the correct form of "they each ref the other" would be that the 
              Connection releases its ref when invalidated
10:50 < smcv> or soemthing

We could have:

TpAccount refs TpConnection until the TpConnection is invalidated. TpConnection refs TpAccount.

10:43 < smcv> I don't think adding a property whose value might be a lie is the 
              right solution
10:43 < danni> smcv: well it's either real or NULL
10:43 < danni> and we can define the semantics by which it will be real or NULL
10:43 < smcv> right, but the NULL case means "either it doesn't belong to an 
              account or I have no idea"
...
10:44 < danni> smcv: if we define the semantics, the programmer will know 
               whether she expects it to be null or not
...
10:55 < smcv> the relationship isn't strictly 1:1, which is an extra wart
10:56 < smcv> if you keep hold of refs to a dead TpConnection, then they still 
              belong to the same Account you first thought of, but are not the 
              *current* Connection for that Account

Global lookup table
===================

Rejected:

10:43 < Zdra> smcv, danni: what about TpAccount 
              *tp_account_lookup_for_connection(TpConnection){return 
              g_hash_table_lookup (global_conn_to_acc_table, connection);}
10:44 < Zdra> hm, nevermind, that's just the same has having prop on the conn

Connection knows the *object path of* its Account
=================================================

This has the same issues as Comment #0 in terms of not always having the necessary information, but unlike Comment #0, it doesn't have cyclic references.

10:57 < smcv> one way to not have the ref cycle would be for the TpConnection 
              to know its own Account *by object path*
...
11:04 < smcv> you can emulate tp_am_ensure with tp_account_ensure 
              (tp_am_ensure_account (am, path), ...) in any case

Ability to look up the account for a connection in the TpAM
===========================================================

telepathy-qt4 has something quite similar to this.

10:32 < wjt> add a method to the AM to get the A for a Conn
10:33 < wjt> see also, the Tp::AccountSet API in tp-qt4  
10:36 < Zdra> smcv, do you prefer something like this? 
              tp_account_manager_get_account_for_connection(connection){for 
              (all accounts) if (account.connection == connection) return 
              account;} ?  
10:36 < danni> the problem is if you have multiple account proxies/connection 
               proxies, it gets messy
10:36 < danni> which one do you mean
10:37 < smcv> danni: the one the AM has in 
              tp_account_manager_get_valid_accounts()
10:37 < smcv> danni: for bonus penguin points match by object path instead of 
              by identity :-)
...
10:40 < danni> smcv: also, now you have to prepare more stuff, which you really 
               don't care about
Comment 2 Guillaume Desmottes 2010-09-15 00:34:51 UTC
*** Bug 30185 has been marked as a duplicate of this bug. ***
Comment 3 Xavier Claessens 2011-06-08 13:03:28 UTC
I have a simple patch for this: http://cgit.collabora.com/git/user/xclaesse/telepathy-glib.git/commit/?h=contact-list&id=e0ffadae465be3dad4125119f28cee096f14b2c5

I think that's already a first step. In the future we could use a ProxyFactory that guarantee uniqueness of TpConnection objects, so if TpAccount uses the same factory as the user used to get its TpConnection, that would guarantee the account is set too.
Comment 4 Guillaume Desmottes 2011-06-09 00:43:32 UTC
It sounds a bit weird to me to have API working only if the TpConnection has been retrieved in a specific way. For example, would it work with the TpConnection received from TpBaseClient's callbacks? User just don't know.
Comment 5 Xavier Claessens 2011-06-09 03:00:12 UTC
Since TpConnection is a CM proxy and TpAccount is a MC proxy, there is just no way a TpConnection get always guarantee to know its TpAccount. The best we can do is guarantee that if a TpAccountManager happens to be prepared, then TpConnection objects shared by an account will have the account set. That's what my branch does.

A 2nd step, would make sure that TpAccount and TpBaseClient actually share the same TpConnection objects, but for that we need a factory that creates unique proxies, like we have (or will have?) for TpChannel.

Once that 2nd step is done, that will become "Your connection has an account if and only if a TpAccount exists and is using the same connection factory than your TpBaseClient".
Comment 6 Xavier Claessens 2011-07-26 05:47:56 UTC
Merged as part of work on bug #38142. Now if a TpAccount lives within the same factory than its TpConnection, then tp_connection_get_account() will return it.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.