From: Christian H. <ch...@us...> - 2003-10-17 16:02:03
|
Update of /cvsroot/gaim/gaim/src/protocols/msn In directory sc8-pr-cvs1:/tmp/cvs-serv21872 Modified Files: Makefile.am msn.c notification.c servconn.c servconn.h session.c session.h switchboard.c Added Files: httpmethod.c httpmethod.h Log Message: 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. --- NEW FILE: httpmethod.c --- /** * @file httpmethod.c HTTP connection method * * gaim * * Copyright (C) 2003 Christian Hammond <ch...@gn...> * * 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; } --- NEW FILE: httpmethod.h --- /** * @file httpmethod.h HTTP connection method * * gaim * * Copyright (C) 2003 Christian Hammond <ch...@gn...> * * 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_ */ Index: Makefile.am =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/msn/Makefile.am,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -p -r1.21 -r1.22 --- Makefile.am 14 Oct 2003 03:12:28 -0000 1.21 +++ Makefile.am 17 Oct 2003 14:57:59 -0000 1.22 @@ -11,6 +11,8 @@ MSNSOURCES = \ error.h \ group.c \ group.h \ + httpmethod.c \ + httpmethod.h \ msg.c \ msg.h \ msn.c \ Index: msn.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/msn/msn.c,v retrieving revision 1.238 retrieving revision 1.239 diff -u -d -p -r1.238 -r1.239 --- msn.c 16 Oct 2003 00:53:02 -0000 1.238 +++ msn.c 17 Oct 2003 14:57:59 -0000 1.239 @@ -446,6 +446,7 @@ msn_login(GaimAccount *account) MsnSession *session; const char *username; const char *server; + gboolean http_method = FALSE; int port; gc = gaim_account_get_connection(account); @@ -458,10 +459,21 @@ msn_login(GaimAccount *account) 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; @@ -1623,6 +1635,13 @@ init_plugin(GaimPlugin *plugin) option = gaim_account_option_int_new(_("Port"), "port", 1863); 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; Index: notification.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/msn/notification.c,v retrieving revision 1.71 retrieving revision 1.72 diff -u -d -p -r1.71 -r1.72 --- notification.c 15 Oct 2003 06:32:13 -0000 1.71 +++ notification.c 17 Oct 2003 14:57:59 -0000 1.72 @@ -1863,6 +1863,9 @@ rng_cmd(MsnServConn *servconn, const cha 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 @@ xfr_cmd(MsnServConn *servconn, const cha 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", @@ -2182,6 +2188,9 @@ msn_notification_new(MsnSession *session msn_servconn_set_server(notification, server, port); 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. */ Index: servconn.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/msn/servconn.c,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -p -r1.21 -r1.22 --- servconn.c 14 Sep 2003 22:00:10 -0000 1.21 +++ servconn.c 17 Oct 2003 14:57:59 -0000 1.22 @@ -186,6 +186,7 @@ connect_cb(gpointer data, gint source, G { 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 @@ msn_servconn_new(MsnSession *session) 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 @@ msn_servconn_new(MsnSession *session) 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); - i = gaim_proxy_connect(servconn->session->account, servconn->server, - servconn->port, connect_cb, servconn); + session = servconn->session; + + 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 @@ msn_servconn_connect(MsnServConn *servco 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 @@ msn_servconn_write(MsnServConn *servconn 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 @@ msn_servconn_unqueue_message(MsnServConn 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 @@ msn_servconn_parse_data(gpointer data, g 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 @@ msn_servconn_parse_data(gpointer data, g 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 @@ msn_servconn_parse_data(gpointer data, g } } } - Index: servconn.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/msn/servconn.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -p -r1.4 -r1.5 --- servconn.h 2 Sep 2003 04:32:16 -0000 1.4 +++ servconn.h 17 Oct 2003 14:57:59 -0000 1.5 @@ -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, @@ -49,6 +50,8 @@ struct _MsnServConn MsnSession *session; gboolean connected; + + MsnHttpMethodData *http_data; char *server; int port; Index: session.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/msn/session.c,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -p -r1.12 -r1.13 --- session.c 14 Sep 2003 01:59:09 -0000 1.12 +++ session.c 17 Oct 2003 14:57:59 -0000 1.13 @@ -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 @@ msn_session_connect(MsnSession *session) 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; } Index: session.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/msn/session.h,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -p -r1.11 -r1.12 --- session.h 2 Sep 2003 04:32:16 -0000 1.11 +++ session.h 17 Oct 2003 14:57:59 -0000 1.12 @@ -48,6 +48,8 @@ struct _MsnSession unsigned int trId; + gboolean http_method; + char *ssl_url; char *ssl_login_host; char *ssl_login_path; Index: switchboard.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/msn/switchboard.c,v retrieving revision 1.49 retrieving revision 1.50 diff -u -d -p -r1.49 -r1.50 --- switchboard.c 2 Oct 2003 02:54:03 -0000 1.49 +++ switchboard.c 17 Oct 2003 14:57:59 -0000 1.50 @@ -459,6 +459,9 @@ msn_switchboard_new(MsnSession *session) 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); |