~vish/ubuntu/maverick/pidgin/bug25979

« back to all changes in this revision

Viewing changes to libpurple/ft.c

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2009-10-09 19:40:26 UTC
  • mfrom: (1.4.1 upstream) (46.1.10 karmic)
  • Revision ID: james.westby@ubuntu.com-20091009194026-wbqqh0bsbz19nx5q
Tags: 1:2.6.2-1ubuntu7
* Don't stick the buddy list window to all desktops as some
  window managers have trouble to properly unstick it (LP: #346840)
  - debian/patches/11_buddy_list_really_show.patch
* Always use default tray icon size on KDE (LP: #209440)
  - debian/patches/62_tray_icon_size_kde.patch
* Use scrollbars in the preferences dialog if the screen height is
  below 700 px instead of 600 px
  - debian/patches/60_1024x600_gtkprefs.c.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
static PurpleXferUiOps *xfer_ui_ops = NULL;
41
41
static GList *xfers;
42
42
 
 
43
/*
 
44
 * A hack to store more data since we can't extend the size of PurpleXfer
 
45
 * easily.
 
46
 */
 
47
static GHashTable *xfers_data = NULL;
 
48
 
 
49
typedef struct _PurpleXferPrivData {
 
50
        /*
 
51
         * Used to moderate the file transfer when either the read/write ui_ops are
 
52
         * set or fd is not set. In those cases, the UI/prpl call the respective
 
53
         * function, which is somewhat akin to a fd watch being triggered.
 
54
         */
 
55
        enum {
 
56
                PURPLE_XFER_READY_NONE = 0x0,
 
57
                PURPLE_XFER_READY_UI   = 0x1,
 
58
                PURPLE_XFER_READY_PRPL = 0x2,
 
59
        } ready;
 
60
} PurpleXferPrivData;
 
61
 
43
62
static int purple_xfer_choose_file(PurpleXfer *xfer);
44
63
 
 
64
static void
 
65
purple_xfer_priv_data_destroy(gpointer data)
 
66
{
 
67
        PurpleXferPrivData *priv = data;
 
68
 
 
69
        g_free(priv);
 
70
}
 
71
 
45
72
GList *
46
73
purple_xfers_get_all()
47
74
{
53
80
{
54
81
        PurpleXfer *xfer;
55
82
        PurpleXferUiOps *ui_ops;
 
83
        PurpleXferPrivData *priv;
56
84
 
57
85
        g_return_val_if_fail(type    != PURPLE_XFER_UNKNOWN, NULL);
58
86
        g_return_val_if_fail(account != NULL,              NULL);
70
98
        xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE;
71
99
        xfer->fd = -1;
72
100
 
 
101
        priv = g_new0(PurpleXferPrivData, 1);
 
102
        priv->ready = PURPLE_XFER_READY_NONE;
 
103
 
 
104
        g_hash_table_insert(xfers_data, xfer, priv);
 
105
 
73
106
        ui_ops = purple_xfer_get_ui_ops(xfer);
74
107
 
75
108
        if (ui_ops != NULL && ui_ops->new_xfer != NULL)
102
135
        g_free(xfer->remote_ip);
103
136
        g_free(xfer->local_filename);
104
137
 
 
138
        g_hash_table_remove(xfers_data, xfer);
 
139
 
105
140
        PURPLE_DBUS_UNREGISTER_POINTER(xfer);
 
141
        xfers = g_list_remove(xfers, xfer);
106
142
        g_free(xfer);
107
 
        xfers = g_list_remove(xfers, xfer);
108
143
}
109
144
 
110
145
void
132
167
{
133
168
        g_return_if_fail(xfer != NULL);
134
169
 
 
170
        if (xfer->status == status)
 
171
                return;
 
172
 
 
173
        xfer->status = status;
 
174
 
135
175
        if(xfer->type == PURPLE_XFER_SEND) {
136
176
                switch(status) {
137
177
                        case PURPLE_XFER_STATUS_ACCEPTED:
169
209
                                break;
170
210
                }
171
211
        }
172
 
 
173
 
        xfer->status = status;
174
212
}
175
213
 
176
214
void purple_xfer_conversation_write(PurpleXfer *xfer, char *message, gboolean is_error)
458
496
{
459
497
        PurpleXferType type;
460
498
        struct stat st;
461
 
        char *msg, *utf8;
 
499
        char *msg, *utf8, *base;
462
500
        PurpleAccount *account;
463
501
        PurpleBuddy *buddy;
464
502
 
479
517
        if (type == PURPLE_XFER_SEND) {
480
518
                /* Sending a file */
481
519
                /* Check the filename. */
 
520
                PurpleXferUiOps *ui_ops;
 
521
                ui_ops = purple_xfer_get_ui_ops(xfer);
 
522
 
482
523
#ifdef _WIN32
483
524
                if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\"))
484
525
#else
485
526
                if (g_strrstr(filename, "../"))
486
527
#endif
487
528
                {
488
 
                        char *utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
 
529
                        utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
489
530
 
490
531
                        msg = g_strdup_printf(_("%s is not a valid filename.\n"), utf8);
491
532
                        purple_xfer_error(type, account, xfer->who, msg);
496
537
                        return;
497
538
                }
498
539
 
499
 
                if (g_stat(filename, &st) == -1) {
500
 
                        purple_xfer_show_file_error(xfer, filename);
501
 
                        purple_xfer_unref(xfer);
502
 
                        return;
 
540
                if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
 
541
                        if (g_stat(filename, &st) == -1) {
 
542
                                purple_xfer_show_file_error(xfer, filename);
 
543
                                purple_xfer_unref(xfer);
 
544
                                return;
 
545
                        }
 
546
 
 
547
                        purple_xfer_set_local_filename(xfer, filename);
 
548
                        purple_xfer_set_size(xfer, st.st_size);
 
549
                } else {
 
550
                        utf8 = g_strdup(filename);
 
551
                        purple_xfer_set_local_filename(xfer, filename);
503
552
                }
504
553
 
505
 
                purple_xfer_set_local_filename(xfer, filename);
506
 
                purple_xfer_set_size(xfer, st.st_size);
507
 
 
508
 
                utf8 = g_filename_to_utf8(g_basename(filename), -1, NULL, NULL, NULL);
 
554
                base = g_path_get_basename(filename);
 
555
                utf8 = g_filename_to_utf8(base, -1, NULL, NULL, NULL);
 
556
                g_free(base);
509
557
                purple_xfer_set_filename(xfer, utf8);
510
558
 
511
559
                msg = g_strdup_printf(_("Offering to send %s to %s"),
512
560
                                utf8, buddy ? purple_buddy_get_alias(buddy) : xfer->who);
513
561
                g_free(utf8);
514
 
 
515
562
                purple_xfer_conversation_write(xfer, msg, FALSE);
516
563
                g_free(msg);
517
564
        }
694
741
 
695
742
        if (completed == TRUE) {
696
743
                char *msg = NULL;
 
744
                PurpleConversation *conv;
 
745
 
697
746
                purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_DONE);
698
747
 
699
748
                if (purple_xfer_get_filename(xfer) != NULL)
700
 
                        msg = g_strdup_printf(_("Transfer of file %s complete"),
701
 
                                                                purple_xfer_get_filename(xfer));
 
749
                {
 
750
                        char *filename = g_markup_escape_text(purple_xfer_get_filename(xfer), -1);
 
751
                        if (purple_xfer_get_local_filename(xfer)
 
752
                         && purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE)
 
753
                        {
 
754
                                char *local = g_markup_escape_text(purple_xfer_get_local_filename(xfer), -1);
 
755
                                msg = g_strdup_printf(_("Transfer of file <A HREF=\"file://%s\">%s</A> complete"),
 
756
                                                      local, filename);
 
757
                                g_free(local);
 
758
                        }
 
759
                        else
 
760
                                msg = g_strdup_printf(_("Transfer of file %s complete"),
 
761
                                                      filename);
 
762
                        g_free(filename);
 
763
                }
702
764
                else
703
765
                        msg = g_strdup(_("File transfer complete"));
704
 
                purple_xfer_conversation_write(xfer, msg, FALSE);
 
766
 
 
767
                conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, xfer->who,
 
768
                                                             purple_xfer_get_account(xfer));
 
769
 
 
770
                if (conv != NULL)
 
771
                        purple_conversation_write(conv, NULL, msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
705
772
                g_free(msg);
706
773
        }
707
774
 
857
924
        else
858
925
                s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size);
859
926
 
860
 
        if (xfer->ops.read != NULL)
 
927
        if (xfer->ops.read != NULL)     {
861
928
                r = (xfer->ops.read)(buffer, xfer);
 
929
        }
862
930
        else {
863
931
                *buffer = g_malloc0(s);
864
932
 
867
935
                        r = 0;
868
936
                else if (r < 0)
869
937
                        r = -1;
870
 
                else if ((purple_xfer_get_size(xfer) > 0) &&
871
 
                        ((purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer)))
872
 
                        purple_xfer_set_completed(xfer, TRUE);
873
938
                else if (r == 0)
874
939
                        r = -1;
875
940
        }
910
975
}
911
976
 
912
977
static void
913
 
transfer_cb(gpointer data, gint source, PurpleInputCondition condition)
 
978
do_transfer(PurpleXfer *xfer)
914
979
{
915
980
        PurpleXferUiOps *ui_ops;
916
 
        PurpleXfer *xfer = (PurpleXfer *)data;
917
981
        guchar *buffer = NULL;
918
982
        gssize r = 0;
919
983
 
920
 
        if (condition & PURPLE_INPUT_READ) {
 
984
        ui_ops = purple_xfer_get_ui_ops(xfer);
 
985
 
 
986
        if (xfer->type == PURPLE_XFER_RECEIVE) {
921
987
                r = purple_xfer_read(xfer, &buffer);
922
988
                if (r > 0) {
923
 
                        const size_t wc = fwrite(buffer, 1, r, xfer->dest_fp);
 
989
                        size_t wc;
 
990
                        if (ui_ops && ui_ops->ui_write)
 
991
                                wc = ui_ops->ui_write(xfer, buffer, r);
 
992
                        else
 
993
                                wc = fwrite(buffer, 1, r, xfer->dest_fp);
 
994
 
924
995
                        if (wc != r) {
925
996
                                purple_debug_error("filetransfer", "Unable to write whole buffer.\n");
926
 
                                purple_xfer_cancel_remote(xfer);
 
997
                                purple_xfer_cancel_local(xfer);
 
998
                                g_free(buffer);
927
999
                                return;
928
1000
                        }
 
1001
 
 
1002
                        if ((purple_xfer_get_size(xfer) > 0) &&
 
1003
                                ((purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer)))
 
1004
                                purple_xfer_set_completed(xfer, TRUE);
929
1005
                } else if(r < 0) {
930
1006
                        purple_xfer_cancel_remote(xfer);
 
1007
                        g_free(buffer);
931
1008
                        return;
932
1009
                }
933
 
        }
934
 
 
935
 
        if (condition & PURPLE_INPUT_WRITE) {
 
1010
        } else if (xfer->type == PURPLE_XFER_SEND) {
936
1011
                size_t result;
937
1012
                size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size);
938
1013
 
946
1021
                        return;
947
1022
                }
948
1023
 
949
 
                buffer = g_malloc0(s);
950
 
 
951
 
                result = fread(buffer, 1, s, xfer->dest_fp);
952
 
                if (result != s) {
953
 
                        purple_debug_error("filetransfer", "Unable to read whole buffer.\n");
954
 
                        purple_xfer_cancel_remote(xfer);
955
 
                        g_free(buffer);
956
 
                        return;
 
1024
                if (ui_ops && ui_ops->ui_read) {
 
1025
                        gssize tmp = ui_ops->ui_read(xfer, &buffer, s);
 
1026
                        if (tmp == 0) {
 
1027
                                /*
 
1028
                                 * UI isn't ready to send data. It will call
 
1029
                                 * purple_xfer_ui_ready when ready, which sets back up this
 
1030
                                 * watcher.
 
1031
                                 */
 
1032
                                if (xfer->watcher != 0) {
 
1033
                                        purple_timeout_remove(xfer->watcher);
 
1034
                                        xfer->watcher = 0;
 
1035
                                }
 
1036
 
 
1037
                                return;
 
1038
                        } else if (tmp < 0) {
 
1039
                                purple_debug_error("filetransfer", "Unable to read whole buffer.\n");
 
1040
                                purple_xfer_cancel_local(xfer);
 
1041
                                return;
 
1042
                        }
 
1043
 
 
1044
                        result = tmp;
 
1045
                } else {
 
1046
                        buffer = g_malloc0(s);
 
1047
                        result = fread(buffer, 1, s, xfer->dest_fp);
 
1048
                        if (result != s) {
 
1049
                                purple_debug_error("filetransfer", "Unable to read whole buffer.\n");
 
1050
                                purple_xfer_cancel_local(xfer);
 
1051
                                g_free(buffer);
 
1052
                                return;
 
1053
                        }
957
1054
                }
958
1055
 
959
1056
                /* Write as much as we're allowed to. */
960
 
                r = purple_xfer_write(xfer, buffer, s);
 
1057
                r = purple_xfer_write(xfer, buffer, result);
961
1058
 
962
1059
                if (r == -1) {
963
1060
                        purple_xfer_cancel_remote(xfer);
964
1061
                        g_free(buffer);
965
1062
                        return;
966
 
                } else if (r < s) {
967
 
                        /* We have to seek back in the file now. */
968
 
                        fseek(xfer->dest_fp, r - s, SEEK_CUR);
 
1063
                } else if (r < result) {
 
1064
                        if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
 
1065
                                /* We have to seek back in the file now. */
 
1066
                                fseek(xfer->dest_fp, r - s, SEEK_CUR);
 
1067
                        }
 
1068
                        else {
 
1069
                                ui_ops->data_not_sent(xfer, buffer + r, result - r);
 
1070
                        }
969
1071
                } else {
970
1072
                        /*
971
1073
                         * We managed to write the entire buffer.  This means our
987
1089
 
988
1090
                g_free(buffer);
989
1091
 
990
 
                ui_ops = purple_xfer_get_ui_ops(xfer);
991
 
 
992
1092
                if (ui_ops != NULL && ui_ops->update_progress != NULL)
993
1093
                        ui_ops->update_progress(xfer,
994
1094
                                purple_xfer_get_progress(xfer));
999
1099
}
1000
1100
 
1001
1101
static void
 
1102
transfer_cb(gpointer data, gint source, PurpleInputCondition condition)
 
1103
{
 
1104
        PurpleXfer *xfer = data;
 
1105
 
 
1106
        if (xfer->dest_fp == NULL) {
 
1107
                /* The UI is moderating its side manually */
 
1108
                PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer);
 
1109
                if (0 == (priv->ready & PURPLE_XFER_READY_UI)) {
 
1110
                        priv->ready |= PURPLE_XFER_READY_PRPL;
 
1111
 
 
1112
                        purple_input_remove(xfer->watcher);
 
1113
                        xfer->watcher = 0;
 
1114
                        return;
 
1115
                }
 
1116
        }
 
1117
 
 
1118
        do_transfer(xfer);
 
1119
}
 
1120
 
 
1121
static void
1002
1122
begin_transfer(PurpleXfer *xfer, PurpleInputCondition cond)
1003
1123
{
1004
1124
        PurpleXferType type = purple_xfer_get_type(xfer);
1005
 
 
1006
 
        xfer->dest_fp = g_fopen(purple_xfer_get_local_filename(xfer),
1007
 
                                                  type == PURPLE_XFER_RECEIVE ? "wb" : "rb");
1008
 
 
1009
 
        if (xfer->dest_fp == NULL) {
1010
 
                purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
1011
 
                purple_xfer_cancel_local(xfer);
1012
 
                return;
 
1125
        PurpleXferUiOps *ui_ops = purple_xfer_get_ui_ops(xfer);
 
1126
 
 
1127
        if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
 
1128
                xfer->dest_fp = g_fopen(purple_xfer_get_local_filename(xfer),
 
1129
                                        type == PURPLE_XFER_RECEIVE ? "wb" : "rb");
 
1130
 
 
1131
                if (xfer->dest_fp == NULL) {
 
1132
                        purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
 
1133
                        purple_xfer_cancel_local(xfer);
 
1134
                        return;
 
1135
                }
 
1136
 
 
1137
                fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
1013
1138
        }
1014
1139
 
1015
 
        fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
1016
 
 
1017
 
        if (xfer->fd)
 
1140
        if (xfer->fd != -1)
1018
1141
                xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer);
1019
1142
 
1020
1143
        xfer->start_time = time(NULL);
1039
1162
}
1040
1163
 
1041
1164
void
 
1165
purple_xfer_ui_ready(PurpleXfer *xfer)
 
1166
{
 
1167
        PurpleInputCondition cond;
 
1168
        PurpleXferType type;
 
1169
        PurpleXferPrivData *priv;
 
1170
 
 
1171
        g_return_if_fail(xfer != NULL);
 
1172
 
 
1173
        priv = g_hash_table_lookup(xfers_data, xfer);
 
1174
        priv->ready |= PURPLE_XFER_READY_UI;
 
1175
 
 
1176
        if (0 == (priv->ready & PURPLE_XFER_READY_PRPL))
 
1177
                return;
 
1178
 
 
1179
        type = purple_xfer_get_type(xfer);
 
1180
        if (type == PURPLE_XFER_SEND)
 
1181
                cond = PURPLE_INPUT_WRITE;
 
1182
        else /* if (type == PURPLE_XFER_RECEIVE) */
 
1183
                cond = PURPLE_INPUT_READ;
 
1184
 
 
1185
        if (xfer->watcher == 0 && xfer->fd != -1)
 
1186
                xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer);
 
1187
 
 
1188
        priv->ready = PURPLE_XFER_READY_NONE;
 
1189
 
 
1190
        do_transfer(xfer);
 
1191
}
 
1192
 
 
1193
void
 
1194
purple_xfer_prpl_ready(PurpleXfer *xfer)
 
1195
{
 
1196
        PurpleXferPrivData *priv;
 
1197
 
 
1198
        g_return_if_fail(xfer != NULL);
 
1199
 
 
1200
        priv = g_hash_table_lookup(xfers_data, xfer);
 
1201
        priv->ready |= PURPLE_XFER_READY_PRPL;
 
1202
 
 
1203
        /* I don't think fwrite/fread are ever *not* ready */
 
1204
        if (xfer->dest_fp == NULL && 0 == (priv->ready & PURPLE_XFER_READY_UI))
 
1205
                return;
 
1206
 
 
1207
        priv->ready = PURPLE_XFER_READY_NONE;
 
1208
 
 
1209
        do_transfer(xfer);
 
1210
}
 
1211
 
 
1212
void
1042
1213
purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip,
1043
1214
                                unsigned int port)
1044
1215
{
1052
1223
 
1053
1224
        purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_STARTED);
1054
1225
 
 
1226
        /*
 
1227
         * FIXME 3.0.0 -- there's too much broken code depending on fd == 0
 
1228
         * meaning "don't use a real fd"
 
1229
         */
 
1230
        if (fd == 0)
 
1231
                fd = -1;
 
1232
 
1055
1233
        if (type == PURPLE_XFER_RECEIVE) {
1056
1234
                cond = PURPLE_INPUT_READ;
1057
1235
 
1098
1276
                xfer->watcher = 0;
1099
1277
        }
1100
1278
 
1101
 
        if (xfer->fd != 0)
 
1279
        if (xfer->fd != -1)
1102
1280
                close(xfer->fd);
1103
1281
 
1104
1282
        if (xfer->dest_fp != NULL) {
1135
1313
 
1136
1314
        if (purple_xfer_get_filename(xfer) != NULL)
1137
1315
        {
1138
 
                msg = g_strdup_printf(_("You canceled the transfer of %s"),
 
1316
                msg = g_strdup_printf(_("You cancelled the transfer of %s"),
1139
1317
                                                          purple_xfer_get_filename(xfer));
1140
1318
        }
1141
1319
        else
1161
1339
                xfer->watcher = 0;
1162
1340
        }
1163
1341
 
1164
 
        if (xfer->fd != 0)
 
1342
        if (xfer->fd != -1)
1165
1343
                close(xfer->fd);
1166
1344
 
1167
1345
        if (xfer->dest_fp != NULL) {
1198
1376
 
1199
1377
        if (purple_xfer_get_filename(xfer) != NULL)
1200
1378
        {
1201
 
                msg = g_strdup_printf(_("%s canceled the transfer of %s"),
 
1379
                msg = g_strdup_printf(_("%s cancelled the transfer of %s"),
1202
1380
                                buddy ? purple_buddy_get_alias(buddy) : xfer->who, purple_xfer_get_filename(xfer));
1203
1381
        }
1204
1382
        else
1205
1383
        {
1206
 
                msg = g_strdup_printf(_("%s canceled the file transfer"),
 
1384
                msg = g_strdup_printf(_("%s cancelled the file transfer"),
1207
1385
                                buddy ? purple_buddy_get_alias(buddy) : xfer->who);
1208
1386
        }
1209
1387
        purple_xfer_conversation_write(xfer, msg, TRUE);
1226
1404
                xfer->watcher = 0;
1227
1405
        }
1228
1406
 
1229
 
        if (xfer->fd != 0)
 
1407
        if (xfer->fd != -1)
1230
1408
                close(xfer->fd);
1231
1409
 
1232
1410
        if (xfer->dest_fp != NULL) {
1296
1474
purple_xfers_init(void) {
1297
1475
        void *handle = purple_xfers_get_handle();
1298
1476
 
 
1477
        xfers_data = g_hash_table_new_full(g_direct_hash, g_direct_equal,
 
1478
                                           NULL, purple_xfer_priv_data_destroy);
 
1479
 
1299
1480
        /* register signals */
1300
1481
        purple_signal_register(handle, "file-recv-accept",
1301
1482
                             purple_marshal_VOID__POINTER, NULL, 1,
1342
1523
 
1343
1524
        purple_signals_disconnect_by_handle(handle);
1344
1525
        purple_signals_unregister_by_instance(handle);
 
1526
 
 
1527
        g_hash_table_destroy(xfers_data);
 
1528
        xfers_data = NULL;
1345
1529
}
1346
1530
 
1347
1531
void