Mercurial > pidgin
changeset 26172:7114d475a9e7
propagate from branch 'im.pidgin.pidgin' (head aa9e255d8e32921a2fe4e6bd74fe36d1ffdc9ec1)
to branch 'im.pidgin.soc.2008.yahoo' (head 9aa024e38a2c67dd29dd2007e9af7a849c90fb26)
author | Sulabh Mahajan <sulabh@soc.pidgin.im> |
---|---|
date | Sun, 08 Mar 2009 06:24:15 +0000 |
parents | bfaed4d103b4 (diff) c0115655a94e (current diff) |
children | 53b04369fb10 |
files | .todo COPYRIGHT libpurple/protocols/jabber/si.h libpurple/protocols/yahoo/yahoo.c |
diffstat | 8 files changed, 1562 insertions(+), 180 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Sat Mar 07 21:05:23 2009 +0000 +++ b/COPYRIGHT Sun Mar 08 06:24:15 2009 +0000 @@ -262,6 +262,7 @@ Lucio Maciel Brian Macke Paolo Maggi +Sulabh Mahajan Willian T. Mahan Kris Marsh Fidel Martinez
--- a/libpurple/ft.c Sat Mar 07 21:05:23 2009 +0000 +++ b/libpurple/ft.c Sun Mar 08 06:24:15 2009 +0000 @@ -857,8 +857,12 @@ else s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size); - if (xfer->ops.read != NULL) + if (xfer->ops.read != NULL) { r = (xfer->ops.read)(buffer, xfer); + if ((purple_xfer_get_size(xfer) > 0) && + ((purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer))) + purple_xfer_set_completed(xfer, TRUE); + } else { *buffer = g_malloc0(s);
--- a/libpurple/protocols/yahoo/yahoo.c Sat Mar 07 21:05:23 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Sun Mar 08 06:24:15 2009 +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" @@ -153,6 +155,7 @@ char *name = NULL; gboolean unicode = FALSE; char *message = NULL; + char *msn_name = NULL; if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { if (!purple_account_get_remember_password(account)) @@ -235,6 +238,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; @@ -350,7 +355,12 @@ if(f && strtol(pair->value, NULL, 10)) f->version_id = strtol(pair->value, NULL, 10); break; - + case 241: /* protocol buddy belongs to */ + if(strtol(pair->value, NULL, 10) == 2) { + msn_name = g_strconcat("msn/", name, NULL); + name = msn_name; + } + break; default: purple_debug_warning("yahoo", "Unknown status key %d\n", pair->key); @@ -472,10 +482,13 @@ struct yahoo_data *yd = gc->proto_data; GHashTable *ht; char *norm_bud = NULL; + char *temp = NULL; YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */ /* But what if you had no friends? */ PurpleBuddy *b; PurpleGroup *g; + int protocol = 0; + int stealth = 0; ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free); @@ -499,6 +512,48 @@ break; case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */ + if(temp != NULL) { + if(protocol == 2) + norm_bud = g_strconcat("msn/", temp, NULL); + else + norm_bud = g_strdup(temp); + + if (yd->current_list15_grp) { + /* This buddy is in a group */ + f = yahoo_friend_find_or_new(gc, norm_bud); + if (!(b = purple_find_buddy(account, norm_bud))) { + if (!(g = purple_find_group(yd->current_list15_grp))) { + g = purple_group_new(yd->current_list15_grp); + purple_blist_add_group(g, NULL); + } + b = purple_buddy_new(account, norm_bud, NULL); + purple_blist_add_buddy(b, NULL, g, NULL); + } + yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp); + if(protocol != 0) { + f->protocol = protocol; + purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol); + } + if(stealth == 2) + f->presence = YAHOO_PRESENCE_PERM_OFFLINE; + + /* set p2p status not connected and no p2p packet sent */ + if(protocol == 0) { + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); + f->p2p_packet_sent = 0; + } else + yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT); + } else { + /* This buddy is on the ignore list (and therefore in no group) */ + purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n",account->username, norm_bud); + purple_privacy_deny_add(account, norm_bud, 1); + } + + protocol = 0; + stealth = 0; + norm_bud = NULL; + temp = NULL; + } break; case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */ break; @@ -507,42 +562,16 @@ yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE); break; case 7: /* buddy's s/n */ - g_free(norm_bud); - norm_bud = g_strdup(purple_normalize(account, pair->value)); - - if (yd->current_list15_grp) { - /* This buddy is in a group */ - f = yahoo_friend_find_or_new(gc, norm_bud); - if (!(b = purple_find_buddy(account, norm_bud))) { - if (!(g = purple_find_group(yd->current_list15_grp))) { - g = purple_group_new(yd->current_list15_grp); - purple_blist_add_group(g, NULL); - } - b = purple_buddy_new(account, norm_bud, NULL); - purple_blist_add_buddy(b, NULL, g, NULL); - } - yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp); - - } else { - /* This buddy is on the ignore list (and therefore in no group) */ - purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n", - account->username, norm_bud); - purple_privacy_deny_add(account, norm_bud, 1); - } + temp = g_strdup(purple_normalize(account, pair->value)); break; case 241: /* another protocol user */ - if (f) { - f->protocol = strtol(pair->value, NULL, 10); - purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol); - } + protocol = strtol(pair->value, NULL, 10); break; case 59: /* somebody told cookies come here too, but im not sure */ yahoo_process_cookie(yd, pair->value); break; case 317: /* Stealth Setting */ - if (f && (strtol(pair->value, NULL, 10) == 2)) { - f->presence = YAHOO_PRESENCE_PERM_OFFLINE; - } + stealth = strtol(pair->value, NULL, 10); break; /* case 242: */ /* this seems related to 241 */ /* break; */ @@ -552,6 +581,7 @@ g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL); g_hash_table_destroy(ht); g_free(norm_bud); + g_free(temp); } static void yahoo_process_list(PurpleConnection *gc, struct yahoo_packet *pkt) @@ -636,6 +666,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); @@ -692,7 +726,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; @@ -701,12 +736,16 @@ char *game = NULL; YahooFriend *f = NULL; GSList *l = pkt->hash; + gint val_11 = 0; + struct yahoo_data *yd = gc->proto_data; + gboolean msn = FALSE; + char *msn_from = NULL; 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; @@ -714,19 +753,43 @@ stat = pair->value; if (pair->key == 14) game = pair->value; + if (pair->key == 11) + val_11 = strtol(pair->value, NULL, 10); + if (pair->key == 241) + if(strtol(pair->value, NULL, 10) == 2) + msn = TRUE; 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(msn) + msn_from = g_strconcat("msn/", from, NULL); + if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING")) && (purple_privacy_check(account, from))) { - if (*stat == '1') - serv_got_typing(gc, from, 0, PURPLE_TYPING); - else - serv_got_typing_stopped(gc, from); + if(msn) { + if (*stat == '1') + serv_got_typing(gc, msn_from, 0, PURPLE_TYPING); + else + serv_got_typing_stopped(gc, msn_from); + } + else { + if (*stat == '1') + serv_got_typing(gc, from, 0, PURPLE_TYPING); + else + serv_got_typing_stopped(gc, from); + } } else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) { PurpleBuddy *bud = purple_find_buddy(account, from); @@ -754,6 +817,7 @@ g_free(buf); } + g_free(msn_from); } @@ -765,7 +829,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; @@ -773,13 +899,17 @@ GSList *list = NULL; struct _yahoo_im *im = NULL; const char *imv = NULL; + gint val_11 = 0; + gboolean msn = FALSE; + char *msn_from = NULL; 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; @@ -799,6 +929,15 @@ if (im) im->msg = pair->value; } + if (pair->key == 241) { + if(strtol(pair->value, NULL, 10) == 2) + msn = TRUE; + } + /* peer session id */ + if (pair->key == 11) { + if (im) + val_11 = strtol(pair->value, NULL, 10); + } /* IMV key */ if (pair->key == 63) { @@ -811,6 +950,17 @@ _("Your Yahoo! message did not get sent."), NULL); } + if(msn) + msn_from = g_strconcat("msn/", im->from, 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) @@ -847,6 +997,7 @@ for (l = list; l; l = l->next) { YahooFriend *f; char *m, *m2; + PurpleConversation *c; im = l->data; if (!im->from || !im->msg) { @@ -869,35 +1020,54 @@ m = m2; purple_util_chrreplace(m, '\r', '\n'); + c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->from, account); + if ((c == NULL) && msn) + c=purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, msn_from, account); + if (!strcmp(m, "<ding>")) { - PurpleConversation *c; char *username; - c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->from, account); - if (c == NULL) - c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, im->from); - - username = g_markup_escape_text(im->from, -1); + if(c == NULL) { + if(msn) + c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, msn_from); + else + c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, im->from); + } + if(msn) + username = g_markup_escape_text(msn_from, -1); + else + username = g_markup_escape_text(im->from, -1); + purple_prpl_got_attention(gc, username, YAHOO_BUZZ); g_free(username); g_free(m); g_free(im); + g_free(msn_from); continue; } m2 = yahoo_codes_to_html(m); g_free(m); - serv_got_im(gc, im->from, m2, 0, im->time); + + if(msn) + serv_got_im(gc, msn_from, m2, 0, im->time); + else + serv_got_im(gc, im->from, m2, 0, im->time); + g_free(m2); - if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) { - if (yahoo_friend_get_buddy_icon_need_request(f)) { - yahoo_send_picture_request(gc, im->from); - yahoo_friend_set_buddy_icon_need_request(f, FALSE); + /* laters : implement buddy icon for msn friends */ + if(!msn) { + if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) { + if (yahoo_friend_get_buddy_icon_need_request(f)) { + yahoo_send_picture_request(gc, im->from); + yahoo_friend_set_buddy_icon_need_request(f, FALSE); + } } } g_free(im); + g_free(msn_from); } g_slist_free(list); } @@ -1030,12 +1200,14 @@ PurpleAccount *account; GSList *l = pkt->hash; const char *msg = NULL; + int protocol = 0; account = purple_connection_get_account(gc); /* Buddy authorized/declined our addition */ if (pkt->status == 1) { - const char *who = NULL; + char *temp = NULL; + char *who = NULL; int response = 0; while (l) { @@ -1043,7 +1215,7 @@ switch (pair->key) { case 4: - who = pair->value; + temp = pair->value; break; case 13: response = strtol(pair->value, NULL, 10); @@ -1051,10 +1223,18 @@ case 14: msg = pair->value; break; + case 241: + protocol = strtol(pair->value, NULL, 10); + break; } l = l->next; } + if(protocol == 0) + who = g_strdup(temp); + else if(protocol == 2) + who = g_strconcat("msn/", temp, NULL); + if (response == 1) /* Authorized */ purple_debug_info("yahoo", "Received authorization from buddy '%s'.\n", who ? who : "(Unknown Buddy)"); else if (response == 2) { /* Declined */ @@ -1062,12 +1242,13 @@ yahoo_buddy_denied_our_add(gc, who, msg); } else purple_debug_error("yahoo", "Received unknown authorization response of %d from buddy '%s'.\n", response, who ? who : "(Unknown Buddy)"); - + g_free(who); } /* Buddy requested authorization to add us. */ else if (pkt->status == 3) { struct yahoo_add_request *add_req; const char *firstname = NULL, *lastname = NULL; + char *temp = NULL; add_req = g_new0(struct yahoo_add_request, 1); add_req->gc = gc; @@ -1077,6 +1258,7 @@ switch (pair->key) { case 4: + temp = pair->value; add_req->who = g_strdup(pair->value); break; case 5: @@ -1098,6 +1280,10 @@ } l = l->next; } + if(add_req->protocol == 2) + add_req->who = g_strconcat("msn/", temp, NULL); + else + add_req->who = g_strdup(temp); if (add_req->id && add_req->who) { char *alias = NULL, *dec_msg = NULL; @@ -2191,11 +2377,15 @@ { int err = 0; char *who = NULL; + char *temp = NULL; char *group = NULL; char *decoded_group; char *buf; YahooFriend *f; GSList *l = pkt->hash; + struct yahoo_data *yd = gc->proto_data; + int protocol = 0; + gboolean msn = FALSE; while (l) { struct yahoo_pair *pair = l->data; @@ -2205,24 +2395,48 @@ err = strtol(pair->value, NULL, 10); break; case 7: - who = pair->value; + temp = pair->value; break; case 65: group = pair->value; break; + case 241: + protocol = strtol(pair->value, NULL, 10); + if(protocol == 2) + msn = TRUE; + break; } l = l->next; } - if (!who) + if (!temp) return; if (!group) group = ""; + + if(msn) + who = g_strconcat("msn/", temp, NULL); + else + who = g_strdup(temp); 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 */ + if(msn) + yahoo_friend_set_p2p_status(f,YAHOO_P2PSTATUS_DO_NOT_CONNECT); + else { + 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; } @@ -2233,6 +2447,431 @@ purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf); g_free(buf); g_free(decoded_group); + g_free(who); +} + +/* 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 timeout */ + purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle); + yd->yahoo_p2p_server_timeout_handle = 0; + + /* 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) @@ -2242,6 +2881,14 @@ char *base64 = NULL; guchar *decoded; gsize len; + gint val_13 = 0; + gint val_11 = 0; + PurpleAccount *account; + YahooFriend *f; + + /* if status is not 1 ie YAHOO_STATUS_BRB, the packet bounced back, so contains our own ip */ + if(!(pkt->status == YAHOO_STATUS_BRB)) + return ; while (l) { struct yahoo_pair *pair = l->data; @@ -2261,14 +2908,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 */ } @@ -2280,6 +2934,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) { @@ -2292,12 +2948,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); + } } } @@ -2377,12 +3055,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); @@ -2459,7 +3137,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; @@ -2493,6 +3172,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", @@ -3008,6 +3690,7 @@ purple_connection_set_display_name(gc, purple_account_get_username(account)); + yd->yahoo_local_p2p_server_fd = -1; yd->fd = -1; yd->txhandler = 0; /* TODO: Is there a good grow size for the buffer? */ @@ -3015,6 +3698,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); @@ -3080,6 +3766,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); @@ -3625,10 +4322,129 @@ 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 = NULL; char *msg = yahoo_html_to_codes(what); char *msg2; gboolean utf8 = TRUE; @@ -3637,7 +4453,8 @@ YahooFriend *f = NULL; gsize lenb = 0; glong lenc = 0; - + struct yahoo_p2p_data *p2p_data; + gboolean msn = FALSE; msg2 = yahoo_string_encode(gc, msg, &utf8); if(msg2) { @@ -3656,9 +4473,67 @@ } } - 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); + msn = g_str_has_prefix(who, "msn/") || g_str_has_prefix(who, "MSN/"); + + 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); + if(msn) { + yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who+4); + yahoo_packet_hash_int(pkt, 241, 2); + } + else { + 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); + } if (utf8) yahoo_packet_hash_str(pkt, 97, "1"); @@ -3697,8 +4572,18 @@ 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)) && !msn ) { + yahoo_packet_hash_int(pkt, 11, p2p_data->session_id); + yahoo_p2p_write_pkt(p2p_data->source, pkt); + } + else { + yahoo_packet_send(pkt, yd); + if(!msn) + yahoo_send_p2p_pkt(gc, who, 0); /* send p2p packet, with val_13=0 */ + } + } else ret = -E2BIG; @@ -3713,12 +4598,35 @@ static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state) { struct yahoo_data *yd = gc->proto_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), + struct yahoo_p2p_data *p2p_data; + gboolean msn = (g_str_has_prefix(who, "msn/") || g_str_has_prefix(who, "MSN/")); + struct yahoo_packet *pkt = NULL; + + /* Don't do anything if sms is being typed */ + if( strncmp(who, "+", 1) == 0 ) + return 0; + + pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0); + + /* check to see if p2p link exists, send through it */ + if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) { + yahoo_packet_hash(pkt, "sssssis", 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); + 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 */ + if(msn) + yahoo_packet_hash(pkt, "sssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc), + 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", + 5, who+4, 1002, "1", 241, "2"); + else + yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc), + 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", + 5, who+4, 1002, "1"); + yahoo_packet_send_and_free(pkt, yd); + } return 0; } @@ -3952,6 +4860,7 @@ char *group2; YahooFriend *f; const char *bname; + gboolean msn = FALSE; if (!yd->logged_in) return; @@ -3961,6 +4870,7 @@ return; f = yahoo_friend_find(gc, bname); + msn = g_str_has_prefix(bname, "msn/") || g_str_has_prefix(bname, "MSN/"); g = purple_buddy_get_group(buddy); if (g) @@ -3970,20 +4880,38 @@ 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, bname, - 334, "0", - 301, "319", - 303, "319" - ); - if (f && f->protocol) + if(msn) { + yahoo_packet_hash(pkt, "sssssssssss", + 14, "", + 65, group2, + 97, "1", + 1, purple_connection_get_display_name(gc), + 302, "319", + 300, "319", + 7, bname + 4, + 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, bname, + 334, "0", + 301, "319", + 303, "319" + ); + } + if (f && f->protocol && !msn) yahoo_packet_hash_int(pkt, 241, f->protocol); + yahoo_packet_send_and_free(pkt, yd); g_free(group2); } @@ -3997,13 +4925,18 @@ gboolean remove = TRUE; char *cg; const char *bname, *gname; + YahooFriend *f = NULL; + gboolean msn = FALSE; bname = purple_buddy_get_name(buddy); - if (!(yahoo_friend_find(gc, bname))) + f = yahoo_friend_find(gc, bname); + if (!f) return; gname = purple_group_get_name(group); buddies = purple_find_buddies(purple_connection_get_account(gc), bname); + if(f->protocol == 2) + msn = TRUE; for (l = buddies; l; l = l->next) { g = purple_buddy_get_group(l->data); if (purple_utf8_strcasecmp(gname, purple_group_get_name(g))) { @@ -4019,8 +4952,15 @@ cg = yahoo_string_encode(gc, gname, NULL); pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0); - yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), + + if(msn) + yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), + 7, bname+4, 65, cg); + else + yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, bname, 65, cg); + if(f->protocol) + yahoo_packet_hash_int(pkt, 241, f->protocol); yahoo_packet_send_and_free(pkt, yd); g_free(cg); } @@ -4093,13 +5033,22 @@ struct yahoo_data *yd = gc->proto_data; struct yahoo_packet *pkt; char *gpn, *gpo; + YahooFriend *f = yahoo_friend_find(gc, who); + gboolean msn = FALSE; + const char *temp = NULL; /* 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(f->protocol == 2) { + msn = TRUE; + temp = who+4; + } else + temp = who; + /* If old and new are the same, we would probably * end up deleting the buddy, which would be bad. * This might happen because of the charset conversation. @@ -4113,8 +5062,13 @@ } pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0); - yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc), - 302, "240", 300, "240", 7, who, 224, gpo, 264, gpn, 301, + if(f->protocol) + yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc), + 302, "240", 300, "240", 7, temp, 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, temp, 224, gpo, 264, gpn, 301, "240", 303, "240"); yahoo_packet_send_and_free(pkt, yd); @@ -4326,10 +5280,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; } @@ -4343,7 +5297,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(); */ @@ -4413,7 +5367,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 */
--- a/libpurple/protocols/yahoo/yahoo.h Sat Mar 07 21:05:23 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo.h Sun Mar 08 06:24:15 2009 +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) @@ -265,4 +296,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_ */
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c Sat Mar 07 21:05:23 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Sun Mar 08 06:24:15 2009 +0000 @@ -26,6 +26,7 @@ #include "prpl.h" #include "util.h" #include "debug.h" +#include "network.h" #include "notify.h" #include "proxy.h" #include "ft.h" @@ -50,7 +51,7 @@ guint rxlen; gchar *xfer_peer_idstring; gchar *xfer_idstring_for_relay; - int version; /*0 for old, 15 for Y7(YMSG 15)*/ + int version; /* 0 for old, 15 for Y7(YMSG 15) */ int info_val_249; enum { @@ -58,14 +59,22 @@ HEAD_REQUESTED, HEAD_REPLY_RECEIVED, TRANSFER_PHASE, - ACCEPTED + ACCEPTED, + P2P_HEAD_REQUESTED, + P2P_HEAD_REPLIED, + P2P_GET_REQUESTED } status_15; /* contains all filenames, in case of multiple transfers, with the first * one in the list being the current file's name (ymsg15) */ GSList *filename_list; - GSList *size_list; /*corresponds to filename_list, with size as **STRING** */ + GSList *size_list; /* corresponds to filename_list, with size as **STRING** */ gboolean firstoflist; + gchar *xfer_url; /* url of the file, used when we are p2p server */ + int yahoo_local_p2p_ft_server_fd; + int yahoo_local_p2p_ft_server_port; + int yahoo_p2p_ft_server_watcher; + int input_event; }; static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd) @@ -78,14 +87,14 @@ gc = xd->gc; yd = gc->proto_data; - /*remove entry from map*/ + /* remove entry from map */ if(xd->xfer_peer_idstring) { xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xd->xfer_peer_idstring); if(xfer) g_hash_table_remove(yd->xfer_peer_idstring_map, xd->xfer_peer_idstring); } - /*empty file & filesize list*/ + /* empty file & filesize list */ for (l = xd->filename_list; l; l = l->next) { g_free(l->data); l->data=NULL; @@ -600,6 +609,26 @@ xfer->data = NULL; } +/* Send HTTP OK after receiving file */ +static void yahoo_p2p_ft_server_send_OK(PurpleXfer *xfer) +{ + char *tx = NULL; + int written; + + tx = g_strdup_printf("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nContent-Type: application/octet-stream\r\nConnection: close\r\n\r\n"); + written = write(xfer->fd, tx, strlen(tx)); + + if (written < 0 && errno == EAGAIN) + written = 0; + else if (written <= 0) + purple_debug_info("yahoo", "p2p filetransfer: Unable to write HTTP OK"); + + /* close connection */ + close(xfer->fd); + xfer->fd = -1; + g_free(tx); +} + static void yahoo_xfer_end(PurpleXfer *xfer_old) { struct yahoo_xfer_data *xfer_data; @@ -611,6 +640,10 @@ if(xfer_data && xfer_data->version == 15 && purple_xfer_get_type(xfer_old) == PURPLE_XFER_RECEIVE && xfer_data->filename_list) { + + /* Send HTTP OK in case of p2p transfer, when we act as server */ + if((xfer_data->xfer_url != NULL) && (xfer_old->fd >=0) && (purple_xfer_get_status(xfer_old) == PURPLE_XFER_STATUS_DONE)) + yahoo_p2p_ft_server_send_OK(xfer_old); /* removing top of filename & size list completely */ g_free( xfer_data->filename_list->data ); @@ -684,7 +717,7 @@ purple_xfer_set_write_fnc(xfer, yahoo_xfer_write); purple_xfer_set_request_denied_fnc(xfer,yahoo_xfer_cancel_recv); - /*update map to current xfer*/ + /* update map to current xfer */ g_hash_table_remove(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring); g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring, xfer); @@ -980,7 +1013,7 @@ return; } - /*TODO:actually, u must try with addr no.1 , if its not working addr no.2 .....*/ + /* TODO:actually, u must try with addr no.1 , if its not working addr no.2 ..... */ addr = hosts->data; actaddr = addr->sin_addr.s_addr; d = actaddr % 256; @@ -1030,30 +1063,24 @@ yahoo_packet_send_and_free(pkt, yd); } - void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file) { struct yahoo_xfer_data *xfer_data; struct yahoo_data *yd = gc->proto_data; - int ver = 0; PurpleXfer *xfer = yahoo_new_xfer(gc, who); - YahooFriend *yf = yahoo_friend_find(gc, who); - - /* To determine if we should use yahoo p15 for transfer. Check other user's - * reported version, but if we're on Yahoo Japan, ignore it. */ - if(yf && yf->version_id > 500000 && !yd->jp) - ver = 15; g_return_if_fail(xfer != NULL); - if(ver == 15) { - xfer_data = xfer->data; - xfer_data->status_15 = STARTED; - purple_xfer_set_init_fnc(xfer, yahoo_xfer_init_15); - xfer_data->version = 15; - xfer_data->xfer_peer_idstring = yahoo_xfer_new_xfer_id(); - g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring, xfer); - } + /* if we don't have a p2p connection, try establishing it now */ + if( !g_hash_table_lookup(yd->peers, who) ) + yahoo_send_p2p_pkt(gc, who, 0); + + xfer_data = xfer->data; + xfer_data->status_15 = STARTED; + purple_xfer_set_init_fnc(xfer, yahoo_xfer_init_15); + xfer_data->version = 15; + xfer_data->xfer_peer_idstring = yahoo_xfer_new_xfer_id(); + g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring, xfer); /* Now perform the request */ if (file) @@ -1062,7 +1089,9 @@ purple_xfer_request(xfer); } -static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message);/*using this in recv_cb*/ +static void yahoo_p2p_ft_server_listen_cb(int listenfd, gpointer data); /* using this in yahoo_xfer_send_cb_15 */ +static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message);/* using this in recv_cb */ + static void yahoo_xfer_recv_cb_15(gpointer data, gint source, PurpleInputCondition condition) { PurpleXfer *xfer; @@ -1102,7 +1131,7 @@ if(xd->status_15 == HEAD_REQUESTED) { xd->status_15 = HEAD_REPLY_RECEIVED; - close(source);/*Is this required?*/ + close(source);/* Is this required? */ g_free(xd->txbuf); xd->txbuf = NULL; if (purple_proxy_connect(NULL, account, xd->host, xd->port, yahoo_xfer_connected_15, xfer) == NULL) @@ -1151,7 +1180,7 @@ xd->txbuf_written = 0; if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == STARTED) - { + { xd->status_15 = HEAD_REQUESTED; xd->tx_handler = purple_input_add(source, PURPLE_INPUT_READ, yahoo_xfer_recv_cb_15, xfer); yahoo_xfer_recv_cb_15(xfer, source, PURPLE_INPUT_READ); @@ -1162,21 +1191,33 @@ xfer->fd = source; purple_xfer_start(xfer, source, NULL, 0); } - else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED) + else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && (xd->status_15 == ACCEPTED || xd->status_15 == P2P_GET_REQUESTED) ) { xd->status_15 = TRANSFER_PHASE; xfer->fd = source; + /* Remove Read event */ + purple_input_remove(xd->input_event); + xd->input_event = 0; purple_xfer_start(xfer, source, NULL, 0); } + else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == P2P_HEAD_REQUESTED) + { + xd->status_15 = P2P_HEAD_REPLIED; + /* Remove Read event and close descriptor */ + purple_input_remove(xd->input_event); + xd->input_event = 0; + close(source); + xfer->fd = -1; + /* start local server, listen for connections */ + purple_network_listen(xd->yahoo_local_p2p_ft_server_port, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer); + } else { purple_debug_error("yahoo", "Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n", purple_xfer_get_type(xfer), xd->status_15); return; } - } - static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message) { PurpleXfer *xfer; @@ -1203,31 +1244,61 @@ cookies = yahoo_get_cookies(xd->gc); if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED) { - xd->txbuf = g_strdup_printf("POST /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost: %s\r\nContent-Length: %ld\r\nCache-Control: no-cache\r\n\r\n", + if(xd->info_val_249 == 2) + { + /* sending file via p2p, we are connected as client */ + xd->txbuf = g_strdup_printf("POST /%s HTTP/1.1\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost: %s\r\nContent-Length: %ld\r\nCache-Control: no-cache\r\n\r\n", + xd->path, + xd->host, + (long int)xfer->size); /* to do, add Referer */ + } + else + { + /* sending file via relaying */ + xd->txbuf = g_strdup_printf("POST /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost: %s\r\nContent-Length: %ld\r\nCache-Control: no-cache\r\n\r\n", purple_url_encode(xd->xfer_idstring_for_relay), purple_normalize(account, purple_account_get_username(account)), xfer->who, cookies, xd->host, (long int)xfer->size); + } } else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == STARTED) { - xd->txbuf = g_strdup_printf("HEAD /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nAccept:*/*\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost:%s\r\nContent-Length: 0\r\nCache-Control: no-cache\r\n\r\n", + if(xd->info_val_249 == 1) + { + /* receiving file via p2p, connected as client */ + xd->txbuf = g_strdup_printf("HEAD /%s HTTP/1.1\r\nAccept:*/*\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost: %s\r\nContent-Length: 0\r\nCache-Control: no-cache\r\n\r\n",xd->path,xd->host); + } + else + { + /* receiving file via relaying */ + xd->txbuf = g_strdup_printf("HEAD /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nAccept:*/*\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost:%s\r\nContent-Length: 0\r\nCache-Control: no-cache\r\n\r\n", purple_url_encode(xd->xfer_idstring_for_relay), purple_normalize(account, purple_account_get_username(account)), xfer->who, cookies, xd->host); + } } else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == HEAD_REPLY_RECEIVED) { - xd->txbuf = g_strdup_printf("GET /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost:%s\r\nConnection: Keep-Alive\r\n\r\n", + if(xd->info_val_249 == 1) + { + /* receiving file via p2p, connected as client */ + xd->txbuf = g_strdup_printf("GET /%s HTTP/1.1\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n",xd->path,xd->host); + } + else + { + /* receiving file via relaying */ + xd->txbuf = g_strdup_printf("GET /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost:%s\r\nConnection: Keep-Alive\r\n\r\n", purple_url_encode(xd->xfer_idstring_for_relay), purple_normalize(account, purple_account_get_username(account)), xfer->who, cookies, xd->host); + } } else { @@ -1248,6 +1319,225 @@ } } +static void yahoo_p2p_ft_POST_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + PurpleXfer *xfer; + struct yahoo_xfer_data *xd; + + xfer = data; + if (!(xd = xfer->data)) { + purple_input_remove(xd->input_event); + purple_xfer_cancel_remote(xfer); + return; + } + + purple_input_remove(xd->input_event); + xd->status_15 = TRANSFER_PHASE; + xfer->fd = source; + purple_xfer_start(xfer, source, NULL, 0); +} + +static void yahoo_p2p_ft_HEAD_GET_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + PurpleXfer *xfer; + struct yahoo_xfer_data *xd; + guchar buf[1024]; + int len; + char *url_head; + char *url_get; + time_t unix_time; + char *time_str; + + xfer = data; + if (!(xd = xfer->data)) { + purple_input_remove(xd->input_event); + purple_xfer_cancel_remote(xfer); + return; + } + + 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-ft: Error in connection, or host disconnected\n"); + purple_input_remove(xd->input_event); + purple_xfer_cancel_remote(xfer); + return; + } + + url_head = g_strdup_printf("HEAD %s", xd->xfer_url); + url_get = g_strdup_printf("GET %s", xd->xfer_url); + + if( strncmp(url_head, (char *)buf, strlen(url_head)) == 0 ) + xd->status_15 = P2P_HEAD_REQUESTED; + else if( strncmp(url_get, (char *)buf, strlen(url_get)) == 0 ) + xd->status_15 = P2P_GET_REQUESTED; + else { + purple_debug_warning("yahoo","p2p-ft: Wrong HEAD/GET request from peer, disconnecting host\n"); + purple_input_remove(xd->input_event); + purple_xfer_cancel_remote(xfer); + g_free(url_head); + return; + } + + unix_time = time(NULL); + time_str = ctime(&unix_time); + strcpy(time_str + strlen(time_str) - 1, "\0"); + + if (xd->txbuflen == 0) { + xd->txbuf = g_strdup_printf("HTTP/1.0 200 OK\r\nDate: %s GMT\r\nServer: Y!/1.0\r\nMIME-version: 1.0\r\nLast-modified: %s GMT\r\nContent-length: %d\r\n\r\n", time_str, time_str, xfer->size); + xd->txbuflen = strlen(xd->txbuf); + xd->txbuf_written = 0; + } + + if (!xd->tx_handler) { + xd->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, yahoo_xfer_send_cb_15, xfer); + yahoo_xfer_send_cb_15(xfer, source, PURPLE_INPUT_WRITE); + } + + g_free(url_head); + g_free(url_get); +} + +static void yahoo_p2p_ft_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + int acceptfd; + PurpleXfer *xfer; + struct yahoo_xfer_data *xd; + + xfer = data; + if (!(xd = xfer->data)) { + purple_xfer_cancel_remote(xfer); + return; + } + + 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)); + purple_xfer_cancel_remote(xfer); + /* remove watcher and close p2p ft server */ + purple_input_remove(xd->yahoo_p2p_ft_server_watcher); + close(xd->yahoo_local_p2p_ft_server_fd); + return; + } + + /* remove watcher and close p2p ft server */ + purple_input_remove(xd->yahoo_p2p_ft_server_watcher); + close(xd->yahoo_local_p2p_ft_server_fd); + + /* Add an Input Read event to the file descriptor */ + xfer->fd = acceptfd; + if(xfer->type == PURPLE_XFER_RECEIVE) + xd->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_ft_POST_cb, data); + else + xd->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_ft_HEAD_GET_cb, data); +} + +static void yahoo_p2p_ft_server_listen_cb(int listenfd, gpointer data) +{ + PurpleXfer *xfer; + struct yahoo_xfer_data *xd; + struct yahoo_packet *pkt; + PurpleAccount *account; + struct yahoo_data *yd; + gchar *filename; + const char *local_ip; + gchar *url_to_send = NULL; + char *filename_without_spaces = NULL; + + xfer = data; + if ( !( (xd = xfer->data) || (listenfd != -1) ) ) { + purple_debug_warning("yahoo","p2p: error starting server for p2p file transfer\n"); + purple_xfer_cancel_remote(xfer); + return; + } + + if( (xfer->type == PURPLE_XFER_RECEIVE) || (xd->status_15 != P2P_HEAD_REPLIED) ) { + yd = xd->gc->proto_data; + account = purple_connection_get_account(xd->gc); + local_ip = purple_network_get_my_ip(listenfd); + xd->yahoo_local_p2p_ft_server_port = purple_network_get_port_from_fd(listenfd); + + filename = g_path_get_basename(purple_xfer_get_local_filename(xfer)); + filename_without_spaces = g_strdup(filename); + purple_util_chrreplace(filename_without_spaces, ' ', '+'); + xd->xfer_url = g_strdup_printf("/Messenger.%s.%d000%s?AppID=Messenger&UserID=%s&K=lc9lu2u89gz1llmplwksajkjx", xfer->who, (int)time(NULL), filename_without_spaces, xfer->who); + url_to_send = g_strdup_printf("http://%s:%d%s", local_ip, xd->yahoo_local_p2p_ft_server_port, xd->xfer_url); + + if(xfer->type == PURPLE_XFER_RECEIVE) { + xd->info_val_249 = 2; /* 249=2: we are p2p server, and receiving file */ + pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_ACC_15, + YAHOO_STATUS_AVAILABLE, yd->session_id); + yahoo_packet_hash(pkt, "ssssis", + 1, purple_normalize(account, purple_account_get_username(account)), + 5, xfer->who, + 265, xd->xfer_peer_idstring, + 27, xfer->filename, + 249, 2, + 250, url_to_send); + } + else { + xd->info_val_249 = 1; /* 249=1: we are p2p server, and sending file */ + pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id); + yahoo_packet_hash(pkt, "ssssis", + 1, purple_normalize(account, purple_account_get_username(account)), + 5, xfer->who, + 265, xd->xfer_peer_idstring, + 27, filename, + 249, 1, + 250, url_to_send); + } + + yahoo_packet_send_and_free(pkt, yd); + + g_free(filename); + g_free(url_to_send); + g_free(filename_without_spaces); + } + + /* Add an Input Read event to the file descriptor */ + xd->yahoo_local_p2p_ft_server_fd = listenfd; + xd->yahoo_p2p_ft_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_ft_server_send_connected_cb, data); +} + +/* send (p2p) file transfer information */ +static void yahoo_p2p_client_send_ft_info(PurpleConnection *gc, PurpleXfer *xfer) +{ + struct yahoo_xfer_data *xd; + struct yahoo_packet *pkt; + PurpleAccount *account; + struct yahoo_data *yd; + gchar *filename; + struct yahoo_p2p_data *p2p_data; + + if (!(xd = xfer->data)) + return; + + account = purple_connection_get_account(gc); + yd = gc->proto_data; + + p2p_data = g_hash_table_lookup(yd->peers, xfer->who); + if( p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER ) + if(purple_network_listen_range(0, 0, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer)) + return; + + pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id); + filename = g_path_get_basename(purple_xfer_get_local_filename(xfer)); + + yahoo_packet_hash(pkt, "ssssi", + 1, purple_normalize(account, purple_account_get_username(account)), + 5, xfer->who, + 265, xd->xfer_peer_idstring, + 27, filename, + 249, 2); /* 249=2: we are p2p client */ + xd->info_val_249 = 2; + yahoo_packet_send_and_free(pkt, yd); + + g_free(filename); +} + void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt) { char *from = NULL; @@ -1293,14 +1583,14 @@ /* 1=send, 2=cancel, 3=accept, 4=reject */ break; - /*check for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it.*/ + /* check for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it. */ case 49: service = pair->value; break; case 63: imv = pair->value; break; - /*end check*/ + /* end check */ } } @@ -1328,6 +1618,14 @@ * so, purple dnsquery is used... but retries, trying with next ip * address etc. is not implemented..TODO */ + + /* To send through p2p */ + if( g_hash_table_lookup(yd->peers, from) ) { + /* send p2p file transfer information */ + yahoo_p2p_client_send_ft_info(gc, xfer); + return; + } + if (yd->jp) { purple_dnsquery_a(YAHOOJP_XFER_RELAY_HOST, YAHOOJP_XFER_RELAY_PORT, @@ -1341,7 +1639,7 @@ return; } - /*processing for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it.*/ + /* processing for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it. */ /* * The remote user has changed their IMVironment. We * record it for later use. @@ -1357,7 +1655,7 @@ return; } } - /*end processing*/ + /* end processing */ if(!filename_list) return; @@ -1432,6 +1730,7 @@ GSList *l; struct yahoo_packet *pkt_to_send; PurpleAccount *account; + struct yahoo_p2p_data *p2p_data; yd = gc->proto_data; @@ -1455,13 +1754,8 @@ val_66 = strtol(pair->value, NULL, 10); break; case 249: - val_249 = strtol(pair->value, NULL, 10); /* - * really pissed off with this- i hv seen 2 occurences of this - * being 1(its normally 3) - and in those cases, the url - * format and corresponding processing seems to be different - * (i havent tested - couldnt reproduce a 1), although i - * guess its easier. - */ + val_249 = strtol(pair->value, NULL, 10); + /* 249 has value 1 or 2 when doing p2p transfer and value 3 when relaying through yahoo server */ break; case 250: url = pair->value; @@ -1489,35 +1783,48 @@ xfer_data->info_val_249 = val_249; xfer_data->xfer_idstring_for_relay = g_strdup(xfer_idstring_for_relay); - if (!purple_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL)) { - purple_xfer_cancel_remote(xfer); - return; - } + if(val_249 == 1 || val_249 == 3) { + if (!purple_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL)) { + purple_xfer_cancel_remote(xfer); + return; + } + + account = purple_connection_get_account(xfer_data->gc); - account = purple_connection_get_account(xfer_data->gc); + pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_ACC_15, + YAHOO_STATUS_AVAILABLE, yd->session_id); + yahoo_packet_hash(pkt_to_send, "ssssisi", + 1, purple_normalize(account, purple_account_get_username(account)), + 5, xfer->who, + 265, xfer_data->xfer_peer_idstring, + 27, xfer->filename, + 249, xfer_data->info_val_249, + 251, xfer_data->xfer_idstring_for_relay, + 222, 3); - pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_ACC_15, - YAHOO_STATUS_AVAILABLE, yd->session_id); + yahoo_packet_send_and_free(pkt_to_send, yd); - yahoo_packet_hash(pkt_to_send, "ssssisi", - 1, purple_normalize(account, purple_account_get_username(account)), - 5, xfer->who, - 265, xfer_data->xfer_peer_idstring, - 27, xfer->filename, - 249, xfer_data->info_val_249, - 251, xfer_data->xfer_idstring_for_relay, - 222, 3); + if (purple_proxy_connect(NULL, account, xfer_data->host, xfer_data->port, + yahoo_xfer_connected_15, xfer) == NULL) { + purple_notify_error(gc, NULL, _("File Transfer Failed"), + _("Unable to establish file descriptor.")); + purple_xfer_cancel_remote(xfer); + } + } + else if(val_249 == 2) { + p2p_data = g_hash_table_lookup(yd->peers, xfer->who); + if( !( p2p_data && (p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER) ) ) { + purple_xfer_cancel_remote(xfer); + return; + } + if(!purple_network_listen_range(0, 0, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer)) { + purple_xfer_cancel_remote(xfer); + return; + } + } +} - yahoo_packet_send_and_free(pkt_to_send, yd); - if (purple_proxy_connect(NULL, account, xfer_data->host, xfer_data->port, - yahoo_xfer_connected_15, xfer) == NULL) { - purple_notify_error(gc, NULL, _("File Transfer Failed"), - _("Unable to establish file descriptor.")); - purple_xfer_cancel_remote(xfer); - } - -} -/*TODO: Check filename etc. No probs till some hacker comes in the way*/ +/* TODO: Check filename etc. No probs till some hacker comes in the way */ void yahoo_process_filetrans_acc_15(PurpleConnection *gc, struct yahoo_packet *pkt) { gchar *xfer_peer_idstring = NULL; @@ -1528,6 +1835,8 @@ GSList *l; PurpleAccount *account; long val_66 = 0; + gchar *url = NULL; + int val_249 = 0; yd = gc->proto_data; for (l = pkt->hash; l; l = l->next) { @@ -1542,19 +1851,35 @@ break; case 66: val_66 = atol(pair->value); + break; + case 249: + val_249 = atol(pair->value); + break; + case 250: + url = pair->value; /* we get a p2p url here when sending file, connected as client */ + break; } } xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xfer_peer_idstring); if(!xfer) return; - if(val_66 == -1 || !(xfer_idstring_for_relay)) + if(val_66 == -1 || ( (!(xfer_idstring_for_relay)) && (val_249 != 2) )) + { + purple_xfer_cancel_remote(xfer); + return; + } + + if( (val_249 == 2) && (!(url)) ) { purple_xfer_cancel_remote(xfer); return; } xfer_data = xfer->data; + if(url) + purple_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL); + xfer_data->xfer_idstring_for_relay = g_strdup(xfer_idstring_for_relay); xfer_data->status_15 = ACCEPTED; account = purple_connection_get_account(gc);
--- a/libpurple/protocols/yahoo/yahoo_friend.c Sat Mar 07 21:05:23 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_friend.c Sun Mar 08 06:24:15 2009 +0000 @@ -147,24 +147,36 @@ { GSList *l = pkt->hash; YahooFriend *f; + char *temp = NULL; char *who = NULL; int value = 0; + int protocol = 0; + gboolean msn = FALSE; while (l) { struct yahoo_pair *pair = l->data; switch (pair->key) { case 7: - who = pair->value; + temp = pair->value; break; case 31: value = strtol(pair->value, NULL, 10); break; + case 241: + protocol = strtol(pair->value, NULL, 10); + msn = TRUE; + break; } l = l->next; } + if(msn) + who = g_strconcat("msn/", temp, NULL); + else + who = g_strdup(temp); + if (value != 1 && value != 2) { purple_debug_error("yahoo", "Received unknown value for presence key: %d\n", value); return; @@ -173,8 +185,10 @@ g_return_if_fail(who != NULL); f = yahoo_friend_find(gc, who); - if (!f) + if (!f) { + g_free(who); return; + } if (pkt->service == YAHOO_SERVICE_PRESENCE_PERM) { purple_debug_info("yahoo", "Setting permanent presence for %s to %d.\n", who, (value == 1)); @@ -194,6 +208,7 @@ else f->presence = YAHOO_PRESENCE_DEFAULT; } + g_free(who); } void yahoo_friend_update_presence(PurpleConnection *gc, const char *name, @@ -204,6 +219,7 @@ YahooFriend *f; const char *thirtyone, *thirteen; int service = -1; + const char *temp = NULL; if (!yd->logged_in) return; @@ -212,6 +228,11 @@ if (!f) return; + if(f->protocol == 2) + temp = name+4; + else + temp = name; + /* No need to change the value if it is already correct */ if (f->presence == presence) { purple_debug_info("yahoo", "Not setting presence because there are no changes.\n"); @@ -236,12 +257,21 @@ if (f->presence == YAHOO_PRESENCE_PERM_OFFLINE) { pkt = yahoo_packet_new(YAHOO_SERVICE_PRESENCE_PERM, YAHOO_STATUS_AVAILABLE, yd->session_id); - yahoo_packet_hash(pkt, "ssssssss", + if(f->protocol) + yahoo_packet_hash(pkt, "ssssssiss", 1, purple_connection_get_display_name(gc), 31, "2", 13, "2", 302, "319", 300, "319", - 7, name, + 7, temp, 241, f->protocol, 301, "319", 303, "319"); + else + yahoo_packet_hash(pkt, "ssssssss", + 1, purple_connection_get_display_name(gc), + 31, "2", 13, "2", + 302, "319", 300, "319", + 7, temp, + 301, "319", 303, "319"); + yahoo_packet_send_and_free(pkt, yd); } @@ -254,13 +284,31 @@ pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id); - yahoo_packet_hash(pkt, "ssssssss", + if(f->protocol) + yahoo_packet_hash(pkt, "ssssssiss", 1, purple_connection_get_display_name(gc), 31, thirtyone, 13, thirteen, 302, "319", 300, "319", - 7, name, + 7, temp, 241, f->protocol, + 301, "319", 303, "319"); + else + yahoo_packet_hash(pkt, "ssssssss", + 1, purple_connection_get_display_name(gc), + 31, thirtyone, 13, thirteen, + 302, "319", 300, "319", + 7, temp, 301, "319", 303, "319"); yahoo_packet_send_and_free(pkt, yd); } } + +void yahoo_friend_set_p2p_status(YahooFriend *f, YahooP2PStatus p2p_status) +{ + f->p2p_status = p2p_status; +} + +YahooP2PStatus yahoo_friend_get_p2p_status(YahooFriend *f) +{ + return f->p2p_status; +}
--- a/libpurple/protocols/yahoo/yahoo_friend.h Sat Mar 07 21:05:23 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_friend.h Sun Mar 08 06:24:15 2009 +0000 @@ -34,6 +34,13 @@ YAHOO_PRESENCE_PERM_OFFLINE } YahooPresenceVisibility; +typedef enum { + YAHOO_P2PSTATUS_NOT_CONNECTED = 0, + YAHOO_P2PSTATUS_DO_NOT_CONNECT, + YAHOO_P2PSTATUS_WE_ARE_SERVER, + YAHOO_P2PSTATUS_WE_ARE_CLIENT +} YahooP2PStatus; + /* these are called friends instead of buddies mainly so I can use variables * named f and not confuse them with variables named b */ @@ -50,6 +57,9 @@ int protocol; /* 1=LCS, 2=MSN*/ long int version_id; gchar *alias_id; + YahooP2PStatus p2p_status; + gboolean p2p_packet_sent; /* 0:not sent, 1=sent */ + gint session_id; /* session id of friend */ } YahooFriend; YahooFriend *yahoo_friend_find(PurpleConnection *gc, const char *name); @@ -76,4 +86,7 @@ void yahoo_friend_update_presence(PurpleConnection *gc, const char *name, YahooPresenceVisibility presence); +void yahoo_friend_set_p2p_status(YahooFriend *f, YahooP2PStatus p2p_status); +YahooP2PStatus yahoo_friend_get_p2p_status(YahooFriend *f); + #endif /* _YAHOO_FRIEND_H_ */
--- a/libpurple/protocols/yahoo/yahoo_packet.h Sat Mar 07 21:05:23 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_packet.h Sun Mar 08 06:24:15 2009 +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 {