comparison src/protocols/oscar/oscar.c @ 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 990314a962fb
children 16485e87b7bb
comparison
equal deleted inserted replaced
8445:46f3c447da4d 8446:d9cf0c2f4339
562 "got information on rendezvous listener\n"); 562 "got information on rendezvous listener\n");
563 if (aim_handlerendconnect(od->sess, conn) < 0) { 563 if (aim_handlerendconnect(od->sess, conn) < 0) {
564 gaim_debug(GAIM_DEBUG_ERROR, "oscar", 564 gaim_debug(GAIM_DEBUG_ERROR, "oscar",
565 "connection error (rendezvous listener)\n"); 565 "connection error (rendezvous listener)\n");
566 aim_conn_kill(od->sess, &conn); 566 aim_conn_kill(od->sess, &conn);
567 /* AAA - Don't we need to gaim_xfer_cancel here? --marv */
567 } 568 }
568 } else { 569 } else {
569 if (aim_get_command(od->sess, conn) >= 0) { 570 if (aim_get_command(od->sess, conn) >= 0) {
570 aim_rxdispatch(od->sess); 571 aim_rxdispatch(od->sess);
571 if (od->killme) { 572 if (od->killme) {
875 * -When they finish sending data we send an AIM_CB_OFT_DONE and then close 876 * -When they finish sending data we send an AIM_CB_OFT_DONE and then close
876 * the connectionn. 877 * the connectionn.
877 */ 878 */
878 static void oscar_sendfile_connected(gpointer data, gint source, GaimInputCondition condition); 879 static void oscar_sendfile_connected(gpointer data, gint source, GaimInputCondition condition);
879 880
880 /* XXX - This function is pretty ugly */ 881 /*
881 static void oscar_xfer_init(GaimXfer *xfer) 882 * Miscellaneous xfer functions
883 */
884 static GaimXfer *oscar_find_xfer_by_cookie(GSList *fts, const fu8_t *ck)
882 { 885 {
883 struct aim_oft_info *oft_info = xfer->data; 886 GaimXfer *xfer;
884 GaimConnection *gc = oft_info->sess->aux_data; 887 struct aim_oft_info *oft_info;
885 OscarData *od = gc->proto_data; 888
886 889 while (fts) {
887 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { 890 xfer = fts->data;
888 int listenfd; 891 oft_info = xfer->data;
889 892
890 xfer->filename = g_path_get_basename(xfer->local_filename); 893 if (oft_info && !memcmp(ck, oft_info->cookie, 8))
891 strncpy(oft_info->fh.name, xfer->filename, 64); 894 return xfer;
892 oft_info->fh.totsize = gaim_xfer_get_size(xfer); 895
893 oft_info->fh.size = gaim_xfer_get_size(xfer); 896 fts = g_slist_next(fts);
894 oft_info->fh.checksum = aim_oft_checksum_file(xfer->local_filename); 897 }
895 898
896 /* Create a listening socket and an associated libfaim conn */ 899 return NULL;
897 if ((listenfd = gaim_network_listen_range(5190, 5199)) < 0) 900 }
898 return; 901
899 xfer->local_port = gaim_network_get_port_from_fd(listenfd); 902 static GaimXfer *oscar_find_xfer_by_conn(GSList *fts, aim_conn_t *conn)
900 oft_info->port = xfer->local_port;
901 aim_sendfile_listen(od->sess, oft_info, listenfd);
902 gaim_debug(GAIM_DEBUG_MISC, "oscar",
903 "port is %d, ip is %s\n",
904 xfer->local_port, oft_info->clientip);
905 if (oft_info->conn) {
906 xfer->watcher = gaim_input_add(oft_info->conn->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
907 aim_im_sendch2_sendfile_ask(od->sess, oft_info);
908 aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED, oscar_sendfile_estblsh, 0);
909 } else {
910 gaim_notify_error(gc, NULL, _("File Transfer Aborted"),
911 _("Unable to establish listener socket."));
912 /* XXX - The below line causes a crash because the transfer is canceled before the "Ok" callback on the file selection thing exists, I think */
913 /* gaim_xfer_cancel_remote(xfer); */
914 }
915 } else if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
916 oft_info->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL);
917 if (oft_info->conn) {
918 oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
919 aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_PROMPT, oscar_sendfile_prompt, 0);
920 oft_info->conn->fd = xfer->fd = gaim_proxy_connect(gaim_connection_get_account(gc), xfer->remote_ip, xfer->remote_port,
921 oscar_sendfile_connected, xfer);
922 if (xfer->fd == -1) {
923 gaim_notify_error(gc, NULL, _("File Transfer Aborted"),
924 _("Unable to establish file descriptor."));
925 /* gaim_xfer_cancel_remote(xfer); */
926 }
927 } else {
928 gaim_notify_error(gc, NULL, _("File Transfer Aborted"),
929 _("Unable to create new connection."));
930 /* gaim_xfer_cancel_remote(xfer); */
931 /* Try a different port? Ask them to connect to us? */
932 }
933
934 }
935 }
936
937 static void oscar_xfer_start(GaimXfer *xfer)
938 { 903 {
939 904 GaimXfer *xfer;
940 gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_start\n"); 905 struct aim_oft_info *oft_info;
941 /* I'm pretty sure we don't need to do jack here. Nor Jill. */ 906
907 while (fts) {
908 xfer = fts->data;
909 oft_info = xfer->data;
910
911 if (oft_info && (conn == oft_info->conn))
912 return xfer;
913
914 fts = g_slist_next(fts);
915 }
916
917 return NULL;
942 } 918 }
943 919
944 static void oscar_xfer_end(GaimXfer *xfer) 920 static void oscar_xfer_end(GaimXfer *xfer)
945 { 921 {
946 struct aim_oft_info *oft_info = xfer->data; 922 struct aim_oft_info *oft_info = xfer->data;
958 aim_oft_destroyinfo(oft_info); 934 aim_oft_destroyinfo(oft_info);
959 xfer->data = NULL; 935 xfer->data = NULL;
960 od->file_transfers = g_slist_remove(od->file_transfers, xfer); 936 od->file_transfers = g_slist_remove(od->file_transfers, xfer);
961 } 937 }
962 938
939 /*
940 * xfer functions used when receiving files
941 */
942
943 static void oscar_xfer_init_recv(GaimXfer *xfer)
944 {
945 struct aim_oft_info *oft_info = xfer->data;
946 GaimConnection *gc = oft_info->sess->aux_data;
947 OscarData *od = gc->proto_data;
948
949 gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_recv_init\n");
950
951 oft_info->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL);
952 if (oft_info->conn) {
953 oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
954 aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_PROMPT, oscar_sendfile_prompt, 0);
955 oft_info->conn->fd = xfer->fd = gaim_proxy_connect(gaim_connection_get_account(gc),
956 xfer->remote_ip, xfer->remote_port, oscar_sendfile_connected, xfer);
957 if (xfer->fd == -1) {
958 gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who,
959 _("Unable to establish file descriptor."));
960 gaim_xfer_cancel_local(xfer);
961 }
962 } else {
963 gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who,
964 _("Unable to create new connection."));
965 gaim_xfer_cancel_local(xfer);
966 /* Try a different port? Ask them to connect to us? /join #gaim and whine? */
967 }
968
969 }
970
971 static void oscar_xfer_cancel_recv(GaimXfer *xfer)
972 {
973 struct aim_oft_info *oft_info = xfer->data;
974 GaimConnection *gc = oft_info->sess->aux_data;
975 OscarData *od = gc->proto_data;
976
977 gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_cancel_recv\n");
978
979 aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info);
980
981 aim_conn_kill(oft_info->sess, &oft_info->conn);
982 aim_oft_destroyinfo(oft_info);
983 xfer->data = NULL;
984 od->file_transfers = g_slist_remove(od->file_transfers, xfer);
985 }
986
987 static void oscar_xfer_ack_recv(GaimXfer *xfer, const char *buffer, size_t size)
988 {
989 struct aim_oft_info *oft_info = xfer->data;
990
991 /* Update our rolling checksum. Like Walmart, yo. */
992 oft_info->fh.recvcsum = aim_oft_checksum_chunk(buffer, size, oft_info->fh.recvcsum);
993 }
994
995 /*
996 * xfer functions used when sending files
997 */
998
999 static void oscar_xfer_init_send(GaimXfer *xfer)
1000 {
1001 struct aim_oft_info *oft_info = xfer->data;
1002 GaimConnection *gc = oft_info->sess->aux_data;
1003 OscarData *od = gc->proto_data;
1004 int listenfd;
1005
1006 gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_send_init\n");
1007
1008 xfer->filename = g_path_get_basename(xfer->local_filename);
1009 strncpy(oft_info->fh.name, xfer->filename, 64);
1010 oft_info->fh.name[63] = '\0';
1011 oft_info->fh.totsize = gaim_xfer_get_size(xfer);
1012 oft_info->fh.size = gaim_xfer_get_size(xfer);
1013 oft_info->fh.checksum = aim_oft_checksum_file(xfer->local_filename);
1014
1015 /* Create a listening socket and an associated libfaim conn */
1016 if ((listenfd = gaim_network_listen_range(5190, 5199)) < 0) {
1017 gaim_xfer_cancel_local(xfer);
1018 return;
1019 }
1020 xfer->local_port = gaim_network_get_port_from_fd(listenfd);
1021 oft_info->port = xfer->local_port;
1022 if (aim_sendfile_listen(od->sess, oft_info, listenfd) != 0) {
1023 gaim_xfer_cancel_local(xfer);
1024 return;
1025 }
1026 gaim_debug(GAIM_DEBUG_MISC, "oscar",
1027 "port is %hu, ip is %s\n",
1028 xfer->local_port, oft_info->clientip);
1029 if (oft_info->conn) {
1030 xfer->watcher = gaim_input_add(oft_info->conn->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
1031 aim_im_sendch2_sendfile_ask(od->sess, oft_info);
1032 aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED, oscar_sendfile_estblsh, 0);
1033 } else {
1034 gaim_xfer_error(GAIM_XFER_SEND, xfer->who,
1035 _("Unable to establish listener socket."));
1036 gaim_xfer_cancel_local(xfer);
1037 }
1038 }
1039
963 static void oscar_xfer_cancel_send(GaimXfer *xfer) 1040 static void oscar_xfer_cancel_send(GaimXfer *xfer)
964 { 1041 {
965 struct aim_oft_info *oft_info = xfer->data; 1042 struct aim_oft_info *oft_info = xfer->data;
966 GaimConnection *gc = oft_info->sess->aux_data; 1043 GaimConnection *gc = oft_info->sess->aux_data;
967 OscarData *od = gc->proto_data; 1044 OscarData *od = gc->proto_data;
968 1045
969 gaim_debug(GAIM_DEBUG_INFO, "oscar", 1046 gaim_debug(GAIM_DEBUG_INFO, "oscar", "AAA - in oscar_xfer_cancel_send\n");
970 "AAA - in oscar_xfer_cancel_send\n");
971 1047
972 aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info); 1048 aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info);
973 1049
974 aim_conn_kill(oft_info->sess, &oft_info->conn); 1050 aim_conn_kill(oft_info->sess, &oft_info->conn);
975 aim_oft_destroyinfo(oft_info); 1051 aim_oft_destroyinfo(oft_info);
976 xfer->data = NULL; 1052 xfer->data = NULL;
977 od->file_transfers = g_slist_remove(od->file_transfers, xfer); 1053 od->file_transfers = g_slist_remove(od->file_transfers, xfer);
978 } 1054 }
979 1055
980 static void oscar_xfer_cancel_recv(GaimXfer *xfer) 1056 static void oscar_xfer_ack_send(GaimXfer *xfer, const char *buffer, size_t size)
981 { 1057 {
982 struct aim_oft_info *oft_info = xfer->data; 1058 struct aim_oft_info *oft_info = xfer->data;
983 GaimConnection *gc = oft_info->sess->aux_data; 1059
984 OscarData *od = gc->proto_data; 1060 /* I'm not sure I like how we do this. --marv
985 1061 * I do. AIM file transfers aren't really meant to be thought
986 gaim_debug(GAIM_DEBUG_INFO, "oscar", 1062 * of as a transferring just a single file. The rendezvous
987 "AAA - in oscar_xfer_cancel_recv\n"); 1063 * establishes a connection between two computers, and then
988 1064 * those computers can use the same connection for transferring
989 aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info); 1065 * multiple files. So we don't want the Gaim core up and closing
990 1066 * the socket all willy-nilly. We want to do that in the oscar
991 aim_conn_kill(oft_info->sess, &oft_info->conn); 1067 * prpl, whenever one side or the other says they're finished
992 aim_oft_destroyinfo(oft_info); 1068 * using the connection. There might be a better way to intercept
993 xfer->data = NULL; 1069 * the socket from the core, however... --KingAnt
994 od->file_transfers = g_slist_remove(od->file_transfers, xfer); 1070 */
995 } 1071
996 1072 /*
997 static void oscar_xfer_ack(GaimXfer *xfer, const char *buffer, size_t size) 1073 * If we're done sending, intercept the socket from the core ft code
998 { 1074 * and wait for the other guy to send the "done" OFT packet.
999 struct aim_oft_info *oft_info = xfer->data; 1075 */
1000 1076 if (gaim_xfer_get_bytes_remaining(xfer) <= 0) {
1001 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { 1077 gaim_input_remove(xfer->watcher);
1002 /* 1078 xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
1003 * If we're done sending, intercept the socket from the core ft code 1079 xfer->fd = 0;
1004 * and wait for the other guy to send the "done" OFT packet. 1080 gaim_xfer_set_completed(xfer, TRUE);
1005 */ 1081 }
1006 if (gaim_xfer_get_bytes_remaining(xfer) <= 0) {
1007 gaim_input_remove(xfer->watcher);
1008 xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
1009 xfer->fd = 0;
1010 gaim_xfer_set_completed(xfer, TRUE);
1011 }
1012 } else if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
1013 /* Update our rolling checksum. Like Walmart, yo. */
1014 oft_info->fh.recvcsum = aim_oft_checksum_chunk(buffer, size, oft_info->fh.recvcsum);
1015 }
1016 }
1017
1018 static GaimXfer *oscar_find_xfer_by_cookie(GSList *fts, const char *ck)
1019 {
1020 GaimXfer *xfer;
1021 struct aim_oft_info *oft_info;
1022
1023 while (fts) {
1024 xfer = fts->data;
1025 oft_info = xfer->data;
1026
1027 if (oft_info && !strcmp(ck, oft_info->cookie))
1028 return xfer;
1029
1030 fts = g_slist_next(fts);
1031 }
1032
1033 return NULL;
1034 }
1035
1036 static GaimXfer *oscar_find_xfer_by_conn(GSList *fts, aim_conn_t *conn)
1037 {
1038 GaimXfer *xfer;
1039 struct aim_oft_info *oft_info;
1040
1041 while (fts) {
1042 xfer = fts->data;
1043 oft_info = xfer->data;
1044
1045 if (oft_info && (conn == oft_info->conn))
1046 return xfer;
1047
1048 fts = g_slist_next(fts);
1049 }
1050
1051 return NULL;
1052 } 1082 }
1053 1083
1054 static void oscar_ask_sendfile(GaimConnection *gc, const char *destsn) { 1084 static void oscar_ask_sendfile(GaimConnection *gc, const char *destsn) {
1055 OscarData *od = (OscarData *)gc->proto_data; 1085 OscarData *od = (OscarData *)gc->proto_data;
1056 GaimAccount *account = gaim_connection_get_account(gc); 1086 GaimAccount *account = gaim_connection_get_account(gc);
1067 ip = gaim_network_get_ip_for_account(account, od->conn ? od->conn->fd : -1); 1097 ip = gaim_network_get_ip_for_account(account, od->conn ? od->conn->fd : -1);
1068 oft_info = aim_oft_createinfo(od->sess, NULL, destsn, ip, 0, 0, 0, NULL); 1098 oft_info = aim_oft_createinfo(od->sess, NULL, destsn, ip, 0, 0, 0, NULL);
1069 xfer->data = oft_info; 1099 xfer->data = oft_info;
1070 1100
1071 /* Setup our I/O op functions */ 1101 /* Setup our I/O op functions */
1072 gaim_xfer_set_init_fnc(xfer, oscar_xfer_init); 1102 gaim_xfer_set_init_fnc(xfer, oscar_xfer_init_send);
1073 gaim_xfer_set_start_fnc(xfer, oscar_xfer_start);
1074 gaim_xfer_set_end_fnc(xfer, oscar_xfer_end); 1103 gaim_xfer_set_end_fnc(xfer, oscar_xfer_end);
1075 gaim_xfer_set_cancel_send_fnc(xfer, oscar_xfer_cancel_send); 1104 gaim_xfer_set_cancel_send_fnc(xfer, oscar_xfer_cancel_send);
1076 gaim_xfer_set_cancel_recv_fnc(xfer, oscar_xfer_cancel_recv); 1105 gaim_xfer_set_request_denied_fnc(xfer, oscar_xfer_cancel_send);
1077 gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack); 1106 gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack_send);
1078 1107
1079 /* Keep track of this transfer for later */ 1108 /* Keep track of this transfer for later */
1080 od->file_transfers = g_slist_append(od->file_transfers, xfer); 1109 od->file_transfers = g_slist_append(od->file_transfers, xfer);
1081 1110
1082 /* Now perform the request */ 1111 /* Now perform the request */
2035 "AAA - in oscar_sendfile_connected\n"); 2064 "AAA - in oscar_sendfile_connected\n");
2036 if (!(xfer = data)) 2065 if (!(xfer = data))
2037 return; 2066 return;
2038 if (!(oft_info = xfer->data)) 2067 if (!(oft_info = xfer->data))
2039 return; 2068 return;
2040 if (source < 0) 2069 if (source < 0) {
2070 gaim_xfer_cancel_remote(xfer);
2041 return; 2071 return;
2072 }
2042 2073
2043 xfer->fd = source; 2074 xfer->fd = source;
2044 oft_info->conn->fd = source; 2075 oft_info->conn->fd = source;
2045 2076
2046 aim_conn_completeconnect(oft_info->sess, oft_info->conn); 2077 aim_conn_completeconnect(oft_info->sess, oft_info->conn);
2389 * directories that look like 'dirname\*' -- arl */ 2420 * directories that look like 'dirname\*' -- arl */
2390 char *tmp = strrchr(args->info.sendfile.filename, '\\'); 2421 char *tmp = strrchr(args->info.sendfile.filename, '\\');
2391 if (tmp && (tmp[1] == '*')) { 2422 if (tmp && (tmp[1] == '*')) {
2392 tmp[0] = '\0'; 2423 tmp[0] = '\0';
2393 } 2424 }
2425 gaim_debug(GAIM_DEBUG_WARNING, "oscar",
2426 "We're receiving a whole directory! What fun! "
2427 "Especially since we don't support that!\n");
2394 } 2428 }
2395 2429
2396 /* Build the file transfer handle */ 2430 /* Build the file transfer handle */
2397 xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, userinfo->sn); 2431 xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, userinfo->sn);
2398 xfer->remote_ip = g_strdup(args->verifiedip); 2432 xfer->remote_ip = g_strdup(args->verifiedip);
2407 if (args->verifiedip) 2441 if (args->verifiedip)
2408 oft_info->verifiedip = g_strdup(args->verifiedip); 2442 oft_info->verifiedip = g_strdup(args->verifiedip);
2409 xfer->data = oft_info; 2443 xfer->data = oft_info;
2410 2444
2411 /* Setup our I/O op functions */ 2445 /* Setup our I/O op functions */
2412 gaim_xfer_set_init_fnc(xfer, oscar_xfer_init); 2446 gaim_xfer_set_init_fnc(xfer, oscar_xfer_init_recv);
2413 gaim_xfer_set_start_fnc(xfer, oscar_xfer_start);
2414 gaim_xfer_set_end_fnc(xfer, oscar_xfer_end); 2447 gaim_xfer_set_end_fnc(xfer, oscar_xfer_end);
2415 gaim_xfer_set_cancel_send_fnc(xfer, oscar_xfer_cancel_send); 2448 gaim_xfer_set_request_denied_fnc(xfer, oscar_xfer_cancel_recv);
2416 gaim_xfer_set_cancel_recv_fnc(xfer, oscar_xfer_cancel_recv); 2449 gaim_xfer_set_cancel_recv_fnc(xfer, oscar_xfer_cancel_recv);
2417 gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack); 2450 gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack_recv);
2418 2451
2419 /* 2452 /*
2420 * XXX - Should do something with args->msg, args->encoding, and args->language 2453 * XXX - Should do something with args->msg, args->encoding, and args->language
2421 * probably make it apply to all ch2 messages. 2454 * probably make it apply to all ch2 messages.
2422 */ 2455 */