| 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 { |
|
| 381 gaim_signal_emit(gaim_xfers_get_handle(), "file-recv-request", xfer); |
|
| 382 if (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) |
|
| 383 { |
|
| 384 /* The file-transfer was cancelled by a plugin */ |
|
| 385 gaim_xfer_cancel_local(xfer); |
|
| 386 } |
|
| 387 else if (gaim_xfer_get_filename(xfer) || |
|
| 388 gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_ACCEPTED) |
|
| 389 { |
|
| 390 gchar* message = NULL; |
|
| 391 GaimBuddy *buddy = gaim_find_buddy(xfer->account, xfer->who); |
|
| 392 message = g_strdup_printf(_("%s is offering to send file %s"), |
|
| 393 buddy ? gaim_buddy_get_alias(buddy) : xfer->who, gaim_xfer_get_filename(xfer)); |
|
| 394 gaim_xfer_conversation_write(xfer, message, FALSE); |
|
| 395 g_free(message); |
|
| 396 /* Ask for a filename to save to if it's not already given by a plugin */ |
|
| 397 if (xfer->local_filename == NULL) |
|
| 398 gaim_xfer_ask_recv(xfer); |
|
| 399 } |
|
| 400 else |
|
| 401 { |
|
| 402 gaim_xfer_ask_accept(xfer); |
|
| 403 } |
|
| 404 } |
|
| 405 else |
|
| 406 { |
|
| 407 gaim_xfer_choose_file(xfer); |
|
| 408 } |
|
| 409 } |
|
| 410 |
|
| 411 void |
|
| 412 gaim_xfer_request_accepted(GaimXfer *xfer, const char *filename) |
|
| 413 { |
|
| 414 GaimXferType type; |
|
| 415 struct stat st; |
|
| 416 char *msg, *utf8; |
|
| 417 GaimAccount *account; |
|
| 418 GaimBuddy *buddy; |
|
| 419 |
|
| 420 if (xfer == NULL) |
|
| 421 return; |
|
| 422 |
|
| 423 type = gaim_xfer_get_type(xfer); |
|
| 424 account = gaim_xfer_get_account(xfer); |
|
| 425 |
|
| 426 if (!filename && type == GAIM_XFER_RECEIVE) { |
|
| 427 xfer->status = GAIM_XFER_STATUS_ACCEPTED; |
|
| 428 xfer->ops.init(xfer); |
|
| 429 return; |
|
| 430 } |
|
| 431 |
|
| 432 buddy = gaim_find_buddy(account, xfer->who); |
|
| 433 |
|
| 434 if (type == GAIM_XFER_SEND) { |
|
| 435 /* Sending a file */ |
|
| 436 /* Check the filename. */ |
|
| 437 #ifdef _WIN32 |
|
| 438 if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\")) { |
|
| 439 #else |
|
| 440 if (g_strrstr(filename, "../")) { |
|
| 441 #endif |
|
| 442 char *utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); |
|
| 443 |
|
| 444 msg = g_strdup_printf(_("%s is not a valid filename.\n"), utf8); |
|
| 445 gaim_xfer_error(type, account, xfer->who, msg); |
|
| 446 g_free(utf8); |
|
| 447 g_free(msg); |
|
| 448 |
|
| 449 gaim_xfer_unref(xfer); |
|
| 450 return; |
|
| 451 } |
|
| 452 |
|
| 453 if (g_stat(filename, &st) == -1) { |
|
| 454 gaim_xfer_show_file_error(xfer, filename); |
|
| 455 gaim_xfer_unref(xfer); |
|
| 456 return; |
|
| 457 } |
|
| 458 |
|
| 459 gaim_xfer_set_local_filename(xfer, filename); |
|
| 460 gaim_xfer_set_size(xfer, st.st_size); |
|
| 461 |
|
| 462 utf8 = g_filename_to_utf8(g_basename(filename), -1, NULL, NULL, NULL); |
|
| 463 gaim_xfer_set_filename(xfer, utf8); |
|
| 464 |
|
| 465 msg = g_strdup_printf(_("Offering to send %s to %s"), |
|
| 466 utf8, buddy ? gaim_buddy_get_alias(buddy) : xfer->who); |
|
| 467 g_free(utf8); |
|
| 468 |
|
| 469 gaim_xfer_conversation_write(xfer, msg, FALSE); |
|
| 470 g_free(msg); |
|
| 471 } |
|
| 472 else { |
|
| 473 /* Receiving a file */ |
|
| 474 xfer->status = GAIM_XFER_STATUS_ACCEPTED; |
|
| 475 gaim_xfer_set_local_filename(xfer, filename); |
|
| 476 |
|
| 477 msg = g_strdup_printf(_("Starting transfer of %s from %s"), |
|
| 478 xfer->filename, buddy ? gaim_buddy_get_alias(buddy) : xfer->who); |
|
| 479 gaim_xfer_conversation_write(xfer, msg, FALSE); |
|
| 480 g_free(msg); |
|
| 481 } |
|
| 482 |
|
| 483 gaim_xfer_add(xfer); |
|
| 484 xfer->ops.init(xfer); |
|
| 485 |
|
| 486 } |
|
| 487 |
|
| 488 void |
|
| 489 gaim_xfer_request_denied(GaimXfer *xfer) |
|
| 490 { |
|
| 491 g_return_if_fail(xfer != NULL); |
|
| 492 |
|
| 493 if (xfer->ops.request_denied != NULL) |
|
| 494 xfer->ops.request_denied(xfer); |
|
| 495 |
|
| 496 gaim_xfer_unref(xfer); |
|
| 497 } |
|
| 498 |
|
| 499 GaimXferType |
|
| 500 gaim_xfer_get_type(const GaimXfer *xfer) |
|
| 501 { |
|
| 502 g_return_val_if_fail(xfer != NULL, GAIM_XFER_UNKNOWN); |
|
| 503 |
|
| 504 return xfer->type; |
|
| 505 } |
|
| 506 |
|
| 507 GaimAccount * |
|
| 508 gaim_xfer_get_account(const GaimXfer *xfer) |
|
| 509 { |
|
| 510 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 511 |
|
| 512 return xfer->account; |
|
| 513 } |
|
| 514 |
|
| 515 GaimXferStatusType |
|
| 516 gaim_xfer_get_status(const GaimXfer *xfer) |
|
| 517 { |
|
| 518 g_return_val_if_fail(xfer != NULL, GAIM_XFER_STATUS_UNKNOWN); |
|
| 519 |
|
| 520 return xfer->status; |
|
| 521 } |
|
| 522 |
|
| 523 gboolean |
|
| 524 gaim_xfer_is_canceled(const GaimXfer *xfer) |
|
| 525 { |
|
| 526 g_return_val_if_fail(xfer != NULL, TRUE); |
|
| 527 |
|
| 528 if ((gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) || |
|
| 529 (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_REMOTE)) |
|
| 530 return TRUE; |
|
| 531 else |
|
| 532 return FALSE; |
|
| 533 } |
|
| 534 |
|
| 535 gboolean |
|
| 536 gaim_xfer_is_completed(const GaimXfer *xfer) |
|
| 537 { |
|
| 538 g_return_val_if_fail(xfer != NULL, TRUE); |
|
| 539 |
|
| 540 return (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_DONE); |
|
| 541 } |
|
| 542 |
|
| 543 const char * |
|
| 544 gaim_xfer_get_filename(const GaimXfer *xfer) |
|
| 545 { |
|
| 546 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 547 |
|
| 548 return xfer->filename; |
|
| 549 } |
|
| 550 |
|
| 551 const char * |
|
| 552 gaim_xfer_get_local_filename(const GaimXfer *xfer) |
|
| 553 { |
|
| 554 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 555 |
|
| 556 return xfer->local_filename; |
|
| 557 } |
|
| 558 |
|
| 559 size_t |
|
| 560 gaim_xfer_get_bytes_sent(const GaimXfer *xfer) |
|
| 561 { |
|
| 562 g_return_val_if_fail(xfer != NULL, 0); |
|
| 563 |
|
| 564 return xfer->bytes_sent; |
|
| 565 } |
|
| 566 |
|
| 567 size_t |
|
| 568 gaim_xfer_get_bytes_remaining(const GaimXfer *xfer) |
|
| 569 { |
|
| 570 g_return_val_if_fail(xfer != NULL, 0); |
|
| 571 |
|
| 572 return xfer->bytes_remaining; |
|
| 573 } |
|
| 574 |
|
| 575 size_t |
|
| 576 gaim_xfer_get_size(const GaimXfer *xfer) |
|
| 577 { |
|
| 578 g_return_val_if_fail(xfer != NULL, 0); |
|
| 579 |
|
| 580 return xfer->size; |
|
| 581 } |
|
| 582 |
|
| 583 double |
|
| 584 gaim_xfer_get_progress(const GaimXfer *xfer) |
|
| 585 { |
|
| 586 g_return_val_if_fail(xfer != NULL, 0.0); |
|
| 587 |
|
| 588 if (gaim_xfer_get_size(xfer) == 0) |
|
| 589 return 0.0; |
|
| 590 |
|
| 591 return ((double)gaim_xfer_get_bytes_sent(xfer) / |
|
| 592 (double)gaim_xfer_get_size(xfer)); |
|
| 593 } |
|
| 594 |
|
| 595 unsigned int |
|
| 596 gaim_xfer_get_local_port(const GaimXfer *xfer) |
|
| 597 { |
|
| 598 g_return_val_if_fail(xfer != NULL, -1); |
|
| 599 |
|
| 600 return xfer->local_port; |
|
| 601 } |
|
| 602 |
|
| 603 const char * |
|
| 604 gaim_xfer_get_remote_ip(const GaimXfer *xfer) |
|
| 605 { |
|
| 606 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 607 |
|
| 608 return xfer->remote_ip; |
|
| 609 } |
|
| 610 |
|
| 611 unsigned int |
|
| 612 gaim_xfer_get_remote_port(const GaimXfer *xfer) |
|
| 613 { |
|
| 614 g_return_val_if_fail(xfer != NULL, -1); |
|
| 615 |
|
| 616 return xfer->remote_port; |
|
| 617 } |
|
| 618 |
|
| 619 void |
|
| 620 gaim_xfer_set_completed(GaimXfer *xfer, gboolean completed) |
|
| 621 { |
|
| 622 GaimXferUiOps *ui_ops; |
|
| 623 |
|
| 624 g_return_if_fail(xfer != NULL); |
|
| 625 |
|
| 626 if (completed == TRUE) { |
|
| 627 char *msg = NULL; |
|
| 628 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_DONE); |
|
| 629 |
|
| 630 if (gaim_xfer_get_filename(xfer) != NULL) |
|
| 631 msg = g_strdup_printf(_("Transfer of file %s complete"), |
|
| 632 gaim_xfer_get_filename(xfer)); |
|
| 633 else |
|
| 634 msg = g_strdup_printf(_("File transfer complete")); |
|
| 635 gaim_xfer_conversation_write(xfer, msg, FALSE); |
|
| 636 g_free(msg); |
|
| 637 } |
|
| 638 |
|
| 639 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 640 |
|
| 641 if (ui_ops != NULL && ui_ops->update_progress != NULL) |
|
| 642 ui_ops->update_progress(xfer, gaim_xfer_get_progress(xfer)); |
|
| 643 } |
|
| 644 |
|
| 645 void |
|
| 646 gaim_xfer_set_message(GaimXfer *xfer, const char *message) |
|
| 647 { |
|
| 648 g_return_if_fail(xfer != NULL); |
|
| 649 |
|
| 650 g_free(xfer->message); |
|
| 651 |
|
| 652 if (message != NULL) |
|
| 653 xfer->message = g_strdup(message); |
|
| 654 else |
|
| 655 xfer->message = NULL; |
|
| 656 } |
|
| 657 |
|
| 658 void |
|
| 659 gaim_xfer_set_filename(GaimXfer *xfer, const char *filename) |
|
| 660 { |
|
| 661 g_return_if_fail(xfer != NULL); |
|
| 662 |
|
| 663 if (xfer->filename != NULL) |
|
| 664 g_free(xfer->filename); |
|
| 665 |
|
| 666 xfer->filename = (filename == NULL ? NULL : g_strdup(filename)); |
|
| 667 } |
|
| 668 |
|
| 669 void |
|
| 670 gaim_xfer_set_local_filename(GaimXfer *xfer, const char *filename) |
|
| 671 { |
|
| 672 g_return_if_fail(xfer != NULL); |
|
| 673 |
|
| 674 if (xfer->local_filename != NULL) |
|
| 675 g_free(xfer->local_filename); |
|
| 676 |
|
| 677 xfer->local_filename = (filename == NULL ? NULL : g_strdup(filename)); |
|
| 678 } |
|
| 679 |
|
| 680 void |
|
| 681 gaim_xfer_set_size(GaimXfer *xfer, size_t size) |
|
| 682 { |
|
| 683 g_return_if_fail(xfer != NULL); |
|
| 684 |
|
| 685 if (xfer->size == 0) |
|
| 686 xfer->bytes_remaining = size - xfer->bytes_sent; |
|
| 687 |
|
| 688 xfer->size = size; |
|
| 689 } |
|
| 690 |
|
| 691 GaimXferUiOps * |
|
| 692 gaim_xfer_get_ui_ops(const GaimXfer *xfer) |
|
| 693 { |
|
| 694 g_return_val_if_fail(xfer != NULL, NULL); |
|
| 695 |
|
| 696 return xfer->ui_ops; |
|
| 697 } |
|
| 698 |
|
| 699 void |
|
| 700 gaim_xfer_set_init_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 701 { |
|
| 702 g_return_if_fail(xfer != NULL); |
|
| 703 |
|
| 704 xfer->ops.init = fnc; |
|
| 705 } |
|
| 706 |
|
| 707 void gaim_xfer_set_request_denied_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 708 { |
|
| 709 g_return_if_fail(xfer != NULL); |
|
| 710 |
|
| 711 xfer->ops.request_denied = fnc; |
|
| 712 } |
|
| 713 |
|
| 714 void |
|
| 715 gaim_xfer_set_read_fnc(GaimXfer *xfer, gssize (*fnc)(guchar **, GaimXfer *)) |
|
| 716 { |
|
| 717 g_return_if_fail(xfer != NULL); |
|
| 718 |
|
| 719 xfer->ops.read = fnc; |
|
| 720 } |
|
| 721 |
|
| 722 void |
|
| 723 gaim_xfer_set_write_fnc(GaimXfer *xfer, |
|
| 724 gssize (*fnc)(const guchar *, size_t, GaimXfer *)) |
|
| 725 { |
|
| 726 g_return_if_fail(xfer != NULL); |
|
| 727 |
|
| 728 xfer->ops.write = fnc; |
|
| 729 } |
|
| 730 |
|
| 731 void |
|
| 732 gaim_xfer_set_ack_fnc(GaimXfer *xfer, |
|
| 733 void (*fnc)(GaimXfer *, const guchar *, size_t)) |
|
| 734 { |
|
| 735 g_return_if_fail(xfer != NULL); |
|
| 736 |
|
| 737 xfer->ops.ack = fnc; |
|
| 738 } |
|
| 739 |
|
| 740 void |
|
| 741 gaim_xfer_set_start_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 742 { |
|
| 743 g_return_if_fail(xfer != NULL); |
|
| 744 |
|
| 745 xfer->ops.start = fnc; |
|
| 746 } |
|
| 747 |
|
| 748 void |
|
| 749 gaim_xfer_set_end_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 750 { |
|
| 751 g_return_if_fail(xfer != NULL); |
|
| 752 |
|
| 753 xfer->ops.end = fnc; |
|
| 754 } |
|
| 755 |
|
| 756 void |
|
| 757 gaim_xfer_set_cancel_send_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 758 { |
|
| 759 g_return_if_fail(xfer != NULL); |
|
| 760 |
|
| 761 xfer->ops.cancel_send = fnc; |
|
| 762 } |
|
| 763 |
|
| 764 void |
|
| 765 gaim_xfer_set_cancel_recv_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) |
|
| 766 { |
|
| 767 g_return_if_fail(xfer != NULL); |
|
| 768 |
|
| 769 xfer->ops.cancel_recv = fnc; |
|
| 770 } |
|
| 771 |
|
| 772 gssize |
|
| 773 gaim_xfer_read(GaimXfer *xfer, guchar **buffer) |
|
| 774 { |
|
| 775 gssize s, r; |
|
| 776 |
|
| 777 g_return_val_if_fail(xfer != NULL, 0); |
|
| 778 g_return_val_if_fail(buffer != NULL, 0); |
|
| 779 |
|
| 780 if (gaim_xfer_get_size(xfer) == 0) |
|
| 781 s = 4096; |
|
| 782 else |
|
| 783 s = MIN(gaim_xfer_get_bytes_remaining(xfer), 4096); |
|
| 784 |
|
| 785 if (xfer->ops.read != NULL) |
|
| 786 r = (xfer->ops.read)(buffer, xfer); |
|
| 787 else { |
|
| 788 *buffer = g_malloc0(s); |
|
| 789 |
|
| 790 r = read(xfer->fd, *buffer, s); |
|
| 791 if (r < 0 && errno == EAGAIN) |
|
| 792 r = 0; |
|
| 793 else if (r < 0) |
|
| 794 r = -1; |
|
| 795 else if ((gaim_xfer_get_size(xfer) > 0) && |
|
| 796 ((gaim_xfer_get_bytes_sent(xfer)+r) >= gaim_xfer_get_size(xfer))) |
|
| 797 gaim_xfer_set_completed(xfer, TRUE); |
|
| 798 else if (r == 0) |
|
| 799 r = -1; |
|
| 800 } |
|
| 801 |
|
| 802 return r; |
|
| 803 } |
|
| 804 |
|
| 805 gssize |
|
| 806 gaim_xfer_write(GaimXfer *xfer, const guchar *buffer, gsize size) |
|
| 807 { |
|
| 808 gssize r, s; |
|
| 809 |
|
| 810 g_return_val_if_fail(xfer != NULL, 0); |
|
| 811 g_return_val_if_fail(buffer != NULL, 0); |
|
| 812 g_return_val_if_fail(size != 0, 0); |
|
| 813 |
|
| 814 s = MIN(gaim_xfer_get_bytes_remaining(xfer), size); |
|
| 815 |
|
| 816 if (xfer->ops.write != NULL) { |
|
| 817 r = (xfer->ops.write)(buffer, s, xfer); |
|
| 818 } else { |
|
| 819 r = write(xfer->fd, buffer, s); |
|
| 820 if (r < 0 && errno == EAGAIN) |
|
| 821 r = 0; |
|
| 822 if ((gaim_xfer_get_bytes_sent(xfer)+r) >= gaim_xfer_get_size(xfer)) |
|
| 823 gaim_xfer_set_completed(xfer, TRUE); |
|
| 824 } |
|
| 825 |
|
| 826 return r; |
|
| 827 } |
|
| 828 |
|
| 829 static void |
|
| 830 transfer_cb(gpointer data, gint source, GaimInputCondition condition) |
|
| 831 { |
|
| 832 GaimXferUiOps *ui_ops; |
|
| 833 GaimXfer *xfer = (GaimXfer *)data; |
|
| 834 guchar *buffer = NULL; |
|
| 835 gssize r = 0; |
|
| 836 |
|
| 837 if (condition & GAIM_INPUT_READ) { |
|
| 838 r = gaim_xfer_read(xfer, &buffer); |
|
| 839 if (r > 0) { |
|
| 840 fwrite(buffer, 1, r, xfer->dest_fp); |
|
| 841 } else if(r <= 0) { |
|
| 842 gaim_xfer_cancel_remote(xfer); |
|
| 843 return; |
|
| 844 } |
|
| 845 } |
|
| 846 |
|
| 847 if (condition & GAIM_INPUT_WRITE) { |
|
| 848 size_t s = MIN(gaim_xfer_get_bytes_remaining(xfer), 4096); |
|
| 849 |
|
| 850 /* this is so the prpl can keep the connection open |
|
| 851 if it needs to for some odd reason. */ |
|
| 852 if (s == 0) { |
|
| 853 if (xfer->watcher) { |
|
| 854 gaim_input_remove(xfer->watcher); |
|
| 855 xfer->watcher = 0; |
|
| 856 } |
|
| 857 return; |
|
| 858 } |
|
| 859 |
|
| 860 buffer = g_malloc0(s); |
|
| 861 |
|
| 862 fread(buffer, 1, s, xfer->dest_fp); |
|
| 863 |
|
| 864 /* Write as much as we're allowed to. */ |
|
| 865 r = gaim_xfer_write(xfer, buffer, s); |
|
| 866 |
|
| 867 if (r == -1) { |
|
| 868 gaim_xfer_cancel_remote(xfer); |
|
| 869 g_free(buffer); |
|
| 870 return; |
|
| 871 } else if (r < s) { |
|
| 872 /* We have to seek back in the file now. */ |
|
| 873 fseek(xfer->dest_fp, r - s, SEEK_CUR); |
|
| 874 } |
|
| 875 } |
|
| 876 |
|
| 877 if (r > 0) { |
|
| 878 if (gaim_xfer_get_size(xfer) > 0) |
|
| 879 xfer->bytes_remaining -= r; |
|
| 880 |
|
| 881 xfer->bytes_sent += r; |
|
| 882 |
|
| 883 if (xfer->ops.ack != NULL) |
|
| 884 xfer->ops.ack(xfer, buffer, r); |
|
| 885 |
|
| 886 g_free(buffer); |
|
| 887 |
|
| 888 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 889 |
|
| 890 if (ui_ops != NULL && ui_ops->update_progress != NULL) |
|
| 891 ui_ops->update_progress(xfer, |
|
| 892 gaim_xfer_get_progress(xfer)); |
|
| 893 } |
|
| 894 |
|
| 895 if (gaim_xfer_is_completed(xfer)) |
|
| 896 gaim_xfer_end(xfer); |
|
| 897 } |
|
| 898 |
|
| 899 static void |
|
| 900 begin_transfer(GaimXfer *xfer, GaimInputCondition cond) |
|
| 901 { |
|
| 902 GaimXferType type = gaim_xfer_get_type(xfer); |
|
| 903 |
|
| 904 xfer->dest_fp = g_fopen(gaim_xfer_get_local_filename(xfer), |
|
| 905 type == GAIM_XFER_RECEIVE ? "wb" : "rb"); |
|
| 906 |
|
| 907 if (xfer->dest_fp == NULL) { |
|
| 908 gaim_xfer_show_file_error(xfer, gaim_xfer_get_local_filename(xfer)); |
|
| 909 gaim_xfer_cancel_local(xfer); |
|
| 910 return; |
|
| 911 } |
|
| 912 |
|
| 913 xfer->watcher = gaim_input_add(xfer->fd, cond, transfer_cb, xfer); |
|
| 914 |
|
| 915 xfer->start_time = time(NULL); |
|
| 916 |
|
| 917 if (xfer->ops.start != NULL) |
|
| 918 xfer->ops.start(xfer); |
|
| 919 } |
|
| 920 |
|
| 921 static void |
|
| 922 connect_cb(gpointer data, gint source, GaimInputCondition condition) |
|
| 923 { |
|
| 924 GaimXfer *xfer = (GaimXfer *)data; |
|
| 925 |
|
| 926 xfer->fd = source; |
|
| 927 |
|
| 928 begin_transfer(xfer, condition); |
|
| 929 } |
|
| 930 |
|
| 931 void |
|
| 932 gaim_xfer_start(GaimXfer *xfer, int fd, const char *ip, |
|
| 933 unsigned int port) |
|
| 934 { |
|
| 935 GaimInputCondition cond; |
|
| 936 GaimXferType type; |
|
| 937 |
|
| 938 g_return_if_fail(xfer != NULL); |
|
| 939 g_return_if_fail(gaim_xfer_get_type(xfer) != GAIM_XFER_UNKNOWN); |
|
| 940 |
|
| 941 type = gaim_xfer_get_type(xfer); |
|
| 942 |
|
| 943 xfer->bytes_remaining = gaim_xfer_get_size(xfer); |
|
| 944 xfer->bytes_sent = 0; |
|
| 945 |
|
| 946 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_STARTED); |
|
| 947 |
|
| 948 if (type == GAIM_XFER_RECEIVE) { |
|
| 949 cond = GAIM_INPUT_READ; |
|
| 950 |
|
| 951 if (ip != NULL) { |
|
| 952 xfer->remote_ip = g_strdup(ip); |
|
| 953 xfer->remote_port = port; |
|
| 954 |
|
| 955 /* Establish a file descriptor. */ |
|
| 956 gaim_proxy_connect(xfer->account, xfer->remote_ip, |
|
| 957 xfer->remote_port, connect_cb, xfer); |
|
| 958 |
|
| 959 return; |
|
| 960 } |
|
| 961 else { |
|
| 962 xfer->fd = fd; |
|
| 963 } |
|
| 964 } |
|
| 965 else { |
|
| 966 cond = GAIM_INPUT_WRITE; |
|
| 967 |
|
| 968 xfer->fd = fd; |
|
| 969 } |
|
| 970 |
|
| 971 begin_transfer(xfer, cond); |
|
| 972 } |
|
| 973 |
|
| 974 void |
|
| 975 gaim_xfer_end(GaimXfer *xfer) |
|
| 976 { |
|
| 977 g_return_if_fail(xfer != NULL); |
|
| 978 |
|
| 979 /* See if we are actually trying to cancel this. */ |
|
| 980 if (!gaim_xfer_is_completed(xfer)) { |
|
| 981 gaim_xfer_cancel_local(xfer); |
|
| 982 return; |
|
| 983 } |
|
| 984 |
|
| 985 xfer->end_time = time(NULL); |
|
| 986 if (xfer->ops.end != NULL) |
|
| 987 xfer->ops.end(xfer); |
|
| 988 |
|
| 989 if (xfer->watcher != 0) { |
|
| 990 gaim_input_remove(xfer->watcher); |
|
| 991 xfer->watcher = 0; |
|
| 992 } |
|
| 993 |
|
| 994 if (xfer->fd != 0) |
|
| 995 close(xfer->fd); |
|
| 996 |
|
| 997 if (xfer->dest_fp != NULL) { |
|
| 998 fclose(xfer->dest_fp); |
|
| 999 xfer->dest_fp = NULL; |
|
| 1000 } |
|
| 1001 |
|
| 1002 gaim_xfer_unref(xfer); |
|
| 1003 } |
|
| 1004 |
|
| 1005 void |
|
| 1006 gaim_xfer_add(GaimXfer *xfer) |
|
| 1007 { |
|
| 1008 GaimXferUiOps *ui_ops; |
|
| 1009 |
|
| 1010 g_return_if_fail(xfer != NULL); |
|
| 1011 |
|
| 1012 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 1013 |
|
| 1014 if (ui_ops != NULL && ui_ops->add_xfer != NULL) |
|
| 1015 ui_ops->add_xfer(xfer); |
|
| 1016 } |
|
| 1017 |
|
| 1018 void |
|
| 1019 gaim_xfer_cancel_local(GaimXfer *xfer) |
|
| 1020 { |
|
| 1021 GaimXferUiOps *ui_ops; |
|
| 1022 char *msg = NULL; |
|
| 1023 |
|
| 1024 g_return_if_fail(xfer != NULL); |
|
| 1025 |
|
| 1026 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_LOCAL); |
|
| 1027 xfer->end_time = time(NULL); |
|
| 1028 |
|
| 1029 if (gaim_xfer_get_filename(xfer) != NULL) |
|
| 1030 { |
|
| 1031 msg = g_strdup_printf(_("You canceled the transfer of %s"), |
|
| 1032 gaim_xfer_get_filename(xfer)); |
|
| 1033 } |
|
| 1034 else |
|
| 1035 { |
|
| 1036 msg = g_strdup_printf(_("File transfer cancelled")); |
|
| 1037 } |
|
| 1038 gaim_xfer_conversation_write(xfer, msg, FALSE); |
|
| 1039 g_free(msg); |
|
| 1040 |
|
| 1041 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) |
|
| 1042 { |
|
| 1043 if (xfer->ops.cancel_send != NULL) |
|
| 1044 xfer->ops.cancel_send(xfer); |
|
| 1045 } |
|
| 1046 else |
|
| 1047 { |
|
| 1048 if (xfer->ops.cancel_recv != NULL) |
|
| 1049 xfer->ops.cancel_recv(xfer); |
|
| 1050 } |
|
| 1051 |
|
| 1052 if (xfer->watcher != 0) { |
|
| 1053 gaim_input_remove(xfer->watcher); |
|
| 1054 xfer->watcher = 0; |
|
| 1055 } |
|
| 1056 |
|
| 1057 if (xfer->fd != 0) |
|
| 1058 close(xfer->fd); |
|
| 1059 |
|
| 1060 if (xfer->dest_fp != NULL) { |
|
| 1061 fclose(xfer->dest_fp); |
|
| 1062 xfer->dest_fp = NULL; |
|
| 1063 } |
|
| 1064 |
|
| 1065 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 1066 |
|
| 1067 if (ui_ops != NULL && ui_ops->cancel_local != NULL) |
|
| 1068 ui_ops->cancel_local(xfer); |
|
| 1069 |
|
| 1070 xfer->bytes_remaining = 0; |
|
| 1071 |
|
| 1072 gaim_xfer_unref(xfer); |
|
| 1073 } |
|
| 1074 |
|
| 1075 void |
|
| 1076 gaim_xfer_cancel_remote(GaimXfer *xfer) |
|
| 1077 { |
|
| 1078 GaimXferUiOps *ui_ops; |
|
| 1079 gchar *msg; |
|
| 1080 GaimAccount *account; |
|
| 1081 GaimBuddy *buddy; |
|
| 1082 |
|
| 1083 g_return_if_fail(xfer != NULL); |
|
| 1084 |
|
| 1085 gaim_request_close_with_handle(xfer); |
|
| 1086 gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_REMOTE); |
|
| 1087 xfer->end_time = time(NULL); |
|
| 1088 |
|
| 1089 account = gaim_xfer_get_account(xfer); |
|
| 1090 buddy = gaim_find_buddy(account, xfer->who); |
|
| 1091 |
|
| 1092 if (gaim_xfer_get_filename(xfer) != NULL) |
|
| 1093 { |
|
| 1094 msg = g_strdup_printf(_("%s canceled the transfer of %s"), |
|
| 1095 buddy ? gaim_buddy_get_alias(buddy) : xfer->who, gaim_xfer_get_filename(xfer)); |
|
| 1096 } |
|
| 1097 else |
|
| 1098 { |
|
| 1099 msg = g_strdup_printf(_("%s canceled the file transfer"), |
|
| 1100 buddy ? gaim_buddy_get_alias(buddy) : xfer->who); |
|
| 1101 } |
|
| 1102 gaim_xfer_conversation_write(xfer, msg, TRUE); |
|
| 1103 gaim_xfer_error(gaim_xfer_get_type(xfer), account, xfer->who, msg); |
|
| 1104 g_free(msg); |
|
| 1105 |
|
| 1106 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) |
|
| 1107 { |
|
| 1108 if (xfer->ops.cancel_send != NULL) |
|
| 1109 xfer->ops.cancel_send(xfer); |
|
| 1110 } |
|
| 1111 else |
|
| 1112 { |
|
| 1113 if (xfer->ops.cancel_recv != NULL) |
|
| 1114 xfer->ops.cancel_recv(xfer); |
|
| 1115 } |
|
| 1116 |
|
| 1117 if (xfer->watcher != 0) { |
|
| 1118 gaim_input_remove(xfer->watcher); |
|
| 1119 xfer->watcher = 0; |
|
| 1120 } |
|
| 1121 |
|
| 1122 if (xfer->fd != 0) |
|
| 1123 close(xfer->fd); |
|
| 1124 |
|
| 1125 if (xfer->dest_fp != NULL) { |
|
| 1126 fclose(xfer->dest_fp); |
|
| 1127 xfer->dest_fp = NULL; |
|
| 1128 } |
|
| 1129 |
|
| 1130 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 1131 |
|
| 1132 if (ui_ops != NULL && ui_ops->cancel_remote != NULL) |
|
| 1133 ui_ops->cancel_remote(xfer); |
|
| 1134 |
|
| 1135 xfer->bytes_remaining = 0; |
|
| 1136 |
|
| 1137 gaim_xfer_unref(xfer); |
|
| 1138 } |
|
| 1139 |
|
| 1140 void |
|
| 1141 gaim_xfer_error(GaimXferType type, GaimAccount *account, const char *who, const char *msg) |
|
| 1142 { |
|
| 1143 char *title; |
|
| 1144 |
|
| 1145 g_return_if_fail(msg != NULL); |
|
| 1146 g_return_if_fail(type != GAIM_XFER_UNKNOWN); |
|
| 1147 |
|
| 1148 if (account) { |
|
| 1149 GaimBuddy *buddy; |
|
| 1150 buddy = gaim_find_buddy(account, who); |
|
| 1151 if (buddy) |
|
| 1152 who = gaim_buddy_get_alias(buddy); |
|
| 1153 } |
|
| 1154 |
|
| 1155 if (type == GAIM_XFER_SEND) |
|
| 1156 title = g_strdup_printf(_("File transfer to %s failed."), who); |
|
| 1157 else |
|
| 1158 title = g_strdup_printf(_("File transfer from %s failed."), who); |
|
| 1159 |
|
| 1160 gaim_notify_error(NULL, NULL, title, msg); |
|
| 1161 |
|
| 1162 g_free(title); |
|
| 1163 } |
|
| 1164 |
|
| 1165 void |
|
| 1166 gaim_xfer_update_progress(GaimXfer *xfer) |
|
| 1167 { |
|
| 1168 GaimXferUiOps *ui_ops; |
|
| 1169 |
|
| 1170 g_return_if_fail(xfer != NULL); |
|
| 1171 |
|
| 1172 ui_ops = gaim_xfer_get_ui_ops(xfer); |
|
| 1173 if (ui_ops != NULL && ui_ops->update_progress != NULL) |
|
| 1174 ui_ops->update_progress(xfer, gaim_xfer_get_progress(xfer)); |
|
| 1175 } |
|
| 1176 |
|
| 1177 |
|
| 1178 /************************************************************************** |
|
| 1179 * File Transfer Subsystem API |
|
| 1180 **************************************************************************/ |
|
| 1181 void * |
|
| 1182 gaim_xfers_get_handle(void) { |
|
| 1183 static int handle = 0; |
|
| 1184 |
|
| 1185 return &handle; |
|
| 1186 } |
|
| 1187 |
|
| 1188 void |
|
| 1189 gaim_xfers_init(void) { |
|
| 1190 void *handle = gaim_xfers_get_handle(); |
|
| 1191 |
|
| 1192 /* register signals */ |
|
| 1193 gaim_signal_register(handle, "file-recv-accept", |
|
| 1194 gaim_marshal_VOID__POINTER, |
|
| 1195 NULL, 1, |
|
| 1196 gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_XFER)); |
|
| 1197 gaim_signal_register(handle, "file-send-accept", |
|
| 1198 gaim_marshal_VOID__POINTER, |
|
| 1199 NULL, 1, |
|
| 1200 gaim_value_new(GAIM_TYPE_POINTER, GAIM_SUBTYPE_XFER)); |
|
| 1201 gaim_signal_register(handle, "file-recv-start", |
|
| 1202 gaim_marshal_VOID__POINTER, |
|
| 1203 NULL, 1, |
|
| 1204 gaim_value_new(GAIM_TYPE_POINTER, GAIM_SUBTYPE_XFER)); |
|
| 1205 gaim_signal_register(handle, "file-send-start", |
|
| 1206 gaim_marshal_VOID__POINTER, |
|
| 1207 NULL, 1, |
|
| 1208 gaim_value_new(GAIM_TYPE_POINTER, GAIM_SUBTYPE_XFER)); |
|
| 1209 gaim_signal_register(handle, "file-send-cancel", |
|
| 1210 gaim_marshal_VOID__POINTER, |
|
| 1211 NULL, 1, |
|
| 1212 gaim_value_new(GAIM_TYPE_POINTER, GAIM_SUBTYPE_XFER)); |
|
| 1213 gaim_signal_register(handle, "file-recv-cancel", |
|
| 1214 gaim_marshal_VOID__POINTER, |
|
| 1215 NULL, 1, |
|
| 1216 gaim_value_new(GAIM_TYPE_POINTER, GAIM_SUBTYPE_XFER)); |
|
| 1217 gaim_signal_register(handle, "file-send-complete", |
|
| 1218 gaim_marshal_VOID__POINTER, |
|
| 1219 NULL, 1, |
|
| 1220 gaim_value_new(GAIM_TYPE_POINTER, GAIM_SUBTYPE_XFER)); |
|
| 1221 gaim_signal_register(handle, "file-recv-complete", |
|
| 1222 gaim_marshal_VOID__POINTER, |
|
| 1223 NULL, 1, |
|
| 1224 gaim_value_new(GAIM_TYPE_POINTER, GAIM_SUBTYPE_XFER)); |
|
| 1225 gaim_signal_register(handle, "file-recv-request", |
|
| 1226 gaim_marshal_VOID__POINTER, |
|
| 1227 NULL, 1, |
|
| 1228 gaim_value_new(GAIM_TYPE_POINTER, GAIM_SUBTYPE_XFER)); |
|
| 1229 } |
|
| 1230 |
|
| 1231 void |
|
| 1232 gaim_xfers_uninit(void) { |
|
| 1233 gaim_signals_disconnect_by_handle(gaim_xfers_get_handle()); |
|
| 1234 } |
|
| 1235 |
|
| 1236 void |
|
| 1237 gaim_xfers_set_ui_ops(GaimXferUiOps *ops) { |
|
| 1238 xfer_ui_ops = ops; |
|
| 1239 } |
|
| 1240 |
|
| 1241 GaimXferUiOps * |
|
| 1242 gaim_xfers_get_ui_ops(void) { |
|
| 1243 return xfer_ui_ops; |
|
| 1244 } |
|