]> git.0d.be Git - empathy.git/blob - libempathy/empathy-ft-factory.c
Merge branch 'gnome-3-8'
[empathy.git] / libempathy / empathy-ft-factory.c
1 /*
2  * empathy-ft-factory.c - Source for EmpathyFTFactory
3  * Copyright (C) 2009 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Author: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
20  */
21
22 /* empathy-ft-factory.c */
23
24 #include "config.h"
25 #include "empathy-ft-factory.h"
26
27 #include "empathy-request-util.h"
28 #include "empathy-utils.h"
29
30 /**
31  * SECTION:empathy-ft-factory
32  * @title:EmpathyFTFactory
33  * @short_description: creates #EmpathyFTHandler objects
34  * @include: libempathy/empathy-ft-factory.h
35  *
36  * #EmpathyFTFactory takes care of the creation of the #EmpathyFTHandler
37  * objects used for file transfer. As the creation of the handlers is
38  * async, a client will have to connect to the ::new-ft-handler signal
39  * to receive the handler.
40  * In case of an incoming file transfer, the handler will need the destination
41  * file before being useful; as this is usually decided by the user (e.g. with
42  * a file selector), a ::new-incoming-transfer is emitted by the factory when
43  * a destination file is needed, which can be set later with
44  * empathy_ft_factory_set_destination_for_incoming_handler().
45  */
46
47 G_DEFINE_TYPE (EmpathyFTFactory, empathy_ft_factory, G_TYPE_OBJECT);
48
49 enum {
50   NEW_FT_HANDLER,
51   NEW_INCOMING_TRANSFER,
52   LAST_SIGNAL
53 };
54
55 static EmpathyFTFactory *factory_singleton = NULL;
56 static guint signals[LAST_SIGNAL] = { 0 };
57
58 /* private structure */
59 typedef struct {
60   TpBaseClient *handler;
61 } EmpathyFTFactoryPriv;
62
63 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTFactory)
64
65 static GObject *
66 do_constructor (GType type,
67     guint n_props,
68     GObjectConstructParam *props)
69 {
70   GObject *retval;
71
72   if (factory_singleton != NULL)
73     {
74       retval = g_object_ref (factory_singleton);
75     }
76   else
77     {
78       retval = G_OBJECT_CLASS (empathy_ft_factory_parent_class)->constructor
79         (type, n_props, props);
80
81       factory_singleton = EMPATHY_FT_FACTORY (retval);
82       g_object_add_weak_pointer (retval, (gpointer *) &factory_singleton);
83     }
84
85   return retval;
86 }
87
88 static void
89 empathy_ft_factory_dispose (GObject *object)
90 {
91   EmpathyFTFactory *self = (EmpathyFTFactory *) object;
92   EmpathyFTFactoryPriv *priv = GET_PRIV (self);
93
94   tp_clear_object (&priv->handler);
95
96   (G_OBJECT_CLASS (empathy_ft_factory_parent_class)->dispose) (object);
97 }
98
99 static void
100 empathy_ft_factory_class_init (EmpathyFTFactoryClass *klass)
101 {
102   GObjectClass *object_class = G_OBJECT_CLASS (klass);
103
104   g_type_class_add_private (klass, sizeof (EmpathyFTFactoryPriv));
105
106   object_class->constructor = do_constructor;
107   object_class->dispose = empathy_ft_factory_dispose;
108
109   /**
110    * EmpathyFTFactory::new-ft-handler
111    * @factory: the object which received the signal
112    * @handler: the handler made available by the factory
113    * @error: a #GError or %NULL
114    *
115    * The signal is emitted when a new #EmpathyFTHandler is available.
116    * Note that @handler is never %NULL even if @error is set, as you might want
117    * to display the error in an UI; in that case, the handler won't support
118    * any transfer.
119    */
120   signals[NEW_FT_HANDLER] =
121     g_signal_new ("new-ft-handler",
122       G_TYPE_FROM_CLASS (klass),
123       G_SIGNAL_RUN_LAST, 0,
124       NULL, NULL,
125       g_cclosure_marshal_generic,
126       G_TYPE_NONE, 2, EMPATHY_TYPE_FT_HANDLER, G_TYPE_POINTER);
127
128   /**
129    * EmpathyFTFactory::new-incoming-transfer
130    * @factory: the object which received the signal
131    * @handler: the incoming handler being constructed
132    * @error: a #GError or %NULL
133    *
134    * The signal is emitted when a new incoming #EmpathyFTHandler is being
135    * constructed, and needs a destination #GFile to be useful.
136    * Clients that connect to this signal will have to call
137    * empathy_ft_factory_set_destination_for_incoming_handler() when they
138    * have a #GFile.
139    * Note that @handler is never %NULL even if @error is set, as you might want
140    * to display the error in an UI; in that case, the handler won't support
141    * any transfer.
142    */
143   signals[NEW_INCOMING_TRANSFER] =
144     g_signal_new ("new-incoming-transfer",
145       G_TYPE_FROM_CLASS (klass),
146       G_SIGNAL_RUN_LAST, 0,
147       NULL, NULL,
148       g_cclosure_marshal_generic,
149       G_TYPE_NONE, 2, EMPATHY_TYPE_FT_HANDLER, G_TYPE_POINTER);
150 }
151
152 static void
153 ft_handler_incoming_ready_cb (EmpathyFTHandler *handler,
154     GError *error,
155     gpointer user_data)
156 {
157   EmpathyFTFactory *factory = user_data;
158
159   g_signal_emit (factory, signals[NEW_INCOMING_TRANSFER], 0, handler, error);
160 }
161
162 static void
163 handle_channels_cb (TpSimpleHandler *handler,
164     TpAccount *account,
165     TpConnection *connection,
166     GList *channels,
167     GList *requests_satisfied,
168     gint64 user_action_time,
169     TpHandleChannelsContext *context,
170     gpointer user_data)
171 {
172   EmpathyFTFactory *self = user_data;
173   GList *l;
174
175   for (l = channels; l != NULL; l = g_list_next (l))
176     {
177       TpChannel *channel = l->data;
178
179       if (tp_proxy_get_invalidated (channel) != NULL)
180         continue;
181
182       if (!TP_IS_FILE_TRANSFER_CHANNEL (channel))
183         continue;
184
185       /* We handle only incoming FT */
186       empathy_ft_handler_new_incoming ((TpFileTransferChannel *) channel,
187           ft_handler_incoming_ready_cb, self);
188     }
189
190
191   tp_handle_channels_context_accept (context);
192 }
193
194 static void
195 empathy_ft_factory_init (EmpathyFTFactory *self)
196 {
197   EmpathyFTFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
198     EMPATHY_TYPE_FT_FACTORY, EmpathyFTFactoryPriv);
199   TpAccountManager *am;
200
201   self->priv = priv;
202
203   am = tp_account_manager_dup ();
204
205   priv->handler = tp_simple_handler_new_with_am (am, FALSE, FALSE,
206       EMPATHY_FT_BUS_NAME_SUFFIX, FALSE, handle_channels_cb, self, NULL);
207
208   tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
209         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
210           TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER,
211         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
212         /* Only handle *incoming* channels as outgoing FT channels has to be
213          * handled by the requester. */
214         TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN, FALSE,
215         NULL));
216
217   g_object_unref (am);
218 }
219
220 static void
221 ft_handler_outgoing_ready_cb (EmpathyFTHandler *handler,
222     GError *error,
223     gpointer user_data)
224 {
225   EmpathyFTFactory *factory = EMPATHY_FT_FACTORY (user_data);
226
227   g_signal_emit (factory, signals[NEW_FT_HANDLER], 0, handler, error);
228
229   g_object_unref (factory);
230 }
231
232 /* public methods */
233
234 /**
235  * empathy_ft_factory_dup_singleton:
236  *
237  * Gives the caller a reference to the #EmpathyFTFactory singleton,
238  * (creating it if necessary).
239  *
240  * Return value: an #EmpathyFTFactory object
241  */
242 EmpathyFTFactory *
243 empathy_ft_factory_dup_singleton (void)
244 {
245   return g_object_new (EMPATHY_TYPE_FT_FACTORY, NULL);
246 }
247
248 /**
249  * empathy_ft_factory_new_transfer_outgoing:
250  * @factory: an #EmpathyFTFactory
251  * @contact: the #EmpathyContact destination of the transfer
252  * @source: the #GFile to be transferred to @contact
253  *
254  * Trigger the creation of an #EmpathyFTHandler object to send @source to
255  * the specified @contact.
256  */
257 void
258 empathy_ft_factory_new_transfer_outgoing (EmpathyFTFactory *factory,
259     EmpathyContact *contact,
260     GFile *source,
261     gint64 action_time)
262 {
263   g_return_if_fail (EMPATHY_IS_FT_FACTORY (factory));
264   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
265   g_return_if_fail (G_IS_FILE (source));
266
267   empathy_ft_handler_new_outgoing (contact, source, action_time,
268       ft_handler_outgoing_ready_cb, g_object_ref (factory));
269 }
270
271 /**
272  * empathy_ft_factory_set_destination_for_incoming_handler:
273  * @factory: an #EmpathyFTFactory
274  * @handler: the #EmpathyFTHandler to set the destination of
275  * @destination: the #GFile destination of the transfer
276  *
277  * Sets @destination as destination file for the transfer. After the call of
278  * this method, the ::new-ft-handler will be emitted for the incoming handler.
279  */
280 void
281 empathy_ft_factory_set_destination_for_incoming_handler (
282     EmpathyFTFactory *factory,
283     EmpathyFTHandler *handler,
284     GFile *destination)
285 {
286   g_return_if_fail (EMPATHY_IS_FT_FACTORY (factory));
287   g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
288   g_return_if_fail (G_IS_FILE (destination));
289
290   empathy_ft_handler_incoming_set_destination (handler, destination);
291
292   g_signal_emit (factory, signals[NEW_FT_HANDLER], 0, handler, NULL);
293 }
294
295 gboolean
296 empathy_ft_factory_register (EmpathyFTFactory *self,
297     GError **error)
298 {
299   EmpathyFTFactoryPriv *priv = GET_PRIV (self);
300
301   return tp_base_client_register (priv->handler, error);
302 }