Mercurial > pidgin.yaz
diff src/protocols/msn/nexus.c @ 8171:d0ba2f7b40e7
[gaim-migrate @ 8884]
Committing one of shx's MSN patches, which splits off the Nexus connection
code into nexus.[ch] and cleans it up a bit.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Tue, 27 Jan 2004 04:46:05 +0000 |
parents | |
children | bbd8cdaf0ad5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/nexus.c Tue Jan 27 04:46:05 2004 +0000 @@ -0,0 +1,372 @@ +#include "msn.h" +#include "nexus.h" +#include "notification.h" + +/************************************************************************** + * Util + **************************************************************************/ + +static size_t +msn_ssl_read(GaimSslConnection *gsc, char **dest_buffer) +{ + size_t size = 0, s; + char *buffer = NULL; + char temp_buf[4096]; + + while ((s = gaim_ssl_read(gsc, temp_buf, sizeof(temp_buf))) > 0) + { + buffer = g_realloc(buffer, size + s + 1); + + strncpy(buffer + size, temp_buf, s); + + buffer[size + s] = '\0'; + + size += s; + } + + *dest_buffer = buffer; + + return size; +} + +/************************************************************************** + * Login + **************************************************************************/ + +static void +login_error_cb(GaimSslConnection *gsc, GaimSslErrorType error, void *data) +{ + MsnNexus *nexus; + MsnSession *session; + GaimAccount *account; + GaimConnection *gc; + + nexus = data; + g_return_if_fail(nexus != NULL); + + session = nexus->session; + g_return_if_fail(session != NULL); + + account = session->account; + g_return_if_fail(account != NULL); + + gc = gaim_account_get_connection(account); + g_return_if_fail(gc != NULL); + + gaim_connection_error(gc, _("Unable to connect to server")); + + msn_nexus_destroy(nexus); + session->nexus = NULL; +} + +static void +login_connect_cb(gpointer data, GaimSslConnection *gsc, + GaimInputCondition cond) +{ + MsnNexus *nexus; + MsnSession *session; + GaimConnection *gc; + char *username, *password; + char *request_str; + char *buffer = NULL; + size_t s; + + nexus = data; + g_return_if_fail(nexus != NULL); + + session = nexus->session; + g_return_if_fail(session != NULL); + + gc = gaim_account_get_connection(session->account); + g_return_if_fail(gc != NULL); + + username = + g_strdup(gaim_url_encode(gaim_account_get_username(session->account))); + + password = + g_strdup(gaim_url_encode(gaim_account_get_password(session->account))); + + request_str = g_strdup_printf( + "GET %s HTTP/1.1\r\n" + "Authorization: Passport1.4 OrgVerb=GET,OrgURL=%s,sign-in=%s,pwd=%s," + "lc=%s,id=%s,tw=%s,fs=%s,ru=%s,ct=%s,kpp=%s,kv=%s,ver=%s,tpf=%s\r\n" + "User-Agent: MSMSGS\r\n" + "Host: %s\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n" + "\r\n", + nexus->login_path, + (char *)g_hash_table_lookup(nexus->challenge_data, "ru"), + username, password, + (char *)g_hash_table_lookup(nexus->challenge_data, "lc"), + (char *)g_hash_table_lookup(nexus->challenge_data, "id"), + (char *)g_hash_table_lookup(nexus->challenge_data, "tw"), + (char *)g_hash_table_lookup(nexus->challenge_data, "fs"), + (char *)g_hash_table_lookup(nexus->challenge_data, "ru"), + (char *)g_hash_table_lookup(nexus->challenge_data, "ct"), + (char *)g_hash_table_lookup(nexus->challenge_data, "kpp"), + (char *)g_hash_table_lookup(nexus->challenge_data, "kv"), + (char *)g_hash_table_lookup(nexus->challenge_data, "ver"), + (char *)g_hash_table_lookup(nexus->challenge_data, "tpf"), + nexus->login_host); + + gaim_debug(GAIM_DEBUG_MISC, "msn", "Sending: {%s}\n", request_str); + + g_free(username); + g_free(password); + + if ((s = gaim_ssl_write(gsc, request_str, strlen(request_str))) <= 0) + { + g_free(request_str); + gaim_connection_error(gc, _("Unable to write to MSN Nexus server.")); + + return; + } + + g_free(request_str); + + if ((s = msn_ssl_read(gsc, &buffer)) <= 0) + { + gaim_connection_error(gc, _("Unable to write to MSN Nexus server.")); + return; + } + + gaim_ssl_close(gsc); + + gaim_debug(GAIM_DEBUG_MISC, "msn", "ssl buffer: {%s}", buffer); + + if (strstr(buffer, "HTTP/1.1 302") != NULL) + { + /* Redirect. */ + char *location, *c; + + location = strstr(buffer, "Location: "); + if (location == NULL) + { + gaim_connection_error(gc, + _("MSN Nexus server returned invalid redirect information.")); + + g_free(buffer); + + return; + } + + location = strchr(location, ' ') + 1; + + if ((c = strchr(location, '\r')) != NULL) + *c = '\0'; + + /* Skip the http:// */ + if ((c = strchr(location, '/')) != NULL) + location = c + 2; + + if ((c = strchr(location, '/')) != NULL) + { + g_free(nexus->login_path); + nexus->login_path = g_strdup(c); + + *c = '\0'; + } + + g_free(nexus->login_host); + nexus->login_host = g_strdup(location); + + gaim_ssl_connect(session->account, nexus->login_host, + GAIM_SSL_DEFAULT_PORT, login_connect_cb, + login_error_cb, nexus); + } + else if (strstr(buffer, "HTTP/1.1 401 Unauthorized") != NULL) + { + GaimConnection *gc; + const char *error, *c; + char *temp; + + if ((error = strstr(buffer, "WWW-Authenticate")) != NULL) + { + if ((error = strstr(error, "cbtxt=")) != NULL) + { + error += strlen("cbtxt="); + + if ((c = strchr(error, '\n')) == NULL) + c = error + strlen(error); + + temp = g_strndup(error, c - error); + error = gaim_url_decode(temp); + g_free(temp); + } + } + + gc = gaim_account_get_connection(session->account); + + if (error == NULL) + { + gaim_connection_error(gc, + _("Unknown error when attempting to authorize with " + "MSN login server.")); + } + else + gaim_connection_error(gc, error); + } + else if (strstr(buffer, "HTTP/1.1 200 OK")) + { + char outparams[MSN_BUF_LEN]; + char *base, *c; + char *login_params; + +#if 0 + /* All your base are belong to us. */ + base = buffer; + + /* For great cookie! */ + while ((base = strstr(base, "Set-Cookie: ")) != NULL) + { + base += strlen("Set-Cookie: "); + + c = strchr(base, ';'); + + session->login_cookies = + g_list_append(session->login_cookies, + g_strndup(base, c - base)); + } +#endif + + base = strstr(buffer, "Authentication-Info: "); + + if(base == NULL) + { + gaim_debug(GAIM_DEBUG_ERROR, "msn", + "Authentication information was not found. This did " + "not just happen, but if it did, you're screwed. " + "Report this.\n"); + + return; + } + + base = strstr(base, "from-PP='"); + base += strlen("from-PP='"); + c = strchr(base, '\''); + + login_params = g_strndup(base, c - base); + + g_snprintf(outparams, sizeof(outparams), + "TWN S %s", login_params); + + msn_servconn_send_command(session->notification_conn, "USR", + outparams); + + g_free(login_params); + + msn_nexus_destroy(nexus); + session->nexus = NULL; + } + + g_free(buffer); +} + +static void +nexus_connect_cb(gpointer data, GaimSslConnection *gsc, + GaimInputCondition cond) +{ + MsnNexus *nexus; + MsnSession *session; + char *request_str; + char *da_login; + char *base, *c; + char *buffer = NULL; + size_t s; + + nexus = data; + g_return_if_fail(nexus != NULL); + + session = nexus->session; + g_return_if_fail(session != NULL); + + request_str = g_strdup_printf("GET /rdr/pprdr.asp\r\n\r\n"); + + if ((s = gaim_ssl_write(gsc, request_str, strlen(request_str))) <= 0) + { + g_free(request_str); + return; + } + + g_free(request_str); + + /* Get the PassportURLs line. */ + if ((s = msn_ssl_read(gsc, &buffer)) <= 0) + return; + + base = strstr(buffer, "PassportURLs"); + + if (base == NULL) + { + g_free(buffer); + return; + } + + if ((da_login = strstr(base, "DALogin=")) != NULL) + { + if ((da_login = strchr(da_login, '=')) != NULL) + da_login++; + + if ((c = strchr(da_login, ',')) != NULL) + *c = '\0'; + + if ((c = strchr(da_login, '/')) != NULL) + { + nexus->login_path = g_strdup(c); + + *c = '\0'; + } + + nexus->login_host = g_strdup(da_login); + } + + g_free(buffer); + + gaim_ssl_close(gsc); + + /* Now begin the connection to the login server. */ + gaim_ssl_connect(session->account, nexus->login_host, + GAIM_SSL_DEFAULT_PORT, login_connect_cb, + login_error_cb, nexus); +} + +/************************************************************************** + * Nexus + **************************************************************************/ + +MsnNexus * +msn_nexus_new(MsnSession *session) +{ + MsnNexus *nexus; + + nexus = g_new0(MsnNexus, 1); + nexus->session = session; + nexus->challenge_data = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + + return nexus; +} + +void +msn_nexus_destroy(MsnNexus *nexus) +{ + if (nexus->login_host != NULL) + g_free(nexus->login_host); + + if (nexus->login_path != NULL) + g_free(nexus->login_path); + + if (nexus->challenge_data != NULL) + g_hash_table_destroy(nexus->challenge_data); + + g_free(nexus); +} + +void +msn_nexus_connect(MsnNexus *nexus) +{ + gaim_ssl_connect(nexus->session->account, "nexus.passport.com", + GAIM_SSL_DEFAULT_PORT, nexus_connect_cb, + login_error_cb, nexus); +}