~ubuntu-branches/ubuntu/utopic/gossip/utopic

« back to all changes in this revision

Viewing changes to libloudermouth/lm-bs-transfer.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2007-10-19 13:02:15 UTC
  • mfrom: (1.1.20 upstream)
  • Revision ID: james.westby@ubuntu.com-20071019130215-k2c45f460ssaft0r
Tags: 1:0.27-4
* Upload to unstable again.
* New patch, 00_debian-branding.patch, to get the distribution into the
  vcard.
* New patch, 01_disable-smooth-scrolling.patch, to disable smooth scrolling
  completely; GNOME #471316.
* New patch, 02_german-translation.patch, to fix german translations.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
/*
 
3
 * Copyright (C) 2007 Free Software Foundation
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public License as
 
7
 * published by the Free Software Foundation; either version 2 of the
 
8
 * License, or (at your option) any later version.
 
9
 *
 
10
 * This program 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 program; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 * 
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include <string.h>
 
24
 
 
25
#include <glib.h>
 
26
#include <glib/gi18n.h>
 
27
 
 
28
#include <loudmouth/lm-connection.h>
 
29
#include <loudmouth/lm-error.h>
 
30
 
 
31
#include "lm-sha.h"
 
32
#include "lm-bs-client.h"
 
33
#include "lm-bs-transfer.h"
 
34
#include "lm-bs-receiver.h"
 
35
#include "lm-bs-private.h"
 
36
 
 
37
#include "libloudermouth-marshal.h"
 
38
 
 
39
#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LM_TYPE_BS_TRANSFER, LmBsTransferPriv))
 
40
 
 
41
#define XMLNS_BYTESTREAMS "http://jabber.org/protocol/bytestreams"
 
42
 
 
43
#define FILE_BUFFER_SIZE 1024
 
44
 
 
45
typedef struct _LmBsTransferPriv LmBsTransferPriv;
 
46
 
 
47
struct _LmBsTransferPriv {
 
48
        LmBsTransferDirection  direction;
 
49
        LmBsTransferStatus     status;
 
50
 
 
51
        LmConnection          *connection;
 
52
        LmBsSession           *session;
 
53
 
 
54
        GHashTable            *streamhosts;
 
55
 
 
56
        gchar                 *peer_jid;
 
57
        gchar                 *location;
 
58
        guint                  id;
 
59
        gchar                 *sid;
 
60
        gchar                 *iq_id;
 
61
 
 
62
        GIOChannel            *file_channel;
 
63
        LmCallback            *activate_cb;
 
64
 
 
65
        guint64                bytes_total;
 
66
        guint64                bytes_transferred;
 
67
};
 
68
 
 
69
typedef struct {
 
70
        LmBsTransfer *transfer;
 
71
        gchar        *jid;
 
72
} StreamHostData;
 
73
 
 
74
enum {
 
75
        INITIATED,
 
76
        COMPLETE,
 
77
        PROGRESS,
 
78
        ERROR,
 
79
        LAST_SIGNAL
 
80
};
 
81
 
 
82
static guint signals[LAST_SIGNAL] = { 0 };
 
83
 
 
84
static void     bs_transfer_finalize               (GObject         *object);
 
85
static void     bs_transfer_free_streamhost_data   (gpointer         data);
 
86
static void     bs_transfer_client_connected_cb    (LmBsClient      *client,
 
87
                                                    StreamHostData  *sreamhost_data);
 
88
static void     bs_transfer_client_disconnected_cb (LmBsClient      *client,
 
89
                                                    StreamHostData  *sreamhost_data);
 
90
static gboolean bs_transfer_channel_open_for_write (LmBsTransfer    *transfer,
 
91
                                                    GError         **error);
 
92
static gboolean bs_transfer_channel_open_for_read  (LmBsTransfer    *transfer,
 
93
                                                    GError         **error);
 
94
static gchar *  bs_transfer_io_error_to_string     (GError          *error);
 
95
static void     bs_transfer_initiated              (LmBsTransfer    *transfer);
 
96
static void     bs_transfer_complete               (LmBsTransfer    *transfer);
 
97
static void     bs_transfer_progress               (LmBsTransfer    *transfer);
 
98
static void     bs_transfer_error                  (LmBsTransfer    *transfer,
 
99
                                                    const gchar     *error_msg);
 
100
static gchar *  bs_transfer_get_initiator          (LmBsTransfer    *transfer);
 
101
static gchar *  bs_transfer_get_target             (LmBsTransfer    *transfer);
 
102
 
 
103
G_DEFINE_TYPE (LmBsTransfer, lm_bs_transfer, G_TYPE_OBJECT);
 
104
 
 
105
static void
 
106
lm_bs_transfer_class_init (LmBsTransferClass *klass)
 
107
{
 
108
        GObjectClass *object_class;
 
109
 
 
110
        object_class = G_OBJECT_CLASS (klass);
 
111
 
 
112
        object_class->finalize = bs_transfer_finalize;
 
113
        
 
114
        signals[INITIATED] =
 
115
                g_signal_new ("initiated",
 
116
                              G_TYPE_FROM_CLASS (klass),
 
117
                              G_SIGNAL_RUN_LAST,
 
118
                              0,
 
119
                              NULL, NULL,
 
120
                              g_cclosure_marshal_VOID__VOID,
 
121
                              G_TYPE_NONE,
 
122
                              0);
 
123
 
 
124
        signals[COMPLETE] =
 
125
                g_signal_new ("complete",
 
126
                              G_TYPE_FROM_CLASS (klass),
 
127
                              G_SIGNAL_RUN_LAST,
 
128
                              0,
 
129
                              NULL, NULL,
 
130
                              g_cclosure_marshal_VOID__VOID,
 
131
                              G_TYPE_NONE,
 
132
                              0);
 
133
 
 
134
        signals[PROGRESS] =
 
135
                g_signal_new ("progress",
 
136
                              G_TYPE_FROM_CLASS (klass),
 
137
                              G_SIGNAL_RUN_LAST,
 
138
                              0,
 
139
                              NULL, NULL,
 
140
                              g_cclosure_marshal_VOID__DOUBLE,
 
141
                              G_TYPE_NONE,
 
142
                              1, G_TYPE_DOUBLE);
 
143
 
 
144
        signals[ERROR] =
 
145
                g_signal_new ("error",
 
146
                              G_TYPE_FROM_CLASS (klass),
 
147
                              G_SIGNAL_RUN_LAST,
 
148
                              0,
 
149
                              NULL, NULL,
 
150
                              g_cclosure_marshal_VOID__POINTER,
 
151
                              G_TYPE_NONE,
 
152
                              1, G_TYPE_POINTER);
 
153
 
 
154
        g_type_class_add_private (object_class, sizeof (LmBsTransferPriv));
 
155
}
 
156
 
 
157
static void
 
158
lm_bs_transfer_init (LmBsTransfer *transfer)
 
159
{
 
160
        LmBsTransferPriv *priv;
 
161
 
 
162
        priv = GET_PRIV (transfer);
 
163
 
 
164
        priv->streamhosts = g_hash_table_new_full (g_str_hash, 
 
165
                                                   g_str_equal, 
 
166
                                                   g_free, 
 
167
                                                   (GDestroyNotify) lm_bs_client_unref);
 
168
}
 
169
 
 
170
static void
 
171
bs_transfer_finalize (GObject *object)
 
172
{
 
173
        LmBsTransferPriv *priv;
 
174
        
 
175
        priv = GET_PRIV (object);
 
176
 
 
177
        if (priv->activate_cb) {
 
178
                _lm_utils_free_callback (priv->activate_cb);
 
179
        }
 
180
 
 
181
        lm_bs_transfer_close_file (LM_BS_TRANSFER (object));
 
182
 
 
183
        g_free (priv->peer_jid);
 
184
        g_free (priv->location);
 
185
        g_free (priv->sid);
 
186
        g_free (priv->iq_id);
 
187
 
 
188
        g_hash_table_destroy (priv->streamhosts);
 
189
 
 
190
        if (priv->session) {
 
191
                g_object_unref (priv->session);
 
192
        }
 
193
 
 
194
        if (priv->connection) {
 
195
                lm_connection_unref (priv->connection);
 
196
        }
 
197
 
 
198
        (G_OBJECT_CLASS (lm_bs_transfer_parent_class)->finalize) (object);
 
199
}
 
200
 
 
201
static void
 
202
bs_transfer_free_streamhost_data (gpointer data)
 
203
{
 
204
        StreamHostData *streamhost_data;
 
205
 
 
206
        streamhost_data = data;
 
207
 
 
208
        if (streamhost_data->transfer) {
 
209
                g_object_unref (streamhost_data->transfer);
 
210
        }
 
211
 
 
212
        g_free (streamhost_data->jid);
 
213
        g_free (streamhost_data);
 
214
}
 
215
 
 
216
static void
 
217
bs_transfer_client_connected_cb (LmBsClient     *client, 
 
218
                                 StreamHostData *streamhost_data)
 
219
{
 
220
        LmBsTransfer     *transfer;
 
221
        LmBsTransferPriv *priv;
 
222
        LmBsReceiver     *receiver;
 
223
 
 
224
        transfer = streamhost_data->transfer;
 
225
 
 
226
        priv = GET_PRIV (transfer);
 
227
 
 
228
        priv->status = LM_BS_TRANSFER_STATUS_CONNECTED;
 
229
 
 
230
        receiver = lm_bs_receiver_new (client, transfer, streamhost_data->jid);
 
231
        g_hash_table_remove_all (priv->streamhosts);
 
232
 
 
233
        lm_bs_receiver_start_transfer (receiver);
 
234
}
 
235
 
 
236
static void
 
237
bs_transfer_client_disconnected_cb (LmBsClient     *client,
 
238
                                    StreamHostData *streamhost_data)
 
239
{
 
240
        LmBsTransfer     *transfer;
 
241
        LmBsTransferPriv *priv;
 
242
        
 
243
        transfer = streamhost_data->transfer;
 
244
 
 
245
        priv = GET_PRIV (transfer);
 
246
 
 
247
        g_hash_table_remove (priv->streamhosts, streamhost_data->jid);
 
248
 
 
249
        if (!g_hash_table_size (priv->streamhosts)) {
 
250
                bs_transfer_error (transfer, _("Unable to connect to the other party"));
 
251
        }
 
252
}
 
253
 
 
254
static gboolean 
 
255
bs_transfer_channel_open_for_write (LmBsTransfer  *transfer,
 
256
                                    GError       **error)
 
257
{
 
258
        LmBsTransferPriv *priv;
 
259
 
 
260
        priv = GET_PRIV (transfer);
 
261
 
 
262
        if (priv->file_channel) {
 
263
                return TRUE;
 
264
        }
 
265
 
 
266
        priv->file_channel = g_io_channel_new_file (priv->location,
 
267
                                                    "w",
 
268
                                                    error);
 
269
 
 
270
        if (!priv->file_channel) {
 
271
                return FALSE;
 
272
        }
 
273
 
 
274
        g_io_channel_set_encoding (priv->file_channel, NULL, NULL);
 
275
        g_io_channel_set_buffered (priv->file_channel, FALSE);
 
276
 
 
277
        return TRUE;
 
278
}
 
279
 
 
280
static gboolean 
 
281
bs_transfer_channel_open_for_read (LmBsTransfer  *transfer,
 
282
                                   GError       **error)
 
283
{
 
284
        LmBsTransferPriv *priv;
 
285
 
 
286
        priv = GET_PRIV (transfer);
 
287
 
 
288
        if (priv->file_channel) {
 
289
                return TRUE;
 
290
        }
 
291
 
 
292
        priv->file_channel = g_io_channel_new_file (priv->location,
 
293
                                                    "r",
 
294
                                                    error);
 
295
 
 
296
        if (!priv->file_channel) {
 
297
                return FALSE;
 
298
        }
 
299
 
 
300
        g_io_channel_set_encoding (priv->file_channel, NULL, NULL);
 
301
        g_io_channel_set_buffered (priv->file_channel, FALSE);
 
302
 
 
303
        return TRUE;
 
304
}
 
305
 
 
306
static gchar*
 
307
bs_transfer_io_error_to_string (GError *error)
 
308
{
 
309
        g_return_val_if_fail (error != NULL, NULL);
 
310
 
 
311
        if (error->domain == G_FILE_ERROR) {
 
312
                switch(error->code) {
 
313
                case G_FILE_ERROR_EXIST:
 
314
                case G_FILE_ERROR_ACCES:
 
315
                case G_FILE_ERROR_PERM:
 
316
                        return _("Permission denied");
 
317
                case G_FILE_ERROR_NAMETOOLONG:
 
318
                        return _("File name is too long");
 
319
                case G_FILE_ERROR_NOENT:
 
320
                        return _("File doesn't exist");
 
321
                case G_FILE_ERROR_ISDIR:
 
322
                        return _("File is a directory");
 
323
                case G_FILE_ERROR_ROFS:
 
324
                        return _("Read only file system");
 
325
                case G_FILE_ERROR_TXTBSY:
 
326
                        return _("File is busy");
 
327
                case G_FILE_ERROR_FAULT:
 
328
                        return _("Bad memory");
 
329
                case G_FILE_ERROR_LOOP:
 
330
                        return _("Too many levels of symbolic links");
 
331
                case G_FILE_ERROR_NOSPC:
 
332
                        return _("No space is available");
 
333
                case G_FILE_ERROR_NOMEM:
 
334
                        return _("Virtual memory exhausted");
 
335
                case G_FILE_ERROR_MFILE:
 
336
                        return _("Too many open files");
 
337
                case G_FILE_ERROR_BADF:
 
338
                case G_FILE_ERROR_IO:
 
339
                        return _("Input/output error");
 
340
                case G_FILE_ERROR_NODEV:
 
341
                case G_FILE_ERROR_NXIO:
 
342
                        return _("No such device");
 
343
                default:
 
344
                        break; /* unknown error */
 
345
                }
 
346
        } else if (error->domain == G_IO_CHANNEL_ERROR) {
 
347
                switch(error->code) {
 
348
                case G_IO_CHANNEL_ERROR_FBIG:
 
349
                        return _("File is too large");
 
350
                case G_IO_CHANNEL_ERROR_IO:
 
351
                        return _("Input/output error");
 
352
                case G_IO_CHANNEL_ERROR_ISDIR:
 
353
                        return _("File is a directory");
 
354
                case G_IO_CHANNEL_ERROR_NOSPC:
 
355
                        return _("No space is available");
 
356
                case G_IO_CHANNEL_ERROR_NXIO:
 
357
                        return _("No such device");
 
358
                default:
 
359
                        break; /* unknown error */
 
360
                }
 
361
        }
 
362
 
 
363
        return _("Unknown error");
 
364
}
 
365
 
 
366
static void
 
367
bs_transfer_initiated (LmBsTransfer *transfer)
 
368
{
 
369
        LmBsTransferPriv *priv;
 
370
 
 
371
        priv = GET_PRIV (transfer);
 
372
 
 
373
        priv->status = LM_BS_TRANSFER_STATUS_INITIAL;
 
374
 
 
375
        g_signal_emit (transfer, signals[INITIATED], 0);
 
376
}
 
377
 
 
378
static void
 
379
bs_transfer_complete (LmBsTransfer *transfer)
 
380
{
 
381
        LmBsTransferPriv *priv;
 
382
 
 
383
        priv = GET_PRIV (transfer);
 
384
 
 
385
        priv->status = LM_BS_TRANSFER_STATUS_COMPLETE;
 
386
 
 
387
        lm_bs_transfer_close_file (transfer);
 
388
 
 
389
        g_signal_emit (transfer, signals[COMPLETE], 0);
 
390
}
 
391
 
 
392
static void
 
393
bs_transfer_progress (LmBsTransfer *transfer)
 
394
{
 
395
        LmBsTransferPriv *priv;
 
396
        gdouble           progress;
 
397
        GTimeVal          current_time;
 
398
        GTimeVal          interval_time;
 
399
        static GTimeVal   last_time = { 0, 0 };
 
400
 
 
401
        priv = GET_PRIV (transfer);
 
402
 
 
403
        progress = 0.0;
 
404
 
 
405
        if (priv->bytes_total > 0) {
 
406
                progress = (gdouble) priv->bytes_transferred / priv->bytes_total;
 
407
        }
 
408
 
 
409
        g_get_current_time (&current_time);
 
410
 
 
411
        /* Only allow signalling every 100th of a second) */
 
412
        interval_time = last_time;
 
413
        g_time_val_add (&interval_time, G_USEC_PER_SEC / 100);
 
414
 
 
415
        /* Throttle the signalling so we don't enter a tight loop */
 
416
        if (current_time.tv_sec - interval_time.tv_sec > 0 ||
 
417
            current_time.tv_usec - interval_time.tv_usec > 0) {
 
418
                g_signal_emit (transfer, signals[PROGRESS], 0, progress);
 
419
                last_time = current_time;
 
420
        }
 
421
}
 
422
 
 
423
static void
 
424
bs_transfer_error (LmBsTransfer *transfer,
 
425
                   const gchar  *error_msg)
 
426
{
 
427
        GError *error;
 
428
 
 
429
        error = g_error_new (lm_error_quark (),
 
430
                             LM_BS_TRANSFER_ERROR_UNABLE_TO_CONNECT,
 
431
                             error_msg);
 
432
        lm_bs_transfer_error (transfer, error);
 
433
        g_error_free (error);
 
434
}
 
435
 
 
436
static gchar *
 
437
bs_transfer_get_initiator (LmBsTransfer *transfer)
 
438
{
 
439
        LmBsTransferPriv *priv;
 
440
 
 
441
        priv = GET_PRIV (transfer);
 
442
 
 
443
        if (priv->direction == LM_BS_TRANSFER_DIRECTION_RECEIVER) {
 
444
                return g_strdup (priv->peer_jid);
 
445
        }
 
446
 
 
447
        return lm_connection_get_full_jid (priv->connection);
 
448
}
 
449
 
 
450
static gchar *
 
451
bs_transfer_get_target (LmBsTransfer *transfer)
 
452
{
 
453
        LmBsTransferPriv *priv;
 
454
 
 
455
        priv = GET_PRIV (transfer);
 
456
 
 
457
        if (priv->direction == LM_BS_TRANSFER_DIRECTION_RECEIVER) {
 
458
                return lm_connection_get_full_jid (priv->connection);
 
459
        }
 
460
        return g_strdup (priv->peer_jid);
 
461
}
 
462
 
 
463
LmBsTransfer *
 
464
lm_bs_transfer_new (LmBsSession           *session,
 
465
                    LmConnection          *connection,
 
466
                    LmBsTransferDirection  direction,
 
467
                    guint                  id,
 
468
                    const gchar           *sid,
 
469
                    const gchar           *peer_jid,
 
470
                    const gchar           *location,
 
471
                    gint64                 bytes_total)
 
472
{
 
473
        LmBsTransfer     *transfer;
 
474
        LmBsTransferPriv *priv;
 
475
 
 
476
        g_return_val_if_fail (connection != NULL, NULL);
 
477
        g_return_val_if_fail (LM_IS_BS_SESSION (session), NULL);
 
478
        g_return_val_if_fail (peer_jid != NULL, NULL);
 
479
        g_return_val_if_fail (location != NULL, NULL);
 
480
        g_return_val_if_fail (sid != NULL, NULL);
 
481
 
 
482
        transfer = g_object_new (LM_TYPE_BS_TRANSFER, NULL);
 
483
 
 
484
        priv = GET_PRIV (transfer);
 
485
 
 
486
        priv->status = LM_BS_TRANSFER_STATUS_INITIAL;
 
487
        priv->direction = direction;
 
488
 
 
489
        priv->connection = lm_connection_ref (connection);
 
490
        priv->session = g_object_ref (session);
 
491
 
 
492
        priv->peer_jid = g_strdup (peer_jid);
 
493
        priv->location = g_strdup (location);
 
494
        priv->id = id;
 
495
        priv->sid = g_strdup (sid);
 
496
        priv->iq_id = NULL;
 
497
 
 
498
        priv->file_channel = NULL;
 
499
        priv->activate_cb = NULL;
 
500
 
 
501
        priv->bytes_total = bytes_total;
 
502
        priv->bytes_transferred = 0;
 
503
 
 
504
        return transfer;
 
505
}
 
506
 
 
507
void
 
508
lm_bs_transfer_error (LmBsTransfer *transfer,
 
509
                      GError       *error)
 
510
{
 
511
        LmBsTransferPriv *priv;
 
512
 
 
513
        g_return_if_fail (LM_IS_BS_TRANSFER (transfer));
 
514
 
 
515
        priv = GET_PRIV (transfer);
 
516
 
 
517
        priv->status = LM_BS_TRANSFER_STATUS_INTERRUPTED;
 
518
 
 
519
        lm_bs_transfer_close_file (transfer);
 
520
 
 
521
        g_signal_emit (transfer, signals[ERROR], 0, error);
 
522
}
 
523
 
 
524
gboolean
 
525
lm_bs_transfer_append_to_file (LmBsTransfer *transfer, 
 
526
                               GString      *data)
 
527
{
 
528
        LmBsTransferPriv *priv;
 
529
        GIOStatus         io_status;
 
530
        GError           *error;
 
531
        const gchar      *error_msg;
 
532
        gsize             bytes_written;
 
533
 
 
534
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), FALSE);
 
535
 
 
536
        priv = GET_PRIV (transfer);
 
537
 
 
538
        g_return_val_if_fail (priv->direction == LM_BS_TRANSFER_DIRECTION_RECEIVER, FALSE);
 
539
 
 
540
        error = NULL;
 
541
 
 
542
        if (!bs_transfer_channel_open_for_write (transfer, &error)) {
 
543
                error_msg = bs_transfer_io_error_to_string (error);
 
544
                g_error_free (error);
 
545
                bs_transfer_error (transfer, error_msg);
 
546
                return FALSE;
 
547
        }
 
548
 
 
549
        io_status = g_io_channel_write_chars (priv->file_channel, 
 
550
                                              data->str,
 
551
                                              data->len,
 
552
                                              &bytes_written,
 
553
                                              &error);
 
554
 
 
555
        if (io_status != G_IO_STATUS_NORMAL) {
 
556
                error_msg = bs_transfer_io_error_to_string (error);
 
557
                g_error_free (error);
 
558
                bs_transfer_error (transfer, error_msg);
 
559
                return FALSE;
 
560
        }
 
561
 
 
562
        priv->bytes_transferred += bytes_written;
 
563
 
 
564
        if (priv->bytes_transferred >= priv->bytes_total) {
 
565
                bs_transfer_complete (transfer);
 
566
                return FALSE;
 
567
        }
 
568
 
 
569
        bs_transfer_progress (transfer);
 
570
 
 
571
        return TRUE;
 
572
}
 
573
 
 
574
gboolean
 
575
lm_bs_transfer_get_file_content (LmBsTransfer  *transfer, 
 
576
                                 GString      **data)
 
577
{
 
578
        LmBsTransferPriv *priv;
 
579
        GIOStatus         io_status;
 
580
        GError           *error;
 
581
        const gchar      *error_msg;
 
582
        gchar            *buffer;
 
583
        gsize             bytes_read;
 
584
 
 
585
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), FALSE);
 
586
        
 
587
        priv = GET_PRIV (transfer);
 
588
 
 
589
        g_return_val_if_fail (priv->direction == LM_BS_TRANSFER_DIRECTION_SENDER, FALSE);
 
590
 
 
591
        error = NULL;
 
592
 
 
593
        if (priv->bytes_transferred >= priv->bytes_total) {
 
594
                bs_transfer_complete (transfer);
 
595
                return FALSE;
 
596
        }
 
597
 
 
598
        if (!bs_transfer_channel_open_for_read (transfer, &error)) {
 
599
                error_msg = bs_transfer_io_error_to_string (error);
 
600
                g_error_free (error);
 
601
                bs_transfer_error (transfer, error_msg);
 
602
                return FALSE;
 
603
        }
 
604
 
 
605
        buffer = g_malloc (FILE_BUFFER_SIZE);
 
606
        io_status = g_io_channel_read_chars (priv->file_channel, 
 
607
                                             buffer,
 
608
                                             FILE_BUFFER_SIZE,
 
609
                                             &bytes_read,
 
610
                                             &error);
 
611
        
 
612
        if (io_status != G_IO_STATUS_NORMAL) {
 
613
                error_msg = bs_transfer_io_error_to_string (error);
 
614
                g_error_free (error);
 
615
                bs_transfer_error (transfer, error_msg);
 
616
                return FALSE;
 
617
        }
 
618
 
 
619
        *data = g_string_new_len (buffer, bytes_read);
 
620
        g_free (buffer);
 
621
 
 
622
        priv->bytes_transferred += bytes_read;
 
623
        bs_transfer_progress (transfer);
 
624
 
 
625
        return TRUE;
 
626
}
 
627
 
 
628
LmBsTransferStatus
 
629
lm_bs_transfer_get_status (LmBsTransfer *transfer)
 
630
{
 
631
        LmBsTransferPriv *priv;
 
632
 
 
633
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), LM_BS_TRANSFER_STATUS_INITIAL);
 
634
 
 
635
        priv = GET_PRIV (transfer);
 
636
 
 
637
        return priv->status;
 
638
}
 
639
 
 
640
guint64
 
641
lm_bs_transfer_get_bytes_transferred (LmBsTransfer *transfer)
 
642
{
 
643
        LmBsTransferPriv *priv;
 
644
 
 
645
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), 0);
 
646
 
 
647
        priv = GET_PRIV (transfer);
 
648
 
 
649
        return priv->bytes_transferred;
 
650
}
 
651
 
 
652
guint64
 
653
lm_bs_transfer_get_bytes_total (LmBsTransfer *transfer)
 
654
{
 
655
        LmBsTransferPriv *priv;
 
656
 
 
657
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), 0);
 
658
 
 
659
        priv = GET_PRIV (transfer);
 
660
 
 
661
        return priv->bytes_total;
 
662
}
 
663
 
 
664
void
 
665
lm_bs_transfer_close_file (LmBsTransfer *transfer)
 
666
{
 
667
        LmBsTransferPriv *priv;
 
668
 
 
669
        g_return_if_fail (LM_IS_BS_TRANSFER (transfer));
 
670
 
 
671
        priv = GET_PRIV (transfer);
 
672
 
 
673
        if (!priv->file_channel) {
 
674
                return;
 
675
        }
 
676
 
 
677
        g_io_channel_unref (priv->file_channel);
 
678
        priv->file_channel = NULL;
 
679
}
 
680
void 
 
681
lm_bs_transfer_set_iq_id (LmBsTransfer *transfer, 
 
682
                          const gchar  *iq_id)
 
683
{
 
684
        LmBsTransferPriv *priv;
 
685
 
 
686
        g_return_if_fail (LM_IS_BS_TRANSFER (transfer));
 
687
 
 
688
        priv = GET_PRIV (transfer);
 
689
 
 
690
        if (priv->iq_id != NULL) {
 
691
                /* The id is already set. no need to override it, 
 
692
                 * because it is same for all streamhosts
 
693
                 */
 
694
                return;
 
695
        }
 
696
 
 
697
        priv->iq_id = g_strdup (iq_id);
 
698
}
 
699
 
 
700
void
 
701
lm_bs_transfer_add_streamhost (LmBsTransfer *transfer,
 
702
                               const gchar  *host,
 
703
                               guint64       port,
 
704
                               const gchar  *jid)
 
705
{
 
706
        GMainContext       *context;
 
707
        LmBsTransferPriv   *priv;
 
708
        LmBsClient         *streamhost;
 
709
        LmBsClientFunction  func;
 
710
        LmCallback         *connected_cb;
 
711
        LmCallback         *disconnect_cb;
 
712
        StreamHostData     *streamhost_data;
 
713
 
 
714
        g_return_if_fail (LM_IS_BS_TRANSFER (transfer));
 
715
 
 
716
        priv = GET_PRIV (transfer);
 
717
 
 
718
        context = _lm_bs_session_get_context (priv->session);
 
719
 
 
720
        if (priv->direction == LM_BS_TRANSFER_DIRECTION_RECEIVER) {
 
721
                streamhost_data = g_new0 (StreamHostData, 1);
 
722
                streamhost_data->transfer = g_object_ref (transfer);
 
723
                streamhost_data->jid = g_strdup (jid);
 
724
 
 
725
                func = (LmBsClientFunction) bs_transfer_client_connected_cb;
 
726
                connected_cb = _lm_utils_new_callback (func,
 
727
                                                       streamhost_data,
 
728
                                                       NULL);
 
729
 
 
730
                func = (LmBsClientFunction) bs_transfer_client_disconnected_cb;
 
731
                disconnect_cb = _lm_utils_new_callback (func, 
 
732
                                                        streamhost_data,
 
733
                                                        (GDestroyNotify) bs_transfer_free_streamhost_data);
 
734
 
 
735
                streamhost = lm_bs_client_new_with_context (port,
 
736
                                                            host,
 
737
                                                            connected_cb,
 
738
                                                            disconnect_cb,
 
739
                                                            NULL,
 
740
                                                            NULL,
 
741
                                                            context);
 
742
        } else {
 
743
                streamhost = lm_bs_client_new_with_context (port,
 
744
                                                            NULL,
 
745
                                                            NULL,
 
746
                                                            NULL,
 
747
                                                            NULL,
 
748
                                                            NULL,
 
749
                                                            context);
 
750
        }
 
751
 
 
752
        g_hash_table_insert (priv->streamhosts,
 
753
                             g_strdup (jid),
 
754
                             streamhost);
 
755
 
 
756
        if (priv->status == LM_BS_TRANSFER_STATUS_INITIAL &&
 
757
            priv->direction == LM_BS_TRANSFER_DIRECTION_RECEIVER) {
 
758
                bs_transfer_initiated (transfer);
 
759
                lm_bs_client_connect (streamhost);
 
760
        }
 
761
}
 
762
 
 
763
guint
 
764
lm_bs_transfer_get_id (LmBsTransfer *transfer)
 
765
{
 
766
        LmBsTransferPriv *priv;
 
767
 
 
768
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), 0);
 
769
 
 
770
        priv = GET_PRIV (transfer);
 
771
 
 
772
        return priv->id;
 
773
}
 
774
 
 
775
const gchar *
 
776
lm_bs_transfer_get_sid (LmBsTransfer *transfer)
 
777
{
 
778
        LmBsTransferPriv *priv;
 
779
 
 
780
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), NULL);
 
781
 
 
782
        priv = GET_PRIV (transfer);
 
783
 
 
784
        return priv->sid;
 
785
}
 
786
 
 
787
gchar * 
 
788
lm_bs_transfer_get_auth_sha (LmBsTransfer *transfer)
 
789
{
 
790
        LmBsTransferPriv *priv;
 
791
        gchar            *concat;
 
792
        const gchar      *sha;
 
793
        gchar            *target;
 
794
        gchar            *initiator;
 
795
 
 
796
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), NULL);
 
797
 
 
798
        priv = GET_PRIV (transfer);
 
799
        
 
800
        initiator = bs_transfer_get_initiator (transfer);
 
801
        target = bs_transfer_get_target (transfer);
 
802
        concat = g_strconcat (priv->sid, initiator, target, NULL);
 
803
        sha = lm_sha_hash (concat);
 
804
 
 
805
        g_free (initiator);
 
806
        g_free (target);
 
807
        g_free (concat);
 
808
 
 
809
        return g_strdup (sha);
 
810
}
 
811
 
 
812
LmBsTransferDirection
 
813
lm_bs_transfer_get_direction (LmBsTransfer *transfer)
 
814
{
 
815
        LmBsTransferPriv *priv;
 
816
 
 
817
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), LM_BS_TRANSFER_DIRECTION_SENDER);
 
818
 
 
819
        priv = GET_PRIV (transfer);
 
820
 
 
821
        return priv->direction;
 
822
}
 
823
 
 
824
const gchar *
 
825
lm_bs_transfer_get_iq_id (LmBsTransfer *transfer)
 
826
{
 
827
        LmBsTransferPriv *priv;
 
828
 
 
829
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), NULL);
 
830
 
 
831
        priv = GET_PRIV (transfer);
 
832
 
 
833
        return priv->iq_id;
 
834
}
 
835
 
 
836
gboolean
 
837
lm_bs_transfer_has_streamhost (LmBsTransfer *transfer, 
 
838
                               const gchar  *jid)
 
839
{
 
840
        LmBsTransferPriv *priv;
 
841
 
 
842
        g_return_val_if_fail (LM_IS_BS_TRANSFER (transfer), FALSE);
 
843
 
 
844
        priv = GET_PRIV (transfer);
 
845
 
 
846
        if (g_hash_table_lookup (priv->streamhosts, jid)) {
 
847
                return TRUE;
 
848
        }
 
849
 
 
850
        return FALSE;
 
851
}
 
852
 
 
853
void 
 
854
lm_bs_transfer_set_activate_cb (LmBsTransfer *transfer,
 
855
                                LmCallback   *activate_cb)
 
856
{
 
857
        LmBsTransferPriv *priv;
 
858
 
 
859
        g_return_if_fail (LM_IS_BS_TRANSFER (transfer));
 
860
 
 
861
        priv = GET_PRIV (transfer);
 
862
 
 
863
        if (priv->activate_cb != NULL) {
 
864
                _lm_utils_free_callback (priv->activate_cb);
 
865
        }
 
866
 
 
867
        priv->activate_cb = activate_cb;
 
868
}
 
869
 
 
870
void
 
871
lm_bs_transfer_send_success_reply (LmBsTransfer *transfer, 
 
872
                                   const gchar  *jid)
 
873
{
 
874
        LmBsTransferPriv *priv;
 
875
        LmMessage        *m;
 
876
        LmMessageNode    *node;
 
877
        LmMessageNode    *node1;
 
878
        GError           *error;
 
879
        gchar            *target_jid;
 
880
 
 
881
        g_return_if_fail (LM_IS_BS_TRANSFER (transfer));
 
882
 
 
883
        priv = GET_PRIV (transfer);
 
884
 
 
885
        g_return_if_fail (priv->direction == LM_BS_TRANSFER_DIRECTION_RECEIVER);
 
886
 
 
887
        m = lm_message_new_with_sub_type (priv->peer_jid, 
 
888
                                          LM_MESSAGE_TYPE_IQ, 
 
889
                                          LM_MESSAGE_SUB_TYPE_RESULT);
 
890
 
 
891
        lm_message_node_set_attribute (m->node, "id", priv->iq_id);
 
892
        target_jid = bs_transfer_get_target (transfer);
 
893
        lm_message_node_set_attribute (m->node,
 
894
                                       "from",
 
895
                                       target_jid);
 
896
 
 
897
        node = lm_message_node_add_child (m->node, "query", NULL);
 
898
        lm_message_node_set_attribute (node, "xmlns", XMLNS_BYTESTREAMS);
 
899
 
 
900
        node1 = lm_message_node_add_child (node, "streamhost-used", NULL);
 
901
        lm_message_node_set_attribute (node1, "jid", jid);
 
902
 
 
903
        error = NULL;
 
904
 
 
905
        if (!lm_connection_send (priv->connection, m, &error)) {
 
906
                g_printerr ("Failed to send message:'%s'\n", 
 
907
                            lm_message_node_to_string (m->node));
 
908
        } 
 
909
 
 
910
        g_free (target_jid);
 
911
        lm_message_unref (m);
 
912
}
 
913
 
 
914
void 
 
915
lm_bs_transfer_activate (LmBsTransfer *transfer,
 
916
                         const gchar  *jid)
 
917
{
 
918
        LmBsTransferPriv *priv;
 
919
        LmCallback       *cb;
 
920
 
 
921
        g_return_if_fail (LM_IS_BS_TRANSFER (transfer));
 
922
        g_return_if_fail (lm_bs_transfer_has_streamhost (transfer, jid));
 
923
 
 
924
        priv = GET_PRIV (transfer);
 
925
 
 
926
        bs_transfer_initiated (transfer);
 
927
 
 
928
        g_hash_table_remove_all (priv->streamhosts);
 
929
 
 
930
        cb = priv->activate_cb;
 
931
        if (cb && cb->func) {
 
932
                (* ((LmBsClientFunction) cb->func)) (NULL, cb->user_data);
 
933
        }
 
934
}