Mercurial > pidgin
diff src/protocols/msn/httpmethod.c @ 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 | |
children | 414c701ef1ff |
line wrap: on
line diff
--- /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; +} +