1 /*
2 * file-transfer-chan.c - Simple file transfer channel
3 *
4 * Copyright (C) 2010-2011 Morten Mjelva <morten.mjelva@gmail.com>
5 * Copyright (C) 2010-2011 Collabora Ltd. <http://www.collabora.co.uk/>
6 *
7 * Copying and distribution of this file, with or without modification,
8 * are permitted in any medium without royalty provided the copyright
9 * notice and this notice are preserved.
10 */
11
12 #include "config.h"
13
14 #include "file-transfer-chan.h"
15 #include "util.h"
16 #include "debug.h"
17
18 #include <telepathy-glib/telepathy-glib.h>
19
20 #include <glib/gstdio.h>
21
22 static void file_transfer_iface_init (gpointer iface, gpointer data);
23
24 G_DEFINE_TYPE_WITH_CODE (TpTestsFileTransferChannel,
25 tp_tests_file_transfer_channel,
26 TP_TYPE_BASE_CHANNEL,
27 G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_FILE_TRANSFER,
28 file_transfer_iface_init);
29 G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA,
30 NULL);
31 )
32
33 enum /* properties */
34 {
35 PROP_AVAILABLE_SOCKET_TYPES = 1,
36 PROP_CONTENT_TYPE,
37 PROP_CONTENT_HASH,
38 PROP_CONTENT_HASH_TYPE,
39 PROP_DATE,
40 PROP_DESCRIPTION,
41 PROP_FILENAME,
42 PROP_INITIAL_OFFSET,
43 PROP_SIZE,
44 PROP_STATE,
45 PROP_TRANSFERRED_BYTES,
46 PROP_URI,
47 PROP_SERVICE_NAME,
48 PROP_METADATA,
49 N_PROPS,
50 };
51
52 struct _TpTestsFileTransferChannelPrivate {
53 /* Exposed properties */
54 gchar *content_type;
55 guint64 date;
56 gchar *description;
57 gchar *filename;
58 guint64 size;
59 TpFileTransferState state;
60 guint64 transferred_bytes;
61 gchar *uri;
62 gchar *service_name;
63 GHashTable *metadata;
64
65 /* Hidden properties */
66 TpFileHashType content_hash_type;
67 gchar *content_hash;
68 GHashTable *available_socket_types;
69 gint64 initial_offset;
70
71 /* Accepting side */
72 GSocketService *service;
73 GValue *access_control_param;
74
75 /* Offering side */
76 TpSocketAddressType address_type;
77 GValue *address;
78 gchar *unix_address;
79 gchar *unix_tmpdir;
80 guint connection_id;
81 TpSocketAccessControl access_control;
82
83 guint timer_id;
84 };
85
86 static void
tp_tests_file_transfer_channel_init(TpTestsFileTransferChannel * self)87 tp_tests_file_transfer_channel_init (TpTestsFileTransferChannel *self)
88 {
89 self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
90 TP_TESTS_TYPE_FILE_TRANSFER_CHANNEL, TpTestsFileTransferChannelPrivate);
91 }
92
93 static void
create_available_socket_types(TpTestsFileTransferChannel * self)94 create_available_socket_types (TpTestsFileTransferChannel *self)
95 {
96 TpSocketAccessControl access_control;
97 GArray *unix_tab;
98
99 g_assert (self->priv->available_socket_types == NULL);
100 self->priv->available_socket_types = g_hash_table_new_full (NULL, NULL,
101 NULL, _tp_destroy_socket_control_list);
102
103 /* SocketAddressTypeUnix */
104 unix_tab = g_array_sized_new (FALSE, FALSE, sizeof (TpSocketAccessControl),
105 1);
106 access_control = TP_SOCKET_ACCESS_CONTROL_LOCALHOST;
107 g_array_append_val (unix_tab, access_control);
108
109 g_hash_table_insert (self->priv->available_socket_types,
110 GUINT_TO_POINTER (TP_SOCKET_ADDRESS_TYPE_UNIX), unix_tab);
111 }
112
113 static GObject *
constructor(GType type,guint n_props,GObjectConstructParam * props)114 constructor (GType type,
115 guint n_props,
116 GObjectConstructParam *props)
117 {
118 GObject *object =
119 G_OBJECT_CLASS (tp_tests_file_transfer_channel_parent_class)->constructor
120 (type, n_props, props);
121 TpTestsFileTransferChannel *self = TP_TESTS_FILE_TRANSFER_CHANNEL (object);
122
123 self->priv->state = TP_FILE_TRANSFER_STATE_PENDING;
124
125 if (self->priv->available_socket_types == NULL)
126 create_available_socket_types (self);
127
128 tp_base_channel_register (TP_BASE_CHANNEL (self));
129
130 return object;
131 }
132
133 static void
dispose(GObject * object)134 dispose (GObject *object)
135 {
136 TpTestsFileTransferChannel *self = TP_TESTS_FILE_TRANSFER_CHANNEL (object);
137
138 if (self->priv->timer_id != 0)
139 {
140 g_source_remove (self->priv->timer_id);
141 self->priv->timer_id = 0;
142 }
143
144 g_free (self->priv->content_hash);
145 g_free (self->priv->content_type);
146 g_free (self->priv->description);
147 g_free (self->priv->filename);
148 g_free (self->priv->uri);
149 g_free (self->priv->service_name);
150
151 tp_clear_pointer (&self->priv->address, tp_g_value_slice_free);
152 tp_clear_pointer (&self->priv->available_socket_types, g_hash_table_unref);
153 tp_clear_pointer (&self->priv->access_control_param, tp_g_value_slice_free);
154 tp_clear_pointer (&self->priv->metadata, g_hash_table_unref);
155
156 if (self->priv->unix_address != NULL)
157 g_unlink (self->priv->unix_address);
158
159 tp_clear_pointer (&self->priv->unix_address, g_free);
160
161 if (self->priv->unix_tmpdir != NULL)
162 g_rmdir (self->priv->unix_tmpdir);
163
164 tp_clear_pointer (&self->priv->unix_tmpdir, g_free);
165
166 ((GObjectClass *) tp_tests_file_transfer_channel_parent_class)->dispose (
167 object);
168 }
169
170 static void
get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)171 get_property (GObject *object,
172 guint property_id,
173 GValue *value,
174 GParamSpec *pspec)
175 {
176 TpTestsFileTransferChannel *self = (TpTestsFileTransferChannel *) object;
177
178 switch (property_id)
179 {
180 case PROP_AVAILABLE_SOCKET_TYPES:
181 g_value_set_boxed (value, self->priv->available_socket_types);
182 break;
183
184 case PROP_CONTENT_HASH:
185 g_value_set_string (value, self->priv->content_hash);
186
187 case PROP_CONTENT_HASH_TYPE:
188 g_value_set_uint (value, self->priv->content_hash_type);
189 break;
190
191 case PROP_CONTENT_TYPE:
192 g_value_set_string (value, self->priv->content_type);
193 break;
194
195 case PROP_DATE:
196 g_value_set_uint64 (value, self->priv->date);
197 break;
198
199 case PROP_DESCRIPTION:
200 g_value_set_string (value, self->priv->description);
201 break;
202
203 case PROP_FILENAME:
204 g_value_set_string (value, self->priv->filename);
205 break;
206
207 case PROP_INITIAL_OFFSET:
208 g_value_set_uint64 (value, self->priv->initial_offset);
209 break;
210
211 case PROP_SIZE:
212 g_value_set_uint64 (value, self->priv->size);
213 break;
214
215 case PROP_STATE:
216 g_value_set_uint (value, self->priv->state);
217 break;
218
219 case PROP_TRANSFERRED_BYTES:
220 g_value_set_uint64 (value, self->priv->transferred_bytes);
221 break;
222
223 case PROP_URI:
224 g_value_set_string (value, self->priv->uri);
225 break;
226
227 case PROP_SERVICE_NAME:
228 g_value_set_string (value, self->priv->service_name);
229 break;
230
231 case PROP_METADATA:
232 g_value_set_boxed (value, self->priv->metadata);
233 break;
234
235 default:
236 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
237 break;
238 }
239 }
240
241 static void
set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)242 set_property (GObject *object,
243 guint property_id,
244 const GValue *value,
245 GParamSpec *pspec)
246 {
247 TpTestsFileTransferChannel *self = (TpTestsFileTransferChannel *) object;
248
249 switch (property_id)
250 {
251 case PROP_AVAILABLE_SOCKET_TYPES:
252 self->priv->available_socket_types = g_value_dup_boxed (value);
253 break;
254
255 case PROP_CONTENT_HASH:
256 self->priv->content_hash = g_value_dup_string (value);
257 break;
258
259 case PROP_CONTENT_HASH_TYPE:
260 break;
261
262 case PROP_CONTENT_TYPE:
263 self->priv->content_type = g_value_dup_string (value);
264 break;
265
266 case PROP_DATE:
267 self->priv->date = g_value_get_uint64 (value);
268 break;
269
270 case PROP_DESCRIPTION:
271 self->priv->description = g_value_dup_string (value);
272 break;
273
274 case PROP_FILENAME:
275 self->priv->filename = g_value_dup_string (value);
276 break;
277
278 case PROP_INITIAL_OFFSET:
279 self->priv->initial_offset = g_value_get_uint64 (value);
280 break;
281
282 case PROP_SIZE:
283 self->priv->size = g_value_get_uint64 (value);
284 break;
285
286 case PROP_STATE:
287 self->priv->state = g_value_get_uint (value);
288 break;
289
290 case PROP_TRANSFERRED_BYTES:
291 self->priv->transferred_bytes = g_value_get_uint64 (value);
292 break;
293
294 case PROP_URI:
295 self->priv->uri = g_value_dup_string (value);
296 break;
297
298 case PROP_SERVICE_NAME:
299 self->priv->service_name = g_value_dup_string (value);
300 break;
301
302 case PROP_METADATA:
303 self->priv->metadata = g_value_dup_boxed (value);
304 break;
305
306 default:
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
308 break;
309 }
310 }
311
312 static void
channel_close(TpBaseChannel * self)313 channel_close (TpBaseChannel *self)
314 {
315 g_print ("entered channel_close");
316 tp_base_channel_destroyed (self);
317 }
318
319 static void
fill_immutable_properties(TpBaseChannel * self,GHashTable * properties)320 fill_immutable_properties (TpBaseChannel *self,
321 GHashTable *properties)
322 {
323 TpBaseChannelClass *klass = TP_BASE_CHANNEL_CLASS (
324 tp_tests_file_transfer_channel_parent_class);
325
326 klass->fill_immutable_properties (self, properties);
327
328 tp_dbus_properties_mixin_fill_properties_hash (
329 G_OBJECT (self), properties,
330 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "AvailableSocketTypes",
331 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "ContentType",
332 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "Filename",
333 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "Size",
334 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "Description",
335 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "Date",
336 TP_IFACE_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA, "ServiceName",
337 TP_IFACE_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA, "Metadata",
338 NULL);
339
340 /* URI is immutable only for outgoing transfers */
341 if (tp_base_channel_is_requested (self))
342 {
343 tp_dbus_properties_mixin_fill_properties_hash (G_OBJECT (self),
344 properties,
345 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "URI", NULL);
346 }
347 }
348
349 static void
change_state(TpTestsFileTransferChannel * self,TpFileTransferState state,TpFileTransferStateChangeReason reason)350 change_state (TpTestsFileTransferChannel *self,
351 TpFileTransferState state,
352 TpFileTransferStateChangeReason reason)
353 {
354 self->priv->state = state;
355
356 tp_svc_channel_type_file_transfer_emit_file_transfer_state_changed (self,
357 state, reason);
358 }
359
360 /* This function imitates the beginning of a filetransfer. It sets the state
361 * to open, and connects to the "incoming" signal of the GSocketService.
362 */
363 static gboolean
start_file_transfer(gpointer data)364 start_file_transfer (gpointer data)
365 {
366 TpTestsFileTransferChannel *self = (TpTestsFileTransferChannel *) data;
367
368 DEBUG ("Setting TP_FILE_TRANSFER_STATE_OPEN");
369 change_state (self, TP_FILE_TRANSFER_STATE_OPEN,
370 TP_FILE_TRANSFER_STATE_CHANGE_REASON_REQUESTED);
371
372 g_object_notify ((GObject *) data, "state");
373 DEBUG ("Fired state signal");
374
375 // g_signal_connect (self->priv->service, "incoming", G_CALLBACK
376 // (incoming_file_transfer_cb));
377
378 self->priv->timer_id = 0;
379 return FALSE;
380 }
381
382 static gboolean
check_address_type(TpTestsFileTransferChannel * self,TpSocketAddressType address_type,TpSocketAccessControl access_control)383 check_address_type (TpTestsFileTransferChannel *self,
384 TpSocketAddressType address_type,
385 TpSocketAccessControl access_control)
386 {
387 GArray *arr;
388 guint i;
389
390 arr = g_hash_table_lookup (self->priv->available_socket_types,
391 GUINT_TO_POINTER (address_type));
392 if (arr == NULL)
393 return FALSE;
394
395 for (i = 0; i < arr->len; i++)
396 {
397 if (g_array_index (arr, TpSocketAccessControl, i) == access_control)
398 return TRUE;
399 }
400
401 return FALSE;
402 }
403
404 static void
service_incoming_cb(GSocketService * service,GSocketConnection * connection,GObject * source_object,gpointer user_data)405 service_incoming_cb (GSocketService *service,
406 GSocketConnection *connection,
407 GObject *source_object,
408 gpointer user_data)
409 {
410 TpTestsFileTransferChannel *self = user_data;
411 GError *error = NULL;
412
413 DEBUG ("Servicing incoming connection");
414 if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS)
415 {
416 GCredentials *creds;
417 guchar byte;
418
419 /* TODO: Async version */
420 creds = tp_unix_connection_receive_credentials_with_byte (
421 connection, &byte, NULL, &error);
422 g_assert_no_error (error);
423
424 g_assert_cmpuint (byte, ==,
425 g_value_get_uchar (self->priv->access_control_param));
426 g_object_unref (creds);
427 }
428 else if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_PORT)
429 {
430 GSocketAddress *addr;
431 guint16 port;
432
433 addr = g_socket_connection_get_remote_address (connection, &error);
434 g_assert_no_error (error);
435
436 port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
437
438 g_assert_cmpuint (port, ==,
439 g_value_get_uint (self->priv->access_control_param));
440
441 g_object_unref (addr);
442 }
443 }
444
445 static void
file_transfer_provide_file(TpSvcChannelTypeFileTransfer * iface,TpSocketAddressType address_type,TpSocketAccessControl access_control,const GValue * access_control_param,DBusGMethodInvocation * context)446 file_transfer_provide_file (TpSvcChannelTypeFileTransfer *iface,
447 TpSocketAddressType address_type,
448 TpSocketAccessControl access_control,
449 const GValue *access_control_param,
450 DBusGMethodInvocation *context)
451 {
452 TpTestsFileTransferChannel *self = (TpTestsFileTransferChannel *) iface;
453 TpBaseChannel *base_chan = (TpBaseChannel *) iface;
454 GError *error = NULL;
455
456 if (tp_base_channel_is_requested (base_chan) != TRUE)
457 {
458 g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
459 "File transfer is not outgoing. Cannot offer file");
460 goto fail;
461 }
462
463 if (self->priv->state != TP_FILE_TRANSFER_STATE_PENDING &&
464 self->priv->state != TP_FILE_TRANSFER_STATE_ACCEPTED)
465 {
466 g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
467 "File transfer is not pending or accepted. Cannot offer file");
468 goto fail;
469 }
470
471 if (self->priv->address != NULL)
472 {
473 g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
474 "ProvideFile has already been called for this channel");
475 goto fail;
476 }
477
478 if (!check_address_type (self, address_type, access_control))
479 {
480 g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
481 "Address type %i is not supported with access control %i",
482 address_type, access_control);
483 goto fail;
484 }
485
486 self->priv->address = _tp_create_local_socket (address_type, access_control,
487 &self->priv->service, &self->priv->unix_address,
488 &self->priv->unix_tmpdir, &error);
489
490 if (self->priv->address == NULL)
491 {
492 g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
493 "Could not set up local socket");
494 goto fail;
495 }
496
497 self->priv->address_type = address_type;
498 self->priv->access_control = access_control;
499
500 DEBUG ("Waiting 500ms and setting state to OPEN");
501 self->priv->timer_id = g_timeout_add (500, start_file_transfer, self);
502
503 // connect to self->priv->service incoming signal
504 // when the signal returns, add x bytes per n seconds using timeout
505 // then close the socket
506 // g_output_stream_write_async
507
508 tp_svc_channel_type_file_transfer_return_from_provide_file (context,
509 self->priv->address);
510
511 return;
512
513 fail:
514 dbus_g_method_return_error (context, error);
515 g_error_free (error);
516 }
517
518 static void
file_transfer_accept_file(TpSvcChannelTypeFileTransfer * iface,TpSocketAddressType address_type,TpSocketAccessControl access_control,const GValue * access_control_param,guint64 offset,DBusGMethodInvocation * context)519 file_transfer_accept_file (TpSvcChannelTypeFileTransfer *iface,
520 TpSocketAddressType address_type,
521 TpSocketAccessControl access_control,
522 const GValue *access_control_param,
523 guint64 offset,
524 DBusGMethodInvocation *context)
525 {
526 TpTestsFileTransferChannel *self = (TpTestsFileTransferChannel *) iface;
527 TpBaseChannel *base_chan = (TpBaseChannel *) iface;
528 GError *error = NULL;
529 GValue *address;
530
531 if (tp_base_channel_is_requested (base_chan) == TRUE)
532 {
533 g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
534 "File transfer is not incoming. Cannot accept file");
535 goto fail;
536 }
537
538 if (self->priv->state != TP_FILE_TRANSFER_STATE_PENDING)
539 {
540 g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
541 "File transfer is not in the pending state");
542 goto fail;
543 }
544
545 if (!check_address_type (self, address_type, access_control))
546 {
547 g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
548 "Address type %i is not supported with access control %i",
549 address_type, access_control);
550 goto fail;
551 }
552
553 address = _tp_create_local_socket (address_type, access_control,
554 &self->priv->service, &self->priv->unix_address,
555 &self->priv->unix_tmpdir, &error);
556
557 tp_g_signal_connect_object (self->priv->service, "incoming",
558 G_CALLBACK (service_incoming_cb), self, 0);
559
560 self->priv->access_control = access_control;
561 self->priv->access_control_param = tp_g_value_slice_dup (
562 access_control_param);
563
564 DEBUG ("Setting TP_FILE_TRANSFER_STATE_ACCEPTED");
565 change_state (self, TP_FILE_TRANSFER_STATE_ACCEPTED,
566 TP_FILE_TRANSFER_STATE_CHANGE_REASON_REQUESTED);
567
568 DEBUG ("Waiting 500ms and setting state to OPEN");
569 self->priv->timer_id = g_timeout_add (500, start_file_transfer, self);
570
571 tp_svc_channel_type_file_transfer_return_from_accept_file (context,
572 address);
573
574 tp_clear_pointer (&address, tp_g_value_slice_free);
575
576 return;
577
578 fail:
579 dbus_g_method_return_error (context, error);
580 g_error_free (error);
581 }
582
583 static void
tp_tests_file_transfer_channel_class_init(TpTestsFileTransferChannelClass * klass)584 tp_tests_file_transfer_channel_class_init (
585 TpTestsFileTransferChannelClass *klass)
586 {
587 GObjectClass *object_class = (GObjectClass *) klass;
588 TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass);
589 GParamSpec *param_spec;
590
591 static TpDBusPropertiesMixinPropImpl file_transfer_props[] = {
592 { "AvailableSocketTypes", "available-socket-types", NULL },
593 { "ContentType", "content-type", NULL },
594 { "Date", "date", NULL },
595 { "Description", "description", NULL },
596 { "Filename", "filename", NULL },
597 { "Size", "size", NULL },
598 { "State", "state", NULL },
599 { "TransferredBytes", "transferred-bytes", NULL },
600 { "URI", "uri", NULL },
601 { NULL }
602 };
603
604 static TpDBusPropertiesMixinPropImpl metadata_props[] = {
605 { "ServiceName", "service-name", NULL },
606 { "Metadata", "metadata", NULL },
607 { NULL }
608 };
609
610 object_class->constructor = constructor;
611 object_class->get_property = get_property;
612 object_class->set_property = set_property;
613 object_class->dispose = dispose;
614
615 base_class->channel_type = TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER;
616 base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT;
617
618 base_class->close = channel_close;
619 base_class->fill_immutable_properties = fill_immutable_properties;
620
621 param_spec = g_param_spec_boxed ("available-socket-types",
622 "AvailableSocketTypes",
623 "The AvailableSocketTypes property of this channel",
624 TP_HASH_TYPE_SUPPORTED_SOCKET_MAP,
625 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
626 g_object_class_install_property (object_class, PROP_AVAILABLE_SOCKET_TYPES,
627 param_spec);
628
629 param_spec = g_param_spec_string ("content-type",
630 "ContentType",
631 "The ContentType property of this channel",
632 NULL,
633 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
634 g_object_class_install_property (object_class, PROP_CONTENT_TYPE,
635 param_spec);
636
637 param_spec = g_param_spec_uint64 ("date",
638 "Date",
639 "The Date property of this channel",
640 0, G_MAXUINT64, 0,
641 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
642 g_object_class_install_property (object_class, PROP_DATE,
643 param_spec);
644
645 param_spec = g_param_spec_string ("description",
646 "Description",
647 "The Description property of this channel",
648 NULL,
649 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
650 g_object_class_install_property (object_class, PROP_DESCRIPTION,
651 param_spec);
652
653 param_spec = g_param_spec_string ("filename",
654 "Filename",
655 "The Filename property of this channel",
656 NULL,
657 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
658 g_object_class_install_property (object_class, PROP_FILENAME,
659 param_spec);
660
661 param_spec = g_param_spec_uint64 ("initial-offset",
662 "InitialOffset",
663 "The InitialOffset property of this channel",
664 0, G_MAXUINT64, 0,
665 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
666 g_object_class_install_property (object_class, PROP_INITIAL_OFFSET,
667 param_spec);
668
669 param_spec = g_param_spec_uint64 ("size",
670 "Size",
671 "The Size property of this channel",
672 0, G_MAXUINT64, 0,
673 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
674 g_object_class_install_property (object_class, PROP_SIZE,
675 param_spec);
676
677 param_spec = g_param_spec_uint ("state",
678 "State",
679 "The State property of this channel",
680 0, TP_NUM_FILE_TRANSFER_STATES, TP_FILE_TRANSFER_STATE_NONE,
681 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
682 g_object_class_install_property (object_class, PROP_STATE,
683 param_spec);
684
685 param_spec = g_param_spec_uint64 ("transferred-bytes",
686 "TransferredBytes",
687 "The TransferredBytes property of this channel",
688 0, G_MAXUINT64, 0,
689 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
690 g_object_class_install_property (object_class, PROP_TRANSFERRED_BYTES,
691 param_spec);
692
693 param_spec = g_param_spec_string ("uri",
694 "URI",
695 "The URI property of this channel",
696 NULL,
697 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
698 g_object_class_install_property (object_class, PROP_URI,
699 param_spec);
700
701 param_spec = g_param_spec_string ("service-name",
702 "ServiceName",
703 "The Metadata.ServiceName property of this channel",
704 "",
705 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
706 g_object_class_install_property (object_class, PROP_SERVICE_NAME,
707 param_spec);
708
709 param_spec = g_param_spec_boxed ("metadata",
710 "Metadata",
711 "The Metadata.Metadata property of this channel",
712 TP_HASH_TYPE_METADATA,
713 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
714 g_object_class_install_property (object_class, PROP_METADATA,
715 param_spec);
716
717 tp_dbus_properties_mixin_implement_interface (object_class,
718 TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER,
719 tp_dbus_properties_mixin_getter_gobject_properties, NULL,
720 file_transfer_props);
721
722 tp_dbus_properties_mixin_implement_interface (object_class,
723 TP_IFACE_QUARK_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA,
724 tp_dbus_properties_mixin_getter_gobject_properties, NULL,
725 metadata_props);
726
727 g_type_class_add_private (object_class,
728 sizeof (TpTestsFileTransferChannelPrivate));
729 }
730
731 static void
file_transfer_iface_init(gpointer iface,gpointer data)732 file_transfer_iface_init (gpointer iface, gpointer data)
733 {
734 TpSvcChannelTypeFileTransferClass *klass = iface;
735
736 #define IMPLEMENT(x) tp_svc_channel_type_file_transfer_implement_##x (klass, \
737 file_transfer_##x)
738 IMPLEMENT(accept_file);
739 IMPLEMENT(provide_file);
740 #undef IMPLEMENT
741 }
742
743 /* Return the address of the file transfer's socket */
744 GSocketAddress *
tp_tests_file_transfer_channel_get_server_address(TpTestsFileTransferChannel * self)745 tp_tests_file_transfer_channel_get_server_address (
746 TpTestsFileTransferChannel *self)
747 {
748 GSocketAddress *address;
749 GError *error = NULL;
750
751 g_assert (self->priv->address != NULL);
752
753 address = tp_g_socket_address_from_variant (self->priv->address_type,
754 self->priv->address, &error);
755
756 if (error != NULL)
757 {
758 g_printf ("%s\n", error->message);
759 }
760
761 return address;
762 }
763