diff options
Diffstat (limited to 'protocols/yahoo/libyahoo2.c')
-rw-r--r-- | protocols/yahoo/libyahoo2.c | 725 |
1 files changed, 516 insertions, 209 deletions
diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index a61955c4..5b2ff44e 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -88,6 +88,7 @@ char *strchr (), *strrchr (); #endif #include "base64.h" +#include "http_client.h" #ifdef USE_STRUCT_CALLBACKS struct yahoo_callbacks *yc=NULL; @@ -168,6 +169,7 @@ enum yahoo_service { /* these are easier to see in hex */ YAHOO_SERVICE_PING, YAHOO_SERVICE_GOTGROUPRENAME, /* < 1, 36(old), 37(new) */ YAHOO_SERVICE_SYSMESSAGE = 0x14, + YAHOO_SERVICE_SKINNAME = 0x15, YAHOO_SERVICE_PASSTHROUGH2 = 0x16, YAHOO_SERVICE_CONFINVITE = 0x18, YAHOO_SERVICE_CONFLOGON, @@ -191,16 +193,19 @@ enum yahoo_service { /* these are easier to see in hex */ YAHOO_SERVICE_AUTHRESP = 0x54, YAHOO_SERVICE_LIST, YAHOO_SERVICE_AUTH = 0x57, + YAHOO_SERVICE_AUTHBUDDY = 0x6d, YAHOO_SERVICE_ADDBUDDY = 0x83, YAHOO_SERVICE_REMBUDDY, YAHOO_SERVICE_IGNORECONTACT, /* > 1, 7, 13 < 1, 66, 13, 0*/ YAHOO_SERVICE_REJECTCONTACT, YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */ + YAHOO_SERVICE_Y7_PING = 0x8A, /* 0 - id and that's it?? */ YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/ YAHOO_SERVICE_CHATGOTO, YAHOO_SERVICE_CHATJOIN, /* > 1 104-room 129-1600326591 62-2 */ YAHOO_SERVICE_CHATLEAVE, YAHOO_SERVICE_CHATEXIT = 0x9b, + YAHOO_SERVICE_CHATADDINVITE = 0x9d, YAHOO_SERVICE_CHATLOGOUT = 0xa0, YAHOO_SERVICE_CHATPING, YAHOO_SERVICE_COMMENT = 0xa8, @@ -208,7 +213,19 @@ enum yahoo_service { /* these are easier to see in hex */ YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd, YAHOO_SERVICE_PICTURE = 0xbe, YAHOO_SERVICE_PICTURE_UPDATE = 0xc1, - YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2 + YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2, + YAHOO_SERVICE_Y6_VISIBILITY=0xc5, + YAHOO_SERVICE_Y6_STATUS_UPDATE=0xc6, + YAHOO_PHOTOSHARE_INIT=0xd2, + YAHOO_SERVICE_CONTACT_YMSG13=0xd6, + YAHOO_PHOTOSHARE_PREV=0xd7, + YAHOO_PHOTOSHARE_KEY=0xd8, + YAHOO_PHOTOSHARE_TRANS=0xda, + YAHOO_FILE_TRANSFER_INIT_YMSG13=0xdc, + YAHOO_FILE_TRANSFER_GET_YMSG13=0xdd, + YAHOO_FILE_TRANSFER_PUT_YMSG13=0xde, + YAHOO_SERVICE_YMSG15_STATUS=0xf0, + YAHOO_SERVICE_YMSG15_BUDDY_LIST=0xf1, }; struct yahoo_pair { @@ -732,7 +749,7 @@ static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet data = y_new0(unsigned char, len + 1); memcpy(data + pos, "YMSG", 4); pos += 4; - pos += yahoo_put16(data + pos, 0x000c); + pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); pos += yahoo_put16(data + pos, 0x0000); pos += yahoo_put16(data + pos, pktlen + extra_pad); pos += yahoo_put16(data + pos, pkt->service); @@ -746,7 +763,7 @@ static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet if( yid->type == YAHOO_CONNECTION_FT ) yahoo_send_data(yid->fd, data, len); else - yahoo_add_to_send_queue(yid, data, len); + yahoo_add_to_send_queue(yid, data, len); FREE(data); } @@ -837,55 +854,6 @@ static int is_same_bud(const void * a, const void * b) { return strcmp(subject->id, object->id); } -static YList * bud_str2list(char *rawlist) -{ - YList * l = NULL; - - char **lines; - char **split; - char **buddies; - char **tmp, **bud; - - lines = y_strsplit(rawlist, "\n", -1); - for (tmp = lines; *tmp; tmp++) { - struct yahoo_buddy *newbud; - - split = y_strsplit(*tmp, ":", 2); - if (!split) - continue; - if (!split[0] || !split[1]) { - y_strfreev(split); - continue; - } - buddies = y_strsplit(split[1], ",", -1); - - for (bud = buddies; bud && *bud; bud++) { - newbud = y_new0(struct yahoo_buddy, 1); - newbud->id = strdup(*bud); - newbud->group = strdup(split[0]); - - if(y_list_find_custom(l, newbud, is_same_bud)) { - FREE(newbud->id); - FREE(newbud->group); - FREE(newbud); - continue; - } - - newbud->real_name = NULL; - - l = y_list_append(l, newbud); - - NOTICE(("Added buddy %s to group %s", newbud->id, newbud->group)); - } - - y_strfreev(buddies); - y_strfreev(split); - } - y_strfreev(lines); - - return l; -} - static char * getcookie(char *rawcookie) { char * cookie=NULL; @@ -1342,134 +1310,150 @@ static void yahoo_process_message(struct yahoo_input_data *yid, struct yahoo_pac y_list_free(messages); } - -static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +static void yahoo_process_status(struct yahoo_input_data *yid, + struct yahoo_packet *pkt) { YList *l; struct yahoo_data *yd = yid->yd; - struct user - { - char *name; /* 7 name */ - int state; /* 10 state */ - int flags; /* 13 flags, bit 0 = pager, bit 1 = chat, bit 2 = game */ - int mobile; /* 60 mobile */ - char *msg; /* 19 custom status message */ - int away; /* 47 away (or invisible)*/ - int buddy_session; /* 11 state */ - int f17; /* 17 in chat? then what about flags? */ - int idle; /* 137 seconds idle */ - int f138; /* 138 state */ - char *f184; /* 184 state */ - int f192; /* 192 state */ - int f10001; /* 10001 state */ - int f10002; /* 10002 state */ - int f198; /* 198 state */ - char *f197; /* 197 state */ - char *f205; /* 205 state */ - int f213; /* 213 state */ - } *u; + struct yahoo_process_status_entry *u; YList *users = 0; - + if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { - YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_DUPL, NULL); + YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id, + YAHOO_LOGIN_DUPL, NULL); return; } + /* Status updates may be spread accross multiple packets and not + even on buddy boundaries, so keeping some state is important. + So, continue where we left off, and only add a user entry to + the list once it's complete (301-315 End buddy). */ + u = yd->half_user; + for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; switch (pair->key) { - case 0: /* we won't actually do anything with this */ + case 300: /* Begin buddy */ + if (!strcmp(pair->value, "315") && !u) { + u = yd->half_user = y_new0(struct yahoo_process_status_entry, 1); + } + break; + case 301: /* End buddy */ + if (!strcmp(pair->value, "315") && u) { + users = y_list_prepend(users, u); + u = yd->half_user = NULL; + } + break; + case 0: /* we won't actually do anything with this */ NOTICE(("key %d:%s", pair->key, pair->value)); break; - case 1: /* we don't get the full buddy list here. */ + case 1: /* we don't get the full buddy list here. */ if (!yd->logged_in) { - yd->logged_in = TRUE; - if(yd->current_status < 0) + yd->logged_in = 1; + if (yd->current_status < 0) yd->current_status = yd->initial_status; - YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL); + YAHOO_CALLBACK(ext_yahoo_login_response) (yd-> + client_id, YAHOO_LOGIN_OK, NULL); } break; - case 8: /* how many online buddies we have */ + case 8: /* how many online buddies we have */ NOTICE(("key %d:%s", pair->key, pair->value)); break; - case 7: /* the current buddy */ - u = y_new0(struct user, 1); + case 7: /* the current buddy */ + if (!u) { + /* This will only happen in case of a single level message */ + u = y_new0(struct yahoo_process_status_entry, 1); + users = y_list_prepend(users, u); + } u->name = pair->value; - users = y_list_prepend(users, u); break; - case 10: /* state */ - ((struct user*)users->data)->state = strtol(pair->value, NULL, 10); + case 10: /* state */ + u->state = strtol(pair->value, NULL, 10); break; - case 19: /* custom status message */ - ((struct user*)users->data)->msg = pair->value; + case 19: /* custom status message */ + u->msg = pair->value; break; - case 47: /* is it an away message or not */ - ((struct user*)users->data)->away = atoi(pair->value); + case 47: /* is it an away message or not. Not applicable for YMSG16 anymore */ + u->away = atoi(pair->value); break; - case 137: /* seconds idle */ - ((struct user*)users->data)->idle = atoi(pair->value); + case 137: /* seconds idle */ + u->idle = atoi(pair->value); break; - case 11: /* this is the buddy's session id */ - ((struct user*)users->data)->buddy_session = atoi(pair->value); + case 11: /* this is the buddy's session id */ + u->buddy_session = atoi(pair->value); break; - case 17: /* in chat? */ - ((struct user*)users->data)->f17 = atoi(pair->value); + case 17: /* in chat? */ + u->f17 = atoi(pair->value); break; - case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */ - ((struct user*)users->data)->flags = atoi(pair->value); + case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */ + u->flags = atoi(pair->value); break; - case 60: /* SMS -> 1 MOBILE USER */ + case 60: /* SMS -> 1 MOBILE USER */ /* sometimes going offline makes this 2, but invisible never sends it */ - ((struct user*)users->data)->mobile = atoi(pair->value); + u->mobile = atoi(pair->value); break; case 138: - ((struct user*)users->data)->f138 = atoi(pair->value); + u->f138 = atoi(pair->value); break; case 184: - ((struct user*)users->data)->f184 = pair->value; + u->f184 = pair->value; break; case 192: - ((struct user*)users->data)->f192 = atoi(pair->value); + u->f192 = atoi(pair->value); break; case 10001: - ((struct user*)users->data)->f10001 = atoi(pair->value); + u->f10001 = atoi(pair->value); break; case 10002: - ((struct user*)users->data)->f10002 = atoi(pair->value); + u->f10002 = atoi(pair->value); break; case 198: - ((struct user*)users->data)->f198 = atoi(pair->value); + u->f198 = atoi(pair->value); break; case 197: - ((struct user*)users->data)->f197 = pair->value; + u->f197 = pair->value; break; case 205: - ((struct user*)users->data)->f205 = pair->value; + u->f205 = pair->value; break; case 213: - ((struct user*)users->data)->f213 = atoi(pair->value); + u->f213 = atoi(pair->value); break; - case 16: /* Custom error message */ - YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM); + case 16: /* Custom error message */ + YAHOO_CALLBACK(ext_yahoo_error) (yd->client_id, + pair->value, 0, E_CUSTOM); break; default: - WARNING(("unknown status key %d:%s", pair->key, pair->value)); + WARNING(("unknown status key %d:%s", pair->key, + pair->value)); break; } } - + while (users) { YList *t = users; - struct user *u = users->data; + struct yahoo_process_status_entry *u = users->data; if (u->name != NULL) { - if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) { - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0); + if (pkt->service == + YAHOO_SERVICE_LOGOFF + /*|| u->flags == 0 No flags for YMSG16 */ ) { + YAHOO_CALLBACK(ext_yahoo_status_changed) (yd-> + client_id, u->name, + YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0); } else { - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile); + /* Key 47 always seems to be 1 for YMSG16 */ + if (!u->state) + u->away = 0; + else + u->away = 1; + + YAHOO_CALLBACK(ext_yahoo_status_changed) (yd-> + client_id, u->name, u->state, u->msg, + u->away, u->idle, u->mobile); } } @@ -1479,88 +1463,130 @@ static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_pack } } -static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +static void yahoo_process_buddy_list(struct yahoo_input_data *yid, + struct yahoo_packet *pkt) { struct yahoo_data *yd = yid->yd; YList *l; + int last_packet = 0; + char *cur_group = NULL; + struct yahoo_buddy *newbud = NULL; - if (!yd->logged_in) { - yd->logged_in = TRUE; - if(yd->current_status < 0) - yd->current_status = yd->initial_status; - YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL); - } - + /* we could be getting multiple packets here */ for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; - switch(pair->key) { - case 87: /* buddies */ - if(!yd->rawbuddylist) - yd->rawbuddylist = strdup(pair->value); - else { - yd->rawbuddylist = y_string_append(yd->rawbuddylist, pair->value); - } + switch (pair->key) { + case 300: + case 301: + case 302: + break; /* Separators. Our logic does not need them */ + case 303: + if (318 == atoi(pair->value)) + last_packet = 1; break; + case 65: + cur_group = strdup(pair->value); + break; + case 7: + newbud = y_new0(struct yahoo_buddy, 1); + newbud->id = strdup(pair->value); + if (cur_group) + newbud->group = strdup(cur_group); + else if (yd->buddies) { + struct yahoo_buddy *lastbud = + (struct yahoo_buddy *)y_list_nth(yd-> + buddies, + y_list_length(yd->buddies) - 1)->data; + newbud->group = strdup(lastbud->group); + } else + newbud->group = strdup("Buddies"); + + yd->buddies = y_list_append(yd->buddies, newbud); - case 88: /* ignore list */ - if(!yd->ignorelist) - yd->ignorelist = strdup("Ignore:"); - yd->ignorelist = y_string_append(yd->ignorelist, pair->value); break; + } + } + + /* we could be getting multiple packets here */ + if (pkt->hash && !last_packet) + return; + + YAHOO_CALLBACK(ext_yahoo_got_buddies) (yd->client_id, yd->buddies); - case 89: /* identities */ + /* Logged in */ + if (!yd->logged_in) { + yd->logged_in = 1; + if (yd->current_status < 0) + yd->current_status = yd->initial_status; + YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id, + YAHOO_LOGIN_OK, NULL); + + /* + yahoo_set_away(yd->client_id, yd->initial_status, NULL, + (yd->initial_status == YAHOO_STATUS_AVAILABLE) ? 0 : 1); + + yahoo_get_yab(yd->client_id); + */ + } + +} + +static void yahoo_process_list(struct yahoo_input_data *yid, + struct yahoo_packet *pkt) +{ + struct yahoo_data *yd = yid->yd; + YList *l; + + /* we could be getting multiple packets here */ + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + case 89: /* identities */ { - char **identities = y_strsplit(pair->value, ",", -1); - int i; - for(i=0; identities[i]; i++) - yd->identities = y_list_append(yd->identities, + char **identities = + y_strsplit(pair->value, ",", -1); + int i; + for (i = 0; identities[i]; i++) + yd->identities = + y_list_append(yd->identities, strdup(identities[i])); - y_strfreev(identities); + y_strfreev(identities); } - YAHOO_CALLBACK(ext_yahoo_got_identities)(yd->client_id, yd->identities); + YAHOO_CALLBACK(ext_yahoo_got_identities) (yd->client_id, + yd->identities); break; - case 59: /* cookies */ - if(yd->ignorelist) { - yd->ignore = bud_str2list(yd->ignorelist); - FREE(yd->ignorelist); - YAHOO_CALLBACK(ext_yahoo_got_ignore)(yd->client_id, yd->ignore); - } - if(yd->rawbuddylist) { - yd->buddies = bud_str2list(yd->rawbuddylist); - FREE(yd->rawbuddylist); - YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies); - } - - if(pair->value[0]=='Y') { + case 59: /* cookies */ + if (pair->value[0] == 'Y') { FREE(yd->cookie_y); FREE(yd->login_cookie); yd->cookie_y = getcookie(pair->value); yd->login_cookie = getlcookie(yd->cookie_y); - } else if(pair->value[0]=='T') { + } else if (pair->value[0] == 'T') { FREE(yd->cookie_t); yd->cookie_t = getcookie(pair->value); - } else if(pair->value[0]=='C') { + } else if (pair->value[0] == 'C') { FREE(yd->cookie_c); yd->cookie_c = getcookie(pair->value); - } - - if(yd->cookie_y && yd->cookie_t && yd->cookie_c) - YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id); + } break; - case 3: /* my id */ - case 90: /* 1 */ - case 100: /* 0 */ - case 101: /* NULL */ - case 102: /* NULL */ - case 93: /* 86400/1440 */ + case 3: /* my id */ + case 90: /* 1 */ + case 100: /* 0 */ + case 101: /* NULL */ + case 102: /* NULL */ + case 93: /* 86400/1440 */ break; } } + + if (yd->cookie_y && yd->cookie_t) /* We don't get cookie_c anymore */ + YAHOO_CALLBACK(ext_yahoo_got_cookies) (yd->client_id); } static void yahoo_process_verify(struct yahoo_input_data *yid, struct yahoo_packet *pkt) @@ -2225,6 +2251,204 @@ static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *se free(crypt_hash); } +struct yahoo_https_auth_data +{ + struct yahoo_input_data *yid; + char *token; + char *chal; +}; + +static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had); +static void yahoo_https_auth_token_finish(struct http_request *req); +static void yahoo_https_auth_init(struct yahoo_https_auth_data *had); +static void yahoo_https_auth_finish(struct http_request *req); + +/* Extract a value from a login.yahoo.com response. Assume CRLF-linebreaks + and FAIL miserably if they're not there... */ +static char *yahoo_ha_find_key(char *response, char *key) +{ + char *s, *end; + int len = strlen(key); + + s = response; + do { + if (strncmp(s, key, len) == 0 && s[len] == '=') { + s += len + 1; + if ((end = strchr(s, '\r'))) + return g_strndup(s, end - s); + else + return g_strdup(s); + } + + if ((s = strchr(s, '\n'))) + s ++; + } while (s && *s); + + return NULL; +} + +static enum yahoo_status yahoo_https_status_parse(int code) +{ + switch (code) + { + case 1212: return YAHOO_LOGIN_PASSWD; + case 1213: return YAHOO_LOGIN_LOCK; + case 1235: return YAHOO_LOGIN_UNAME; + default: return (enum yahoo_status) code; + } +} + +static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn) +{ + struct yahoo_https_auth_data *had = g_new0(struct yahoo_https_auth_data, 1); + + had->yid = yid; + had->chal = g_strdup(seed); + + yahoo_https_auth_token_init(had); +} + +static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had) +{ + struct yahoo_input_data *yid = had->yid; + struct yahoo_data *yd = yid->yd; + struct http_request *req; + char *login, *passwd, *chal; + char *url; + + login = g_strndup(yd->user, 3 * strlen(yd->user)); + http_encode(login); + passwd = g_strndup(yd->password, 3 * strlen(yd->password)); + http_encode(passwd); + chal = g_strndup(had->chal, 3 * strlen(had->chal)); + http_encode(chal); + + url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=%d&login=%s&passwd=%s&chal=%s", + (int) time(NULL), login, passwd, chal); + + req = http_dorequest_url(url, yahoo_https_auth_token_finish, had); + + g_free(url); + g_free(chal); + g_free(passwd); + g_free(login); +} + +static void yahoo_https_auth_token_finish(struct http_request *req) +{ + struct yahoo_https_auth_data *had = req->data; + struct yahoo_input_data *yid; + struct yahoo_data *yd; + int st; + + if (y_list_find(inputs, had->yid) == NULL) + return; + + yid = had->yid; + yd = yid->yd; + + if (req->status_code != 200) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL); + goto fail; + } + + if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL); + goto fail; + } + + if ((had->token = yahoo_ha_find_key(req->reply_body, "ymsgr")) == NULL) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3001, NULL); + goto fail; + } + + return yahoo_https_auth_init(had); + +fail: + g_free(had->token); + g_free(had->chal); + g_free(had); +} + +static void yahoo_https_auth_init(struct yahoo_https_auth_data *had) +{ + struct http_request *req; + char *url; + + url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=%d&token=%s", + (int) time(NULL), had->token); + + req = http_dorequest_url(url, yahoo_https_auth_finish, had); + + g_free(url); +} + +static void yahoo_https_auth_finish(struct http_request *req) +{ + struct yahoo_https_auth_data *had = req->data; + struct yahoo_input_data *yid; + struct yahoo_data *yd; + struct yahoo_packet *pack; + char *crumb = NULL; + int st; + + if (y_list_find(inputs, had->yid) == NULL) + return; + + yid = had->yid; + yd = yid->yd; + + md5_byte_t result[16]; + md5_state_t ctx; + + unsigned char yhash[32]; + + if (req->status_code != 200) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL); + goto fail; + } + + if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL); + goto fail; + } + + if ((yd->cookie_y = yahoo_ha_find_key(req->reply_body, "Y")) == NULL || + (yd->cookie_t = yahoo_ha_find_key(req->reply_body, "T")) == NULL || + (crumb = yahoo_ha_find_key(req->reply_body, "crumb")) == NULL) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3002, NULL); + goto fail; + } + + md5_init(&ctx); + md5_append(&ctx, (unsigned char*) crumb, 11); + md5_append(&ctx, (unsigned char*) had->chal, strlen(had->chal)); + md5_finish(&ctx, result); + to_y64(yhash, result, 16); + + pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id); + yahoo_packet_hash(pack, 1, yd->user); + yahoo_packet_hash(pack, 0, yd->user); + yahoo_packet_hash(pack, 277, yd->cookie_y); + yahoo_packet_hash(pack, 278, yd->cookie_t); + yahoo_packet_hash(pack, 307, (char*) yhash); + yahoo_packet_hash(pack, 244, "524223"); + yahoo_packet_hash(pack, 2, yd->user); + yahoo_packet_hash(pack, 2, "1"); + yahoo_packet_hash(pack, 98, "us"); + yahoo_packet_hash(pack, 135, "7.5.0.647"); + + yahoo_send_packet(yid, pack, 0); + + yahoo_packet_free(pack); + +fail: + g_free(crumb); + g_free(had->token); + g_free(had->chal); + g_free(had); +} + static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { char *seed = NULL; @@ -2253,6 +2477,9 @@ static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet case 1: yahoo_process_auth_0x0b(yid, seed, sn); break; + case 2: + yahoo_process_auth_0x10(yid, seed, sn); + break; default: /* call error */ WARNING(("unknown auth type %d", m)); @@ -2407,7 +2634,7 @@ static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_pa bud->real_name = NULL; yd->buddies = y_list_append(yd->buddies, bud); - + /* Possibly called already, but at least the call above doesn't seem to happen every time (not anytime I tried). */ YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, me, who, NULL); @@ -2416,6 +2643,26 @@ static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_pa /* YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */ } +static void yahoo_process_contact_ymsg13(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ + char* who=NULL; + char* me=NULL; + char* msg=NULL; + YList *l; + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + if (pair->key == 4) + who = pair->value; + else if (pair->key == 5) + me = pair->value; + else + DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value)); + } + + if(pkt->status==3) + YAHOO_CALLBACK(ext_yahoo_contact_auth_request)(yid->yd->client_id, me, who, msg); +} + static void yahoo_process_buddydel(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { struct yahoo_data *yd = yid->yd; @@ -2627,7 +2874,7 @@ static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_ char *who = NULL; YList *l; - yahoo_dump_unhandled(pkt); + // yahoo_dump_unhandled(pkt); for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; if (pair->key == 5) @@ -2649,6 +2896,7 @@ static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service)); + yahoo_dump_unhandled(pkt); switch (pkt->service) { case YAHOO_SERVICE_USERSTAT: @@ -2660,6 +2908,8 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_GAMELOGOFF: case YAHOO_SERVICE_IDACT: case YAHOO_SERVICE_IDDEACT: + case YAHOO_SERVICE_Y6_STATUS_UPDATE: + case YAHOO_SERVICE_YMSG15_STATUS: yahoo_process_status(yid, pkt); break; case YAHOO_SERVICE_NOTIFY: @@ -2673,6 +2923,7 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_NEWMAIL: yahoo_process_mail(yid, pkt); break; + case YAHOO_SERVICE_REJECTCONTACT: case YAHOO_SERVICE_NEWCONTACT: yahoo_process_contact(yid, pkt); break; @@ -2713,6 +2964,9 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_ADDBUDDY: yahoo_process_buddyadd(yid, pkt); break; + case YAHOO_SERVICE_CONTACT_YMSG13: + yahoo_process_contact_ymsg13(yid,pkt); + break; case YAHOO_SERVICE_REMBUDDY: yahoo_process_buddydel(yid, pkt); break; @@ -2741,7 +2995,6 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_CHATLOGON: case YAHOO_SERVICE_CHATLOGOFF: case YAHOO_SERVICE_CHATMSG: - case YAHOO_SERVICE_REJECTCONTACT: case YAHOO_SERVICE_PEERTOPEER: WARNING(("unhandled service 0x%02x", pkt->service)); yahoo_dump_unhandled(pkt); @@ -2755,6 +3008,8 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_PICTURE_UPLOAD: yahoo_process_picture_upload(yid, pkt); break; + case YAHOO_SERVICE_YMSG15_BUDDY_LIST: /* Buddy List */ + yahoo_process_buddy_list(yid, pkt); default: WARNING(("unknown service 0x%02x", pkt->service)); yahoo_dump_unhandled(pkt); @@ -3538,7 +3793,7 @@ static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = yahoo_process_webcam_master_connection, yahoo_process_webcam_connection, yahoo_process_chatcat_connection, - yahoo_process_search_connection + yahoo_process_search_connection, }; int yahoo_read_ready(int id, int fd, void *data) @@ -3556,7 +3811,7 @@ int yahoo_read_ready(int id, int fd, void *data) len = read(fd, buf, sizeof(buf)); } while(len == -1 && errno == EINTR); - if(len == -1 && errno == EAGAIN) /* we'll try again later */ + if(len == -1 && (errno == EAGAIN||errno == EINTR)) /* we'll try again later */ return 1; if (len <= 0) { @@ -3759,7 +4014,7 @@ void yahoo_send_typing(int id, const char *from, const char *who, int typ) pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yd->session_id); yahoo_packet_hash(pkt, 5, who); - yahoo_packet_hash(pkt, 4, from?from:yd->user); + yahoo_packet_hash(pkt, 1, from?from:yd->user); yahoo_packet_hash(pkt, 14, " "); yahoo_packet_hash(pkt, 13, typ ? "1" : "0"); yahoo_packet_hash(pkt, 49, "TYPING"); @@ -3774,46 +4029,40 @@ void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away) struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); struct yahoo_data *yd; struct yahoo_packet *pkt = NULL; - int service; + int old_status; char s[4]; if(!yid) return; yd = yid->yd; + old_status = yd->current_status; + yd->current_status = state; - if (msg) { - yd->current_status = YAHOO_STATUS_CUSTOM; - } else { - yd->current_status = state; - } + /* Thank you libpurple :) */ + if (yd->current_status == YAHOO_STATUS_INVISIBLE) { + pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 13, "2"); + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); - if (yd->current_status == YAHOO_STATUS_AVAILABLE) - service = YAHOO_SERVICE_ISBACK; - else - service = YAHOO_SERVICE_ISAWAY; - - if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) { - pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id); - yahoo_packet_hash(pkt, 10, "999"); - yahoo_packet_hash(pkt, 47, "2"); - }else { - pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id); - snprintf(s, sizeof(s), "%d", yd->current_status); - yahoo_packet_hash(pkt, 10, s); - if (yd->current_status == YAHOO_STATUS_CUSTOM) { - yahoo_packet_hash(pkt, 19, msg); - yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); - } else { - yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); - } - - - + return; } + pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, yd->current_status, yd->session_id); + snprintf(s, sizeof(s), "%d", yd->current_status); + yahoo_packet_hash(pkt, 10, s); + yahoo_packet_hash(pkt, 19, msg && state == YAHOO_STATUS_CUSTOM ? msg : ""); + yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); yahoo_send_packet(yid, pkt, 0); yahoo_packet_free(pkt); + + if(old_status == YAHOO_STATUS_INVISIBLE) { + pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 13, "1"); + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); + } } void yahoo_logoff(int id) @@ -3828,7 +4077,10 @@ void yahoo_logoff(int id) LOG(("yahoo_logoff: current status: %d", yd->current_status)); - if(yd->current_status != -1) { + if(yd->current_status != -1 && 0) { + /* Meh. Don't send this. The event handlers are not going to + get to do this so it'll just leak memory. And the TCP + connection reset will hopefully be clear enough. */ pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id); yd->current_status = -1; @@ -4061,12 +4313,24 @@ void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg if (!yd->logged_in) return; - pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id); - yahoo_packet_hash(pkt, 1, yd->user); - yahoo_packet_hash(pkt, 7, who); - yahoo_packet_hash(pkt, 65, group); + pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YPACKET_STATUS_DEFAULT, yd->session_id); + if (msg != NULL) /* add message/request "it's me add me" */ yahoo_packet_hash(pkt, 14, msg); + else + yahoo_packet_hash(pkt,14,""); + + yahoo_packet_hash(pkt, 65, group); + yahoo_packet_hash(pkt, 97, "1"); + yahoo_packet_hash(pkt, 1, yd->user); + yahoo_packet_hash(pkt, 302, "319"); + yahoo_packet_hash(pkt, 300, "319"); + yahoo_packet_hash(pkt, 7, who); + yahoo_packet_hash(pkt, 334, "0"); + yahoo_packet_hash(pkt, 301, "319"); + yahoo_packet_hash(pkt, 303, "319"); + + yahoo_send_packet(yid, pkt, 0); yahoo_packet_free(pkt); } @@ -4090,6 +4354,49 @@ void yahoo_remove_buddy(int id, const char *who, const char *group) yahoo_packet_free(pkt); } +void yahoo_accept_buddy_ymsg13(int id,const char* me,const char* who){ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + + if(!yid) + return; + yd = yid->yd; + + struct yahoo_packet* pkt=NULL; + pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0); + + yahoo_packet_hash(pkt,1,me ?: yd->user); + yahoo_packet_hash(pkt,5,who); + yahoo_packet_hash(pkt,13,"1"); + yahoo_packet_hash(pkt,334,"0"); + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); +} + +void yahoo_reject_buddy_ymsg13(int id,const char* me,const char* who,const char* msg){ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + + if(!yid) + return; + yd = yid->yd; + + struct yahoo_packet* pkt=NULL; + pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0); + + yahoo_packet_hash(pkt,1,me ?: yd->user); + yahoo_packet_hash(pkt,5,who); +// yahoo_packet_hash(pkt,241,YAHOO_PROTO_VER); + yahoo_packet_hash(pkt,13,"2"); + yahoo_packet_hash(pkt,334,"0"); + yahoo_packet_hash(pkt,97,"1"); + yahoo_packet_hash(pkt,14,msg?:""); + + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); + +} + void yahoo_reject_buddy(int id, const char *who, const char *msg) { struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); |