comparison libpurple/ft.c @ 29298:fb99a0067812

propagate from branch 'im.pidgin.pidgin' (head 70d69397ed952b26b453423c381c70d6783eb66d) to branch 'im.pidgin.cpw.attention_ui' (head 1cf0dea282a0d0e4aeac4770e0150d6d0c10830a)
author Marcus Lundblad <ml@update.uu.se>
date Thu, 13 Aug 2009 17:42:44 +0000
parents e30de9ebfa69
children 901476dc70b9 52cb819c6668
comparison
equal deleted inserted replaced
29297:338d6a211055 29298:fb99a0067812
38 #define FT_MAX_BUFFER_SIZE 65535 38 #define FT_MAX_BUFFER_SIZE 65535
39 39
40 static PurpleXferUiOps *xfer_ui_ops = NULL; 40 static PurpleXferUiOps *xfer_ui_ops = NULL;
41 static GList *xfers; 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 static int purple_xfer_choose_file(PurpleXfer *xfer); 62 static int purple_xfer_choose_file(PurpleXfer *xfer);
63
64 static void
65 purple_xfer_priv_data_destroy(gpointer data)
66 {
67 PurpleXferPrivData *priv = data;
68
69 g_free(priv);
70 }
44 71
45 GList * 72 GList *
46 purple_xfers_get_all() 73 purple_xfers_get_all()
47 { 74 {
48 return xfers; 75 return xfers;
51 PurpleXfer * 78 PurpleXfer *
52 purple_xfer_new(PurpleAccount *account, PurpleXferType type, const char *who) 79 purple_xfer_new(PurpleAccount *account, PurpleXferType type, const char *who)
53 { 80 {
54 PurpleXfer *xfer; 81 PurpleXfer *xfer;
55 PurpleXferUiOps *ui_ops; 82 PurpleXferUiOps *ui_ops;
83 PurpleXferPrivData *priv;
56 84
57 g_return_val_if_fail(type != PURPLE_XFER_UNKNOWN, NULL); 85 g_return_val_if_fail(type != PURPLE_XFER_UNKNOWN, NULL);
58 g_return_val_if_fail(account != NULL, NULL); 86 g_return_val_if_fail(account != NULL, NULL);
59 g_return_val_if_fail(who != NULL, NULL); 87 g_return_val_if_fail(who != NULL, NULL);
60 88
68 xfer->ui_ops = purple_xfers_get_ui_ops(); 96 xfer->ui_ops = purple_xfers_get_ui_ops();
69 xfer->message = NULL; 97 xfer->message = NULL;
70 xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE; 98 xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE;
71 xfer->fd = -1; 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 ui_ops = purple_xfer_get_ui_ops(xfer); 106 ui_ops = purple_xfer_get_ui_ops(xfer);
74 107
75 if (ui_ops != NULL && ui_ops->new_xfer != NULL) 108 if (ui_ops != NULL && ui_ops->new_xfer != NULL)
76 ui_ops->new_xfer(xfer); 109 ui_ops->new_xfer(xfer);
77 110
100 g_free(xfer->who); 133 g_free(xfer->who);
101 g_free(xfer->filename); 134 g_free(xfer->filename);
102 g_free(xfer->remote_ip); 135 g_free(xfer->remote_ip);
103 g_free(xfer->local_filename); 136 g_free(xfer->local_filename);
104 137
138 g_hash_table_remove(xfers_data, xfer);
139
105 PURPLE_DBUS_UNREGISTER_POINTER(xfer); 140 PURPLE_DBUS_UNREGISTER_POINTER(xfer);
141 xfers = g_list_remove(xfers, xfer);
106 g_free(xfer); 142 g_free(xfer);
107 xfers = g_list_remove(xfers, xfer);
108 } 143 }
109 144
110 void 145 void
111 purple_xfer_ref(PurpleXfer *xfer) 146 purple_xfer_ref(PurpleXfer *xfer)
112 { 147 {
129 164
130 static void 165 static void
131 purple_xfer_set_status(PurpleXfer *xfer, PurpleXferStatusType status) 166 purple_xfer_set_status(PurpleXfer *xfer, PurpleXferStatusType status)
132 { 167 {
133 g_return_if_fail(xfer != NULL); 168 g_return_if_fail(xfer != NULL);
169
170 if (xfer->status == status)
171 return;
134 172
135 xfer->status = status; 173 xfer->status = status;
136 174
137 if(xfer->type == PURPLE_XFER_SEND) { 175 if(xfer->type == PURPLE_XFER_SEND) {
138 switch(status) { 176 switch(status) {
477 buddy = purple_find_buddy(account, xfer->who); 515 buddy = purple_find_buddy(account, xfer->who);
478 516
479 if (type == PURPLE_XFER_SEND) { 517 if (type == PURPLE_XFER_SEND) {
480 /* Sending a file */ 518 /* Sending a file */
481 /* Check the filename. */ 519 /* Check the filename. */
520 PurpleXferUiOps *ui_ops;
521 ui_ops = purple_xfer_get_ui_ops(xfer);
522
482 #ifdef _WIN32 523 #ifdef _WIN32
483 if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\")) 524 if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\"))
484 #else 525 #else
485 if (g_strrstr(filename, "../")) 526 if (g_strrstr(filename, "../"))
486 #endif 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 msg = g_strdup_printf(_("%s is not a valid filename.\n"), utf8); 531 msg = g_strdup_printf(_("%s is not a valid filename.\n"), utf8);
491 purple_xfer_error(type, account, xfer->who, msg); 532 purple_xfer_error(type, account, xfer->who, msg);
492 g_free(utf8); 533 g_free(utf8);
493 g_free(msg); 534 g_free(msg);
494 535
495 purple_xfer_unref(xfer); 536 purple_xfer_unref(xfer);
496 return; 537 return;
497 } 538 }
498 539
499 if (g_stat(filename, &st) == -1) { 540 if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
500 purple_xfer_show_file_error(xfer, filename); 541 if (g_stat(filename, &st) == -1) {
501 purple_xfer_unref(xfer); 542 purple_xfer_show_file_error(xfer, filename);
502 return; 543 purple_xfer_unref(xfer);
503 } 544 return;
504 545 }
505 purple_xfer_set_local_filename(xfer, filename); 546
506 purple_xfer_set_size(xfer, st.st_size); 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);
552 }
507 553
508 base = g_path_get_basename(filename); 554 base = g_path_get_basename(filename);
509 utf8 = g_filename_to_utf8(base, -1, NULL, NULL, NULL); 555 utf8 = g_filename_to_utf8(base, -1, NULL, NULL, NULL);
510 g_free(base); 556 g_free(base);
511 purple_xfer_set_filename(xfer, utf8); 557 purple_xfer_set_filename(xfer, utf8);
512 558
513 msg = g_strdup_printf(_("Offering to send %s to %s"), 559 msg = g_strdup_printf(_("Offering to send %s to %s"),
514 utf8, buddy ? purple_buddy_get_alias(buddy) : xfer->who); 560 utf8, buddy ? purple_buddy_get_alias(buddy) : xfer->who);
515 g_free(utf8); 561 g_free(utf8);
516
517 purple_xfer_conversation_write(xfer, msg, FALSE); 562 purple_xfer_conversation_write(xfer, msg, FALSE);
518 g_free(msg); 563 g_free(msg);
519 } 564 }
520 else { 565 else {
521 /* Receiving a file */ 566 /* Receiving a file */
879 else 924 else
880 s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size); 925 s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size);
881 926
882 if (xfer->ops.read != NULL) { 927 if (xfer->ops.read != NULL) {
883 r = (xfer->ops.read)(buffer, xfer); 928 r = (xfer->ops.read)(buffer, xfer);
884 if ((purple_xfer_get_size(xfer) > 0) &&
885 ((purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer)))
886 purple_xfer_set_completed(xfer, TRUE);
887 } 929 }
888 else { 930 else {
889 *buffer = g_malloc0(s); 931 *buffer = g_malloc0(s);
890 932
891 r = read(xfer->fd, *buffer, s); 933 r = read(xfer->fd, *buffer, s);
892 if (r < 0 && errno == EAGAIN) 934 if (r < 0 && errno == EAGAIN)
893 r = 0; 935 r = 0;
894 else if (r < 0) 936 else if (r < 0)
895 r = -1; 937 r = -1;
896 else if ((purple_xfer_get_size(xfer) > 0) &&
897 ((purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer)))
898 purple_xfer_set_completed(xfer, TRUE);
899 else if (r == 0) 938 else if (r == 0)
900 r = -1; 939 r = -1;
901 } 940 }
902 941
903 if (r == xfer->current_buffer_size) 942 if (r == xfer->current_buffer_size)
934 973
935 return r; 974 return r;
936 } 975 }
937 976
938 static void 977 static void
939 transfer_cb(gpointer data, gint source, PurpleInputCondition condition) 978 do_transfer(PurpleXfer *xfer)
940 { 979 {
941 PurpleXferUiOps *ui_ops; 980 PurpleXferUiOps *ui_ops;
942 PurpleXfer *xfer = (PurpleXfer *)data;
943 guchar *buffer = NULL; 981 guchar *buffer = NULL;
944 gssize r = 0; 982 gssize r = 0;
945 983
946 if (condition & PURPLE_INPUT_READ) { 984 ui_ops = purple_xfer_get_ui_ops(xfer);
985
986 if (xfer->type == PURPLE_XFER_RECEIVE) {
947 r = purple_xfer_read(xfer, &buffer); 987 r = purple_xfer_read(xfer, &buffer);
948 if (r > 0) { 988 if (r > 0) {
949 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
950 if (wc != r) { 995 if (wc != r) {
951 purple_debug_error("filetransfer", "Unable to write whole buffer.\n"); 996 purple_debug_error("filetransfer", "Unable to write whole buffer.\n");
952 purple_xfer_cancel_local(xfer); 997 purple_xfer_cancel_local(xfer);
998 g_free(buffer);
953 return; 999 return;
954 } 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);
955 } else if(r < 0) { 1005 } else if(r < 0) {
956 purple_xfer_cancel_remote(xfer); 1006 purple_xfer_cancel_remote(xfer);
1007 g_free(buffer);
957 return; 1008 return;
958 } 1009 }
959 } 1010 } else if (xfer->type == PURPLE_XFER_SEND) {
960
961 if (condition & PURPLE_INPUT_WRITE) {
962 size_t result; 1011 size_t result;
963 size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size); 1012 size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size);
964 1013
965 /* this is so the prpl can keep the connection open 1014 /* this is so the prpl can keep the connection open
966 if it needs to for some odd reason. */ 1015 if it needs to for some odd reason. */
970 xfer->watcher = 0; 1019 xfer->watcher = 0;
971 } 1020 }
972 return; 1021 return;
973 } 1022 }
974 1023
975 buffer = g_malloc0(s); 1024 if (ui_ops && ui_ops->ui_read) {
976 1025 gssize tmp = ui_ops->ui_read(xfer, &buffer, s);
977 result = fread(buffer, 1, s, xfer->dest_fp); 1026 if (tmp == 0) {
978 if (result != s) { 1027 /*
979 purple_debug_error("filetransfer", "Unable to read whole buffer.\n"); 1028 * UI isn't ready to send data. It will call
980 purple_xfer_cancel_remote(xfer); 1029 * purple_xfer_ui_ready when ready, which sets back up this
981 g_free(buffer); 1030 * watcher.
982 return; 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 }
983 } 1054 }
984 1055
985 /* Write as much as we're allowed to. */ 1056 /* Write as much as we're allowed to. */
986 r = purple_xfer_write(xfer, buffer, s); 1057 r = purple_xfer_write(xfer, buffer, result);
987 1058
988 if (r == -1) { 1059 if (r == -1) {
989 purple_xfer_cancel_remote(xfer); 1060 purple_xfer_cancel_remote(xfer);
990 g_free(buffer); 1061 g_free(buffer);
991 return; 1062 return;
992 } else if (r < s) { 1063 } else if (r < result) {
993 /* We have to seek back in the file now. */ 1064 if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
994 fseek(xfer->dest_fp, r - s, SEEK_CUR); 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 }
995 } else { 1071 } else {
996 /* 1072 /*
997 * We managed to write the entire buffer. This means our 1073 * We managed to write the entire buffer. This means our
998 * network is fast and our buffer is too small, so make it 1074 * network is fast and our buffer is too small, so make it
999 * bigger. 1075 * bigger.
1011 if (xfer->ops.ack != NULL) 1087 if (xfer->ops.ack != NULL)
1012 xfer->ops.ack(xfer, buffer, r); 1088 xfer->ops.ack(xfer, buffer, r);
1013 1089
1014 g_free(buffer); 1090 g_free(buffer);
1015 1091
1016 ui_ops = purple_xfer_get_ui_ops(xfer);
1017
1018 if (ui_ops != NULL && ui_ops->update_progress != NULL) 1092 if (ui_ops != NULL && ui_ops->update_progress != NULL)
1019 ui_ops->update_progress(xfer, 1093 ui_ops->update_progress(xfer,
1020 purple_xfer_get_progress(xfer)); 1094 purple_xfer_get_progress(xfer));
1021 } 1095 }
1022 1096
1023 if (purple_xfer_is_completed(xfer)) 1097 if (purple_xfer_is_completed(xfer))
1024 purple_xfer_end(xfer); 1098 purple_xfer_end(xfer);
1025 } 1099 }
1026 1100
1027 static void 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
1028 begin_transfer(PurpleXfer *xfer, PurpleInputCondition cond) 1122 begin_transfer(PurpleXfer *xfer, PurpleInputCondition cond)
1029 { 1123 {
1030 PurpleXferType type = purple_xfer_get_type(xfer); 1124 PurpleXferType type = purple_xfer_get_type(xfer);
1031 1125 PurpleXferUiOps *ui_ops = purple_xfer_get_ui_ops(xfer);
1032 xfer->dest_fp = g_fopen(purple_xfer_get_local_filename(xfer), 1126
1033 type == PURPLE_XFER_RECEIVE ? "wb" : "rb"); 1127 if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
1034 1128 xfer->dest_fp = g_fopen(purple_xfer_get_local_filename(xfer),
1035 if (xfer->dest_fp == NULL) { 1129 type == PURPLE_XFER_RECEIVE ? "wb" : "rb");
1036 purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer)); 1130
1037 purple_xfer_cancel_local(xfer); 1131 if (xfer->dest_fp == NULL) {
1038 return; 1132 purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
1039 } 1133 purple_xfer_cancel_local(xfer);
1040 1134 return;
1041 fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET); 1135 }
1042 1136
1043 if (xfer->fd) 1137 fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
1138 }
1139
1140 if (xfer->fd != -1)
1044 xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer); 1141 xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer);
1045 1142
1046 xfer->start_time = time(NULL); 1143 xfer->start_time = time(NULL);
1047 1144
1048 if (xfer->ops.start != NULL) 1145 if (xfer->ops.start != NULL)
1063 1160
1064 begin_transfer(xfer, PURPLE_INPUT_READ); 1161 begin_transfer(xfer, PURPLE_INPUT_READ);
1065 } 1162 }
1066 1163
1067 void 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
1068 purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip, 1213 purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip,
1069 unsigned int port) 1214 unsigned int port)
1070 { 1215 {
1071 PurpleInputCondition cond; 1216 PurpleInputCondition cond;
1072 PurpleXferType type; 1217 PurpleXferType type;
1075 g_return_if_fail(purple_xfer_get_type(xfer) != PURPLE_XFER_UNKNOWN); 1220 g_return_if_fail(purple_xfer_get_type(xfer) != PURPLE_XFER_UNKNOWN);
1076 1221
1077 type = purple_xfer_get_type(xfer); 1222 type = purple_xfer_get_type(xfer);
1078 1223
1079 purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_STARTED); 1224 purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_STARTED);
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;
1080 1232
1081 if (type == PURPLE_XFER_RECEIVE) { 1233 if (type == PURPLE_XFER_RECEIVE) {
1082 cond = PURPLE_INPUT_READ; 1234 cond = PURPLE_INPUT_READ;
1083 1235
1084 if (ip != NULL) { 1236 if (ip != NULL) {
1122 if (xfer->watcher != 0) { 1274 if (xfer->watcher != 0) {
1123 purple_input_remove(xfer->watcher); 1275 purple_input_remove(xfer->watcher);
1124 xfer->watcher = 0; 1276 xfer->watcher = 0;
1125 } 1277 }
1126 1278
1127 if (xfer->fd != 0) 1279 if (xfer->fd != -1)
1128 close(xfer->fd); 1280 close(xfer->fd);
1129 1281
1130 if (xfer->dest_fp != NULL) { 1282 if (xfer->dest_fp != NULL) {
1131 fclose(xfer->dest_fp); 1283 fclose(xfer->dest_fp);
1132 xfer->dest_fp = NULL; 1284 xfer->dest_fp = NULL;
1185 if (xfer->watcher != 0) { 1337 if (xfer->watcher != 0) {
1186 purple_input_remove(xfer->watcher); 1338 purple_input_remove(xfer->watcher);
1187 xfer->watcher = 0; 1339 xfer->watcher = 0;
1188 } 1340 }
1189 1341
1190 if (xfer->fd != 0) 1342 if (xfer->fd != -1)
1191 close(xfer->fd); 1343 close(xfer->fd);
1192 1344
1193 if (xfer->dest_fp != NULL) { 1345 if (xfer->dest_fp != NULL) {
1194 fclose(xfer->dest_fp); 1346 fclose(xfer->dest_fp);
1195 xfer->dest_fp = NULL; 1347 xfer->dest_fp = NULL;
1250 if (xfer->watcher != 0) { 1402 if (xfer->watcher != 0) {
1251 purple_input_remove(xfer->watcher); 1403 purple_input_remove(xfer->watcher);
1252 xfer->watcher = 0; 1404 xfer->watcher = 0;
1253 } 1405 }
1254 1406
1255 if (xfer->fd != 0) 1407 if (xfer->fd != -1)
1256 close(xfer->fd); 1408 close(xfer->fd);
1257 1409
1258 if (xfer->dest_fp != NULL) { 1410 if (xfer->dest_fp != NULL) {
1259 fclose(xfer->dest_fp); 1411 fclose(xfer->dest_fp);
1260 xfer->dest_fp = NULL; 1412 xfer->dest_fp = NULL;
1319 } 1471 }
1320 1472
1321 void 1473 void
1322 purple_xfers_init(void) { 1474 purple_xfers_init(void) {
1323 void *handle = purple_xfers_get_handle(); 1475 void *handle = purple_xfers_get_handle();
1476
1477 xfers_data = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1478 NULL, purple_xfer_priv_data_destroy);
1324 1479
1325 /* register signals */ 1480 /* register signals */
1326 purple_signal_register(handle, "file-recv-accept", 1481 purple_signal_register(handle, "file-recv-accept",
1327 purple_marshal_VOID__POINTER, NULL, 1, 1482 purple_marshal_VOID__POINTER, NULL, 1,
1328 purple_value_new(PURPLE_TYPE_SUBTYPE, 1483 purple_value_new(PURPLE_TYPE_SUBTYPE,
1366 { 1521 {
1367 void *handle = purple_xfers_get_handle(); 1522 void *handle = purple_xfers_get_handle();
1368 1523
1369 purple_signals_disconnect_by_handle(handle); 1524 purple_signals_disconnect_by_handle(handle);
1370 purple_signals_unregister_by_instance(handle); 1525 purple_signals_unregister_by_instance(handle);
1526
1527 g_hash_table_destroy(xfers_data);
1528 xfers_data = NULL;
1371 } 1529 }
1372 1530
1373 void 1531 void
1374 purple_xfers_set_ui_ops(PurpleXferUiOps *ops) { 1532 purple_xfers_set_ui_ops(PurpleXferUiOps *ops) {
1375 xfer_ui_ops = ops; 1533 xfer_ui_ops = ops;