# HG changeset patch # User Tim Ringenbach # Date 1085018614 0 # Node ID 460d02fe03df69b78327b0da5ce02ef3d8511469 # Parent a4fd6666bb8321add93a39171b19ed89b8f5f1d6 [gaim-migrate @ 9758] This makes us tell the other person to connect to us if we can't connect to them, for direct im. Also I made us used the clientip instead of the verified ip for direct im, because I get the impression that's what the official aim clients use, and I think it sort of makes sense. Maybe I should compare the two and not bother trying if they're different. committer: Tailor Script diff -r a4fd6666bb83 -r 460d02fe03df src/protocols/oscar/aim.h --- a/src/protocols/oscar/aim.h Thu May 20 00:14:14 2004 +0000 +++ b/src/protocols/oscar/aim.h Thu May 20 02:03:34 2004 +0000 @@ -932,6 +932,7 @@ faim_export int aim_odc_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing); faim_export int aim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding, int isawaymsg); faim_export const char *aim_odc_getsn(aim_conn_t *conn); +faim_export const char *aim_odc_getcookie(aim_conn_t *conn); faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn); faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn, int listenfd, const fu8_t *localip, fu16_t port, const fu8_t *mycookie); diff -r a4fd6666bb83 -r 460d02fe03df src/protocols/oscar/ft.c --- a/src/protocols/oscar/ft.c Thu May 20 00:14:14 2004 +0000 +++ b/src/protocols/oscar/ft.c Thu May 20 02:03:34 2004 +0000 @@ -390,7 +390,7 @@ /** * Get the screen name of the peer of a direct connection. - * + * * @param conn The ODC connection. * @return The screen name of the dude, or NULL if there was an anomaly. */ @@ -401,7 +401,7 @@ if (!conn || !conn->internal) return NULL; - if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || + if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) return NULL; @@ -411,6 +411,28 @@ } /** + * Get the cookie of a direct connection. + * + * @param conn The ODC connection. + * @return The cookie, an 8 byte unterminated string, or NULL if there was an anomaly. + */ +faim_export const char *aim_odc_getcookie(aim_conn_t *conn) +{ + struct aim_odc_intdata *intdata; + + if (!conn || !conn->internal) + return NULL; + + if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || + (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) + return NULL; + + intdata = (struct aim_odc_intdata *)conn->internal; + + return intdata->cookie; +} + +/** * Find the conn of a direct connection with the given buddy. * * @param sess The session. diff -r a4fd6666bb83 -r 460d02fe03df src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Thu May 20 00:14:14 2004 +0000 +++ b/src/protocols/oscar/oscar.c Thu May 20 02:03:34 2004 +0000 @@ -288,6 +288,7 @@ /* just because */ static void oscar_callback(gpointer data, gint source, GaimInputCondition condition); +static void oscar_direct_im_initiate(GaimConnection *gc, const char *who, const char *cookie); /* remove these at some point? */ /* Because I don't like forward declarations? I think that was why... */ @@ -795,7 +796,15 @@ } if (source < 0) { - oscar_direct_im_disconnect(od, dim); + fu8_t cookie[8]; + char *who = g_strdup(dim->name); + const char *tmp = aim_odc_getcookie(dim->conn); + + memcpy(cookie, tmp, 8); + oscar_direct_im_destroy(od, dim); + oscar_direct_im_initiate(gc, who, cookie); + gaim_debug_info("oscar", "asking direct im initiator to connect to us\n"); + g_free(who); return; } @@ -804,13 +813,26 @@ conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, dim->name); /* This is the best way to see if we're connected or not */ + /* Is this really needed? */ if (getpeername(source, &name, &name_len) == 0) { g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), dim->name); dim->connected = TRUE; gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); - } - - dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); + dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); + } else { + fu8_t cookie[8]; + char *who = g_strdup(dim->name); + const char *tmp = aim_odc_getcookie(dim->conn); + + memcpy(cookie, tmp, 8); + oscar_direct_im_destroy(od, dim); + oscar_direct_im_initiate(gc, who, cookie); + gaim_debug_info("oscar", "asking direct im initiator to connect to us\n"); + g_free(who); + return; + } + + } static void accept_direct_im_request(struct ask_direct *d) { @@ -872,7 +894,7 @@ port); gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL)); g_free(tmp); - + g_free(host); if (rc < 0) { dim->gpc_pend = FALSE; @@ -1237,22 +1259,25 @@ g_free(data); } -static void oscar_direct_im(struct ask_do_dir_im *data) { - GaimConnection *gc = data->gc; +/* this function is used to initiate a direct im session with someone. + * we start listening on a port and send a request. they either connect + * or send some kind of reply. If they can't connect, they ask us to + * connect to them, and so we do that. + * + * this function will also get called if the other side initiate's a direct + * im and we try to connect and fail. in that case cookie will not be null. + * + * note that cookie is an 8 byte string that isn't NULL terminated + */ +static void oscar_direct_im_initiate(GaimConnection *gc, const char *who, const char *cookie) { OscarData *od; struct oscar_direct_im *dim; int listenfd; const char *ip; - if (!g_list_find(gaim_connections_get_all(), gc)) { - g_free(data->who); - g_free(data); - return; - } - od = (OscarData *)gc->proto_data; - dim = oscar_direct_im_find(od, data->who); + dim = oscar_direct_im_find(od, who); if (dim) { if (!(dim->connected)) { /* We'll free the old, unconnected dim, and start over */ oscar_direct_im_disconnect(od, dim); @@ -1260,18 +1285,16 @@ "Gave up on old direct IM, trying again\n"); } else { gaim_notify_error(gc, NULL, "DirectIM already open.", NULL); - g_free(data->who); - g_free(data); return; } } dim = g_new0(struct oscar_direct_im, 1); dim->gc = gc; - g_snprintf(dim->name, sizeof dim->name, "%s", data->who); + g_snprintf(dim->name, sizeof dim->name, "%s", who); listenfd = gaim_network_listen_range(5190, 5199); ip = gaim_network_get_my_ip(od->conn ? od->conn->fd : -1); - dim->conn = aim_odc_initiate(od->sess, data->who, listenfd, gaim_network_ip_atoi(ip), gaim_network_get_port_from_fd(listenfd), NULL); + dim->conn = aim_odc_initiate(od->sess, who, listenfd, gaim_network_ip_atoi(ip), gaim_network_get_port_from_fd(listenfd), cookie); if (dim->conn != NULL) { char *tmp; GaimConversation *conv; @@ -1282,8 +1305,8 @@ aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED, gaim_odc_initiate, 0); - conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, data->who); - tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for Direct IM."), data->who, ip, + conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, who); + tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for Direct IM."), who, ip, gaim_network_get_port_from_fd(listenfd)); gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL)); g_free(tmp); @@ -1291,7 +1314,18 @@ gaim_notify_error(gc, NULL, _("Unable to open Direct IM"), NULL); oscar_direct_im_destroy(od, dim); } - +} + +static void oscar_direct_im(struct ask_do_dir_im *data) { + GaimConnection *gc = data->gc; + + if (!g_list_find(gaim_connections_get_all(), gc)) { + g_free(data->who); + g_free(data); + return; + } + + oscar_direct_im_initiate(gc, data->who, NULL); g_free(data->who); g_free(data); } @@ -3184,6 +3218,7 @@ char buf[256]; if (!args->verifiedip) { + /* TODO: do something about this, after figuring out what it means */ gaim_debug_info("oscar", "directim kill blocked (%s)\n", userinfo->sn); return 1; @@ -3191,17 +3226,20 @@ gaim_debug_info("oscar", "%s received direct im request from %s (%s)\n", - username, userinfo->sn, args->verifiedip); + username, userinfo->sn, args->clientip); d->gc = gc; d->sn = g_strdup(userinfo->sn); - snprintf(d->ip, sizeof(d->ip), "%s:%d", args->verifiedip, args->port?args->port:5190); + /* Let's use the clientip here, because I think that's what AIM does. + * Besides, if the clientip is wrong, we'll probably timeout faster, + * and then ask them to connect to us. */ + snprintf(d->ip, sizeof(d->ip), "%s:%d", args->clientip, args->port?args->port:5190); memcpy(d->cookie, args->cookie, 8); - if (dim && !dim->connected) { + if (dim && !dim->connected && (!memcmp(aim_odc_getcookie(dim->conn), args->cookie, 8))) { oscar_direct_im_destroy(od, dim); accept_direct_im_request(d); } else { - if (dim) + if (dim && !dim->connected) gaim_debug_warning("oscar", "DirectIM: received direct im request while " "already connected to that buddy!"); g_snprintf(buf, sizeof buf, _("%s has just asked to directly connect to %s"), userinfo->sn, username);