Don't assume a connected TpAccount always have a TpConnection
[empathy-mirror.git] / libempathy / empathy-ft-factory.c
blob597bbaf5110378777efb29959849d3197d1db568
1 /*
2 * empathy-ft-factory.c - Source for EmpathyFTFactory
3 * Copyright (C) 2009 Collabora Ltd.
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.
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.
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
19 * Author: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
22 /* empathy-ft-factory.c */
24 #include <glib.h>
26 #include <telepathy-glib/telepathy-glib.h>
28 #include "empathy-ft-factory.h"
29 #include "empathy-ft-handler.h"
30 #include "empathy-marshal.h"
31 #include "empathy-request-util.h"
32 #include "empathy-utils.h"
34 /**
35 * SECTION:empathy-ft-factory
36 * @title:EmpathyFTFactory
37 * @short_description: creates #EmpathyFTHandler objects
38 * @include: libempathy/empathy-ft-factory.h
40 * #EmpathyFTFactory takes care of the creation of the #EmpathyFTHandler
41 * objects used for file transfer. As the creation of the handlers is
42 * async, a client will have to connect to the ::new-ft-handler signal
43 * to receive the handler.
44 * In case of an incoming file transfer, the handler will need the destination
45 * file before being useful; as this is usually decided by the user (e.g. with
46 * a file selector), a ::new-incoming-transfer is emitted by the factory when
47 * a destination file is needed, which can be set later with
48 * empathy_ft_factory_set_destination_for_incoming_handler().
51 G_DEFINE_TYPE (EmpathyFTFactory, empathy_ft_factory, G_TYPE_OBJECT);
53 enum {
54 NEW_FT_HANDLER,
55 NEW_INCOMING_TRANSFER,
56 LAST_SIGNAL
59 static EmpathyFTFactory *factory_singleton = NULL;
60 static guint signals[LAST_SIGNAL] = { 0 };
62 /* private structure */
63 typedef struct {
64 TpBaseClient *handler;
65 } EmpathyFTFactoryPriv;
67 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTFactory)
69 static GObject *
70 do_constructor (GType type,
71 guint n_props,
72 GObjectConstructParam *props)
74 GObject *retval;
76 if (factory_singleton != NULL)
78 retval = g_object_ref (factory_singleton);
80 else
82 retval = G_OBJECT_CLASS (empathy_ft_factory_parent_class)->constructor
83 (type, n_props, props);
85 factory_singleton = EMPATHY_FT_FACTORY (retval);
86 g_object_add_weak_pointer (retval, (gpointer *) &factory_singleton);
89 return retval;
92 static void
93 empathy_ft_factory_dispose (GObject *object)
95 EmpathyFTFactory *self = (EmpathyFTFactory *) object;
96 EmpathyFTFactoryPriv *priv = GET_PRIV (self);
98 tp_clear_object (&priv->handler);
100 (G_OBJECT_CLASS (empathy_ft_factory_parent_class)->dispose) (object);
103 static void
104 empathy_ft_factory_class_init (EmpathyFTFactoryClass *klass)
106 GObjectClass *object_class = G_OBJECT_CLASS (klass);
108 g_type_class_add_private (klass, sizeof (EmpathyFTFactoryPriv));
110 object_class->constructor = do_constructor;
111 object_class->dispose = empathy_ft_factory_dispose;
114 * EmpathyFTFactory::new-ft-handler
115 * @factory: the object which received the signal
116 * @handler: the handler made available by the factory
117 * @error: a #GError or %NULL
119 * The signal is emitted when a new #EmpathyFTHandler is available.
120 * Note that @handler is never %NULL even if @error is set, as you might want
121 * to display the error in an UI; in that case, the handler won't support
122 * any transfer.
124 signals[NEW_FT_HANDLER] =
125 g_signal_new ("new-ft-handler",
126 G_TYPE_FROM_CLASS (klass),
127 G_SIGNAL_RUN_LAST, 0,
128 NULL, NULL,
129 _empathy_marshal_VOID__OBJECT_POINTER,
130 G_TYPE_NONE, 2, EMPATHY_TYPE_FT_HANDLER, G_TYPE_POINTER);
133 * EmpathyFTFactory::new-incoming-transfer
134 * @factory: the object which received the signal
135 * @handler: the incoming handler being constructed
136 * @error: a #GError or %NULL
138 * The signal is emitted when a new incoming #EmpathyFTHandler is being
139 * constructed, and needs a destination #GFile to be useful.
140 * Clients that connect to this signal will have to call
141 * empathy_ft_factory_set_destination_for_incoming_handler() when they
142 * have a #GFile.
143 * Note that @handler is never %NULL even if @error is set, as you might want
144 * to display the error in an UI; in that case, the handler won't support
145 * any transfer.
147 signals[NEW_INCOMING_TRANSFER] =
148 g_signal_new ("new-incoming-transfer",
149 G_TYPE_FROM_CLASS (klass),
150 G_SIGNAL_RUN_LAST, 0,
151 NULL, NULL,
152 _empathy_marshal_VOID__OBJECT_POINTER,
153 G_TYPE_NONE, 2, EMPATHY_TYPE_FT_HANDLER, G_TYPE_POINTER);
156 static void
157 ft_handler_incoming_ready_cb (EmpathyFTHandler *handler,
158 GError *error,
159 gpointer user_data)
161 EmpathyFTFactory *factory = user_data;
163 g_signal_emit (factory, signals[NEW_INCOMING_TRANSFER], 0, handler, error);
166 static void
167 handle_channels_cb (TpSimpleHandler *handler,
168 TpAccount *account,
169 TpConnection *connection,
170 GList *channels,
171 GList *requests_satisfied,
172 gint64 user_action_time,
173 TpHandleChannelsContext *context,
174 gpointer user_data)
176 EmpathyFTFactory *self = user_data;
177 GList *l;
179 for (l = channels; l != NULL; l = g_list_next (l))
181 TpChannel *channel = l->data;
182 EmpathyTpFile *tp_file;
184 if (tp_proxy_get_invalidated (channel) != NULL)
185 continue;
187 if (tp_channel_get_channel_type_id (channel) !=
188 TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER)
189 continue;
191 tp_file = empathy_tp_file_new (channel);
193 /* We handle only incoming FT */
194 empathy_ft_handler_new_incoming (tp_file, ft_handler_incoming_ready_cb,
195 self);
197 g_object_unref (tp_file);
201 tp_handle_channels_context_accept (context);
204 static void
205 empathy_ft_factory_init (EmpathyFTFactory *self)
207 EmpathyFTFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
208 EMPATHY_TYPE_FT_FACTORY, EmpathyFTFactoryPriv);
209 TpAccountManager *am;
211 self->priv = priv;
213 am = tp_account_manager_dup ();
215 priv->handler = tp_simple_handler_new_with_am (am, FALSE, FALSE,
216 EMPATHY_FT_BUS_NAME_SUFFIX, FALSE, handle_channels_cb, self, NULL);
218 tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
219 TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
220 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER,
221 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
222 /* Only handle *incoming* channels as outgoing FT channels has to be
223 * handled by the requester. */
224 TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN, FALSE,
225 NULL));
227 g_object_unref (am);
230 static void
231 ft_handler_outgoing_ready_cb (EmpathyFTHandler *handler,
232 GError *error,
233 gpointer user_data)
235 EmpathyFTFactory *factory = user_data;
237 g_signal_emit (factory, signals[NEW_FT_HANDLER], 0, handler, error);
240 /* public methods */
243 * empathy_ft_factory_dup_singleton:
245 * Gives the caller a reference to the #EmpathyFTFactory singleton,
246 * (creating it if necessary).
248 * Return value: an #EmpathyFTFactory object
250 EmpathyFTFactory *
251 empathy_ft_factory_dup_singleton (void)
253 return g_object_new (EMPATHY_TYPE_FT_FACTORY, NULL);
257 * empathy_ft_factory_new_transfer_outgoing:
258 * @factory: an #EmpathyFTFactory
259 * @contact: the #EmpathyContact destination of the transfer
260 * @source: the #GFile to be transferred to @contact
262 * Trigger the creation of an #EmpathyFTHandler object to send @source to
263 * the specified @contact.
265 void
266 empathy_ft_factory_new_transfer_outgoing (EmpathyFTFactory *factory,
267 EmpathyContact *contact,
268 GFile *source)
270 g_return_if_fail (EMPATHY_IS_FT_FACTORY (factory));
271 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
272 g_return_if_fail (G_IS_FILE (source));
274 empathy_ft_handler_new_outgoing (contact, source,
275 ft_handler_outgoing_ready_cb, factory);
279 * empathy_ft_factory_set_destination_for_incoming_handler:
280 * @factory: an #EmpathyFTFactory
281 * @handler: the #EmpathyFTHandler to set the destination of
282 * @destination: the #GFile destination of the transfer
284 * Sets @destination as destination file for the transfer. After the call of
285 * this method, the ::new-ft-handler will be emitted for the incoming handler.
287 void
288 empathy_ft_factory_set_destination_for_incoming_handler (
289 EmpathyFTFactory *factory,
290 EmpathyFTHandler *handler,
291 GFile *destination)
293 g_return_if_fail (EMPATHY_IS_FT_FACTORY (factory));
294 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
295 g_return_if_fail (G_IS_FILE (destination));
297 empathy_ft_handler_incoming_set_destination (handler, destination);
299 g_signal_emit (factory, signals[NEW_FT_HANDLER], 0, handler, NULL);
302 gboolean
303 empathy_ft_factory_register (EmpathyFTFactory *self,
304 GError **error)
306 EmpathyFTFactoryPriv *priv = GET_PRIV (self);
308 return tp_base_client_register (priv->handler, error);