| 1 /** |
|
| 2 * @file ft.c File Transfer API |
|
| 3 * |
|
| 4 * gaim |
|
| 5 * |
|
| 6 * Gaim is the legal property of its developers, whose names are too numerous |
|
| 7 * to list here. Please refer to the COPYRIGHT file distributed with this |
|
| 8 * source distribution. |
|
| 9 * |
|
| 10 * This program is free software; you can redistribute it and/or modify |
|
| 11 * it under the terms of the GNU General Public License as published by |
|
| 12 * the Free Software Foundation; either version 2 of the License, or |
|
| 13 * (at your option) any later version. |
|
| 14 * |
|
| 15 * This program is distributed in the hope that it will be useful, |
|
| 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 18 * GNU General Public License for more details. |
|
| 19 * |
|
| 20 * You should have received a copy of the GNU General Public License |
|
| 21 * along with this program; if not, write to the Free Software |
|
| 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 23 * |
|
| 24 */ |
|
| 25 #include "internal.h" |
|
| 26 #include "ft.h" |
|
| 27 #include "network.h" |
|
| 28 #include "notify.h" |
|
| 29 #include "prefs.h" |
|
| 30 #include "proxy.h" |
|
| 31 #include "request.h" |
|
| 32 #include "util.h" |
|
| 33 |
|
| 34 static GaimXferUiOps *xfer_ui_ops = NULL; |
|
| 35 |
|
| 36 GaimXfer * |
|
| 37 gaim_xfer_new(GaimAccount *account, GaimXferType type, const char *who) |
|
| 38 { |
|
| 39 GaimXfer *xfer; |
|
| 40 GaimXferUiOps *ui_ops; |
|
| 41 |
|
| 42 g_return_val_if_fail(type != GAIM_XFER_UNKNOWN, NULL); |
|
| 43 g_return_val_if_fail(account != NULL, NULL); |
|
| 44 g_return_val_if_fail(who != NULL, NULL); |
|
| 45 |
|
| 46 xfer = g_new0(GaimXfer, 1); |
|
| 47 |
|
| 48 xfer->ref = 1; |
|
| 49 xfer->type = type; |
|
| 50 xfer->account = account; |
|
| 51 xfer->who = g_strdup(who); |
|
| 52 xfer->ui_ops = gaim_xfers_get_ui_ops(); |
|
| 53 xfer->message = NULL; |
|
| 54 |
|
| 55 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 56 |
|
| 57 if (ui_ops != NULL && ui_ops->new_xfer != NULL) |
|
| 58 ui_ops->new_xfer(xfer); |
|
| 59 |
|
| 60 return xfer; |
|
| 61 } |
|
| 62 |
|
| 63 static void |
|
| 64 gaim_xfer_destroy(GaimXfer *xfer) |
|
| 65 { |
|
| 66 GaimXferUiOps *ui_ops; |
|
| 67 |
|
| 68 g_return_if_fail(xfer != NULL); |
|
| 69 |
|
| 70 /* Close the file browser, if it's open */ |
|
| 71 gaim_request_close_with_handle(xfer); |
|
| 72 |
|
| 73 if (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_STARTED) |
|
| 74 gaim_xfer_cancel_local(xfer); |
|
| 75 |
|
| 76 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 77 |
|
| 78 if (ui_ops != NULL && ui_ops->destroy != NULL) |
|
| 79 ui_ops->destroy(xfer); |
|
| 80 |
|
| 81 g_free(xfer->who); |
|
| 82 g_free(xfer->filename); |
|
| 83 g_free(xfer->remote_ip); |
|
| 84 g_free(xfer->local_filename); |
|
| 85 |
|
| 86 g_free(xfer); |
|
| 87 } |
|
| 88 |
|
| 89 void |
|
| 90 gaim_xfer_ref(GaimXfer *xfer) |
|
| 91 { |
|
| 92 g_return_if_fail(xfer != NULL); |
|
| 93 |
|
| 94 xfer->ref++; |
|
| 95 } |
|
| 96 |
|
| 97 void |
|
| 98 gaim_xfer_unref(GaimXfer *xfer) |
|
| 99 { |
|
| 100 g_return_if_fail(xfer != NULL); |
|
| 101 g_return_if_fail(xfer->ref > 0); |
|
| 102 |
|
| 103 xfer->ref--; |
|
| 104 |
|
| 105 if (xfer->ref == 0) |
|
| 106 gaim_xfer_destroy(xfer); |
|
| 107 } |
|
| 108 |
|
| 109 static void |
|
| 110 gaim_xfer_set_status(GaimXfer *xfer, GaimXferStatusType status) |
|
| 111 { |
|
| 112 g_return_if_fail(xfer != NULL); |
|
| 113 |
|
| 114 if(xfer->type == GAIM_XFER_SEND) { |
|
| 115 switch(status) { |
|
| 116 case GAIM_XFER_STATUS_ACCEPTED: |
|
| 117 gaim_signal_emit(gaim_xfers_get_handle(), "file-send-accept", xfer); |
|
| 118 break; |
|
| 119 case GAIM_XFER_STATUS_STARTED: |
|
| 120 gaim_signal_emit(gaim_xfers_get_handle(), "file-send-start", xfer); |
|
| 121 break; |
|
| 122 case GAIM_XFER_STATUS_DONE: |
|
| 123 gaim_signal_emit(gaim_xfers_get_handle(), "file-send-complete", xfer); |
|
| 124 break; |
|
| 125 case GAIM_XFER_STATUS_CANCEL_LOCAL: |
|
| 126 case GAIM_XFER_STATUS_CANCEL_REMOTE: |
|
| 127 gaim_signal_emit(gaim_xfers_get_handle(), "file-send-cancel", xfer); |
|
| 128 break; |
|
| 129 default: |
|
| 130 break; |
|
| 131 } |
|
| 132 } else if(xfer->type == GAIM_XFER_RECEIVE) { |
|
| 133 switch(status) { |
|
| 134 case GAIM_XFER_STATUS_ACCEPTED: |
|
| 135 gaim_signal_emit(gaim_xfers_get_handle(), "file-recv-accept", xfer); |
|
| 136 break; |
|
| 137 case GAIM_XFER_STATUS_STARTED: |
|
| 138 gaim_signal_emit(gaim_xfers_get_handle(), "file-recv-start", xfer); |
|
| 139 break; |
|
| 140 case GAIM_XFER_STATUS_DONE: |
|
| 141 gaim_signal_emit(gaim_xfers_get_handle(), "file-recv-complete", xfer); |
|
| 142 break; |
|
| 143 case GAIM_XFER_STATUS_CANCEL_LOCAL: |
|
| 144 case GAIM_XFER_STATUS_CANCEL_REMOTE: |
|
| 145 gaim_signal_emit(gaim_xfers_get_handle(), "file-recv-cancel", xfer); |
|
| 146 break; |
|
| 147 default: |
|
| 148 break; |
|
| 149 } |
|
| 150 } |
|
| 151 |
|
| 152 xfer->status = status; |
|
| 153 } |
|
| 154 |
|
| 155 void gaim_xfer_conversation_write(GaimXfer *xfer, char *message, gboolean is_error) |
|
| 156 { |
|
| 157 GaimConversation *conv = NULL; |
|
| 158 GaimMessageFlags flags = GAIM_MESSAGE_SYSTEM; |
|
| 159 char *escaped; |
|
| 160 |
|
| 161 g_return_if_fail(xfer != NULL); |
|
| 162 g_return_if_fail(message != NULL); |
|
| 163 |
|
| 164 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, xfer->who, |
|
| 165 gaim_xfer_get_account(xfer)); |
|
| 166 |
|
| 167 if (conv == NULL) |
|
| 168 return; |
|
| 169 |
|
| 170 escaped = g_markup_escape_text(message, -1); |
|
| 171 |
|
| 172 if (is_error) |
|
| 173 flags = GAIM_MESSAGE_ERROR; |
|
| 174 |
|
| 175 gaim_conversation_write(conv, NULL, escaped, flags, time(NULL)); |
|
| 176 g_free(escaped); |
|
| 177 } |
|
| 178 |
|
| 179 static void gaim_xfer_show_file_error(GaimXfer *xfer, const char *filename) |
|
| 180 { |
|
| 181 int err = errno; |
|
| 182 gchar *msg = NULL, *utf8; |
|
| 183 GaimXferType xfer_type = gaim_xfer_get_type(xfer); |
|
| 184 GaimAccount *account = gaim_xfer_get_account(xfer); |
|
| 185 |
|
| 186 utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); |
|
| 187 switch(xfer_type) { |
|
| 188 case GAIM_XFER_SEND: |
|
| 189 msg = g_strdup_printf(_("Error reading %s: \n%s.\n"), |
|
| 190 utf8, strerror(err)); |
|
| 191 break; |
|
| 192 case GAIM_XFER_RECEIVE: |
|
| 193 msg = g_strdup_printf(_("Error writing %s: \n%s.\n"), |
|
| 194 utf8, strerror(err)); |
|
| 195 break; |
|
| 196 default: |
|
| 197 msg = g_strdup_printf(_("Error accessing %s: \n%s.\n"), |
|
| 198 utf8, strerror(err)); |
|
| 199 break; |
|
| 200 } |
|
| 201 g_free(utf8); |
|
| 202 |
|
| 203 gaim_xfer_conversation_write(xfer, msg, TRUE); |
|
| 204 gaim_xfer_error(xfer_type, account, xfer->who, msg); |
|
| 205 g_free(msg); |
|
| 206 } |
|
| 207 |
|
| 208 static void |
|
| 209 gaim_xfer_choose_file_ok_cb(void *user_data, const char *filename) |
|
| 210 { |
|
| 211 GaimXfer *xfer; |
|
| 212 struct stat st; |
|
| 213 |
|
| 214 xfer = (GaimXfer *)user_data; |
|
| 215 |
|
| 216 if (g_stat(filename, &st) != 0) { |
|
| 217 /* File not found. */ |
|
| 218 if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) { |
|
| 219 gaim_xfer_request_accepted(xfer, filename); |
|
| 220 } |
|
| 221 else { |
|
| 222 gaim_xfer_show_file_error(xfer, filename); |
|
| 223 gaim_xfer_request_denied(xfer); |
|
| 224 } |
|
| 225 } |
|
| 226 else if ((gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) && |
|
| 227 (st.st_size == 0)) { |
|
| 228 |
|
| 229 gaim_notify_error(NULL, NULL, |
|
| 230 _("Cannot send a file of 0 bytes."), NULL); |
|
| 231 |
|
| 232 gaim_xfer_request_denied(xfer); |
|
| 233 } |
|
| 234 else if ((gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) && |
|
| 235 S_ISDIR(st.st_mode)) { |
|
| 236 /* |
|
| 237 * XXX - Sending a directory should be valid for some protocols. |
|
| 238 */ |
|
| 239 gaim_notify_error(NULL, NULL, |
|
| 240 _("Cannot send a directory."), NULL); |
|
| 241 |
|
| 242 gaim_xfer_request_denied(xfer); |
|
| 243 } |
|
| 244 else if ((gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) && |
|
| 245 S_ISDIR(st.st_mode)) { |
|
| 246 char *msg, *utf8; |
|
| 247 utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); |
|
| 248 msg = g_strdup_printf( |
|
| 249 _("%s is not a regular file. Cowardly refusing to overwrite it.\n"), utf8); |
|
| 250 g_free(utf8); |
|
| 251 gaim_notify_error(NULL, NULL, msg, NULL); |
|
| 252 g_free(msg); |
|
| 253 gaim_xfer_request_denied(xfer); |
|
| 254 } |
|
| 255 else { |
|
| 256 gaim_xfer_request_accepted(xfer, filename); |
|
| 257 } |
|
| 258 |
|
| 259 gaim_xfer_unref(xfer); |
|
| 260 } |
|
| 261 |
|
| 262 static void |
|
| 263 gaim_xfer_choose_file_cancel_cb(void *user_data, const char *filename) |
|
| 264 { |
|
| 265 GaimXfer *xfer = (GaimXfer *)user_data; |
|
| 266 |
|
| 267 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_LOCAL); |
|
| 268 gaim_xfer_request_denied(xfer); |
|
| 269 } |
|
| 270 |
|
| 271 static int |
|
| 272 gaim_xfer_choose_file(GaimXfer *xfer) |
|
| 273 { |
|
| 274 gaim_request_file(xfer, NULL, gaim_xfer_get_filename(xfer), |
|
| 275 (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE), |
|
| 276 G_CALLBACK(gaim_xfer_choose_file_ok_cb), |
|
| 277 G_CALLBACK(gaim_xfer_choose_file_cancel_cb), xfer); |
|
| 278 |
|
| 279 return 0; |
|
| 280 } |
|
| 281 |
|
| 282 static int |
|
| 283 cancel_recv_cb(GaimXfer *xfer) |
|
| 284 { |
|
| 285 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_LOCAL); |
|
| 286 gaim_xfer_request_denied(xfer); |
|
| 287 gaim_xfer_unref(xfer); |
|
| 288 |
|
| 289 return 0; |
|
| 290 } |
|
| 291 |
|
| 292 static void |
|
| 293 gaim_xfer_ask_recv(GaimXfer *xfer) |
|
| 294 { |
|
| 295 char *buf, *size_buf; |
|
| 296 size_t size; |
|
| 297 |
|
| 298 /* If we have already accepted the request, ask the destination file |
|
| 299 name directly */ |
|
| 300 if (gaim_xfer_get_status(xfer) != GAIM_XFER_STATUS_ACCEPTED) { |
|
| 301 GaimBuddy *buddy = gaim_find_buddy(xfer->account, xfer->who); |
|
| 302 |
|
| 303 if (gaim_xfer_get_filename(xfer) != NULL) |
|
| 304 { |
|
| 305 size = gaim_xfer_get_size(xfer); |
|
| 306 size_buf = gaim_str_size_to_units(size); |
|
| 307 buf = g_strdup_printf(_("%s wants to send you %s (%s)"), |
|
| 308 buddy ? gaim_buddy_get_alias(buddy) : xfer->who, |
|
| 309 gaim_xfer_get_filename(xfer), size_buf); |
|
| 310 g_free(size_buf); |
|
| 311 } |
|
| 312 else |
|
| 313 { |
|
| 314 buf = g_strdup_printf(_("%s wants to send you a file"), |
|
| 315 buddy ? gaim_buddy_get_alias(buddy) : xfer->who); |
|
| 316 } |
|
| 317 |
|
| 318 if (xfer->message != NULL) |
|
| 319 serv_got_im(gaim_account_get_connection(xfer->account), |
|
| 320 xfer->who, xfer->message, 0, time(NULL)); |
|
| 321 |
|
| 322 gaim_request_accept_cancel(xfer, NULL, buf, NULL, |
|
| 323 GAIM_DEFAULT_ACTION_NONE, xfer, |
|
| 324 G_CALLBACK(gaim_xfer_choose_file), |
|
| 325 G_CALLBACK(cancel_recv_cb)); |
|
| 326 |
|
| 327 g_free(buf); |
|
| 328 } else |
|
| 329 gaim_xfer_choose_file(xfer); |
|
| 330 } |
|
| 331 |
|
| 332 static int |
|
| 333 ask_accept_ok(GaimXfer *xfer) |
|
| 334 { |
|
| 335 gaim_xfer_request_accepted(xfer, NULL); |
|
| 336 |
|
| 337 return 0; |
|
| 338 } |
|
| 339 |
|
| 340 static int |
|
| 341 ask_accept_cancel(GaimXfer *xfer) |
|
| 342 { |
|
| 343 gaim_xfer_request_denied(xfer); |
|
| 344 gaim_xfer_unref(xfer); |
|
| 345 |
|
| 346 return 0; |
|
| 347 } |
|
| 348 |
|
| 349 static void |
|
| 350 gaim_xfer_ask_accept(GaimXfer *xfer) |
|
| 351 { |
|
| 352 char *buf, *buf2 = NULL; |
|
| 353 GaimBuddy *buddy = gaim_find_buddy(xfer->account, xfer->who); |
|
| 354 |
|
| 355 buf = g_strdup_printf(_("Accept file transfer request from %s?"), |
|
| 356 buddy ? gaim_buddy_get_alias(buddy) : xfer->who); |
|
| 357 if (gaim_xfer_get_remote_ip(xfer) && |
|
| 358 gaim_xfer_get_remote_port(xfer)) |
|
| 359 buf2 = g_strdup_printf(_("A file is available for download from:\n" |
|
| 360 "Remote host: %s\nRemote port: %d"), |
|
| 361 gaim_xfer_get_remote_ip(xfer), |
|
| 362 gaim_xfer_get_remote_port(xfer)); |
|
| 363 gaim_request_accept_cancel(xfer, NULL, buf, buf2, |
|
| 364 GAIM_DEFAULT_ACTION_NONE, xfer, |
|
| 365 G_CALLBACK(ask_accept_ok), |
|
| 366 G_CALLBACK(ask_accept_cancel)); |
|
| 367 g_free(buf); |
|
| 368 g_free(buf2); |
|
| 369 } |
|
| 370 |
|
| 371 void |
|
| 372 gaim_xfer_request(GaimXfer *xfer) |
|
| 373 { |
|
| 374 g_return_if_fail(xfer != NULL); |
|
| 375 g_return_if_fail(xfer->ops.init != NULL); |
|
| 376 |
|
| 377 gaim_xfer_ref(xfer); |
|
| 378 |
|
| 379 if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) { |
|
| 380 if (gaim_xfer_get_filename(xfer) || |
|
| 381 gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_ACCEPTED) { |
|
| 382 gchar* message = NULL; |
|
| 383 message = g_strdup_printf(_("%s is offering to send file %s"), |
|
| 384 xfer->who, gaim_xfer_get_filename(xfer)); |
|
| 385 gaim_xfer_conversation_write(xfer, message, FALSE); |
|
| 386 g_free(message); |
|
| 387 gaim_xfer_ask_recv(xfer); |
|
| 388 } else { |
|
| 389 gaim_xfer_ask_accept(xfer); |
|
| 390 } |
|
| 391 } else |
|
| 392 gaim_xfer_choose_file(xfer); |
|
| 393 } |
|
| 394 |
|
| 395 void |
|
| 396 gaim_xfer_request_accepted(GaimXfer *xfer, const char *filename) |
|
| 397 { |
|
| 398 GaimXferType type; |
|
| 399 struct stat st; |
|
| 400 char *msg, *utf8; |
|
| 401 GaimAccount *account; |
|
| 402 GaimBuddy *buddy; |
|
| 403 |
|
| 404 if (xfer == NULL) |
|
| 405 return; |
|
| 406 |
|
| 407 type = gaim_xfer_get_type(xfer); |
|
| 408 account = gaim_xfer_get_account(xfer); |
|
| 409 |
|
| 410 if (!filename && type == GAIM_XFER_RECEIVE) { |
|
| 411 xfer->status = GAIM_XFER_STATUS_ACCEPTED; |
|
| 412 xfer->ops.init(xfer); |
|
| 413 return; |
|
| 414 } |
|
| 415 |
|
| 416 buddy = gaim_find_buddy(account, xfer->who); |
|
| 417 |
|
| 418 if (type == GAIM_XFER_SEND) { |
|
| 419 /* Check the filename. */ |
|
| 420 #ifdef _WIN32 |
|
| 421 if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\")) { |
|
| 422 #else |
|
| 423 if (g_strrstr(filename, "../")) { |
|
| 424 #endif |
|
| 425 char *utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); |
|
| 426 |
|
| 427 msg = g_strdup_printf(_("%s is not a valid filename.\n"), utf8); |
|
| 428 gaim_xfer_error(type, account, xfer->who, msg); |
|
| 429 g_free(utf8); |
|
| 430 g_free(msg); |
|
| 431 |
|
| 432 gaim_xfer_unref(xfer); |
|
| 433 return; |
|
| 434 } |
|
| 435 |
|
| 436 if (g_stat(filename, &st) == -1) { |
|
| 437 gaim_xfer_show_file_error(xfer, filename); |
|
| 438 gaim_xfer_unref(xfer); |
|
| 439 return; |
|
| 440 } |
|
| 441 |
|
| 442 gaim_xfer_set_local_filename(xfer, filename); |
|
| 443 gaim_xfer_set_size(xfer, st.st_size); |
|
| 444 |
|
| 445 utf8 = g_filename_to_utf8(g_basename(filename), -1, NULL, NULL, NULL); |
|
| 446 gaim_xfer_set_filename(xfer, utf8); |
|
| 447 |
|
| 448 msg = g_strdup_printf(_("Offering to send %s to %s"), |
|
| 449 utf8, buddy ? gaim_buddy_get_alias(buddy) : xfer->who); |
|
| 450 g_free(utf8); |
|
| 451 |
|
| 452 gaim_xfer_conversation_write(xfer, msg, FALSE); |
|
| 453 g_free(msg); |
|
| 454 } |
|
| 455 else { |
|
| 456 xfer->status = GAIM_XFER_STATUS_ACCEPTED; |
|
| 457 gaim_xfer_set_local_filename(xfer, filename); |
|
| 458 |
|
| 459 msg = g_strdup_printf(_("Starting transfer of %s from %s"), |
|
| 460 xfer->filename, buddy ? gaim_buddy_get_alias(buddy) : xfer->who); |
|
| 461 gaim_xfer_conversation_write(xfer, msg, FALSE); |
|
| 462 g_free(msg); |
|
| 463 } |
|
| 464 |
|
| 465 gaim_xfer_add(xfer); |
|
| 466 xfer->ops.init(xfer); |
|
| 467 |
|
| 468 } |
|
| 469 |
|
| 470 void |
|
| 471 gaim_xfer_request_denied(GaimXfer *xfer) |
|
| 472 { |
|
| 473 g_return_if_fail(xfer != NULL); |
|
| 474 |
|
| 475 if (xfer->ops.request_denied != NULL) |
|
| 476 xfer->ops.request_denied(xfer); |
|
| 477 |
|
| 478 gaim_xfer_unref(xfer); |
|
| 479 } |
|
| 480 |
|
| 481 GaimXferType |
|
| 482 gaim_xfer_get_type(const GaimXfer *xfer) |
|
| 483 { |
|
| 484 g_return_val_if_fail(xfer != NULL, GAIM_XFER_UNKNOWN); |
|
| 485 |
|
| 486 return xfer->type; |
|
| 487 } |
|
| 488 |
|
| 489 GaimAccount * |
|
| 490 gaim_xfer_get_account(const GaimXfer *xfer) |
|
| 491 { |
|
| 492 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 493 |
|
| 494 return xfer->account; |
|
| 495 } |
|
| 496 |
|
| 497 GaimXferStatusType |
|
| 498 gaim_xfer_get_status(const GaimXfer *xfer) |
|
| 499 { |
|
| 500 g_return_val_if_fail(xfer != NULL, GAIM_XFER_STATUS_UNKNOWN); |
|
| 501 |
|
| 502 return xfer->status; |
|
| 503 } |
|
| 504 |
|
| 505 gboolean |
|
| 506 gaim_xfer_is_canceled(const GaimXfer *xfer) |
|
| 507 { |
|
| 508 g_return_val_if_fail(xfer != NULL, TRUE); |
|
| 509 |
|
| 510 if ((gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) || |
|
| 511 (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_REMOTE)) |
|
| 512 return TRUE; |
|
| 513 else |
|
| 514 return FALSE; |
|
| 515 } |
|
| 516 |
|
| 517 gboolean |
|
| 518 gaim_xfer_is_completed(const GaimXfer *xfer) |
|
| 519 { |
|
| 520 g_return_val_if_fail(xfer != NULL, TRUE); |
|
| 521 |
|
| 522 return (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_DONE); |
|
| 523 } |
|
| 524 |
|
| 525 const char * |
|
| 526 gaim_xfer_get_filename(const GaimXfer *xfer) |
|
| 527 { |
|
| 528 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 529 |
|
| 530 return xfer->filename; |
|
| 531 } |
|
| 532 |
|
| 533 const char * |
|
| 534 gaim_xfer_get_local_filename(const GaimXfer *xfer) |
|
| 535 { |
|
| 536 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 537 |
|
| 538 return xfer->local_filename; |
|
| 539 } |
|
| 540 |
|
| 541 size_t |
|
| 542 gaim_xfer_get_bytes_sent(const GaimXfer *xfer) |
|
| 543 { |
|
| 544 g_return_val_if_fail(xfer != NULL, 0); |
|
| 545 |
|
| 546 return xfer->bytes_sent; |
|
| 547 } |
|
| 548 |
|
| 549 size_t |
|
| 550 gaim_xfer_get_bytes_remaining(const GaimXfer *xfer) |
|
| 551 { |
|
| 552 g_return_val_if_fail(xfer != NULL, 0); |
|
| 553 |
|
| 554 return xfer->bytes_remaining; |
|
| 555 } |
|
| 556 |
|
| 557 size_t |
|
| 558 gaim_xfer_get_size(const GaimXfer *xfer) |
|
| 559 { |
|
| 560 g_return_val_if_fail(xfer != NULL, 0); |
|
| 561 |
|
| 562 return xfer->size; |
|
| 563 } |
|
| 564 |
|
| 565 double |
|
| 566 gaim_xfer_get_progress(const GaimXfer *xfer) |
|
| 567 { |
|
| 568 g_return_val_if_fail(xfer != NULL, 0.0); |
|
| 569 |
|
| 570 if (gaim_xfer_get_size(xfer) == 0) |
|
| 571 return 0.0; |
|
| 572 |
|
| 573 return ((double)gaim_xfer_get_bytes_sent(xfer) / |
|
| 574 (double)gaim_xfer_get_size(xfer)); |
|
| 575 } |
|
| 576 |
|
| 577 unsigned int |
|
| 578 gaim_xfer_get_local_port(const GaimXfer *xfer) |
|
| 579 { |
|
| 580 g_return_val_if_fail(xfer != NULL, -1); |
|
| 581 |
|
| 582 return xfer->local_port; |
|
| 583 } |
|
| 584 |
|
| 585 const char * |
|
| 586 gaim_xfer_get_remote_ip(const GaimXfer *xfer) |
|
| 587 { |
|
| 588 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 589 |
|
| 590 return xfer->remote_ip; |
|
| 591 } |
|
| 592 |
|
| 593 unsigned int |
|
| 594 gaim_xfer_get_remote_port(const GaimXfer *xfer) |
|
| 595 { |
|
| 596 g_return_val_if_fail(xfer != NULL, -1); |
|
| 597 |
|
| 598 return xfer->remote_port; |
|
| 599 } |
|
| 600 |
|
| 601 void |
|
| 602 gaim_xfer_set_completed(GaimXfer *xfer, gboolean completed) |
|
| 603 { |
|
| 604 GaimXferUiOps *ui_ops; |
|
| 605 |
|
| 606 g_return_if_fail(xfer != NULL); |
|
| 607 |
|
| 608 if (completed == TRUE) { |
|
| 609 char *msg = NULL; |
|
| 610 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_DONE); |
|
| 611 |
|
| 612 if (gaim_xfer_get_filename(xfer) != NULL) |
|
| 613 msg = g_strdup_printf(_("Transfer of file %s complete"), |
|
| 614 gaim_xfer_get_filename(xfer)); |
|
| 615 else |
|
| 616 msg = g_strdup_printf(_("File transfer complete")); |
|
| 617 gaim_xfer_conversation_write(xfer, msg, FALSE); |
|
| 618 g_free(msg); |
|
| 619 } |
|
| 620 |
|
| 621 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 622 |
|
| 623 if (ui_ops != NULL && ui_ops->update_progress != NULL) |
|
| 624 ui_ops->update_progress(xfer, gaim_xfer_get_progress(xfer)); |
|
| 625 } |
|
| 626 |
|
| 627 void |
|
| 628 gaim_xfer_set_message(GaimXfer *xfer, const char *message) |
|
| 629 { |
|
| 630 g_return_if_fail(xfer != NULL); |
|
| 631 |
|
| 632 g_free(xfer->message); |
|
| 633 |
|
| 634 if (message != NULL) |
|
| 635 xfer->message = g_strdup(message); |
|
| 636 else |
|
| 637 xfer->message = NULL; |
|
| 638 } |
|
| 639 |
|
| 640 void |
|
| 641 gaim_xfer_set_filename(GaimXfer *xfer, const char *filename) |
|
| 642 { |
|
| 643 g_return_if_fail(xfer != NULL); |
|
| 644 |
|
| 645 if (xfer->filename != NULL) |
|
| 646 g_free(xfer->filename); |
|
| 647 |
|
| 648 xfer->filename = (filename == NULL ? NULL : g_strdup(filename)); |
|
| 649 } |
|
| 650 |
|
| 651 void |
|
| 652 gaim_xfer_set_local_filename(GaimXfer *xfer, const char *filename) |
|
| 653 { |
|
| 654 g_return_if_fail(xfer != NULL); |
|
| 655 |
|
| 656 if (xfer->local_filename != NULL) |
|
| 657 g_free(xfer->local_filename); |
|
| 658 |
|
| 659 xfer->local_filename = (filename == NULL ? NULL : g_strdup(filename)); |
|
| 660 } |
|
| 661 |
|
| 662 void |
|
| 663 gaim_xfer_set_size(GaimXfer *xfer, size_t size) |
|
| 664 { |
|
| 665 g_return_if_fail(xfer != NULL); |
|
| 666 |
|
| 667 if (xfer->size == 0) |
|
| 668 xfer->bytes_remaining = size - xfer->bytes_sent; |
|
| 669 |
|
| 670 xfer->size = size; |
|
| 671 } |
|
| 672 |
|
| 673 GaimXferUiOps * |
|
| 674 gaim_xfer_get_ui_ops(const GaimXfer *xfer) |
|
| 675 { |
|
| 676 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 677 |
|
| 678 return xfer->ui_ops; |
|
| 679 } |
|
| 680 |
|
| 681 void |
|
| 682 gaim_xfer_set_init_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 683 { |
|
| 684 g_return_if_fail(xfer != NULL); |
|
| 685 |
|
| 686 xfer->ops.init = fnc; |
|
| 687 } |
|
| 688 |
|
| 689 void gaim_xfer_set_request_denied_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 690 { |
|
| 691 g_return_if_fail(xfer != NULL); |
|
| 692 |
|
| 693 xfer->ops.request_denied = fnc; |
|
| 694 } |
|
| 695 |
|
| 696 void |
|
| 697 gaim_xfer_set_read_fnc(GaimXfer *xfer, gssize (*fnc)(guchar **, GaimXfer *)) |
|
| 698 { |
|
| 699 g_return_if_fail(xfer != NULL); |
|
| 700 |
|
| 701 xfer->ops.read = fnc; |
|
| 702 } |
|
| 703 |
|
| 704 void |
|
| 705 gaim_xfer_set_write_fnc(GaimXfer *xfer, |
|
| 706 gssize (*fnc)(const guchar *, size_t, GaimXfer *)) |
|
| 707 { |
|
| 708 g_return_if_fail(xfer != NULL); |
|
| 709 |
|
| 710 xfer->ops.write = fnc; |
|
| 711 } |
|
| 712 |
|
| 713 void |
|
| 714 gaim_xfer_set_ack_fnc(GaimXfer *xfer, |
|
| 715 void (*fnc)(GaimXfer *, const guchar *, size_t)) |
|
| 716 { |
|
| 717 g_return_if_fail(xfer != NULL); |
|
| 718 |
|
| 719 xfer->ops.ack = fnc; |
|
| 720 } |
|
| 721 |
|
| 722 void |
|
| 723 gaim_xfer_set_start_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 724 { |
|
| 725 g_return_if_fail(xfer != NULL); |
|
| 726 |
|
| 727 xfer->ops.start = fnc; |
|
| 728 } |
|
| 729 |
|
| 730 void |
|
| 731 gaim_xfer_set_end_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 732 { |
|
| 733 g_return_if_fail(xfer != NULL); |
|
| 734 |
|
| 735 xfer->ops.end = fnc; |
|
| 736 } |
|
| 737 |
|
| 738 void |
|
| 739 gaim_xfer_set_cancel_send_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 740 { |
|
| 741 g_return_if_fail(xfer != NULL); |
|
| 742 |
|
| 743 xfer->ops.cancel_send = fnc; |
|
| 744 } |
|
| 745 |
|
| 746 void |
|
| 747 gaim_xfer_set_cancel_recv_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 748 { |
|
| 749 g_return_if_fail(xfer != NULL); |
|
| 750 |
|
| 751 xfer->ops.cancel_recv = fnc; |
|
| 752 } |
|
| 753 |
|
| 754 gssize |
|
| 755 gaim_xfer_read(GaimXfer *xfer, guchar **buffer) |
|
| 756 { |
|
| 757 gssize s, r; |
|
| 758 |
|
| 759 g_return_val_if_fail(xfer != NULL, 0); |
|
| 760 g_return_val_if_fail(buffer != NULL, 0); |
|
| 761 |
|
| 762 if (gaim_xfer_get_size(xfer) == 0) |
|
| 763 s = 4096; |
|
| 764 else |
|
| 765 s = MIN(gaim_xfer_get_bytes_remaining(xfer), 4096); |
|
| 766 |
|
| 767 if (xfer->ops.read != NULL) |
|
| 768 r = (xfer->ops.read)(buffer, xfer); |
|
| 769 else { |
|
| 770 *buffer = g_malloc0(s); |
|
| 771 |
|
| 772 r = read(xfer->fd, *buffer, s); |
|
| 773 if (r < 0 && errno == EAGAIN) |
|
| 774 r = 0; |
|
| 775 else if (r < 0) |
|
| 776 r = -1; |
|
| 777 else if ((gaim_xfer_get_size(xfer) > 0) && |
|
| 778 ((gaim_xfer_get_bytes_sent(xfer)+r) >= gaim_xfer_get_size(xfer))) |
|
| 779 gaim_xfer_set_completed(xfer, TRUE); |
|
| 780 } |
|
| 781 |
|
| 782 return r; |
|
| 783 } |
|
| 784 |
|
| 785 gssize |
|
| 786 gaim_xfer_write(GaimXfer *xfer, const guchar *buffer, size_t size) |
|
| 787 { |
|
| 788 gssize r, s; |
|
| 789 |
|
| 790 g_return_val_if_fail(xfer != NULL, 0); |
|
| 791 g_return_val_if_fail(buffer != NULL, 0); |
|
| 792 g_return_val_if_fail(size != 0, 0); |
|
| 793 |
|
| 794 s = MIN(gaim_xfer_get_bytes_remaining(xfer), size); |
|
| 795 |
|
| 796 if (xfer->ops.write != NULL) { |
|
| 797 r = (xfer->ops.write)(buffer, s, xfer); |
|
| 798 } else { |
|
| 799 r = write(xfer->fd, buffer, s); |
|
| 800 if (r < 0 && errno == EAGAIN) |
|
| 801 r = 0; |
|
| 802 if ((gaim_xfer_get_bytes_sent(xfer)+r) >= gaim_xfer_get_size(xfer)) |
|
| 803 gaim_xfer_set_completed(xfer, TRUE); |
|
| 804 } |
|
| 805 |
|
| 806 return r; |
|
| 807 } |
|
| 808 |
|
| 809 static void |
|
| 810 transfer_cb(gpointer data, gint source, GaimInputCondition condition) |
|
| 811 { |
|
| 812 GaimXferUiOps *ui_ops; |
|
| 813 GaimXfer *xfer = (GaimXfer *)data; |
|
| 814 guchar *buffer = NULL; |
|
| 815 gssize r = 0; |
|
| 816 |
|
| 817 if (condition & GAIM_INPUT_READ) { |
|
| 818 r = gaim_xfer_read(xfer, &buffer); |
|
| 819 if (r > 0) { |
|
| 820 fwrite(buffer, 1, r, xfer->dest_fp); |
|
| 821 } else if(r < 0) { |
|
| 822 gaim_xfer_cancel_remote(xfer); |
|
| 823 return; |
|
| 824 } else if(r == 0) |
|
| 825 return; |
|
| 826 } |
|
| 827 |
|
| 828 if (condition & GAIM_INPUT_WRITE) { |
|
| 829 size_t s = MIN(gaim_xfer_get_bytes_remaining(xfer), 4096); |
|
| 830 |
|
| 831 /* this is so the prpl can keep the connection open |
|
| 832 if it needs to for some odd reason. */ |
|
| 833 if (s == 0) { |
|
| 834 if (xfer->watcher) { |
|
| 835 gaim_input_remove(xfer->watcher); |
|
| 836 xfer->watcher = 0; |
|
| 837 } |
|
| 838 return; |
|
| 839 } |
|
| 840 |
|
| 841 buffer = g_malloc0(s); |
|
| 842 |
|
| 843 fread(buffer, 1, s, xfer->dest_fp); |
|
| 844 |
|
| 845 /* Write as much as we're allowed to. */ |
|
| 846 r = gaim_xfer_write(xfer, buffer, s); |
|
| 847 |
|
| 848 if (r == -1) { |
|
| 849 gaim_xfer_cancel_remote(xfer); |
|
| 850 g_free(buffer); |
|
| 851 return; |
|
| 852 } else if (r < s) { |
|
| 853 /* We have to seek back in the file now. */ |
|
| 854 fseek(xfer->dest_fp, r - s, SEEK_CUR); |
|
| 855 } |
|
| 856 } |
|
| 857 |
|
| 858 if (gaim_xfer_get_size(xfer) > 0) |
|
| 859 xfer->bytes_remaining -= r; |
|
| 860 |
|
| 861 xfer->bytes_sent += r; |
|
| 862 |
|
| 863 if (xfer->ops.ack != NULL) |
|
| 864 xfer->ops.ack(xfer, buffer, r); |
|
| 865 |
|
| 866 g_free(buffer); |
|
| 867 |
|
| 868 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 869 |
|
| 870 if (ui_ops != NULL && ui_ops->update_progress != NULL) |
|
| 871 ui_ops->update_progress(xfer, gaim_xfer_get_progress(xfer)); |
|
| 872 |
|
| 873 if (gaim_xfer_is_completed(xfer)) |
|
| 874 gaim_xfer_end(xfer); |
|
| 875 } |
|
| 876 |
|
| 877 static void |
|
| 878 begin_transfer(GaimXfer *xfer, GaimInputCondition cond) |
|
| 879 { |
|
| 880 GaimXferType type = gaim_xfer_get_type(xfer); |
|
| 881 |
|
| 882 xfer->dest_fp = g_fopen(gaim_xfer_get_local_filename(xfer), |
|
| 883 type == GAIM_XFER_RECEIVE ? "wb" : "rb"); |
|
| 884 |
|
| 885 if (xfer->dest_fp == NULL) { |
|
| 886 gaim_xfer_show_file_error(xfer, gaim_xfer_get_local_filename(xfer)); |
|
| 887 gaim_xfer_cancel_local(xfer); |
|
| 888 return; |
|
| 889 } |
|
| 890 |
|
| 891 xfer->watcher = gaim_input_add(xfer->fd, cond, transfer_cb, xfer); |
|
| 892 |
|
| 893 if (xfer->ops.start != NULL) |
|
| 894 xfer->ops.start(xfer); |
|
| 895 } |
|
| 896 |
|
| 897 static void |
|
| 898 connect_cb(gpointer data, gint source, GaimInputCondition condition) |
|
| 899 { |
|
| 900 GaimXfer *xfer = (GaimXfer *)data; |
|
| 901 |
|
| 902 xfer->fd = source; |
|
| 903 |
|
| 904 begin_transfer(xfer, condition); |
|
| 905 } |
|
| 906 |
|
| 907 void |
|
| 908 gaim_xfer_start(GaimXfer *xfer, int fd, const char *ip, |
|
| 909 unsigned int port) |
|
| 910 { |
|
| 911 GaimInputCondition cond; |
|
| 912 GaimXferType type; |
|
| 913 |
|
| 914 g_return_if_fail(xfer != NULL); |
|
| 915 g_return_if_fail(gaim_xfer_get_type(xfer) != GAIM_XFER_UNKNOWN); |
|
| 916 |
|
| 917 type = gaim_xfer_get_type(xfer); |
|
| 918 |
|
| 919 xfer->bytes_remaining = gaim_xfer_get_size(xfer); |
|
| 920 xfer->bytes_sent = 0; |
|
| 921 |
|
| 922 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_STARTED); |
|
| 923 |
|
| 924 if (type == GAIM_XFER_RECEIVE) { |
|
| 925 cond = GAIM_INPUT_READ; |
|
| 926 |
|
| 927 if (ip != NULL) { |
|
| 928 xfer->remote_ip = g_strdup(ip); |
|
| 929 xfer->remote_port = port; |
|
| 930 |
|
| 931 /* Establish a file descriptor. */ |
|
| 932 gaim_proxy_connect(xfer->account, xfer->remote_ip, |
|
| 933 xfer->remote_port, connect_cb, xfer); |
|
| 934 |
|
| 935 return; |
|
| 936 } |
|
| 937 else { |
|
| 938 xfer->fd = fd; |
|
| 939 } |
|
| 940 } |
|
| 941 else { |
|
| 942 cond = GAIM_INPUT_WRITE; |
|
| 943 |
|
| 944 xfer->fd = fd; |
|
| 945 } |
|
| 946 |
|
| 947 begin_transfer(xfer, cond); |
|
| 948 } |
|
| 949 |
|
| 950 void |
|
| 951 gaim_xfer_end(GaimXfer *xfer) |
|
| 952 { |
|
| 953 g_return_if_fail(xfer != NULL); |
|
| 954 |
|
| 955 /* See if we are actually trying to cancel this. */ |
|
| 956 if (gaim_xfer_get_status(xfer) != GAIM_XFER_STATUS_DONE) { |
|
| 957 gaim_xfer_cancel_local(xfer); |
|
| 958 return; |
|
| 959 } |
|
| 960 |
|
| 961 if (xfer->ops.end != NULL) |
|
| 962 xfer->ops.end(xfer); |
|
| 963 |
|
| 964 if (xfer->watcher != 0) { |
|
| 965 gaim_input_remove(xfer->watcher); |
|
| 966 xfer->watcher = 0; |
|
| 967 } |
|
| 968 |
|
| 969 if (xfer->fd != 0) |
|
| 970 close(xfer->fd); |
|
| 971 |
|
| 972 if (xfer->dest_fp != NULL) { |
|
| 973 fclose(xfer->dest_fp); |
|
| 974 xfer->dest_fp = NULL; |
|
| 975 } |
|
| 976 |
|
| 977 gaim_xfer_unref(xfer); |
|
| 978 } |
|
| 979 |
|
| 980 void |
|
| 981 gaim_xfer_add(GaimXfer *xfer) |
|
| 982 { |
|
| 983 GaimXferUiOps *ui_ops; |
|
| 984 |
|
| 985 g_return_if_fail(xfer != NULL); |
|
| 986 |
|
| 987 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 988 |
|
| 989 if (ui_ops != NULL && ui_ops->add_xfer != NULL) |
|
| 990 ui_ops->add_xfer(xfer); |
|
| 991 } |
|
| 992 |
|
| 993 void |
|
| 994 gaim_xfer_cancel_local(GaimXfer *xfer) |
|
| 995 { |
|
| 996 GaimXferUiOps *ui_ops; |
|
| 997 char *msg = NULL; |
|
| 998 |
|
| 999 g_return_if_fail(xfer != NULL); |
|
| 1000 |
|
| 1001 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_LOCAL); |
|
| 1002 |
|
| 1003 if (gaim_xfer_get_filename(xfer) != NULL) |
|
| 1004 { |
|
| 1005 msg = g_strdup_printf(_("You canceled the transfer of %s"), |
|
| 1006 gaim_xfer_get_filename(xfer)); |
|
| 1007 } |
|
| 1008 else |
|
| 1009 { |
|
| 1010 msg = g_strdup_printf(_("File transfer cancelled")); |
|
| 1011 } |
|
| 1012 gaim_xfer_conversation_write(xfer, msg, FALSE); |
|
| 1013 g_free(msg); |
|
| 1014 |
|
| 1015 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) |
|
| 1016 { |
|
| 1017 if (xfer->ops.cancel_send != NULL) |
|
| 1018 xfer->ops.cancel_send(xfer); |
|
| 1019 } |
|
| 1020 else |
|
| 1021 { |
|
| 1022 if (xfer->ops.cancel_recv != NULL) |
|
| 1023 xfer->ops.cancel_recv(xfer); |
|
| 1024 } |
|
| 1025 |
|
| 1026 if (xfer->watcher != 0) { |
|
| 1027 gaim_input_remove(xfer->watcher); |
|
| 1028 xfer->watcher = 0; |
|
| 1029 } |
|
| 1030 |
|
| 1031 if (xfer->fd != 0) |
|
| 1032 close(xfer->fd); |
|
| 1033 |
|
| 1034 if (xfer->dest_fp != NULL) { |
|
| 1035 fclose(xfer->dest_fp); |
|
| 1036 xfer->dest_fp = NULL; |
|
| 1037 } |
|
| 1038 |
|
| 1039 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 1040 |
|
| 1041 if (ui_ops != NULL && ui_ops->cancel_local != NULL) |
|
| 1042 ui_ops->cancel_local(xfer); |
|
| 1043 |
|
| 1044 xfer->bytes_remaining = 0; |
|
| 1045 |
|
| 1046 gaim_xfer_unref(xfer); |
|
| 1047 } |
|
| 1048 |
|
| 1049 void |
|
| 1050 gaim_xfer_cancel_remote(GaimXfer *xfer) |
|
| 1051 { |
|
| 1052 GaimXferUiOps *ui_ops; |
|
| 1053 gchar *msg; |
|
| 1054 GaimAccount *account; |
|
| 1055 GaimBuddy *buddy; |
|
| 1056 |
|
| 1057 g_return_if_fail(xfer != NULL); |
|
| 1058 |
|
| 1059 gaim_request_close_with_handle(xfer); |
|
| 1060 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_REMOTE); |
|
| 1061 |
|
| 1062 account = gaim_xfer_get_account(xfer); |
|
| 1063 buddy = gaim_find_buddy(account, xfer->who); |
|
| 1064 |
|
| 1065 if (gaim_xfer_get_filename(xfer) != NULL) |
|
| 1066 { |
|
| 1067 msg = g_strdup_printf(_("%s canceled the transfer of %s"), |
|
| 1068 buddy ? gaim_buddy_get_alias(buddy) : xfer->who, gaim_xfer_get_filename(xfer)); |
|
| 1069 } |
|
| 1070 else |
|
| 1071 { |
|
| 1072 msg = g_strdup_printf(_("%s canceled the file transfer"), |
|
| 1073 buddy ? gaim_buddy_get_alias(buddy) : xfer->who); |
|
| 1074 } |
|
| 1075 gaim_xfer_conversation_write(xfer, msg, TRUE); |
|
| 1076 gaim_xfer_error(gaim_xfer_get_type(xfer), account, xfer->who, msg); |
|
| 1077 g_free(msg); |
|
| 1078 |
|
| 1079 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) |
|
| 1080 { |
|
| 1081 if (xfer->ops.cancel_send != NULL) |
|
| 1082 xfer->ops.cancel_send(xfer); |
|
| 1083 } |
|
| 1084 else |
|
| 1085 { |
|
| 1086 if (xfer->ops.cancel_recv != NULL) |
|
| 1087 xfer->ops.cancel_recv(xfer); |
|
| 1088 } |
|
| 1089 |
|
| 1090 if (xfer->watcher != 0) { |
|
| 1091 gaim_input_remove(xfer->watcher); |
|
| 1092 xfer->watcher = 0; |
|
| 1093 } |
|
| 1094 |
|
| 1095 if (xfer->fd != 0) |
|
| 1096 close(xfer->fd); |
|
| 1097 |
|
| 1098 if (xfer->dest_fp != NULL) { |
|
| 1099 fclose(xfer->dest_fp); |
|
| 1100 xfer->dest_fp = NULL; |
|
| 1101 } |
|
| 1102 |
|
| 1103 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 1104 |
|
| 1105 if (ui_ops != NULL && ui_ops->cancel_remote != NULL) |
|
| 1106 ui_ops->cancel_remote(xfer); |
|
| 1107 |
|
| 1108 xfer->bytes_remaining = 0; |
|
| 1109 |
|
| 1110 gaim_xfer_unref(xfer); |
|
| 1111 } |
|
| 1112 |
|
| 1113 void |
|
| 1114 gaim_xfer_error(GaimXferType type, GaimAccount *account, const char *who, const char *msg) |
|
| 1115 { |
|
| 1116 char *title; |
|
| 1117 |
|
| 1118 g_return_if_fail(msg != NULL); |
|
| 1119 g_return_if_fail(type != GAIM_XFER_UNKNOWN); |
|
| 1120 |
|
| 1121 if (account) { |
|
| 1122 GaimBuddy *buddy; |
|
| 1123 buddy = gaim_find_buddy(account, who); |
|
| 1124 if (buddy) |
|
| 1125 who = gaim_buddy_get_alias(buddy); |
|
| 1126 } |
|
| 1127 |
|
| 1128 if (type == GAIM_XFER_SEND) |
|
| 1129 title = g_strdup_printf(_("File transfer to %s failed."), who); |
|
| 1130 else |
|
| 1131 title = g_strdup_printf(_("File transfer from %s failed."), who); |
|
| 1132 |
|
| 1133 gaim_notify_error(NULL, NULL, title, msg); |
|
| 1134 |
|
| 1135 g_free(title); |
|
| 1136 } |
|
| 1137 |
|
| 1138 void |
|
| 1139 gaim_xfer_update_progress(GaimXfer *xfer) |
|
| 1140 { |
|
| 1141 GaimXferUiOps *ui_ops; |
|
| 1142 |
|
| 1143 g_return_if_fail(xfer != NULL); |
|
| 1144 |
|
| 1145 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 1146 if (ui_ops != NULL && ui_ops->update_progress != NULL) |
|
| 1147 ui_ops->update_progress(xfer, gaim_xfer_get_progress(xfer)); |
|
| 1148 } |
|
| 1149 |
|
| 1150 |
|
| 1151 /************************************************************************** |
|
| 1152 * File Transfer Subsystem API |
|
| 1153 **************************************************************************/ |
|
| 1154 void * |
|
| 1155 gaim_xfers_get_handle(void) { |
|
| 1156 static int handle = 0; |
|
| 1157 |
|
| 1158 return &handle; |
|
| 1159 } |
|
| 1160 |
|
| 1161 void |
|
| 1162 gaim_xfers_init(void) { |
|
| 1163 void *handle = gaim_xfers_get_handle(); |
|
| 1164 |
|
| 1165 /* register signals */ |
|
| 1166 gaim_signal_register(handle, "file-recv-accept", |
|
| 1167 gaim_marshal_VOID__POINTER, |
|
| 1168 NULL, 1, |
|
| 1169 gaim_value_new(GAIM_TYPE_POINTER)); |
|
| 1170 gaim_signal_register(handle, "file-send-accept", |
|
| 1171 gaim_marshal_VOID__POINTER, |
|
| 1172 NULL, 1, |
|
| 1173 gaim_value_new(GAIM_TYPE_POINTER)); |
|
| 1174 gaim_signal_register(handle, "file-recv-start", |
|
| 1175 gaim_marshal_VOID__POINTER, |
|
| 1176 NULL, 1, |
|
| 1177 gaim_value_new(GAIM_TYPE_POINTER)); |
|
| 1178 gaim_signal_register(handle, "file-send-start", |
|
| 1179 gaim_marshal_VOID__POINTER, |
|
| 1180 NULL, 1, |
|
| 1181 gaim_value_new(GAIM_TYPE_POINTER)); |
|
| 1182 gaim_signal_register(handle, "file-send-cancel", |
|
| 1183 gaim_marshal_VOID__POINTER, |
|
| 1184 NULL, 1, |
|
| 1185 gaim_value_new(GAIM_TYPE_POINTER)); |
|
| 1186 gaim_signal_register(handle, "file-recv-cancel", |
|
| 1187 gaim_marshal_VOID__POINTER, |
|
| 1188 NULL, 1, |
|
| 1189 gaim_value_new(GAIM_TYPE_POINTER)); |
|
| 1190 gaim_signal_register(handle, "file-send-complete", |
|
| 1191 gaim_marshal_VOID__POINTER, |
|
| 1192 NULL, 1, |
|
| 1193 gaim_value_new(GAIM_TYPE_POINTER)); |
|
| 1194 gaim_signal_register(handle, "file-recv-complete", |
|
| 1195 gaim_marshal_VOID__POINTER, |
|
| 1196 NULL, 1, |
|
| 1197 gaim_value_new(GAIM_TYPE_POINTER)); |
|
| 1198 } |
|
| 1199 |
|
| 1200 void |
|
| 1201 gaim_xfers_uninit(void) { |
|
| 1202 gaim_signals_disconnect_by_handle(gaim_xfers_get_handle()); |
|
| 1203 } |
|
| 1204 |
|
| 1205 void |
|
| 1206 gaim_xfers_set_ui_ops(GaimXferUiOps *ops) { |
|
| 1207 xfer_ui_ops = ops; |
|
| 1208 } |
|
| 1209 |
|
| 1210 GaimXferUiOps * |
|
| 1211 gaim_xfers_get_ui_ops(void) { |
|
| 1212 return xfer_ui_ops; |
|
| 1213 } |
|