Mercurial > pidgin
diff src/protocols/yahoo/yahoo.c @ 7134:67f9b43c402a
[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 <tailor@pidgin.im>
| author | Sean Egan <seanegan@gmail.com> |
|---|---|
| date | Fri, 03 Oct 2003 23:01:13 +0000 |
| parents | 8246bd3141ae |
| children | f189f8ccaa98 |
line wrap: on
line diff
--- 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, "<input "))) { + c = strstr(c, "name=\"") + strlen("name=\""); + for (d = name; *c!='"'; c++, d++) + *d = *c; + *d = '\0'; + d = strstr(c, "value=\"") + strlen("value=\""); + if (strchr(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 }
