# HG changeset patch # User Sean Egan # Date 1065222073 0 # Node ID 67f9b43c402ae4b97d4ce706e9068afaa8bfeba5 # Parent 28dd20b5f4cf489d27ef992bd3766353e5b058fc [gaim-migrate @ 7701] I think this is the fifth Yahoo authentication method Gaim's seen in its days. Please tell me if anything stops working. committer: Tailor Script diff -r 28dd20b5f4cf -r 67f9b43c402a src/protocols/msn/msn.c --- a/src/protocols/msn/msn.c Fri Oct 03 21:57:44 2003 +0000 +++ b/src/protocols/msn/msn.c Fri Oct 03 23:01:13 2003 +0000 @@ -72,7 +72,7 @@ } g_snprintf(outparams, sizeof(outparams), "%s %s", - gaim_account_get_username(account), msn_url_encode(alias)); + gaim_account_get_username(account), gaim_url_encode(alias)); g_free(alias); @@ -94,7 +94,7 @@ g_snprintf(outparams, sizeof(outparams), "%s ", type); else g_snprintf(outparams, sizeof(outparams), "%s %s", type, - msn_url_encode(entry)); + gaim_url_encode(entry)); if (!msn_servconn_send_command(session->notification_conn, "PRP", outparams)) { @@ -1066,7 +1066,7 @@ if (new_group == NULL) { g_snprintf(outparams, sizeof(outparams), "%s 0", - msn_url_encode(new_group_name)); + gaim_url_encode(new_group_name)); if (!msn_servconn_send_command(session->notification_conn, "ADG", outparams)) { @@ -1086,7 +1086,7 @@ } else { g_snprintf(outparams, sizeof(outparams), "FL %s %s %d", - who, msn_url_encode(friendly), + who, gaim_url_encode(friendly), msn_group_get_id(new_group)); if (!msn_servconn_send_command(session->notification_conn, @@ -1133,7 +1133,7 @@ g_snprintf(outparams, sizeof(outparams), "%d %s 0", msn_group_get_id(old_group), - msn_url_encode(new_group_name)); + gaim_url_encode(new_group_name)); if (!msn_servconn_send_command(session->notification_conn, "REG", outparams)) { @@ -1145,7 +1145,7 @@ } else { g_snprintf(outparams, sizeof(outparams), "%s 0", - msn_url_encode(new_group_name)); + gaim_url_encode(new_group_name)); if (!msn_servconn_send_command(session->notification_conn, "ADG", outparams)) { diff -r 28dd20b5f4cf -r 67f9b43c402a src/protocols/msn/notification.c --- a/src/protocols/msn/notification.c Fri Oct 03 21:57:44 2003 +0000 +++ b/src/protocols/msn/notification.c Fri Oct 03 23:01:13 2003 +0000 @@ -172,7 +172,7 @@ g_snprintf(outparams, sizeof(outparams), "AL %s %s", msn_user_get_passport(pa->user), - msn_url_encode(msn_user_get_name(pa->user))); + gaim_url_encode(msn_user_get_name(pa->user))); if (msn_servconn_send_command(session->notification_conn, "ADD", outparams) <= 0) { @@ -200,7 +200,7 @@ g_snprintf(outparams, sizeof(outparams), "BL %s %s", msn_user_get_passport(pa->user), - msn_url_encode(msn_user_get_name(pa->user))); + gaim_url_encode(msn_user_get_name(pa->user))); if (msn_servconn_send_command(session->notification_conn, "ADD", outparams) <= 0) { @@ -325,9 +325,9 @@ size_t s; username = - g_strdup(msn_url_encode(gaim_account_get_username(session->account))); + g_strdup(gaim_url_encode(gaim_account_get_username(session->account))); password = - g_strdup(msn_url_encode(gaim_account_get_password(session->account))); + g_strdup(gaim_url_encode(gaim_account_get_password(session->account))); request_str = g_strdup_printf( "GET %s HTTP/1.1\r\n" @@ -428,7 +428,7 @@ if ((error = strstr(buffer, "cbtxt=")) != NULL) error += strlen("cbtxt="); - error = msn_url_decode(error); + error = gaim_url_decode(error); } @@ -600,7 +600,7 @@ */ if (!g_ascii_strcasecmp(params[1], "OK")) { - const char *friendly = msn_url_decode(params[3]); + const char *friendly = gaim_url_decode(params[3]); /* OK */ @@ -658,7 +658,7 @@ g_free(challenge_data); #if 0 - passport_str = g_strdup(msn_url_decode(params[3])); + passport_str = g_strdup(gaim_url_decode(params[3])); for (c = passport_str; *c != '\0'; c++) { @@ -888,7 +888,7 @@ list = params[1]; passport = params[3]; - friend = msn_url_decode(params[4]); + friend = gaim_url_decode(params[4]); if (param_count >= 6) group_id = params[5]; @@ -939,7 +939,7 @@ group_id = atoi(params[3]); - group_name = msn_url_decode(params[2]); + group_name = gaim_url_decode(params[2]); group = msn_group_new(session, group_id, group_name); @@ -1022,11 +1022,11 @@ } } else if (!strcmp(type, "PHH")) - msn_user_set_home_phone(user, msn_url_decode(value)); + msn_user_set_home_phone(user, gaim_url_decode(value)); else if (!strcmp(type, "PHW")) - msn_user_set_work_phone(user, msn_url_decode(value)); + msn_user_set_work_phone(user, gaim_url_decode(value)); else if (!strcmp(type, "PHM")) - msn_user_set_mobile_phone(user, msn_url_decode(value)); + msn_user_set_mobile_phone(user, gaim_url_decode(value)); } return TRUE; @@ -1057,7 +1057,7 @@ state = params[1]; passport = params[2]; - friend = msn_url_decode(params[3]); + friend = gaim_url_decode(params[3]); user = msn_users_find_with_passport(session->users, passport); @@ -1067,7 +1067,7 @@ if (session->protocol_ver >= 9 && param_count == 6) { - msnobj = msn_object_new_from_string(msn_url_decode(params[5])); + msnobj = msn_object_new_from_string(gaim_url_decode(params[5])); msn_user_set_object(user, msnobj); } @@ -1121,13 +1121,13 @@ if (session->protocol_ver >= 8) { group_id = atoi(params[0]); - name = msn_url_decode(params[1]); + name = gaim_url_decode(params[1]); } else { num_groups = atoi(params[3]); group_id = atoi(params[4]); - name = msn_url_decode(params[5]); + name = gaim_url_decode(params[5]); if (num_groups == 0) return TRUE; @@ -1164,7 +1164,7 @@ int list_op; passport = params[0]; - friend = msn_url_decode(params[1]); + friend = gaim_url_decode(params[1]); list_op = atoi(params[2]); group_nums = params[3]; @@ -1332,7 +1332,7 @@ if (num_users > 0) { passport = params[5]; - friend = msn_url_decode(params[6]); + friend = gaim_url_decode(params[6]); } if (session->syncing_lists && session->lists_synced) @@ -1478,7 +1478,7 @@ state = params[0]; passport = params[1]; - friend = msn_url_decode(params[2]); + friend = gaim_url_decode(params[2]); user = msn_users_find_with_passport(session->users, passport); @@ -1488,7 +1488,7 @@ if (session->protocol_ver >= 9 && param_count == 5) { - msnobj = msn_object_new_from_string(msn_url_decode(params[4])); + msnobj = msn_object_new_from_string(gaim_url_decode(params[4])); msn_user_set_object(user, msnobj); } @@ -1538,11 +1538,11 @@ if (param_count == 4) { if (!strcmp(type, "PHH")) - msn_user_set_home_phone(session->user, msn_url_decode(value)); + msn_user_set_home_phone(session->user, gaim_url_decode(value)); else if (!strcmp(type, "PHW")) - msn_user_set_work_phone(session->user, msn_url_decode(value)); + msn_user_set_work_phone(session->user, gaim_url_decode(value)); else if (!strcmp(type, "PHM")) - msn_user_set_mobile_phone(session->user, msn_url_decode(value)); + msn_user_set_mobile_phone(session->user, gaim_url_decode(value)); } return TRUE; @@ -1556,7 +1556,7 @@ GaimConnection *gc = session->account->gc; char *friend; - friend = msn_url_decode(params[3]); + friend = gaim_url_decode(params[3]); gaim_connection_set_display_name(gc, friend); @@ -1574,7 +1574,7 @@ group_id = atoi(params[2]); - group_name = msn_url_decode(params[3]); + group_name = gaim_url_decode(params[3]); group = msn_groups_find_with_id(session->groups, group_id); @@ -1637,7 +1637,7 @@ friendly = passport; g_snprintf(outparams, sizeof(outparams), "FL %s %s %d", - passport, msn_url_encode(friendly), + passport, gaim_url_encode(friendly), msn_group_get_id(group)); if (!msn_servconn_send_command(session->notification_conn, diff -r 28dd20b5f4cf -r 67f9b43c402a src/protocols/msn/utils.c --- a/src/protocols/msn/utils.c Fri Oct 03 21:57:44 2003 +0000 +++ b/src/protocols/msn/utils.c Fri Oct 03 23:01:13 2003 +0000 @@ -21,65 +21,6 @@ */ #include "msn.h" -char * -msn_url_decode(const char *str) -{ - static char buf[MSN_BUF_LEN]; - int i, j = 0; - char *bum; - - g_return_val_if_fail(str != NULL, NULL); - - for (i = 0; i < strlen(str); i++) { - char hex[3]; - - if (str[i] != '%') - buf[j++] = str[i]; - else { - strncpy(hex, str + ++i, 2); - hex[2] = '\0'; - - /* i is pointing to the start of the number */ - i++; - - /* - * Now it's at the end and at the start of the for loop - * will be at the next character. - */ - buf[j++] = strtol(hex, NULL, 16); - } - } - - buf[j] = '\0'; - - if (!g_utf8_validate(buf, -1, (const char **)&bum)) - *bum = '\0'; - - return buf; -} - -char * -msn_url_encode(const char *str) -{ - static char buf[MSN_BUF_LEN]; - int i, j = 0; - - g_return_val_if_fail(str != NULL, NULL); - - for (i = 0; i < strlen(str); i++) { - if (isalnum(str[i])) - buf[j++] = str[i]; - else { - sprintf(buf + j, "%%%02x", (unsigned char)str[i]); - j += 3; - } - } - - buf[j] = '\0'; - - return buf; -} - void msn_parse_format(const char *mime, char **pre_ret, char **post_ret) { @@ -146,7 +87,7 @@ } } - cur = g_strdup(msn_url_decode(pre->str)); + cur = g_strdup(gaim_url_decode(pre->str)); g_string_free(pre, TRUE); if (pre_ret != NULL) @@ -154,7 +95,7 @@ else g_free(cur); - cur = g_strdup(msn_url_decode(post->str)); + cur = g_strdup(gaim_url_decode(post->str)); g_string_free(post, TRUE); if (post_ret != NULL) diff -r 28dd20b5f4cf -r 67f9b43c402a src/protocols/msn/utils.h --- a/src/protocols/msn/utils.h Fri Oct 03 21:57:44 2003 +0000 +++ b/src/protocols/msn/utils.h Fri Oct 03 23:01:13 2003 +0000 @@ -23,28 +23,6 @@ #define _MSN_UTILS_H_ /** - * Decodes a URL into a plain string. - * - * This will change hex codes and such to their ascii equivalents. - * - * @param str The string to translate. - * - * @return The resulting string. - */ -char *msn_url_decode(const char *str); - -/** - * Encodes a URL into an escaped string. - * - * This will change non-alphanumeric characters to hex codes. - * - * @param str The string to translate. - * - * @return The resulting string. - */ -char *msn_url_encode(const char *str); - -/** * Parses the MSN message formatting into a format compatible with Gaim. * * @param mime The mime header with the formatting. diff -r 28dd20b5f4cf -r 67f9b43c402a src/protocols/yahoo/yahoo.c --- a/src/protocols/yahoo/yahoo.c Fri Oct 03 21:57:44 2003 +0000 +++ b/src/protocols/yahoo/yahoo.c Fri Oct 03 23:01:13 2003 +0000 @@ -39,6 +39,8 @@ #include "yahoochat.h" #include "md5.h" +#define YAHOO_WEBMESSENGER + extern char *yahoo_crypt(const char *, const char *); typedef struct @@ -56,7 +58,11 @@ #define YAHOO_PAGER_PORT 5050 #define YAHOO_PROFILE_URL "http://profiles.yahoo.com/" +#ifdef YAHOO_WEBMESSENGER +#define YAHOO_PROTO_VER 0x0065 +#else #define YAHOO_PROTO_VER 0x000b +#endif #define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4) @@ -1490,7 +1496,6 @@ default: msg = _("Unknown error."); } - gaim_connection_error(gc, msg); } @@ -1725,6 +1730,188 @@ gc->inpa = gaim_input_add(yd->fd, GAIM_INPUT_READ, yahoo_pending, gc); } +#ifdef YAHOO_WEBMESSENGER +static void yahoo_got_web_connected(gpointer data, gint source, GaimInputCondition cond) +{ + GaimConnection *gc = data; + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + if (!g_list_find(gaim_connections_get_all(), gc)) { + close(source); + return; + } + + if (source < 0) { + gaim_connection_error(gc, _("Unable to connect")); + return; + } + + yd = gc->proto_data; + yd->fd = source; + + pkt = yahoo_packet_new(YAHOO_SERVICE_WEBLOGIN, YAHOO_STATUS_WEBLOGIN, 0); + + yahoo_packet_hash(pkt, 0, gaim_normalize(gaim_account_get_username(gaim_connection_get_account(gc)))); + yahoo_packet_hash(pkt, 1, gaim_normalize(gaim_account_get_username(gaim_connection_get_account(gc)))); + yahoo_packet_hash(pkt, 6, yd->auth); + yahoo_send_packet(yd, pkt); + + yahoo_packet_free(pkt); + g_free(yd->auth); + gc->inpa = gaim_input_add(yd->fd, GAIM_INPUT_READ, yahoo_pending, gc); +} + +static void yahoo_web_pending(gpointer data, gint source, GaimInputCondition cond) +{ + GaimConnection *gc = data; + GaimAccount *account = gaim_connection_get_account(gc); + struct yahoo_data *yd = gc->proto_data; + char buf[1024], buf2[256], *i = buf, *r = buf2; + int len, o = 0; + + len = read(source, buf, sizeof(buf)); + + if (len <= 0 || strncmp(buf, "HTTP/1.0 302", strlen("HTTP/1.0 302"))) { + gaim_connection_error(gc, _("Unable to read")); + return; + } + + while ((i = strstr(i, "Set-Cookie: ")) && 0 < 2) { + i += strlen("Set-Cookie: "); + for (;*i != ';'; r++, i++) { + *r = *i; + } + *r=';'; + r++; + *r=' '; + r++; + o++; + } + /* Get rid of that "; " */ + *(r-2) = '\0'; + yd->auth = g_strdup(buf2); + gaim_input_remove(gc->inpa); + close(source); + + /* Now we have our cookies to login with. I'll go get the milk. */ + if (gaim_proxy_connect(account, "wcs1.msg.sc5.yahoo.com", + gaim_account_get_int(account, "port", YAHOO_PAGER_PORT), + yahoo_got_web_connected, gc) != 0) { + gaim_connection_error(gc, _("Connection problem")); + return; + } +} + +static void yahoo_got_cookies(gpointer data, gint source, GaimInputCondition cond) +{ + GaimConnection *gc = data; + struct yahoo_data *yd = gc->proto_data; + if (source < 0) { + gaim_connection_error(gc, _("Unable to connect")); + return; + } + write(source, yd->auth, strlen(yd->auth)); + g_free(yd->auth); + gc->inpa = gaim_input_add(source, GAIM_INPUT_READ, yahoo_web_pending, gc); +} + +static void yahoo_login_page_hash_iter(const char *key, const char *val, GString *url) +{ + if (!strcmp(key, "passwd")) + return; + url = g_string_append_c(url, '&'); + url = g_string_append(url, key); + url = g_string_append_c(url, '='); + if (!strcmp(key, ".save") || !strcmp(key, ".js")) + url = g_string_append_c(url, '1'); + else if (!strcmp(key, ".challenge")) + url = g_string_append(url, val); + else + url = g_string_append(url, gaim_url_encode(val)); +} + +static GHashTable *yahoo_login_page_hash(const char *buf, size_t len) +{ + GHashTable *hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + const char *c = buf, *d; + char name[64], value[64]; + while ((c < (buf + len)) && (c = strstr(c, "') < d) + break; + for (c = d, d = value; *c!='"'; c++, d++) + *d = *c; + *d = '\0'; + g_hash_table_insert(hash, g_strdup(name), g_strdup(value)); + } + return hash; +} + +static void yahoo_login_page_cb(GaimConnection *gc, const char *buf, size_t len) +{ + GaimAccount *account = gaim_connection_get_account(gc); + struct yahoo_data *yd = gc->proto_data; + const char *sn = gaim_account_get_username(account); + const char *pass = gaim_account_get_password(account); + + GHashTable *hash = yahoo_login_page_hash(buf, len); + GString *url = g_string_new("GET /config/login?login="); + url = g_string_append(url, sn); + url = g_string_append(url, "&passwd="); + + char md5[33], *hashp = md5, *chal; + int i; + md5_byte_t result[16]; + md5_state_t ctx; + md5_init(&ctx); + md5_append(&ctx, pass, strlen(pass)); + md5_finish(&ctx, result); + for (i = 0; i < 16; ++i) { + g_snprintf(hashp, 3, "%02x", result[i]); + hashp += 2; + } + chal = g_strconcat(md5, g_hash_table_lookup(hash, ".challenge"), NULL); + md5_init(&ctx); + md5_append(&ctx, chal, strlen(chal)); + md5_finish(&ctx, result); + hashp = md5; + for (i = 0; i < 16; ++i) { + g_snprintf(hashp, 3, "%02x", result[i]); + hashp += 2; + } + /* + md5_init(&ctx); + md5_append(&ctx, md5, strlen(md5)); + md5_finish(&ctx, result); + hashp = md5; + for (i = 0; i < 16; ++i) { + g_snprintf(hashp, 3, "%02x", result[i]); + hashp += 2; + } + */ + g_free(chal); + + url = g_string_append(url, md5); + g_hash_table_foreach(hash, yahoo_login_page_hash_iter, url); + + url = g_string_append(url, "&.hash=1&.md5=1 HTTP/1.1\r\n" + "Host: login.yahoo.com\r\n\r\n"); + g_hash_table_destroy(hash); + + yd->auth = g_string_free(url, FALSE); + if (gaim_proxy_connect(account, "login.yahoo.com", 80, yahoo_got_cookies, gc) != 0) { + gaim_connection_error(gc, _("Connection problem")); + return; + } +} + +#endif /* YAHOO_WEBMESSENGER */ + static void yahoo_login(GaimAccount *account) { GaimConnection *gc = gaim_account_get_connection(account); struct yahoo_data *yd = gc->proto_data = g_new0(struct yahoo_data, 1); @@ -1738,12 +1925,16 @@ yd->confs = NULL; yd->conf_id = 2; +#ifndef YAHOO_WEBMESSENGER if (gaim_proxy_connect(account, gaim_account_get_string(account, "server", YAHOO_PAGER_HOST), gaim_account_get_int(account, "port", YAHOO_PAGER_PORT), yahoo_got_connected, gc) != 0) { gaim_connection_error(gc, _("Connection problem")); return; } +#else + gaim_url_fetch(WEBMESSENGER_URL, TRUE, "Gaim/" VERSION, FALSE, yahoo_login_page_cb, gc); +#endif } diff -r 28dd20b5f4cf -r 67f9b43c402a src/protocols/yahoo/yahoo.h --- a/src/protocols/yahoo/yahoo.h Fri Oct 03 21:57:44 2003 +0000 +++ b/src/protocols/yahoo/yahoo.h Fri Oct 03 23:01:13 2003 +0000 @@ -25,6 +25,8 @@ #include "prpl.h" +#define WEBMESSENGER_URL "http://login.yahoo.com/config/login?.src=pg" + enum yahoo_service { /* these are easier to see in hex */ YAHOO_SERVICE_LOGON = 1, YAHOO_SERVICE_LOGOFF, @@ -83,7 +85,8 @@ YAHOO_SERVICE_CHATADDINVITE = 0x9d, YAHOO_SERVICE_CHATLOGOUT = 0xa0, YAHOO_SERVICE_CHATPING, - YAHOO_SERVICE_COMMENT = 0xa8 + YAHOO_SERVICE_COMMENT = 0xa8, + YAHOO_SERVICE_WEBLOGIN = 0x0226 }; enum yahoo_status { @@ -100,6 +103,7 @@ YAHOO_STATUS_INVISIBLE = 12, YAHOO_STATUS_CUSTOM = 99, YAHOO_STATUS_IDLE = 999, + YAHOO_STATUS_WEBLOGIN = 0x5a55aa55, YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */ YAHOO_STATUS_TYPING = 0x16 }; @@ -117,6 +121,7 @@ gboolean chat_online; gboolean in_chat; char *chat_name; + char *auth; }; struct yahoo_pair { diff -r 28dd20b5f4cf -r 67f9b43c402a src/util.c --- a/src/util.c Fri Oct 03 21:57:44 2003 +0000 +++ b/src/util.c Fri Oct 03 23:01:13 2003 +0000 @@ -1918,6 +1918,64 @@ } } +char * +gaim_url_decode(const char *str) +{ + static char buf[BUF_LEN]; + int i, j = 0; + char *bum; + + g_return_val_if_fail(str != NULL, NULL); + + for (i = 0; i < strlen(str); i++) { + char hex[3]; + + if (str[i] != '%') + buf[j++] = str[i]; + else { + strncpy(hex, str + ++i, 2); + hex[2] = '\0'; + + /* i is pointing to the start of the number */ + i++; + + /* + * Now it's at the end and at the start of the for loop + * will be at the next character. + */ + buf[j++] = strtol(hex, NULL, 16); + } + } + + buf[j] = '\0'; + + if (!g_utf8_validate(buf, -1, (const char **)&bum)) + *bum = '\0'; + + return buf; +} + +char * +gaim_url_encode(const char *str) +{ + static char buf[BUF_LEN]; + int i, j = 0; + + g_return_val_if_fail(str != NULL, NULL); + + for (i = 0; i < strlen(str); i++) { + if (isalnum(str[i])) + buf[j++] = str[i]; + else { + sprintf(buf + j, "%%%02x", (unsigned char)str[i]); + j += 3; + } + } + + buf[j] = '\0'; + + return buf; +} /************************************************************************** * UTF8 String Functions diff -r 28dd20b5f4cf -r 67f9b43c402a src/util.h --- a/src/util.h Fri Oct 03 21:57:44 2003 +0000 +++ b/src/util.h Fri Oct 03 23:01:13 2003 +0000 @@ -454,10 +454,30 @@ const char *user_agent, gboolean http11, void (*cb)(void *, const char *, size_t), void *data); +/** + * Decodes a URL into a plain string. + * + * This will change hex codes and such to their ascii equivalents. + * + * @param str The string to translate. + * + * @return The resulting string. + */ +char *gaim_url_decode(const char *str); + +/** + * Encodes a URL into an escaped string. + * + * This will change non-alphanumeric characters to hex codes. + * + * @param str The string to translate. + * + * @return The resulting string. + */ +char *gaim_url_encode(const char *str); /*@}*/ - /************************************************************************** * UTF8 String Functions **************************************************************************/