Mercurial > pidgin
changeset 7288:ff9127038a5a
[gaim-migrate @ 7869]
It doesn't completely work yet, but this is the beginnings of the MSN HTTP
port 80 connect method. I don't have it set so it can be enabled, so it's
harmless to commit this now, but I want a second set of eyes, and I also
want to do other MSN work without dealing with hand-merging patches.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Fri, 17 Oct 2003 14:57:59 +0000 |
parents | 3a41c3f80228 |
children | ab2085024a29 |
files | src/protocols/msn/Makefile.am src/protocols/msn/httpmethod.c src/protocols/msn/httpmethod.h src/protocols/msn/msn.c src/protocols/msn/notification.c src/protocols/msn/servconn.c src/protocols/msn/servconn.h src/protocols/msn/session.c src/protocols/msn/session.h src/protocols/msn/switchboard.c |
diffstat | 10 files changed, 665 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/src/protocols/msn/Makefile.am Fri Oct 17 05:58:16 2003 +0000 +++ b/src/protocols/msn/Makefile.am Fri Oct 17 14:57:59 2003 +0000 @@ -11,6 +11,8 @@ error.h \ group.c \ group.h \ + httpmethod.c \ + httpmethod.h \ msg.c \ msg.h \ msn.c \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/httpmethod.c Fri Oct 17 14:57:59 2003 +0000 @@ -0,0 +1,406 @@ +/** + * @file httpmethod.c HTTP connection method + * + * gaim + * + * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "debug.h" +#include "httpmethod.h" + +#define GET_NEXT(tmp) \ + while (*(tmp) && *(tmp) != ' ' && *(tmp) != '\r') \ + (tmp)++; \ + if (*(tmp) != '\0') *(tmp)++ = '\0'; \ + if (*(tmp) == '\n') (tmp)++; \ + while (*(tmp) && *(tmp) == ' ') \ + (tmp)++ + +#define GET_NEXT_LINE(tmp) \ + while (*(tmp) && *(tmp) != '\r') \ + (tmp)++; \ + if (*(tmp) != '\0') *(tmp)++ = '\0'; \ + if (*(tmp) == '\n') (tmp)++ + +typedef struct +{ + MsnServConn *servconn; + char *buffer; + size_t size; + const char *server_type; + +} MsnHttpQueueData; + +static gboolean +http_poll(gpointer data) +{ + MsnServConn *servconn = data; + + gaim_debug_info("msn", "Polling server %s.\n", + servconn->http_data->gateway_ip); + + msn_http_servconn_poll(servconn); + + servconn->http_data->timer = 0; + + return FALSE; +} + +static void +stop_timer(MsnServConn *servconn) +{ + if (servconn->http_data->timer) + { + g_source_remove(servconn->http_data->timer); + servconn->http_data->timer = 0; + } +} + +static void +start_timer(MsnServConn *servconn) +{ + stop_timer(servconn); + + servconn->http_data->timer = g_timeout_add(5000, http_poll, servconn); +} + +size_t +msn_http_servconn_write(MsnServConn *servconn, const char *buf, size_t size, + const char *server_type) +{ + size_t s; + char *params; + char *temp; + gboolean first; + + g_return_val_if_fail(servconn != NULL, 0); + g_return_val_if_fail(buf != NULL, 0); + g_return_val_if_fail(size > 0, 0); + g_return_val_if_fail(servconn->http_data != NULL, 0); + + if (servconn->http_data->waiting_response || + servconn->http_data->queue != NULL) + { + MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1); + + queue_data->servconn = servconn; + queue_data->buffer = g_strdup(buf); + queue_data->size = size; + queue_data->server_type = server_type; + + servconn->http_data->queue = + g_list_append(servconn->http_data->queue, queue_data); + + return size; + } + + first = servconn->http_data->virgin; + + if (first) + { + if (server_type) + { + params = g_strdup_printf("Action=open&Server=%s&IP=%s", + server_type, + servconn->http_data->gateway_ip); + } + else + { + params = g_strdup_printf("Action=open&IP=%s", + servconn->http_data->gateway_ip); + } + } + else + { + params = g_strdup_printf("SessionID=%s", + servconn->http_data->session_id); + } + + temp = g_strdup_printf( + "POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n" + "Accept: */*\r\n" + "Accept-Language: en-us\r\n" + "User-Agent: MSMSGS\r\n" + "Host: %s\r\n" + "Proxy-Connection: Keep-Alive\r\n" + "Connection: Keep-Alive\r\n" + "Pragma: no-cache\r\n" + "Content-Type: application/x-msn-messenger\r\n" + "Content-Length: %d\r\n" + "\r\n" + "%s", + servconn->http_data->gateway_ip, + params, + servconn->http_data->gateway_ip, + size, + buf); + + g_free(params); + +#if 0 + gaim_debug_misc("msn", "Writing to HTTP: {%s}\n", temp); +#endif + + s = write(servconn->fd, temp, strlen(temp)); + + g_free(temp); + + servconn->http_data->waiting_response = TRUE; + + servconn->http_data->virgin = FALSE; + + stop_timer(servconn); + + return s; +} + +void +msn_http_servconn_poll(MsnServConn *servconn) +{ + size_t s; + char *temp; + + g_return_if_fail(servconn != NULL); + g_return_if_fail(servconn->http_data != NULL); + + if (servconn->http_data->waiting_response || + servconn->http_data->queue != NULL) + { + return; + } + + temp = g_strdup_printf( + "POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n" + "Accept: */*\r\n" + "Accept-Language: en-us\r\n" + "User-Agent: MSMSGS\r\n" + "Host: %s\r\n" + "Proxy-Connection: Keep-Alive\r\n" + "Connection: Keep-Alive\r\n" + "Pragma: no-cache\r\n" + "Content-Type: application/x-msn-messenger\r\n" + "Content-Length: 0\r\n" + "\r\n", + servconn->http_data->gateway_ip, + servconn->http_data->session_id, + servconn->http_data->gateway_ip); + +#if 0 + gaim_debug_misc("msn", "Writing to HTTP: {%s}\n", temp); +#endif + + s = write(servconn->fd, temp, strlen(temp)); + + g_free(temp); + + servconn->http_data->waiting_response = TRUE; + + stop_timer(servconn); + + if (s <= 0) + gaim_connection_error(servconn->session->account->gc, + _("Write error")); +} + +gboolean +msn_http_servconn_parse_data(MsnServConn *servconn, const char *buf, + size_t size, char **ret_buf, size_t *ret_size, + gboolean *error) +{ + GaimConnection *gc; + const char *s, *c; + char *headers, *body; + char *tmp; + size_t len = 0; + + g_return_val_if_fail(servconn != NULL, FALSE); + g_return_val_if_fail(buf != NULL, FALSE); + g_return_val_if_fail(size > 0, FALSE); + g_return_val_if_fail(ret_buf != NULL, FALSE); + g_return_val_if_fail(ret_size != NULL, FALSE); + g_return_val_if_fail(error != NULL, FALSE); + + servconn->http_data->waiting_response = FALSE; + + gc = gaim_account_get_connection(servconn->session->account); + + /* Healthy defaults. */ + *ret_buf = NULL; + *ret_size = 0; + *error = FALSE; + + /* First, some tests to see if we have a full block of stuff. */ + + if (strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0 && + strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0) + { + *error = TRUE; + + return FALSE; + } + + if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0) + { + if ((s = strstr(buf, "\r\n\r\n")) == NULL) + return FALSE; + + s += 4; + + if (*s == '\0') + { + *ret_buf = g_strdup(""); + *ret_size = 0; + + return TRUE; + } + + buf = s; + size -= (s - buf); + } + + if ((s = strstr(buf, "\r\n\r\n")) == NULL) + return FALSE; + + headers = g_strndup(buf, s - buf); + s += 4; /* Skip \r\n */ + body = g_strndup(s, size - (s - buf)); + +#if 0 + gaim_debug_misc("msn", "Incoming HTTP buffer: {%s\r\n%s}", headers, body); +#endif + + if ((s = strstr(headers, "Content-Length: ")) != NULL) + { + s += strlen("Content-Length: "); + + if ((c = strchr(s, '\r')) == NULL) + { + g_free(headers); + g_free(body); + + return FALSE; + } + + tmp = g_strndup(s, c - s); + len = atoi(tmp); + g_free(tmp); + + if (strlen(body) != len) + { + g_free(headers); + g_free(body); + + gaim_debug_warning("msn", + "body length (%d) != content length (%d)\n", + strlen(body), len); + return FALSE; + } + } + + /* Now we should be able to process the data. */ + if ((s = strstr(headers, "X-MSN-Messenger: ")) != NULL) + { + char *session_id, *gw_ip; + char *c2, *s2; + + s += strlen("X-MSN-Messenger: "); + + if ((c = strchr(s, '\r')) == NULL) + { + gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); + return FALSE; + } + + tmp = g_strndup(s, c - s); + + /* Find the value for the Session ID */ + if ((s2 = strchr(tmp, '=')) == NULL) + { + gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); + return FALSE; + } + + s2++; + + /* Terminate the ; so we can g_strdup it. */ + if ((c2 = strchr(s2, ';')) == NULL) + { + gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); + return FALSE; + } + + *c2 = '\0'; + c2++; + + /* Now grab that session ID. */ + session_id = g_strdup(s2); + + /* Continue to the gateway IP */ + if ((s2 = strchr(c2, '=')) == NULL) + { + gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); + return FALSE; + } + + s2++; + + /* Grab the gateway IP */ + gw_ip = g_strdup(s2); + + g_free(tmp); + + /* Set the new data. */ + if (servconn->http_data->session_id != NULL) + g_free(servconn->http_data->session_id); + + if (servconn->http_data->old_gateway_ip != NULL) + g_free(servconn->http_data->old_gateway_ip); + + servconn->http_data->old_gateway_ip = servconn->http_data->gateway_ip; + + servconn->http_data->session_id = session_id; + servconn->http_data->gateway_ip = gw_ip; + } + + g_free(headers); + + *ret_buf = body; + *ret_size = len; + + if (servconn->http_data->queue != NULL) + { + MsnHttpQueueData *queue_data; + + queue_data = (MsnHttpQueueData *)servconn->http_data->queue->data; + + servconn->http_data->queue = + g_list_remove(servconn->http_data->queue, queue_data); + + msn_http_servconn_write(queue_data->servconn, + queue_data->buffer, + queue_data->size, + queue_data->server_type); + + g_free(queue_data->buffer); + g_free(queue_data); + } + else + start_timer(servconn); + + return TRUE; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/httpmethod.h Fri Oct 17 14:57:59 2003 +0000 @@ -0,0 +1,83 @@ +/** + * @file httpmethod.h HTTP connection method + * + * gaim + * + * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_HTTP_METHOD_H_ +#define _MSN_HTTP_METHOD_H_ + +typedef struct _MsnHttpMethodData MsnHttpMethodData; + +#include "servconn.h" + +struct _MsnHttpMethodData +{ + char *session_id; + char *old_gateway_ip; + char *gateway_ip; + const char *server_type; + + int timer; + + gboolean virgin; + gboolean waiting_response; + + GList *queue; +}; + +/** + * Writes data to the server using the HTTP connection method. + * + * @param servconn The server connection. + * @param buf The data to write. + * @param size The size of the data to write. + * @param server_type The optional server type. + * + * @return The number of bytes written. + */ +size_t msn_http_servconn_write(MsnServConn *servconn, const char *buf, + size_t size, const char *server_type); + +/** + * Polls the server for data. + * + * @param servconn The server connection. + */ +void msn_http_servconn_poll(MsnServConn *servconn); + +/** + * Processes an incoming message and returns a string the rest of MSN + * can deal with. + * + * @param servconn The server connection. + * @param buf The incoming buffer. + * @param size The incoming size. + * @param ret_buf The returned buffer. + * @param ret_len The returned length. + * @param error TRUE if there was an HTTP error. + * + * @return TRUE if the returned buffer is ready to be processed. + * FALSE otherwise. + */ +gboolean msn_http_servconn_parse_data(MsnServConn *servconn, + const char *buf, size_t size, + char **ret_buf, size_t *ret_size, + gboolean *error); + +#endif /* _MSN_HTTP_METHOD_H_ */
--- a/src/protocols/msn/msn.c Fri Oct 17 05:58:16 2003 +0000 +++ b/src/protocols/msn/msn.c Fri Oct 17 14:57:59 2003 +0000 @@ -446,6 +446,7 @@ MsnSession *session; const char *username; const char *server; + gboolean http_method = FALSE; int port; gc = gaim_account_get_connection(account); @@ -458,10 +459,21 @@ return; } - server = gaim_account_get_string(account, "server", MSN_SERVER); - port = gaim_account_get_int(account, "port", MSN_PORT); + if (gaim_account_get_bool(account, "http_method", FALSE)) + { + http_method = TRUE; + + server = "gateway.messenger.hotmail.com"; + port = 80; + } + else + { + server = gaim_account_get_string(account, "server", MSN_SERVER); + port = gaim_account_get_int(account, "port", MSN_PORT); + } session = msn_session_new(account, server, port); + session->http_method = http_method; session->prpl = my_protocol; gc->proto_data = session; @@ -1624,6 +1636,13 @@ prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); +#if 0 + option = gaim_account_option_bool_new(_("Use HTTP Method"), "http_method", + FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, + option); +#endif + my_protocol = plugin; gaim_prefs_add_none("/plugins/prpl/msn");
--- a/src/protocols/msn/notification.c Fri Oct 17 05:58:16 2003 +0000 +++ b/src/protocols/msn/notification.c Fri Oct 17 14:57:59 2003 +0000 @@ -1863,6 +1863,9 @@ else port = 1863; + if (session->http_method) + port = 80; + swboard = msn_switchboard_new(session); user = msn_user_new(session, params[4], NULL); @@ -1925,6 +1928,9 @@ msn_switchboard_set_auth_key(swboard, params[4]); + if (session->http_method) + port = 80; + if (!msn_switchboard_connect(swboard, host, port)) { gaim_debug(GAIM_DEBUG_ERROR, "msn", "Unable to connect to switchboard on %s, port %d\n", @@ -2183,6 +2189,9 @@ msn_servconn_set_connect_cb(notification, connect_cb); msn_servconn_set_failed_read_cb(notification, failed_read_cb); + if (session->http_method) + notification->http_data->server_type = "NS"; + if (notification_commands == NULL) { /* Register the command callbacks. */ msn_servconn_register_command(notification, "ADD", add_cmd);
--- a/src/protocols/msn/servconn.c Fri Oct 17 05:58:16 2003 +0000 +++ b/src/protocols/msn/servconn.c Fri Oct 17 14:57:59 2003 +0000 @@ -186,6 +186,7 @@ { MsnServConn *servconn = data; + gaim_debug_info("msn", "In servconn's connect_cb\n"); if (servconn->connect_cb(data, source, cond)) servconn->inpa = gaim_input_add(servconn->fd, GAIM_INPUT_READ, servconn->login_cb, data); @@ -203,6 +204,12 @@ servconn->login_cb = msn_servconn_parse_data; servconn->session = session; + if (session->http_method) + { + servconn->http_data = g_new0(MsnHttpMethodData, 1); + servconn->http_data->virgin = TRUE; + } + servconn->commands = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); @@ -217,14 +224,23 @@ gboolean msn_servconn_connect(MsnServConn *servconn) { + MsnSession *session; int i; - g_return_val_if_fail(servconn != NULL, FALSE); + g_return_val_if_fail(servconn != NULL, FALSE); g_return_val_if_fail(servconn->server != NULL, FALSE); - g_return_val_if_fail(!servconn->connected, TRUE); + g_return_val_if_fail(!servconn->connected, TRUE); + + session = servconn->session; - i = gaim_proxy_connect(servconn->session->account, servconn->server, - servconn->port, connect_cb, servconn); + if (session->http_method) + { + servconn->http_data->gateway_ip = g_strdup(servconn->server); + servconn->port = 80; + } + + i = gaim_proxy_connect(session->account, servconn->server, + servconn->port, connect_cb, servconn); if (i == 0) servconn->connected = TRUE; @@ -235,14 +251,35 @@ void msn_servconn_disconnect(MsnServConn *servconn) { + MsnSession *session; + g_return_if_fail(servconn != NULL); g_return_if_fail(servconn->connected); + session = servconn->session; + if (servconn->inpa) gaim_input_remove(servconn->inpa); close(servconn->fd); + if (servconn->http_data != NULL) + { + if (servconn->http_data->session_id != NULL) + g_free(servconn->http_data->session_id); + + if (servconn->http_data->old_gateway_ip != NULL) + g_free(servconn->http_data->old_gateway_ip); + + if (servconn->http_data->gateway_ip != NULL) + g_free(servconn->http_data->gateway_ip); + + if (servconn->http_data->timer) + g_source_remove(servconn->http_data->timer); + + g_free(servconn->http_data); + } + if (servconn->rxqueue != NULL) g_free(servconn->rxqueue); @@ -340,7 +377,11 @@ gaim_debug(GAIM_DEBUG_MISC, "msn", "C: %s%s", buf, (*(buf + size - 1) == '\n' ? "" : "\n")); - return write(servconn->fd, buf, size); + if (servconn->session->http_method) + return msn_http_servconn_write(servconn, buf, size, + servconn->http_data->server_type); + else + return write(servconn->fd, buf, size); } gboolean @@ -389,7 +430,8 @@ g_return_if_fail(servconn != NULL); g_return_if_fail(msg != NULL); - for (l = servconn->msg_queue; l != NULL; l = l->next) { + for (l = servconn->msg_queue; l != NULL; l = l->next) + { entry = l->data; if (entry->msg == msg) @@ -448,7 +490,8 @@ len = read(servconn->fd, buf, sizeof(buf)); - if (len <= 0) { + if (len <= 0) + { if (servconn->failed_read_cb != NULL) servconn->failed_read_cb(data, source, cond); @@ -459,8 +502,75 @@ memcpy(servconn->rxqueue + servconn->rxlen, buf, len); servconn->rxlen += len; - while (cont) { - if (servconn->parsing_multiline) { + if (session->http_method) + { + char *result_msg = NULL; + size_t result_len = 0; + gboolean error; + char *tmp; + + tmp = g_strndup(servconn->rxqueue, servconn->rxlen); + + if (!msn_http_servconn_parse_data(servconn, tmp, + servconn->rxlen, &result_msg, + &result_len, &error)) + { + g_free(tmp); + return; + } + + g_free(tmp); + + if (error) + { + gaim_connection_error( + gaim_account_get_connection(session->account), + _("Received HTTP error. Please report this.")); + + return; + } + + if (servconn->http_data->session_id != NULL && + !strcmp(servconn->http_data->session_id, "close")) + { + msn_servconn_destroy(servconn); + + return; + } + +#if 0 + if (strcmp(servconn->http_data->gateway_ip, + msn_servconn_get_server(servconn)) != 0) + { + int i; + + /* Evil hackery. I promise to remove it, even though I can't. */ + + servconn->connected = FALSE; + + if (servconn->inpa) + gaim_input_remove(servconn->inpa); + + close(servconn->fd); + + i = gaim_proxy_connect(session->account, servconn->server, + servconn->port, servconn->login_cb, + servconn); + + if (i == 0) + servconn->connected = TRUE; + } +#endif + + g_free(servconn->rxqueue); + servconn->rxqueue = result_msg; + servconn->rxlen = result_len; + } + + while (cont) + { + if (servconn->parsing_multiline) + { char *msg; if (servconn->rxlen == 0) @@ -539,4 +649,3 @@ } } } -
--- a/src/protocols/msn/servconn.h Fri Oct 17 05:58:16 2003 +0000 +++ b/src/protocols/msn/servconn.h Fri Oct 17 14:57:59 2003 +0000 @@ -27,6 +27,7 @@ typedef struct _MsnServConn MsnServConn; #include "msg.h" +#include "httpmethod.h" typedef gboolean (*MsnServConnCommandCb)(MsnServConn *servconn, const char *cmd, const char **params, @@ -50,6 +51,8 @@ gboolean connected; + MsnHttpMethodData *http_data; + char *server; int port;
--- a/src/protocols/msn/session.c Fri Oct 17 05:58:16 2003 +0000 +++ b/src/protocols/msn/session.c Fri Oct 17 14:57:59 2003 +0000 @@ -22,6 +22,7 @@ #include "msn.h" #include "session.h" #include "dispatch.h" +#include "notification.h" MsnSession * msn_session_new(GaimAccount *account, const char *server, int port) @@ -103,12 +104,23 @@ session->connected = TRUE; - session->dispatch_conn = msn_dispatch_new(session, - session->dispatch_server, - session->dispatch_port); + if (session->http_method) + { + session->notification_conn = + msn_notification_new(session, "gateway.messenger.hotmail.com", 80); - if (msn_servconn_connect(session->dispatch_conn)) - return TRUE; + if (msn_servconn_connect(session->notification_conn)) + return TRUE; + } + else + { + session->dispatch_conn = msn_dispatch_new(session, + session->dispatch_server, + session->dispatch_port); + + if (msn_servconn_connect(session->dispatch_conn)) + return TRUE; + } return FALSE; }
--- a/src/protocols/msn/session.h Fri Oct 17 05:58:16 2003 +0000 +++ b/src/protocols/msn/session.h Fri Oct 17 14:57:59 2003 +0000 @@ -48,6 +48,8 @@ unsigned int trId; + gboolean http_method; + char *ssl_url; char *ssl_login_host; char *ssl_login_path;
--- a/src/protocols/msn/switchboard.c Fri Oct 17 05:58:16 2003 +0000 +++ b/src/protocols/msn/switchboard.c Fri Oct 17 14:57:59 2003 +0000 @@ -459,6 +459,9 @@ msn_servconn_set_connect_cb(servconn, connect_cb); msn_servconn_set_failed_read_cb(servconn, failed_read_cb); + if (session->http_method) + swboard->servconn->http_data->server_type = "SB"; + servconn->data = swboard; session->switches = g_list_append(session->switches, swboard);