--- a/src/protocols/oscar/oscar.c Sat Oct 19 05:04:58 2002 +0000 +++ b/src/protocols/oscar/oscar.c Sat Oct 19 05:22:30 2002 +0000 @@ -189,8 +189,6 @@ int watcher; }; -static struct oscar_file_transfer *oft_listening; - struct icon_req { char *user; time_t timestamp; @@ -383,6 +381,7 @@ struct file_transfer *); static int oscar_sendfile_request(aim_session_t *sess, struct oscar_file_transfer *oft); +static int oscar_sendfile_timeout(aim_session_t *sess, aim_frame_t *fr, ...); static char *msgerrreason[] = { "Invalid error", @@ -761,29 +760,16 @@ static void oscar_ask_send_file(struct gaim_connection *gc, char *destsn) { struct oscar_data *od = (struct oscar_data *)gc->proto_data; - struct oscar_file_transfer *oft = oft_listening; - - /* Kludge: if we try to send a file to a client that doesn't - * support it, the BOS server sends us back an error without - * any information identifying which transfer was aborted. So - * we only allow one sendfile request at a time, to ensure that - * the transfer referenced by an error is unambiguous. It's ugly, - * but what else can we do? -- wtm - */ - if (oft) { - do_error_dialog(_("Sorry, you already have an outgoing transfer pending. Due to limitations of the Oscar protocol, only one outgoing transfer request is permitted at a time."), NULL, GAIM_ERROR); - } - else { - struct oscar_file_transfer *oft = g_new0(struct oscar_file_transfer, - 1); - - oft->type = OFT_SENDFILE_OUT; - oft->sn = g_strdup(destsn); - - od->file_transfers = g_slist_append(od->file_transfers, oft); - - oft->xfer = transfer_out_add(gc, oft->sn); - } + + struct oscar_file_transfer *oft = g_new0(struct oscar_file_transfer, + 1); + + oft->type = OFT_SENDFILE_OUT; + oft->sn = g_strdup(destsn); + + od->file_transfers = g_slist_append(od->file_transfers, oft); + + oft->xfer = transfer_out_add(gc, oft->sn); } static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { @@ -892,6 +878,7 @@ aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RIGHTSINFO, gaim_ssi_parserights, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_LIST, gaim_ssi_parselist, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_NOLIST, gaim_ssi_parselist, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_MSGTIMEOUT, oscar_sendfile_timeout, 0); ((struct oscar_data *)gc->proto_data)->conn = bosconn; for (i = 0; i < (int)strlen(info->bosip); i++) { @@ -1540,9 +1527,7 @@ struct oscar_file_transfer *oft; va_list ap; aim_conn_t *conn, *listenerconn; -#ifndef NOSIGALARM - alarm(0); /* reset timeout alarm */ -#endif + va_start(ap, fr); conn = va_arg(ap, aim_conn_t *); listenerconn = va_arg(ap, aim_conn_t *); @@ -1553,8 +1538,6 @@ /* Stop watching listener conn; watch transfer conn instead */ gaim_input_remove(oft->watcher); aim_conn_kill(sess, &listenerconn); - /* We no longer need to block other outgoing transfers. */ - oft_listening = NULL; aim_conn_addhandler(od->sess, oft->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, @@ -1573,27 +1556,27 @@ return 0; } -void oscar_sendfile_timeout(int sig) -{ - struct oscar_file_transfer *oft = oft_listening; - - if (oft) { - aim_session_t *sess = aim_conn_getsess(oft->conn); - aim_conn_t *bosconn; - { - /* XXX is this valid? is there a better way? -- wtm */ - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *odata = (struct oscar_data *)gc->proto_data; - bosconn = odata->conn; - } - - oft_listening = NULL; +static int oscar_sendfile_timeout(aim_session_t *sess, aim_frame_t *fr, ...) { + struct gaim_connection *gc = sess->aux_data; + va_list ap; + struct oscar_file_transfer *oft; + char *cookie; + aim_conn_t *bosconn; + + va_start(ap, fr); + bosconn = va_arg(ap, aim_conn_t *); + cookie = va_arg(ap, char *); + va_end(ap); + + if ((oft = find_oft_by_cookie(gc, cookie))) { aim_canceltransfer(sess, bosconn, oft->cookie, oft->sn, AIM_CAPS_SENDFILE); transfer_abort(oft->xfer, _("Transfer timed out")); oscar_file_transfer_disconnect(sess, oft->conn); } + + return 1; /* success */ } /* Called once at the beginning of an outgoing transfer session. */ @@ -1607,7 +1590,6 @@ oft->totsize = totsize; oft->totfiles = totfiles; oft->filesdone = 0; - oft_listening = oft; oft->conn = aim_sendfile_initiate(od->sess, oft->sn, name, totfiles, oft->totsize, oft->cookie); @@ -1617,18 +1599,7 @@ GAIM_ERROR); return; } -#ifndef NOSIGALARM - { - /* XXX is there a good glib-oriented way of doing this? - * -- wtm */ - struct sigaction act; - act.sa_handler = oscar_sendfile_timeout; - act.sa_flags = SA_RESETHAND; - sigemptyset (&act.sa_mask); - sigaction(SIGALRM, &act, NULL); - alarm(OFT_TIMEOUT); - } -#endif + aim_conn_addhandler(od->sess, oft->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, oscar_sendfile_accepted, @@ -1860,6 +1831,7 @@ return 0; } else if (args->status != AIM_RENDEZVOUS_PROPOSE) { + debug_printf("unknown rendezvous status\n"); return 1; } @@ -1879,20 +1851,65 @@ g_free(name); } else if (args->reqclass & AIM_CAPS_SENDFILE) { struct oscar_file_transfer *oft; - - if (!args->verifiedip) { - /* It seems that Trillian sends a message - * with no file data during multiple-file - * transfers. + struct oscar_data *od = gc->proto_data; + + if ((oft = find_oft_by_cookie(sess->aux_data, args->cookie))) + { + /* This is a request for a reverse connection, + * which is used by newer clients when for some + * reason they are unable to connect to our listener + * (e.g. they are behind a firewall). + */ + if (oft->type != OFT_SENDFILE_OUT) + return -1; + + /* It seems that Trillian sends some weird + * packets. Sanity check. + */ + if (!args->verifiedip) + return -1; + + /* This connection isn't used for anything, since + * we're using a reverse connection instead. */ - debug_printf("sendfile: didn't get any data\n"); - return -1; + gaim_input_remove(oft->watcher); + aim_conn_kill(sess, &oft->conn); + + debug_printf("sendfile: doing reverse connection to %s:%d\n", args->verifiedip, args->port); + + oft->conn = aim_accepttransfer(sess, od->conn, + userinfo->sn, + args->cookie, args->verifiedip, + args->port, + AIM_CAPS_SENDFILE); + + /* XXX: this is a bit of a hack: ideally + * we should wait on GAIM_INPUT_WRITE. -- wtm + */ + aim_conn_completeconnect(sess, oft->conn); + + oscar_sendfile_request(sess, oft); + + aim_conn_addhandler(sess, oft->conn, + AIM_CB_FAM_OFT, + AIM_CB_OFT_GETFILECOMPLETE, + oscar_sendfile_out_done, + 0); + aim_conn_addhandler(sess, oft->conn, + AIM_CB_FAM_OFT, + AIM_CB_OFT_GETFILEFILESEND, + oscar_file_transfer_do, + 0); + oft->watcher = gaim_input_add(oft->conn->fd, + GAIM_INPUT_READ, oscar_callback, + oft->conn); + return 0; } - oft = g_new0(struct oscar_file_transfer, 1); - debug_printf("%s (%s) requests to send a file to %s\n", userinfo->sn, args->verifiedip, gc->username); + + oft = g_new0(struct oscar_file_transfer, 1); oft->type = OFT_SENDFILE_IN; oft->sn = g_strdup(userinfo->sn); @@ -1900,11 +1917,7 @@ oft->port = args->port; memcpy(oft->cookie, args->cookie, 8); - { /* XXX ugly... */ - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *od = gc->proto_data; - od->file_transfers = g_slist_append(od->file_transfers, oft); - } + od->file_transfers = g_slist_append(od->file_transfers, oft); oft->xfer = transfer_in_add(gc, userinfo->sn, args->info.sendfile.filename, @@ -2224,10 +2237,6 @@ if (oft) { buf = g_strdup_printf(_("%s has declined to receive a file from %s.\n"), who, gc->username); -#ifndef NOSIGALARM - alarm(0); /* reset timeout alarm */ -#endif - oft_listening = NULL; transfer_abort(oft->xfer, buf); g_free(buf); oscar_file_transfer_disconnect(sess, oft->conn); @@ -2328,23 +2337,19 @@ static int gaim_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - char *destn; + char *data; fu16_t reason; char buf[1024]; - struct oscar_file_transfer *oft = oft_listening; - + struct gaim_connection *gc = sess->aux_data; + struct oscar_file_transfer *oft; + va_start(ap, fr); reason = (fu16_t)va_arg(ap, unsigned int); - destn = va_arg(ap, char *); + data = va_arg(ap, char *); va_end(ap); - if (oft) { - /* If we try to send a file but it isn't supported, then - * we get this error without any information identifying - * the failed connection. So we can only have one outgoing - * transfer at a time. Ugh. -- wtm - */ - oft_listening = NULL; + /* If this was a file transfer request, data is a cookie. */ + if ((oft = find_oft_by_cookie(gc, data))) { transfer_abort(oft->xfer, (reason < msgerrreasonlen) ? msgerrreason[reason] : _("No reason was given.")); @@ -2352,7 +2357,8 @@ return 1; } - snprintf(buf, sizeof(buf), _("Your message to %s did not get sent:"), destn); + /* Data is assumed to be the destination sn. */ + snprintf(buf, sizeof(buf), _("Your message to %s did not get sent:"), data); do_error_dialog(buf, (reason < msgerrreasonlen) ? msgerrreason[reason] : _("No reason was given."), GAIM_ERROR); return 1; @@ -4165,13 +4171,9 @@ oscar_file_transfer_disconnect(sess, conn); } else if (oft->type == OFT_SENDFILE_OUT) { -#if 0 /* Wait for response before closing connection. */ oft->watcher = gaim_input_add(conn->fd, GAIM_INPUT_READ, oscar_callback, conn); -#else - oscar_file_transfer_disconnect(sess, conn); -#endif } } @@ -4180,6 +4182,7 @@ va_list ap; aim_conn_t *conn; struct oscar_file_transfer *oft; + int err; va_start(ap, fr); conn = va_arg(ap, aim_conn_t *); @@ -4193,16 +4196,23 @@ if (oft->type == OFT_SENDFILE_IN) { const char *name = va_arg(ap, const char *); int size = va_arg(ap, int); - if (transfer_in_do(oft->xfer, conn->fd, name, size)) - oscar_file_transfer_disconnect(sess, oft->conn); + err = transfer_in_do(oft->xfer, conn->fd, name, size); } else { int offset = va_arg(ap, int); - if (transfer_out_do(oft->xfer, conn->fd, offset)) - oscar_file_transfer_disconnect(sess, oft->conn); + err = transfer_out_do(oft->xfer, conn->fd, offset); } va_end(ap); + if (err) { + /* There was an error; cancel the transfer. */ + struct oscar_data *od = (struct oscar_data *)gc->proto_data; + aim_conn_t *bosconn = od->conn; + aim_canceltransfer(sess, bosconn, oft->cookie, + oft->sn, AIM_CAPS_SENDFILE); + oscar_file_transfer_disconnect(sess, oft->conn); + } + return 0; } @@ -4431,13 +4441,13 @@ pbm->callback = oscar_ask_direct_im; pbm->gc = gc; m = g_list_append(m, pbm); + + pbm = g_new0(struct proto_buddy_menu, 1); + pbm->label = _("Send File"); + pbm->callback = oscar_ask_send_file; + pbm->gc = gc; + m = g_list_append(m, pbm); } - - pbm = g_new0(struct proto_buddy_menu, 1); - pbm->label = _("Send File"); - pbm->callback = oscar_ask_send_file; - pbm->gc = gc; - m = g_list_append(m, pbm); } pbm = g_new0(struct proto_buddy_menu, 1);