# HG changeset patch # User Sulabh Mahajan # Date 1226485393 0 # Node ID 3e788c0db3a6f4a59cd604842f6248d6f3d801ed # Parent eb21f65728c007f70abfa5412cf9fbc616ca0313 resolved conflict -- merged im.pidgin.pidgin to im.pidgin.soc.2008.yahoo diff -r eb21f65728c0 -r 3e788c0db3a6 libpurple/protocols/yahoo/yahoo.c --- a/libpurple/protocols/yahoo/yahoo.c Wed Nov 12 10:18:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Wed Nov 12 10:23:13 2008 +0000 @@ -30,6 +30,7 @@ #include "cmds.h" #include "core.h" #include "debug.h" +#include "network.h" #include "notify.h" #include "privacy.h" #include "prpl.h" @@ -38,6 +39,7 @@ #include "server.h" #include "util.h" #include "version.h" +#include "xmlnode.h" #include "yahoo.h" #include "yahoochat.h" @@ -235,6 +237,8 @@ message = pair->value; break; case 11: /* this is the buddy's session id */ + if (f) + f->session_id = strtol(pair->value, NULL, 10); break; case 17: /* in chat? */ break; @@ -521,6 +525,10 @@ purple_blist_add_buddy(b, NULL, g, NULL); } yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp); + + /* set p2p status not connected and no p2p packet sent */ + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); + f->p2p_packet_sent = 0; } else { /* This buddy is on the ignore list (and therefore in no group) */ @@ -635,6 +643,10 @@ } yahoo_do_group_check(account, ht, norm_bud, grp); + /* set p2p status not connected and no p2p packet sent */ + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); + f->p2p_packet_sent = 0; + g_free(norm_bud); } g_strfreev(buddies); @@ -691,7 +703,8 @@ yahoo_fetch_aliases(gc); } -static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt) +/* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */ +static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type) { PurpleAccount *account; char *msg = NULL; @@ -700,12 +713,14 @@ char *game = NULL; YahooFriend *f = NULL; GSList *l = pkt->hash; + gint val_11 = 0; + struct yahoo_data *yd = gc->proto_data; account = purple_connection_get_account(gc); while (l) { struct yahoo_pair *pair = l->data; - if (pair->key == 4) + if (pair->key == 4 || pair->key == 1) from = pair->value; if (pair->key == 49) msg = pair->value; @@ -713,12 +728,22 @@ stat = pair->value; if (pair->key == 14) game = pair->value; + if (pair->key == 11) + val_11 = strtol(pair->value, NULL, 10); l = l->next; } if (!from || !msg) return; + /* disconnect the peer if connected through p2p and sends wrong value for session id */ + if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) { + purple_debug_warning("yahoo","p2p: %s sent us notify with wrong session id. Disconnecting p2p connection to peer\n", from); + /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ + g_hash_table_remove(yd->peers, from); + return; + } + if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING")) && (purple_privacy_check(account, from))) { @@ -764,7 +789,69 @@ char *msg; }; -static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt) +static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt) +{ + PurpleAccount *account; + GSList *l = pkt->hash; + struct _yahoo_im *sms = NULL; + struct yahoo_data *yd; + char *server_msg = NULL; + char *m; + + yd = gc->proto_data; + account = purple_connection_get_account(gc); + + while (l != NULL) { + struct yahoo_pair *pair = l->data; + if (pair->key == 4) { + sms = g_new0(struct _yahoo_im, 1); + sms->from = g_strdup_printf("+%s", pair->value); + sms->time = time(NULL); + sms->utf8 = TRUE; + } + if (pair->key == 14) { + if (sms) + sms->msg = pair->value; + } + if (pair->key == 68) + if(sms) + g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value)); + if (pair->key == 16) + server_msg = pair->value; + l = l->next; + } + + if( (pkt->status == -1) || (pkt->status == YAHOO_STATUS_DISCONNECTED) ) { + if (server_msg) { + PurpleConversation *c; + c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms->from, account); + if (c == NULL) + c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sms->from); + purple_conversation_write(c, NULL, server_msg, PURPLE_MESSAGE_SYSTEM, time(NULL)); + } + else + purple_notify_error(gc, NULL, _("Your SMS was not delivered"), NULL); + + g_free(sms->from); + g_free(sms); + return ; + } + + if (!sms->from || !sms->msg) { + g_free(sms); + return; + } + + m = yahoo_string_decode(gc, sms->msg, sms->utf8); + serv_got_im(gc, sms->from, m, 0, sms->time); + + g_free(m); + g_free(sms->from); + g_free(sms); +} + +/* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */ +static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type) { PurpleAccount *account; struct yahoo_data *yd = gc->proto_data; @@ -772,13 +859,15 @@ GSList *list = NULL; struct _yahoo_im *im = NULL; const char *imv = NULL; + gint val_11 = 0; account = purple_connection_get_account(gc); - if (pkt->status <= 1 || pkt->status == 5) { + if (pkt->status <= 1 || pkt->status == 5 || pkt->status == YAHOO_STATUS_OFFLINE) { + /* messages are received with status YAHOO_STATUS_OFFLINE in case of p2p */ while (l != NULL) { struct yahoo_pair *pair = l->data; - if (pair->key == 4) { + if (pair->key == 4 || pair->key == 1) { im = g_new0(struct _yahoo_im, 1); list = g_slist_append(list, im); im->from = pair->value; @@ -798,6 +887,11 @@ if (im) im->msg = pair->value; } + /* peer session id */ + if (pair->key == 11) { + if (im) + val_11 = strtol(pair->value, NULL, 10); + } /* IMV key */ if (pair->key == 63) { @@ -810,6 +904,14 @@ _("Your Yahoo! message did not get sent."), NULL); } + /* disconnect the peer if connected through p2p and sends wrong value for session id */ + if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) { + purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im->from); + /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ + g_hash_table_remove(yd->peers, im->from); + return; + } + /** TODO: It seems that this check should be per IM, not global */ /* Check for the Doodle IMV */ if (im != NULL && imv!= NULL && im->from != NULL) @@ -2187,6 +2289,8 @@ char *buf; YahooFriend *f; GSList *l = pkt->hash; + struct yahoo_data *yd = gc->proto_data; + int protocol = 0; while (l) { struct yahoo_pair *pair = l->data; @@ -2201,6 +2305,9 @@ case 65: group = pair->value; break; + case 241: + protocol = strtol(pair->value, NULL, 10); + break; } l = l->next; @@ -2214,6 +2321,16 @@ if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */ f = yahoo_friend_find_or_new(gc, who); yahoo_update_status(gc, who, f); + if(protocol) + f->protocol = protocol; + + if( !g_hash_table_lookup(yd->peers, who) ) { + /* we are not connected as client, so set friend to not connected */ + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); + f->p2p_packet_sent = 0; + } + else /* we are already connected. set friend to YAHOO_P2PSTATUS_WE_ARE_CLIENT */ + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT); return; } @@ -2226,6 +2343,426 @@ g_free(decoded_group); } +/* write pkt to the source */ +static void yahoo_p2p_write_pkt(gint source, struct yahoo_packet *pkt) +{ + size_t pkt_len; + guchar *raw_packet; + + /*build the raw packet and send it to the host*/ + pkt_len = yahoo_packet_build(pkt, 0, 0, 0, &raw_packet); + if(write(source, raw_packet, pkt_len) != pkt_len) + purple_debug_warning("yahoo","p2p: couldn't write to the source\n"); + g_free(raw_packet); +} + +static void yahoo_p2p_keepalive_cb(gpointer key, gpointer value, gpointer user_data) +{ + struct yahoo_p2p_data *p2p_data = value; + PurpleConnection *gc = user_data; + struct yahoo_packet *pkt_to_send; + PurpleAccount *account; + struct yahoo_data *yd = gc->proto_data; + + account = purple_connection_get_account(gc); + + pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id); + yahoo_packet_hash(pkt_to_send, "ssisi", + 4, purple_normalize(account, purple_account_get_username(account)), + 5, p2p_data->host_username, + 241, 0, /* Protocol identifier */ + 49, "PEERTOPEER", + 13, 7); + yahoo_p2p_write_pkt(p2p_data->source, pkt_to_send); + + yahoo_packet_free(pkt_to_send); +} + +static gboolean yahoo_p2p_keepalive(gpointer data) +{ + PurpleConnection *gc = data; + struct yahoo_data *yd = gc->proto_data; + + g_hash_table_foreach(yd->peers, yahoo_p2p_keepalive_cb, gc); + + return TRUE; +} + +/* destroy p2p_data associated with a peer and close p2p connection. + * g_hash_table_remove() calls this function to destroy p2p_data associated with the peer, + * call g_hash_table_remove() instead of this fucntion if peer has an entry in the table */ +static void yahoo_p2p_disconnect_destroy_data(gpointer data) +{ + struct yahoo_p2p_data *p2p_data; + YahooFriend *f; + + if(!(p2p_data = data)) + return ; + + /* If friend, set him not connected */ + f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username); + if (f) + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); + + if(p2p_data->source >= 0) + close(p2p_data->source); + purple_input_remove(p2p_data->input_event); + g_free(p2p_data->host_ip); + g_free(p2p_data->host_username); + g_free(p2p_data); +} + +/* exchange of initial p2pfilexfer packets, service type YAHOO_SERVICE_P2PFILEXFER */ +static void yahoo_p2p_process_p2pfilexfer(gpointer data, gint source, struct yahoo_packet *pkt) +{ + struct yahoo_p2p_data *p2p_data; + char *who = NULL; + GSList *l = pkt->hash; + struct yahoo_packet *pkt_to_send; + PurpleAccount *account; + int val_13_to_send = 0; + struct yahoo_data *yd; + YahooFriend *f; + + if(!(p2p_data = data)) + return ; + + yd = p2p_data->gc->proto_data; + + /* lets see whats in the packet */ + while (l) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + case 4: + who = pair->value; + if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) { + /* from whom are we receiving the packets ?? */ + purple_debug_warning("yahoo","p2p: received data from wrong user\n"); + return; + } + break; + case 13: + p2p_data->val_13 = strtol(pair->value, NULL, 10); /* Value should be 5-7 */ + break; + /* case 5, 49 look laters, no use right now */ + } + l = l->next; + } + + account = purple_connection_get_account(p2p_data->gc); + + /* key_13: sort of a counter. + * WHEN WE ARE CLIENT: yahoo server sends val_13 = 0, we send to peer val_13 = 1, receive back val_13 = 5, + * we send val_13=6, receive val_13=7, we send val_13=7, HALT. Keep sending val_13 = 7 as keep alive. + * WHEN WE ARE SERVER: we send val_13 = 0 to yahoo server, peer sends us val_13 = 1, we send val_13 = 5, + * receive val_13 = 6, send val_13 = 7, receive val_13 = 7. HALT. Keep sending val_13 = 7 as keep alive. */ + + switch(p2p_data->val_13) { + case 1 : val_13_to_send = 5; break; + case 5 : val_13_to_send = 6; break; + case 6 : val_13_to_send = 7; break; + case 7 : if( g_hash_table_lookup(yd->peers, p2p_data->host_username) ) + return; + val_13_to_send = 7; break; + default: purple_debug_warning("yahoo","p2p:Unknown value for key 13\n"); + return; + } + + /* Build the yahoo packet */ + pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id); + yahoo_packet_hash(pkt_to_send, "ssisi", + 4, purple_normalize(account, purple_account_get_username(account)), + 5, p2p_data->host_username, + 241, 0, /* Protocol identifier */ + 49, "PEERTOPEER", + 13, val_13_to_send); + + /* build the raw packet and send it to the host */ + yahoo_p2p_write_pkt(source, pkt_to_send); + yahoo_packet_free(pkt_to_send); + + if( val_13_to_send == 7 ) + if( !g_hash_table_lookup(yd->peers, p2p_data->host_username) ) { + g_hash_table_insert(yd->peers, g_strdup(p2p_data->host_username), p2p_data); + /* If the peer is a friend, set him connected */ + f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username); + if (f) { + if(p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER) { + p2p_data->session_id = f->session_id; + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_SERVER); + } + else + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT); + } + } +} + +/* callback function associated with receiving of data, not considering receipt of multiple YMSG packets in a single TCP packet */ +static void yahoo_p2p_read_pkt_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + guchar buf[1024]; /* is it safe to assume a fixed array length of 1024 ?? */ + int len; + int pos = 0; + int pktlen; + struct yahoo_packet *pkt; + guchar *start = NULL; + struct yahoo_p2p_data *p2p_data; + struct yahoo_data *yd; + + if(!(p2p_data = data)) + return ; + yd = p2p_data->gc->proto_data; + + len = read(source, buf, sizeof(buf)); + if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) + return ; /* No Worries*/ + else if (len <= 0) + { + purple_debug_warning("yahoo","p2p: Error in connection, or host disconnected\n"); + /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ + if( g_hash_table_lookup(yd->peers, p2p_data->host_username) ) + g_hash_table_remove(yd->peers,p2p_data->host_username); + else + yahoo_p2p_disconnect_destroy_data(data); + return; + } + + if(len < YAHOO_PACKET_HDRLEN) + return; + + if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) { + /* Not a YMSG packet */ + purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n"); + + start = memchr(buf + 1, 'Y', len - 1); + if(start) { + g_memmove(buf, start, len - (start - buf)); + len -= start - buf; + } else { + g_free(buf); + return; + } + } + + pos += 4; /* YMSG */ + pos += 2; + pos += 2; + + pktlen = yahoo_get16(buf + pos); pos += 2; + purple_debug(PURPLE_DEBUG_MISC, "yahoo", "p2p: %d bytes to read\n", len); + + pkt = yahoo_packet_new(0, 0, 0); + pkt->service = yahoo_get16(buf + pos); pos += 2; + pkt->status = yahoo_get32(buf + pos); pos += 4; + pkt->id = yahoo_get32(buf + pos); pos += 4; + + purple_debug(PURPLE_DEBUG_MISC, "yahoo", "p2p: Yahoo Service: 0x%02x Status: %d\n",pkt->service, pkt->status); + yahoo_packet_read(pkt, buf + pos, pktlen); + + /* packet processing */ + switch(pkt->service) { + case YAHOO_SERVICE_P2PFILEXFER: + yahoo_p2p_process_p2pfilexfer(data, source, pkt); + break; + case YAHOO_SERVICE_MESSAGE: + yahoo_process_message(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P); + break; + case YAHOO_SERVICE_NOTIFY: + yahoo_process_notify(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P); + break; + default: + purple_debug_warning("yahoo","p2p: p2p service %d Unhandled\n",pkt->service); + } + + yahoo_packet_free(pkt); +} + +static void yahoo_p2p_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + int acceptfd; + struct yahoo_p2p_data *p2p_data; + struct yahoo_data *yd; + + if(!(p2p_data = data)) + return ; + yd = p2p_data->gc->proto_data; + + acceptfd = accept(source, NULL, 0); + if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + return; + else if(acceptfd == -1) { + purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno)); + yahoo_p2p_disconnect_destroy_data(data); + return; + } + + /* remove watcher and close p2p server */ + purple_input_remove(yd->yahoo_p2p_server_watcher); + close(yd->yahoo_local_p2p_server_fd); + yd->yahoo_local_p2p_server_fd = -1; + + /* Add an Input Read event to the file descriptor */ + p2p_data->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data); + p2p_data->source = acceptfd; +} + +static gboolean yahoo_cancel_p2p_server_listen_cb(gpointer data) +{ + struct yahoo_p2p_data *p2p_data; + struct yahoo_data *yd; + + if(!(p2p_data = data)) + return FALSE; + + yd = p2p_data->gc->proto_data; + + purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect"); + yahoo_p2p_disconnect_destroy_data(data); + purple_input_remove(yd->yahoo_p2p_server_watcher); + yd->yahoo_p2p_server_watcher = 0; + close(yd->yahoo_local_p2p_server_fd); + yd->yahoo_local_p2p_server_fd = -1; + yd->yahoo_p2p_server_timeout_handle = 0; + + return FALSE; +} + +static void yahoo_p2p_server_listen_cb(int listenfd, gpointer data) +{ + struct yahoo_p2p_data *p2p_data; + struct yahoo_data *yd; + + if(!(p2p_data = data)) + return ; + + if(listenfd == -1) { + purple_debug_warning("yahoo","p2p: error starting p2p server\n"); + yahoo_p2p_disconnect_destroy_data(data); + return; + } + + yd = p2p_data->gc->proto_data; + + /* Add an Input Read event to the file descriptor */ + yd->yahoo_local_p2p_server_fd = listenfd; + yd->yahoo_p2p_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_server_send_connected_cb,data); + + /* add timeout */ + yd->yahoo_p2p_server_timeout_handle = purple_timeout_add_seconds(YAHOO_P2P_SERVER_TIMEOUT, yahoo_cancel_p2p_server_listen_cb, data); +} + +/* send p2p pkt containing our encoded ip, asking peer to connect to us */ +void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13) +{ + const char *public_ip; + guint32 temp[4]; + guint32 ip; + char temp_str[100]; + gchar *base64_ip = NULL; + YahooFriend *f; + struct yahoo_packet *pkt; + PurpleAccount *account; + struct yahoo_data *yd = gc->proto_data; + struct yahoo_p2p_data *p2p_data; + + f = yahoo_friend_find(gc, who); + account = purple_connection_get_account(gc); + + /* Do not send invitation if already listening for other connection */ + if(yd->yahoo_local_p2p_server_fd >= 0) + return; + + /* One shouldn't try to connect to self */ + if( strcmp(purple_normalize(account, purple_account_get_username(account)), who) == 0) + return; + + /* send packet to only those friends who arent p2p connected and to whom we havent already sent. Do not send if this condition doesn't hold good */ + if( !( f && (yahoo_friend_get_p2p_status(f) == YAHOO_P2PSTATUS_NOT_CONNECTED) && (f->p2p_packet_sent == 0)) ) + return; + + /* Dont send p2p packet to buddies of other protocols */ + if(f->protocol) + return; + + /* Finally, don't try to connect to buddies not online or on sms */ + if( (f->status == YAHOO_STATUS_OFFLINE) || f->sms ) + return; + + public_ip = purple_network_get_public_ip(); + if( (sscanf(public_ip, "%u.%u.%u.%u", &temp[0], &temp[1], &temp[2], &temp[3])) !=4 ) + return ; + + ip = (temp[3] << 24) | (temp[2] <<16) | (temp[1] << 8) | temp[0]; + sprintf(temp_str, "%d", ip); + base64_ip = purple_base64_encode( (guchar *)temp_str, strlen(temp_str) ); + + pkt = yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, "sssissis", + 1, purple_normalize(account, purple_account_get_username(account)), + 4, purple_normalize(account, purple_account_get_username(account)), + 12, base64_ip, /* base64 encode ip */ + 61, 0, /* To-do : figure out what is 61 for?? */ + 2, "", + 5, who, + 13, val_13, + 49, "PEERTOPEER"); + yahoo_packet_send_and_free(pkt, yd); + + f->p2p_packet_sent = 1; /* set p2p_packet_sent to sent */ + + p2p_data = g_new0(struct yahoo_p2p_data, 1); + + p2p_data->gc = gc; + p2p_data->host_ip = NULL; + p2p_data->host_username = g_strdup(who); + p2p_data->val_13 = val_13; + p2p_data->connection_type = YAHOO_P2P_WE_ARE_SERVER; + + purple_network_listen(YAHOO_PAGER_PORT_P2P, SOCK_STREAM, yahoo_p2p_server_listen_cb, p2p_data); + + g_free(base64_ip); +} + +/* function called when connection to p2p host is setup */ +static void yahoo_p2p_init_cb(gpointer data, gint source, const gchar *error_message) +{ + struct yahoo_p2p_data *p2p_data; + struct yahoo_packet *pkt_to_send; + PurpleAccount *account; + struct yahoo_data *yd; + + if(!(p2p_data = data)) + return ; + yd = p2p_data->gc->proto_data; + + if(error_message != NULL) { + purple_debug_warning("yahoo","p2p: %s\n",error_message); + yahoo_send_p2p_pkt(p2p_data->gc, p2p_data->host_username, 2);/* send p2p init packet with val_13=2 */ + + yahoo_p2p_disconnect_destroy_data(p2p_data); + return; + } + + /* Add an Input Read event to the file descriptor */ + p2p_data->input_event = purple_input_add(source, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data); + p2p_data->source = source; + + account = purple_connection_get_account(p2p_data->gc); + + /* Build the yahoo packet */ + pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id); + yahoo_packet_hash(pkt_to_send, "ssisi", + 4, purple_normalize(account, purple_account_get_username(account)), + 5, p2p_data->host_username, + 241, 0, /* Protocol identifier */ + 49, "PEERTOPEER", + 13, 1); /* we receive key13= 0 or 2, we send key13=1 */ + + yahoo_p2p_write_pkt(source, pkt_to_send); /* build raw packet and send */ + yahoo_packet_free(pkt_to_send); +} + static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt) { GSList *l = pkt->hash; @@ -2233,6 +2770,14 @@ char *base64 = NULL; guchar *decoded; gsize len; + gint val_13 = 0; + gint val_11 = 0; + PurpleAccount *account; + YahooFriend *f; + + /* if status is YAHOO_STATUS_BUSY, don't do anything, peer wont connect */ + if(pkt->status == YAHOO_STATUS_BUSY) + return ; while (l) { struct yahoo_pair *pair = l->data; @@ -2252,14 +2797,21 @@ /* so, this is an ip address. in base64. decoded it's in ascii. after strtol, it's in reversed byte order. Who thought this up?*/ break; + case 13: + val_13 = strtol(pair->value, NULL, 10); + break; + case 11: + val_11 = strtol(pair->value, NULL, 10); /* session id of peer */ + if( (f = yahoo_friend_find(gc, who)) ) + f->session_id = val_11; + break; /* TODO: figure these out yahoo: Key: 61 Value: 0 yahoo: Key: 2 Value: - yahoo: Key: 13 Value: 0 + yahoo: Key: 13 Value: 0 packet count ?? yahoo: Key: 49 Value: PEERTOPEER yahoo: Key: 140 Value: 1 - yahoo: Key: 11 Value: -1786225828 */ } @@ -2271,6 +2823,8 @@ guint32 ip; char *tmp2; YahooFriend *f; + char *host_ip; + struct yahoo_p2p_data *p2p_data = g_new0(struct yahoo_p2p_data, 1); decoded = purple_base64_decode(base64, &len); if (len) { @@ -2283,12 +2837,34 @@ ip = strtol(tmp2, NULL, 10); g_free(tmp2); g_free(decoded); - tmp2 = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, + host_ip = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff); f = yahoo_friend_find(gc, who); if (f) - yahoo_friend_set_ip(f, tmp2); - g_free(tmp2); + yahoo_friend_set_ip(f, host_ip); + purple_debug_info("yahoo", "IP : %s\n", host_ip); + + account = purple_connection_get_account(gc); + + if(val_11==0) { + if(!f) + return; + else + val_11 = f->session_id; + } + + p2p_data->host_username = g_strdup(who); + p2p_data->val_13 = val_13; + p2p_data->session_id = val_11; + p2p_data->host_ip = host_ip; + p2p_data->gc = gc; + p2p_data->connection_type = YAHOO_P2P_WE_ARE_CLIENT; + + /* connect to host */ + if((purple_proxy_connect(NULL, account, host_ip, YAHOO_PAGER_PORT_P2P, yahoo_p2p_init_cb, p2p_data))==NULL) { + yahoo_p2p_disconnect_destroy_data(p2p_data); + purple_debug_info("yahoo","p2p: Connection to %s failed\n", host_ip); + } } } @@ -2368,12 +2944,12 @@ yahoo_process_status(gc, pkt); break; case YAHOO_SERVICE_NOTIFY: - yahoo_process_notify(gc, pkt); + yahoo_process_notify(gc, pkt, YAHOO_PKT_TYPE_SERVER); break; case YAHOO_SERVICE_MESSAGE: case YAHOO_SERVICE_GAMEMSG: case YAHOO_SERVICE_CHATMSG: - yahoo_process_message(gc, pkt); + yahoo_process_message(gc, pkt, YAHOO_PKT_TYPE_SERVER); break; case YAHOO_SERVICE_SYSMESSAGE: yahoo_process_sysmessage(gc, pkt); @@ -2450,7 +3026,8 @@ break; case YAHOO_SERVICE_P2PFILEXFER: /* This case had no break and continued; thus keeping it this way.*/ - yahoo_process_p2pfilexfer(gc, pkt); + yahoo_process_p2p(gc, pkt); /* P2PFILEXFER handled the same way as process_p2p */ + yahoo_process_p2pfilexfer(gc, pkt); /* redundant ??, need to have a break now */ case YAHOO_SERVICE_FILETRANSFER: yahoo_process_filetransfer(gc, pkt); break; @@ -2484,6 +3061,9 @@ case YAHOO_SERVICE_FILETRANS_ACC_15: yahoo_process_filetrans_acc_15(gc, pkt); break; + case YAHOO_SERVICE_SMS_MSG: + yahoo_process_sms_message(gc, pkt); + break; default: purple_debug(PURPLE_DEBUG_ERROR, "yahoo", @@ -3005,6 +3585,9 @@ yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free); yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); + yd->peers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_p2p_disconnect_destroy_data); + yd->sms_carrier = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + yd->yahoo_p2p_timer = purple_timeout_add_seconds(YAHOO_P2P_KEEPALIVE_SECS, yahoo_p2p_keepalive, gc); yd->confs = NULL; yd->conf_id = 2; yd->last_keepalive = yd->last_ping = time(NULL); @@ -3070,6 +3653,17 @@ if (yd->in_chat) yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */ + purple_timeout_remove(yd->yahoo_p2p_timer); + if(yd->yahoo_p2p_server_timeout_handle != 0) + purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle); + + /* close p2p server if it is waiting for a peer to connect */ + purple_input_remove(yd->yahoo_p2p_server_watcher); + close(yd->yahoo_local_p2p_server_fd); + yd->yahoo_local_p2p_server_fd = -1; + + g_hash_table_destroy(yd->sms_carrier); + g_hash_table_destroy(yd->peers); g_hash_table_destroy(yd->friends); g_hash_table_destroy(yd->imvironments); g_hash_table_destroy(yd->xfer_peer_idstring_map); @@ -3609,22 +4203,195 @@ return m; } +struct yahoo_sms_carrier_cb_data { + PurpleConnection *gc; + char *who; + char *what; +}; + +static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags); + +static void yahoo_get_sms_carrier_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, + const gchar *webdata, size_t len, const gchar *error_message) +{ + struct yahoo_sms_carrier_cb_data *sms_cb_data = user_data; + PurpleConnection *gc = sms_cb_data->gc; + struct yahoo_data *yd = gc->proto_data; + char *mobile_no = NULL; + char *status = NULL; + char *carrier = NULL; + PurpleAccount *account = purple_connection_get_account(gc); + PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account); + + if (error_message != NULL) { + purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL)); + + g_free(sms_cb_data->who); + g_free(sms_cb_data->what); + g_free(sms_cb_data); + return ; + } + else if (len > 0 && webdata && *webdata) { + xmlnode *validate_data_root = xmlnode_from_str(webdata, -1); + xmlnode *validate_data_child = xmlnode_get_child(validate_data_root, "mobile_no"); + mobile_no = (char *)xmlnode_get_attrib(validate_data_child, "msisdn"); + + validate_data_root = xmlnode_copy(validate_data_child); + validate_data_child = xmlnode_get_child(validate_data_root, "status"); + status = xmlnode_get_data(validate_data_child); + + validate_data_child = xmlnode_get_child(validate_data_root, "carrier"); + carrier = xmlnode_get_data(validate_data_child); + + purple_debug_info("yahoo","SMS validate data: Mobile:%s, Status:%s, Carrier:%s\n", mobile_no, status, carrier); + + if( strcmp(status, "Valid") == 0) { + g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup(carrier)); + yahoo_send_im(sms_cb_data->gc, sms_cb_data->who, sms_cb_data->what, PURPLE_MESSAGE_SEND); + } + else { + g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup("Unknown")); + purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL)); + } + + xmlnode_free(validate_data_child); + xmlnode_free(validate_data_root); + g_free(sms_cb_data->who); + g_free(sms_cb_data->what); + g_free(sms_cb_data); + g_free(mobile_no); + g_free(status); + g_free(carrier); + } +} + +static void yahoo_get_sms_carrier(PurpleConnection *gc, gpointer data) +{ + struct yahoo_data *yd = gc->proto_data; + PurpleUtilFetchUrlData *url_data; + struct yahoo_sms_carrier_cb_data *sms_cb_data; + char *validate_request_str = NULL; + char *request = NULL; + gboolean use_whole_url = FALSE; + xmlnode *validate_request_root = NULL; + xmlnode *validate_request_child = NULL; + + if(!(sms_cb_data = data)) + return; + + validate_request_root = xmlnode_new("validate"); + xmlnode_set_attrib(validate_request_root, "intl", "us"); + xmlnode_set_attrib(validate_request_root, "version", YAHOO_CLIENT_VERSION); + xmlnode_set_attrib(validate_request_root, "qos", "0"); + + validate_request_child = xmlnode_new_child(validate_request_root, "mobile_no"); + xmlnode_set_attrib(validate_request_child, "msisdn", sms_cb_data->who + 1); + + validate_request_str = xmlnode_to_str(validate_request_root, NULL); + + xmlnode_free(validate_request_child); + xmlnode_free(validate_request_root); + + request = g_strdup_printf( + "POST /mobileno?intl=us&version=%s HTTP/1.1\r\n" + "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s; path=/; domain=.yahoo.com;\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n" + "Host: validate.msg.yahoo.com\r\n" + "Content-Length: %d\r\n" + "Cache-Control: no-cache\r\n\r\n%s", + YAHOO_CLIENT_VERSION, yd->cookie_t, yd->cookie_y, strlen(validate_request_str), validate_request_str); + + /* use whole URL if using HTTP Proxy */ + if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) + use_whole_url = TRUE; + + url_data = purple_util_fetch_url_request(YAHOO_SMS_CARRIER_URL, use_whole_url, + "Mozilla/4.0 (compatible; MSIE 5.5)", TRUE, request, FALSE, + yahoo_get_sms_carrier_cb, data); + + g_free(request); + g_free(validate_request_str); + + if (!url_data) { + PurpleAccount *account = purple_connection_get_account(gc); + PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account); + purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(sms_cb_data->who); + g_free(sms_cb_data->what); + g_free(sms_cb_data); + } +} + static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags) { struct yahoo_data *yd = gc->proto_data; - struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0); + struct yahoo_packet *pkt; char *msg = yahoo_html_to_codes(what); char *msg2; gboolean utf8 = TRUE; PurpleWhiteboard *wb; int ret = 1; YahooFriend *f = NULL; + struct yahoo_p2p_data *p2p_data; msg2 = yahoo_string_encode(gc, msg, &utf8); + if( strncmp(who, "+", 1) == 0 ) { + /* we have an sms to be sent */ + gchar *carrier = NULL; + const char *alias = NULL; + PurpleAccount *account = purple_connection_get_account(gc); + PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account); + + carrier = g_hash_table_lookup(yd->sms_carrier, who); + if (!carrier) { + struct yahoo_sms_carrier_cb_data *sms_cb_data; + sms_cb_data = g_malloc(sizeof(struct yahoo_sms_carrier_cb_data)); + sms_cb_data->gc = gc; + sms_cb_data->who = g_malloc(strlen(who)); + sms_cb_data->what = g_malloc(strlen(what)); + strcpy(sms_cb_data->who, who); + strcpy(sms_cb_data->what, what); + + purple_conversation_write(conv, NULL, "Getting mobile carrier to send the sms", PURPLE_MESSAGE_SYSTEM, time(NULL)); + + yahoo_get_sms_carrier(gc, sms_cb_data); + + g_free(msg); + g_free(msg2); + return ret; + } + else if( strcmp(carrier,"Unknown") == 0 ) { + purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL)); + + g_free(msg); + g_free(msg2); + return -1; + } + + alias = purple_account_get_alias(account); + pkt = yahoo_packet_new(YAHOO_SERVICE_SMS_MSG, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, "sssss", + 1, purple_connection_get_display_name(gc), + 69, alias, + 5, who + 1, + 68, carrier, + 14, msg2); + yahoo_packet_send_and_free(pkt, yd); + + g_free(msg); + g_free(msg2); + + return ret; + } + + pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0); yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who); if ((f = yahoo_friend_find(gc, who)) && f->protocol) yahoo_packet_hash_int(pkt, 241, f->protocol); + else + if(strchr(who,'@')) + yahoo_packet_hash_int(pkt, 241, 2); if (utf8) yahoo_packet_hash_str(pkt, 97, "1"); @@ -3663,8 +4430,17 @@ yahoo_packet_hash_str(pkt, 206, "2"); /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */ - if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) - yahoo_packet_send(pkt, yd); + if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) { + /* if p2p link exists, send through it. To-do: key 15, time value to be sent in case of p2p */ + if( (p2p_data = g_hash_table_lookup(yd->peers, who)) ) { + yahoo_packet_hash_int(pkt, 11, p2p_data->session_id); + yahoo_p2p_write_pkt(p2p_data->source, pkt); + } + else { + yahoo_packet_send(pkt, yd); + yahoo_send_p2p_pkt(gc, who, 0); /* send p2p packet, with val_13=0 */ + } + } else ret = -E2BIG; @@ -3679,12 +4455,28 @@ static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state) { struct yahoo_data *yd = gc->proto_data; + struct yahoo_p2p_data *p2p_data; + struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0); - yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc), + + /* Don't do anything if sms is being typed */ + if( strncmp(who, "+", 1) == 0 ) + return 0; + + /* check to see if p2p link exists, send through it */ + if( (p2p_data = g_hash_table_lookup(yd->peers, who)) ) { + yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc), + 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", + 5, who, 11, p2p_data->session_id, 1002, "1"); /* To-do: key 15 to be sent in case of p2p */ + yahoo_p2p_write_pkt(p2p_data->source, pkt); + yahoo_packet_free(pkt); + } + else { /* send through yahoo server */ + yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc), 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", 5, who, 1002, "1"); - - yahoo_packet_send_and_free(pkt, yd); + yahoo_packet_send_and_free(pkt, yd); + } return 0; } @@ -3935,18 +4727,36 @@ group2 = yahoo_string_encode(gc, group, NULL); pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0); - yahoo_packet_hash(pkt, "ssssssssss", - 14, "", - 65, group2, - 97, "1", - 1, purple_connection_get_display_name(gc), - 302, "319", - 300, "319", - 7, buddy->name, - 334, "0", - 301, "319", - 303, "319" - ); + if(strchr(buddy->name, '@')) { + yahoo_packet_hash(pkt, "sssssssssss", + 14, "", + 65, group2, + 97, "1", + 1, purple_connection_get_display_name(gc), + 302, "319", + 300, "319", + 7, buddy->name, + 241, "2", + 334, "0", + 301, "319", + 303, "319" + ); + } + else { + yahoo_packet_hash(pkt, "ssssssssss", + 14, "", + 65, group2, + 97, "1", + 1, purple_connection_get_display_name(gc), + 302, "319", + 300, "319", + 7, buddy->name, + 334, "0", + 301, "319", + 303, "319" + ); + } + if (f && f->protocol) yahoo_packet_hash_int(pkt, 241, f->protocol); yahoo_packet_send_and_free(pkt, yd); @@ -3961,8 +4771,9 @@ PurpleGroup *g; gboolean remove = TRUE; char *cg; - - if (!(yahoo_friend_find(gc, buddy->name))) + YahooFriend *f = yahoo_friend_find(gc, buddy->name); + + if (!f) return; buddies = purple_find_buddies(purple_connection_get_account(gc), buddy->name); @@ -3983,6 +4794,8 @@ pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0); yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, buddy->name, 65, cg); + if(f->protocol) + yahoo_packet_hash_int(pkt, 241, f->protocol); yahoo_packet_send_and_free(pkt, yd); g_free(cg); } @@ -4055,11 +4868,12 @@ struct yahoo_data *yd = gc->proto_data; struct yahoo_packet *pkt; char *gpn, *gpo; + YahooFriend *f = yahoo_friend_find(gc, who); /* Step 0: If they aren't on the server list anyway, * don't bother letting the server know. */ - if (!yahoo_friend_find(gc, who)) + if (!f) return; /* If old and new are the same, we would probably @@ -4075,7 +4889,12 @@ } pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0); - yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc), + if(f->protocol) + yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc), + 302, "240", 300, "240", 7, who, 241, f->protocol, 224, gpo, 264, gpn, 301, + "240", 303, "240"); + else + yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc), 302, "240", 300, "240", 7, who, 224, gpo, 264, gpn, 301, "240", 303, "240"); yahoo_packet_send_and_free(pkt, yd); @@ -4289,10 +5108,10 @@ purple_conv_send_confirm(conv, message); } } - /*else + /* else **If pidgindialogs_im() was in the core, we could use it here. * It is all purple_request_* based, but I'm not sure it really belongs in the core - pidgindialogs_im();*/ + pidgindialogs_im(); */ return TRUE; } @@ -4306,7 +5125,7 @@ g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat")); serv_join_chat(purple_account_get_connection(acct), params); } - /*else + /* else ** Same as above (except that this would have to be re-written using purple_request_*) pidgin_blist_joinchat_show(); */ @@ -4376,7 +5195,7 @@ yahoo_add_buddy, NULL, /* add_buddies */ yahoo_remove_buddy, - NULL, /*remove_buddies */ + NULL, /* remove_buddies */ NULL, /* add_permit */ yahoo_add_deny, NULL, /* rem_permit */ diff -r eb21f65728c0 -r 3e788c0db3a6 libpurple/protocols/yahoo/yahoo.h --- a/libpurple/protocols/yahoo/yahoo.h Wed Nov 12 10:18:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.h Wed Nov 12 10:23:13 2008 +0000 @@ -30,6 +30,9 @@ #define YAHOO_PAGER_HOST "scs.msg.yahoo.com" #define YAHOO_PAGER_PORT 5050 +#define YAHOO_PAGER_PORT_P2P 5101 +#define YAHOO_P2P_KEEPALIVE_SECS 300 +#define YAHOO_P2P_SERVER_TIMEOUT 10 #define YAHOO_PROFILE_URL "http://profiles.yahoo.com/" #define YAHOO_MAIL_URL "https://login.yahoo.com/config/login?.src=ym" #define YAHOO_XFER_HOST "filetransfer.msg.yahoo.com" @@ -45,7 +48,7 @@ #define YAHOOJP_MAIL_URL "http://mail.yahoo.co.jp/" #define YAHOOJP_XFER_HOST "filetransfer.msg.yahoo.co.jp" #define YAHOOJP_WEBCAM_HOST "wc.yahoo.co.jp" -/*not sure, must test:*/ +/* not sure, must test: */ #define YAHOOJP_XFER_RELAY_HOST "relay.msg.yahoo.co.jp" #define YAHOOJP_XFER_RELAY_PORT 80 #define YAHOOJP_ROOMLIST_URL "http://insider.msg.yahoo.co.jp/ycontent/" @@ -55,6 +58,8 @@ #define WEBMESSENGER_URL "http://login.yahoo.com/config/login?.src=pg" +#define YAHOO_SMS_CARRIER_URL "http://lookup.msg.vip.mud.yahoo.com" + #define YAHOO_PICURL_SETTING "picture_url" #define YAHOO_PICCKSUM_SETTING "picture_checksum" #define YAHOO_PICEXPIRE_SETTING "picture_expire" @@ -80,10 +85,19 @@ #define YAHOOJP_CLIENT_VERSION_ID "524223" #define YAHOOJP_CLIENT_VERSION "7,0,1,1" - /* Index into attention types list. */ #define YAHOO_BUZZ 0 +typedef enum { + YAHOO_PKT_TYPE_SERVER = 0, + YAHOO_PKT_TYPE_P2P +} yahoo_pkt_type; + +typedef enum { + YAHOO_P2P_WE_ARE_CLIENT =0, + YAHOO_P2P_WE_ARE_SERVER +} yahoo_p2p_connection_type; + enum yahoo_status { YAHOO_STATUS_AVAILABLE = 0, YAHOO_STATUS_BRB, @@ -113,6 +127,17 @@ guint watcher; }; +struct yahoo_p2p_data { + PurpleConnection *gc; + char *host_ip; + char *host_username; + int val_13; + guint input_event; + gint source; + int session_id; + yahoo_p2p_connection_type connection_type; +}; + struct _YchtConn; struct yahoo_data { @@ -168,8 +193,8 @@ * for when we lookup people profile or photo information. */ GSList *url_datas; - GHashTable *xfer_peer_idstring_map;/*Hey, i dont know, but putting this HashTable next to friends gives a run time fault...*/ - GSList *cookies;/*contains all cookies, including _y and _t*/ + GHashTable *xfer_peer_idstring_map;/* Hey, i dont know, but putting this HashTable next to friends gives a run time fault... */ + GSList *cookies;/* contains all cookies, including _y and _t */ /** * We may receive a list15 in multiple packets with no prior warning as to how many we'll be getting; @@ -178,6 +203,12 @@ char *current_list15_grp; time_t last_ping; time_t last_keepalive; + GHashTable *peers; /* information about p2p data */ + int yahoo_p2p_timer; + int yahoo_local_p2p_server_fd; + int yahoo_p2p_server_watcher; + GHashTable *sms_carrier; /* sms carrier data */ + guint yahoo_p2p_server_timeout_handle; }; #define YAHOO_MAX_STATUS_MESSAGE_LENGTH (255) @@ -250,4 +281,7 @@ gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type); GList *yahoo_attention_types(PurpleAccount *account); +/* send p2p pkt containing our encoded ip, asking peer to connect to us */ +void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13); + #endif /* _YAHOO_H_ */ diff -r eb21f65728c0 -r 3e788c0db3a6 libpurple/protocols/yahoo/yahoo_packet.h --- a/libpurple/protocols/yahoo/yahoo_packet.h Wed Nov 12 10:18:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_packet.h Wed Nov 12 10:23:13 2008 +0000 @@ -98,15 +98,18 @@ YAHOO_SERVICE_AVATAR_UPDATE = 0xc7, YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8, YAHOO_SERVICE_AUDIBLE = 0xd0, + /* YAHOO_SERVICE_CHAT_SESSION = 0xd4,?? Reports start of chat session, gets an id from server */ YAHOO_SERVICE_AUTH_REQ_15 = 0xd6, + YAHOO_SERVICE_FILETRANS_15 = 0xdc, + YAHOO_SERVICE_FILETRANS_INFO_15 = 0xdd, + YAHOO_SERVICE_FILETRANS_ACC_15 = 0xde, + /* photo sharing services ?? - 0xd2, 0xd7, 0xd8, 0xda */ YAHOO_SERVICE_CHGRP_15 = 0xe7, YAHOO_SERVICE_STATUS_15 = 0xf0, YAHOO_SERVICE_LIST_15 = 0xf1, - YAHOO_SERVICE_FILETRANS_15 = 0xdc, - YAHOO_SERVICE_FILETRANS_INFO_15 = 0xdd, - YAHOO_SERVICE_FILETRANS_ACC_15 = 0xde, YAHOO_SERVICE_WEBLOGIN = 0x0226, YAHOO_SERVICE_SMS_MSG = 0x02ea + /* YAHOO_SERVICE_DISCONNECT = 0x07d1 Server forces us to disconnect. Is sent with TCP FIN flag set */ }; struct yahoo_pair {