changeset 8446:d9cf0c2f4339

[gaim-migrate @ 9176] Some nice AIM over OSCAR file transfer cleanup from marv. This should make sending and receiving a bit smoother. Let one of us know if this causes something to crash. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 15 Mar 2004 01:30:16 +0000
parents 46f3c447da4d
children be4cf7c09ca3
files src/protocols/oscar/ft.c src/protocols/oscar/oscar.c
diffstat 2 files changed, 188 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/oscar/ft.c	Sun Mar 14 19:01:53 2004 +0000
+++ b/src/protocols/oscar/ft.c	Mon Mar 15 01:30:16 2004 +0000
@@ -175,7 +175,7 @@
 	int ret = 0;
 	aim_conn_t *newconn;
 	char ip[20];
-	int port;
+	unsigned short int port;
 
 	if ((acceptfd = accept(cur->fd, &addr, &addrlen)) == -1)
 		return 0; /* not an error */
@@ -204,7 +204,7 @@
 
 		priv = (struct aim_odc_intdata *)(newconn->internal = cur->internal);
 		cur->internal = NULL;
-		snprintf(priv->ip, sizeof(priv->ip), "%s:%u", ip, port);
+		snprintf(priv->ip, sizeof(priv->ip), "%s:%hu", ip, port);
 
 		if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED)))
 			ret = userfunc(sess, NULL, newconn, cur);
@@ -648,8 +648,10 @@
 	new->fh.rfcsum = 0xffff0000;
 	new->fh.recvcsum = 0xffff0000;
 	strncpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32", 31);
-	if (filename)
+	if (filename) {
 		strncpy(new->fh.name, filename, 63);
+		new->fh.name[63] = '\0';
+	}
 
 	new->next = sess->oft_info;
 	sess->oft_info = new;
@@ -760,6 +762,7 @@
 	fh->nencode = aimbs_get16(bs);
 	fh->nlanguage = aimbs_get16(bs);
 	aimbs_getrawbuf(bs, fh->name, 64); /* XXX - filenames longer than 64B */
+	fh->name[63] = '\0';
 
 	return fh;
 } 
--- a/src/protocols/oscar/oscar.c	Sun Mar 14 19:01:53 2004 +0000
+++ b/src/protocols/oscar/oscar.c	Mon Mar 15 01:30:16 2004 +0000
@@ -564,6 +564,7 @@
 				gaim_debug(GAIM_DEBUG_ERROR, "oscar",
 						   "connection error (rendezvous listener)\n");
 				aim_conn_kill(od->sess, &conn);
+				/* AAA - Don't we need to gaim_xfer_cancel here? --marv */
 			}
 		} else {
 			if (aim_get_command(od->sess, conn) >= 0) {
@@ -877,145 +878,10 @@
  */
 static void oscar_sendfile_connected(gpointer data, gint source, GaimInputCondition condition);
 
-/* XXX - This function is pretty ugly */
-static void oscar_xfer_init(GaimXfer *xfer)
-{
-	struct aim_oft_info *oft_info = xfer->data;
-	GaimConnection *gc = oft_info->sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) {
-		int listenfd;
-
-		xfer->filename = g_path_get_basename(xfer->local_filename);
-		strncpy(oft_info->fh.name, xfer->filename, 64);
-		oft_info->fh.totsize = gaim_xfer_get_size(xfer);
-		oft_info->fh.size = gaim_xfer_get_size(xfer);
-		oft_info->fh.checksum = aim_oft_checksum_file(xfer->local_filename);
-
-		/* Create a listening socket and an associated libfaim conn */
-		if ((listenfd = gaim_network_listen_range(5190, 5199)) < 0)
-			return;
-		xfer->local_port = gaim_network_get_port_from_fd(listenfd);
-		oft_info->port = xfer->local_port;
-		aim_sendfile_listen(od->sess, oft_info, listenfd);
-		gaim_debug(GAIM_DEBUG_MISC, "oscar",
-				   "port is %d, ip is %s\n",
-				   xfer->local_port, oft_info->clientip);
-		if (oft_info->conn) {
-			xfer->watcher = gaim_input_add(oft_info->conn->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
-			aim_im_sendch2_sendfile_ask(od->sess, oft_info);
-			aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED, oscar_sendfile_estblsh, 0);
-		} else {
-			gaim_notify_error(gc, NULL, _("File Transfer Aborted"),
-							  _("Unable to establish listener socket."));
-			/* XXX - The below line causes a crash because the transfer is canceled before the "Ok" callback on the file selection thing exists, I think */
-			/* gaim_xfer_cancel_remote(xfer); */
-		}
-	} else if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
-		oft_info->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL);
-		if (oft_info->conn) {
-			oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
-			aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_PROMPT, oscar_sendfile_prompt, 0);
-			oft_info->conn->fd = xfer->fd = gaim_proxy_connect(gaim_connection_get_account(gc), xfer->remote_ip, xfer->remote_port, 
-								      oscar_sendfile_connected, xfer);
-			if (xfer->fd == -1) {
-				gaim_notify_error(gc, NULL, _("File Transfer Aborted"),
-								  _("Unable to establish file descriptor."));
-				/* gaim_xfer_cancel_remote(xfer); */
-			}
-		} else {
-			gaim_notify_error(gc, NULL, _("File Transfer Aborted"),
-							  _("Unable to create new connection."));
-			/* gaim_xfer_cancel_remote(xfer); */
-			/* Try a different port? Ask them to connect to us? */
-		}
-
-	}
-}
-
-static void oscar_xfer_start(GaimXfer *xfer)
-{
-
-	gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_start\n");
-	/* I'm pretty sure we don't need to do jack here.  Nor Jill. */
-}
-
-static void oscar_xfer_end(GaimXfer *xfer)
-{
-	struct aim_oft_info *oft_info = xfer->data;
-	GaimConnection *gc = oft_info->sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_end\n");
-
-	if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
-		oft_info->fh.nrecvd = gaim_xfer_get_bytes_sent(xfer);
-		aim_oft_sendheader(oft_info->sess, AIM_CB_OFT_DONE, oft_info);
-	}
-
-	aim_conn_kill(oft_info->sess, &oft_info->conn);
-	aim_oft_destroyinfo(oft_info);
-	xfer->data = NULL;
-	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-}
-
-static void oscar_xfer_cancel_send(GaimXfer *xfer)
-{
-	struct aim_oft_info *oft_info = xfer->data;
-	GaimConnection *gc = oft_info->sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	gaim_debug(GAIM_DEBUG_INFO, "oscar",
-			   "AAA - in oscar_xfer_cancel_send\n");
-
-	aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info);
-
-	aim_conn_kill(oft_info->sess, &oft_info->conn);
-	aim_oft_destroyinfo(oft_info);
-	xfer->data = NULL;
-	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-}
-
-static void oscar_xfer_cancel_recv(GaimXfer *xfer)
-{
-	struct aim_oft_info *oft_info = xfer->data;
-	GaimConnection *gc = oft_info->sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	gaim_debug(GAIM_DEBUG_INFO, "oscar",
-			   "AAA - in oscar_xfer_cancel_recv\n");
-
-	aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info);
-
-	aim_conn_kill(oft_info->sess, &oft_info->conn);
-	aim_oft_destroyinfo(oft_info);
-	xfer->data = NULL;
-	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-}
-
-static void oscar_xfer_ack(GaimXfer *xfer, const char *buffer, size_t size)
-{
-	struct aim_oft_info *oft_info = xfer->data;
-
-	if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) {
-		/*
-		 * If we're done sending, intercept the socket from the core ft code
-		 * and wait for the other guy to send the "done" OFT packet.
-		 */
-		if (gaim_xfer_get_bytes_remaining(xfer) <= 0) {
-			gaim_input_remove(xfer->watcher);
-			xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
-			xfer->fd = 0;
-			gaim_xfer_set_completed(xfer, TRUE);
-		}
-	} else if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
-		/* Update our rolling checksum.  Like Walmart, yo. */
-		oft_info->fh.recvcsum = aim_oft_checksum_chunk(buffer, size, oft_info->fh.recvcsum);
-	}
-}
-
-static GaimXfer *oscar_find_xfer_by_cookie(GSList *fts, const char *ck)
+/*
+ * Miscellaneous xfer functions
+ */
+static GaimXfer *oscar_find_xfer_by_cookie(GSList *fts, const fu8_t *ck)
 {
 	GaimXfer *xfer;
 	struct aim_oft_info *oft_info;
@@ -1024,7 +890,7 @@
 		xfer = fts->data;
 		oft_info = xfer->data;
 
-		if (oft_info && !strcmp(ck, oft_info->cookie))
+		if (oft_info && !memcmp(ck, oft_info->cookie, 8))
 			return xfer;
 
 		fts = g_slist_next(fts);
@@ -1051,6 +917,170 @@
 	return NULL;
 }
 
+static void oscar_xfer_end(GaimXfer *xfer)
+{
+	struct aim_oft_info *oft_info = xfer->data;
+	GaimConnection *gc = oft_info->sess->aux_data;
+	OscarData *od = gc->proto_data;
+
+	gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_end\n");
+
+	if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
+		oft_info->fh.nrecvd = gaim_xfer_get_bytes_sent(xfer);
+		aim_oft_sendheader(oft_info->sess, AIM_CB_OFT_DONE, oft_info);
+	}
+
+	aim_conn_kill(oft_info->sess, &oft_info->conn);
+	aim_oft_destroyinfo(oft_info);
+	xfer->data = NULL;
+	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
+}
+
+/*
+ * xfer functions used when receiving files
+ */
+
+static void oscar_xfer_init_recv(GaimXfer *xfer)
+{
+	struct aim_oft_info *oft_info = xfer->data;
+	GaimConnection *gc = oft_info->sess->aux_data;
+	OscarData *od = gc->proto_data;
+
+	gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_recv_init\n");
+
+	oft_info->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL);
+	if (oft_info->conn) {
+		oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
+		aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_PROMPT, oscar_sendfile_prompt, 0);
+		oft_info->conn->fd = xfer->fd = gaim_proxy_connect(gaim_connection_get_account(gc),
+					xfer->remote_ip, xfer->remote_port,	oscar_sendfile_connected, xfer);
+		if (xfer->fd == -1) {
+			gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who,
+							_("Unable to establish file descriptor."));
+			gaim_xfer_cancel_local(xfer);
+		}
+	} else {
+		gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who,
+						_("Unable to create new connection."));
+		gaim_xfer_cancel_local(xfer);
+		/* Try a different port? Ask them to connect to us? /join #gaim and whine? */
+	}
+
+}
+
+static void oscar_xfer_cancel_recv(GaimXfer *xfer)
+{
+	struct aim_oft_info *oft_info = xfer->data;
+	GaimConnection *gc = oft_info->sess->aux_data;
+	OscarData *od = gc->proto_data;
+
+	gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_cancel_recv\n");
+
+	aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info);
+
+	aim_conn_kill(oft_info->sess, &oft_info->conn);
+	aim_oft_destroyinfo(oft_info);
+	xfer->data = NULL;
+	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
+}
+
+static void oscar_xfer_ack_recv(GaimXfer *xfer, const char *buffer, size_t size)
+{
+	struct aim_oft_info *oft_info = xfer->data;
+
+	/* Update our rolling checksum.  Like Walmart, yo. */
+	oft_info->fh.recvcsum = aim_oft_checksum_chunk(buffer, size, oft_info->fh.recvcsum);
+}
+
+/*
+ * xfer functions used when sending files
+ */
+
+static void oscar_xfer_init_send(GaimXfer *xfer)
+{
+	struct aim_oft_info *oft_info = xfer->data;
+	GaimConnection *gc = oft_info->sess->aux_data;
+	OscarData *od = gc->proto_data;
+	int listenfd;
+
+	gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_send_init\n");
+
+	xfer->filename = g_path_get_basename(xfer->local_filename);
+	strncpy(oft_info->fh.name, xfer->filename, 64);
+	oft_info->fh.name[63] = '\0';
+	oft_info->fh.totsize = gaim_xfer_get_size(xfer);
+	oft_info->fh.size = gaim_xfer_get_size(xfer);
+	oft_info->fh.checksum = aim_oft_checksum_file(xfer->local_filename);
+
+	/* Create a listening socket and an associated libfaim conn */
+	if ((listenfd = gaim_network_listen_range(5190, 5199)) < 0) {
+		gaim_xfer_cancel_local(xfer);
+		return;
+	}
+	xfer->local_port = gaim_network_get_port_from_fd(listenfd);
+	oft_info->port = xfer->local_port;
+	if (aim_sendfile_listen(od->sess, oft_info, listenfd) != 0) {
+		gaim_xfer_cancel_local(xfer);
+		return;
+	}
+	gaim_debug(GAIM_DEBUG_MISC, "oscar",
+			   "port is %hu, ip is %s\n",
+			   xfer->local_port, oft_info->clientip);
+	if (oft_info->conn) {
+		xfer->watcher = gaim_input_add(oft_info->conn->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
+		aim_im_sendch2_sendfile_ask(od->sess, oft_info);
+		aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED, oscar_sendfile_estblsh, 0);
+	} else {
+		gaim_xfer_error(GAIM_XFER_SEND, xfer->who,
+						_("Unable to establish listener socket."));
+		gaim_xfer_cancel_local(xfer);
+	}
+}
+
+static void oscar_xfer_cancel_send(GaimXfer *xfer)
+{
+	struct aim_oft_info *oft_info = xfer->data;
+	GaimConnection *gc = oft_info->sess->aux_data;
+	OscarData *od = gc->proto_data;
+
+	gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_cancel_send\n");
+
+	aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info);
+
+	aim_conn_kill(oft_info->sess, &oft_info->conn);
+	aim_oft_destroyinfo(oft_info);
+	xfer->data = NULL;
+	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
+}
+
+static void oscar_xfer_ack_send(GaimXfer *xfer, const char *buffer, size_t size)
+{
+	struct aim_oft_info *oft_info = xfer->data;
+
+	/* I'm not sure I like how we do this. --marv
+	 * I do.  AIM file transfers aren't really meant to be thought
+	 * of as a transferring just a single file.  The rendezvous
+	 * establishes a connection between two computers, and then
+	 * those computers can use the same connection for transferring
+	 * multiple files.  So we don't want the Gaim core up and closing
+	 * the socket all willy-nilly.  We want to do that in the oscar
+	 * prpl, whenever one side or the other says they're finished
+	 * using the connection.  There might be a better way to intercept
+	 * the socket from the core, however...  --KingAnt
+	 */
+
+	/*
+	 * If we're done sending, intercept the socket from the core ft code
+	 * and wait for the other guy to send the "done" OFT packet.
+	 */
+	if (gaim_xfer_get_bytes_remaining(xfer) <= 0) {
+		gaim_input_remove(xfer->watcher);
+		xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
+		xfer->fd = 0;
+		gaim_xfer_set_completed(xfer, TRUE);
+	}
+}
+
 static void oscar_ask_sendfile(GaimConnection *gc, const char *destsn) {
 	OscarData *od = (OscarData *)gc->proto_data;
 	GaimAccount *account = gaim_connection_get_account(gc);
@@ -1069,12 +1099,11 @@
 	xfer->data = oft_info;
 
 	 /* Setup our I/O op functions */
-	gaim_xfer_set_init_fnc(xfer, oscar_xfer_init);
-	gaim_xfer_set_start_fnc(xfer, oscar_xfer_start);
+	gaim_xfer_set_init_fnc(xfer, oscar_xfer_init_send);
 	gaim_xfer_set_end_fnc(xfer, oscar_xfer_end);
 	gaim_xfer_set_cancel_send_fnc(xfer, oscar_xfer_cancel_send);
-	gaim_xfer_set_cancel_recv_fnc(xfer, oscar_xfer_cancel_recv);
-	gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack);
+	gaim_xfer_set_request_denied_fnc(xfer, oscar_xfer_cancel_send);
+	gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack_send);
 
 	/* Keep track of this transfer for later */
 	od->file_transfers = g_slist_append(od->file_transfers, xfer);
@@ -2037,8 +2066,10 @@
 		return;
 	if (!(oft_info = xfer->data))
 		return;
-	if (source < 0)
+	if (source < 0) {
+		gaim_xfer_cancel_remote(xfer);
 		return;
+	}
 
 	xfer->fd = source;
 	oft_info->conn->fd = source;
@@ -2391,6 +2422,9 @@
 				if (tmp && (tmp[1] == '*')) {
 					tmp[0] = '\0';
 				}
+				gaim_debug(GAIM_DEBUG_WARNING, "oscar",
+						   "We're receiving a whole directory! What fun! "
+						   "Especially since we don't support that!\n");
 			}
 
 			/* Build the file transfer handle */
@@ -2409,12 +2443,11 @@
 			xfer->data = oft_info;
 
 			 /* Setup our I/O op functions */
-			gaim_xfer_set_init_fnc(xfer, oscar_xfer_init);
-			gaim_xfer_set_start_fnc(xfer, oscar_xfer_start);
+			gaim_xfer_set_init_fnc(xfer, oscar_xfer_init_recv);
 			gaim_xfer_set_end_fnc(xfer, oscar_xfer_end);
-			gaim_xfer_set_cancel_send_fnc(xfer, oscar_xfer_cancel_send);
+			gaim_xfer_set_request_denied_fnc(xfer, oscar_xfer_cancel_recv);
 			gaim_xfer_set_cancel_recv_fnc(xfer, oscar_xfer_cancel_recv);
-			gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack);
+			gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack_recv);
 
 			/*
 			 * XXX - Should do something with args->msg, args->encoding, and args->language