Mercurial > pidgin
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; |