# HG changeset patch # User Stu Tomlinson # Date 1104510862 0 # Node ID 9bed28273ec742349e5dce6a73e7fef5a202346d # Parent f7b32dd67bdf3c999372528c24143c0f8e399c8a [gaim-migrate @ 11737] Felipe Contreras fixed the MSN HTTP Method. Yay! Thanks Felipe. committer: Tailor Script diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/Makefile.am --- a/src/protocols/msn/Makefile.am Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/Makefile.am Fri Dec 31 16:34:22 2004 +0000 @@ -18,8 +18,8 @@ group.h \ history.c \ history.h \ - httpmethod.c \ - httpmethod.h \ + httpconn.c \ + httpconn.h \ msg.c \ msg.h \ msn.c \ diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/Makefile.mingw --- a/src/protocols/msn/Makefile.mingw Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/Makefile.mingw Fri Dec 31 16:34:22 2004 +0000 @@ -75,7 +75,7 @@ error.c \ group.c \ history.c \ - httpmethod.c \ + httpconn.c \ msg.c \ msn.c \ nexus.c \ diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/cmdproc.h --- a/src/protocols/msn/cmdproc.h Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/cmdproc.h Fri Dec 31 16:34:22 2004 +0000 @@ -55,6 +55,8 @@ /* MsnPayloadCb payload_cb; */ MsnHistory *history; + + void *data; /**< Extra data, like the switchboard. */ }; MsnCmdProc *msn_cmdproc_new(MsnSession *session); diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/httpconn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/httpconn.c Fri Dec 31 16:34:22 2004 +0000 @@ -0,0 +1,742 @@ +/** + * @file httpmethod.c HTTP connection method + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 "msn.h" +#include "debug.h" +#include "httpconn.h" + +typedef struct +{ + MsnHttpConn *httpconn; + char *buffer; + size_t size; + +} MsnHttpQueueData; + +static void read_cb(gpointer data, gint source, GaimInputCondition cond); +void msn_httpconn_process_queue(MsnHttpConn *httpconn); +gboolean msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf, + size_t size, char **ret_buf, size_t *ret_size, + gboolean *error); + +MsnHttpConn * +msn_httpconn_new(MsnServConn *servconn) +{ + MsnHttpConn *httpconn; + + g_return_val_if_fail(servconn != NULL, NULL); + + httpconn = g_new0(MsnHttpConn, 1); + + /* TODO: Remove this */ + httpconn->session = servconn->session; + + httpconn->servconn = servconn; + + return httpconn; +} + +void +msn_httpconn_destroy(MsnHttpConn *httpconn) +{ + g_return_if_fail(httpconn != NULL); + + if (httpconn->connected) + msn_httpconn_disconnect(httpconn); + + if (httpconn->host != NULL) + g_free(httpconn->host); + + g_free(httpconn); +} + +static void +show_error(MsnHttpConn *httpconn) +{ + GaimConnection *gc; + char *tmp; + char *cmd; + + const char *names[] = { "Notification", "Switchboard" }; + const char *name; + + gc = gaim_account_get_connection(httpconn->servconn->session->account); + name = names[httpconn->servconn->type]; + + switch (httpconn->servconn->cmdproc->error) + { + case MSN_ERROR_CONNECT: + tmp = g_strdup_printf(_("Unable to connect to %s server"), + name); + break; + case MSN_ERROR_WRITE: + tmp = g_strdup_printf(_("Error writing to %s server"), name); + break; + case MSN_ERROR_READ: + cmd = httpconn->servconn->cmdproc->last_trans; + tmp = g_strdup_printf(_("Error reading from %s server"), name); + gaim_debug_info("msn", "Last command was: %s\n", cmd); + break; + default: + tmp = g_strdup_printf(_("Unknown error from %s server"), name); + break; + } + + if (httpconn->servconn->type == MSN_SERVER_NS) + { + gaim_connection_error(gc, tmp); + } + else + { + MsnSwitchBoard *swboard; + swboard = httpconn->servconn->cmdproc->data; + swboard->error = MSN_SB_ERROR_CONNECTION; + } + + g_free(tmp); +} + +static ssize_t +write_raw(MsnHttpConn *httpconn, const void *buffer, size_t len) +{ + ssize_t s; + ssize_t res; /* result of the write operation */ + +#ifdef MSN_DEBUG_HTTP + gaim_debug_misc("msn", "Writing HTTP: {%s}\n", buffer); +#endif + + s = 0; + + do + { + res = write(httpconn->fd, buffer, len); + if (res >= 0) + { + s += res; + } + else if (errno != EAGAIN) + { + httpconn->servconn->cmdproc->error = MSN_ERROR_WRITE; + show_error(httpconn); + return -1; + } + } while (s < len); + + return s; +} + +void +msn_httpconn_poll(MsnHttpConn *httpconn) +{ + int r; + char *temp; + + g_return_if_fail(httpconn != NULL); + + if (httpconn->waiting_response || + httpconn->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", + httpconn->host, + httpconn->full_session_id, + httpconn->host); + + r = write_raw(httpconn, temp, strlen(temp)); + + g_free(temp); + + if (r > 0) + { + httpconn->waiting_response = TRUE; + httpconn->dirty = FALSE; + } +} + +static gboolean +poll(gpointer data) +{ + MsnHttpConn *httpconn; + + httpconn = data; + +#if 0 + gaim_debug_info("msn", "polling from %s\n", httpconn->session_id); +#endif + + if (httpconn->dirty) + msn_httpconn_poll(httpconn); + + return TRUE; +} + +static void +connect_cb(gpointer data, gint source, GaimInputCondition cond) +{ + MsnHttpConn *httpconn = data; + + httpconn->fd = source; + + if (source > 0) + { + httpconn->inpa = gaim_input_add(httpconn->fd, GAIM_INPUT_READ, + read_cb, data); + + httpconn->timer = gaim_timeout_add(2000, poll, httpconn); + + httpconn->waiting_response = FALSE; + msn_httpconn_process_queue(httpconn); + } + else + { + gaim_debug_error("msn", "HTTP: Connection error\n"); + show_error(httpconn); + } +} + +gboolean +msn_httpconn_connect(MsnHttpConn *httpconn, const char *host, int port) +{ + int r; + + g_return_val_if_fail(httpconn != NULL, FALSE); + g_return_val_if_fail(host != NULL, FALSE); + g_return_val_if_fail(port > 0, FALSE); + + if (httpconn->connected) + msn_httpconn_disconnect(httpconn); + + r = gaim_proxy_connect(httpconn->session->account, + "gateway.messenger.hotmail.com", 80, connect_cb, + httpconn); + + if (r == 0) + { + httpconn->waiting_response = TRUE; + httpconn->connected = TRUE; + } + + return httpconn->connected; +} + +void +msn_httpconn_disconnect(MsnHttpConn *httpconn) +{ + g_return_if_fail(httpconn != NULL); + g_return_if_fail(httpconn->connected); + + if (httpconn->timer) + gaim_timeout_remove(httpconn->timer); + + httpconn->timer = 0; + + if (httpconn->inpa > 0) + { + gaim_input_remove(httpconn->inpa); + httpconn->inpa = 0; + } + + close(httpconn->fd); + + httpconn->rx_buf = NULL; + httpconn->rx_len = 0; + + httpconn->connected = FALSE; + + /* msn_servconn_disconnect(httpconn->servconn); */ +} + +static void +read_cb(gpointer data, gint source, GaimInputCondition cond) +{ + MsnHttpConn *httpconn; + MsnServConn *servconn; + MsnSession *session; + char buf[MSN_BUF_LEN]; + char *cur, *end, *old_rx_buf; + int len, cur_len; + char *result_msg = NULL; + size_t result_len = 0; + gboolean error; + + httpconn = data; + servconn = NULL; + session = httpconn->session; + + len = read(httpconn->fd, buf, sizeof(buf) - 1); + + if (len <= 0) + { + gaim_debug_error("msn", "HTTP: Read error\n"); + show_error(httpconn); + msn_httpconn_disconnect(httpconn); + + return; + } + + buf[len] = '\0'; + + httpconn->rx_buf = g_realloc(httpconn->rx_buf, len + httpconn->rx_len + 1); + memcpy(httpconn->rx_buf + httpconn->rx_len, buf, len + 1); + httpconn->rx_len += len; + + if (!msn_httpconn_parse_data(httpconn, httpconn->rx_buf, httpconn->rx_len, + &result_msg, &result_len, &error)) + { + /* We must wait for more input */ + + return; + } + + httpconn->servconn->processing = FALSE; + + servconn = httpconn->servconn; + + if (error) + { + gaim_debug_error("msn", "HTTP: Special error\n"); + show_error(httpconn); + msn_httpconn_disconnect(httpconn); + + return; + } + + if (result_len == 0) + { + /* Nothing to do here */ +#if 0 + gaim_debug_info("msn", "HTTP: nothing to do here\n"); +#endif + g_free(httpconn->rx_buf); + httpconn->rx_buf = NULL; + httpconn->rx_len = 0; + return; + } + + g_free(httpconn->rx_buf); + httpconn->rx_buf = NULL; + httpconn->rx_len = 0; + + servconn->rx_buf = result_msg; + servconn->rx_len = result_len; + + end = old_rx_buf = servconn->rx_buf; + + servconn->processing = TRUE; + + do + { + cur = end; + + if (servconn->payload_len) + { + if (servconn->payload_len > servconn->rx_len) + /* The payload is still not complete. */ + break; + + cur_len = servconn->payload_len; + end += cur_len; + } + else + { + end = strstr(cur, "\r\n"); + + if (end == NULL) + /* The command is still not complete. */ + break; + + *end = '\0'; + end += 2; + cur_len = end - cur; + } + + servconn->rx_len -= cur_len; + + if (servconn->payload_len) + { + msn_cmdproc_process_payload(servconn->cmdproc, cur, cur_len); + servconn->payload_len = 0; + } + else + { + msn_cmdproc_process_cmd_text(servconn->cmdproc, cur); + } + } while (servconn->connected && servconn->rx_len > 0); + + if (servconn->connected) + { + if (servconn->rx_len > 0) + servconn->rx_buf = g_memdup(cur, servconn->rx_len); + else + servconn->rx_buf = NULL; + } + + servconn->processing = FALSE; + + if (servconn->wasted) + msn_servconn_destroy(servconn); + + g_free(old_rx_buf); +} + +void +msn_httpconn_process_queue(MsnHttpConn *httpconn) +{ + if (httpconn->queue != NULL) + { + MsnHttpQueueData *queue_data; + + queue_data = (MsnHttpQueueData *)httpconn->queue->data; + + httpconn->queue = g_list_remove(httpconn->queue, queue_data); + + msn_httpconn_write(queue_data->httpconn, + queue_data->buffer, + queue_data->size); + + g_free(queue_data->buffer); + g_free(queue_data); + } + else + { + httpconn->dirty = TRUE; + } +} + +size_t +msn_httpconn_write(MsnHttpConn *httpconn, const char *buf, size_t size) +{ + char *params; + char *temp; + gboolean first; + const char *server_types[] = { "NS", "SB" }; + const char *server_type; + size_t r; /* result of the write operation */ + size_t len; + char *host; + MsnServConn *servconn; + + /* TODO: remove http data from servconn */ + + g_return_val_if_fail(httpconn != NULL, 0); + g_return_val_if_fail(buf != NULL, 0); + g_return_val_if_fail(size > 0, 0); + + servconn = httpconn->servconn; + + if (httpconn->waiting_response) + { + MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1); + + queue_data->httpconn = httpconn; + queue_data->buffer = g_memdup(buf, size); + queue_data->size = size; + + httpconn->queue = g_list_append(httpconn->queue, queue_data); + /* httpconn->dirty = TRUE; */ + + /* servconn->processing = TRUE; */ + + return size; + } + + first = httpconn->virgin; + server_type = server_types[servconn->type]; + + if (first) + { + host = "gateway.messenger.hotmail.com"; + + /* The first time servconn->host is the host we should connect to. */ + params = g_strdup_printf("Action=open&Server=%s&IP=%s", + server_type, + servconn->host); + } + else + { + /* The rest of the times servconn->host is the gateway host. */ + host = httpconn->host; + + params = g_strdup_printf("SessionID=%s", + httpconn->full_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", + host, + params, + host, + (int)size); + + g_free(params); + + len = strlen(temp); + temp = g_realloc(temp, len + size + 1); + memcpy(temp + len, buf, size); + len += size; + temp[len] = '\0'; + + r = write_raw(httpconn, temp, len); + + g_free(temp); + + if (r > 0) + { + httpconn->virgin = FALSE; + httpconn->waiting_response = TRUE; + httpconn->dirty = FALSE; + } + + return r; +} + +gboolean +msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf, + size_t size, char **ret_buf, size_t *ret_size, + gboolean *error) +{ + GaimConnection *gc; + const char *s, *c; + char *headers, *body; + const char *body_start; + char *tmp; + size_t body_len = 0; + gboolean wasted = FALSE; + + g_return_val_if_fail(httpconn != 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); + +#if 0 + gaim_debug_info("msn", "HTTP: parsing data {%s}\n", buf); +#endif + + httpconn->waiting_response = FALSE; + + gc = gaim_account_get_connection(httpconn->session->account); + + /* Healthy defaults. */ + body = NULL; + + *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)) && + ((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) && + (strncmp(buf, "HTTP/1.0 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; + + msn_httpconn_process_queue(httpconn); + + 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_start = s; + body_len = size - (body_start - buf); + + if ((s = strstr(headers, "Content-Length: ")) != NULL) + { + int tmp_len; + + s += strlen("Content-Length: "); + + if ((c = strchr(s, '\r')) == NULL) + { + g_free(headers); + + return FALSE; + } + + tmp = g_strndup(s, c - s); + tmp_len = atoi(tmp); + g_free(tmp); + + if (body_len != tmp_len) + { + g_free(headers); + +#if 0 + gaim_debug_warning("msn", + "body length (%d) != content length (%d)\n", + body_len, tmp_len); +#endif + + return FALSE; + } + } + + body = g_memdup(body_start, body_len); + +#ifdef MSN_DEBUG_HTTP + gaim_debug_misc("msn", "Incoming HTTP buffer: {%s\r\n\r\n%s}\n", headers, body); +#endif + + /* Now we should be able to process the data. */ + if ((s = strstr(headers, "X-MSN-Messenger: ")) != NULL) + { + char *full_session_id, *gw_ip, *session_action; + char *t, *session_id; + char **elems, **cur, **tokens; + + full_session_id = gw_ip = session_action = NULL; + + s += strlen("X-MSN-Messenger: "); + + if ((c = strchr(s, '\r')) == NULL) + { + gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); + gaim_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}", + buf); + + return FALSE; + } + + tmp = g_strndup(s, c - s); + + elems = g_strsplit(tmp, "; ", 0); + + for (cur = elems; *cur != NULL; cur++) + { + tokens = g_strsplit(*cur, "=", 2); + + if (strcmp(tokens[0], "SessionID") == 0) + full_session_id = tokens[1]; + else if (strcmp(tokens[0], "GW-IP") == 0) + gw_ip = tokens[1]; + else if (strcmp(tokens[0], "Session") == 0) + session_action = tokens[1]; + + g_free(tokens[0]); + /* Don't free each of the tokens, only the array. */ + g_free(tokens); + } + + g_strfreev(elems); + + g_free(tmp); + + if ((session_action != NULL) && (strcmp(session_action, "close") == 0)) + wasted = TRUE; + + g_free(session_action); + + t = strchr(full_session_id, '.'); + session_id = g_strndup(full_session_id, t - full_session_id); + + if (!wasted) + { + if (httpconn->full_session_id != NULL); + g_free(httpconn->full_session_id); + + httpconn->full_session_id = full_session_id; + + if (httpconn->session_id != NULL); + g_free(httpconn->session_id); + + httpconn->session_id = session_id; + + if (httpconn->host != NULL); + g_free(httpconn->host); + + httpconn->host = gw_ip; + } + else + { + MsnServConn *servconn; + + /* It's going to die. */ + + servconn = httpconn->servconn; + + if (servconn != NULL) + servconn->wasted = TRUE; + + g_free(full_session_id); + g_free(gw_ip); + } + } + + g_free(headers); + + *ret_buf = body; + *ret_size = body_len; + + msn_httpconn_process_queue(httpconn); + + return TRUE; +} diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/httpconn.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/httpconn.h Fri Dec 31 16:34:22 2004 +0000 @@ -0,0 +1,128 @@ +/** + * @file httpconn.h HTTP connection + * + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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_HTTPCONN_H_ +#define _MSN_HTTPCONN_H_ + +typedef struct _MsnHttpConn MsnHttpConn; + +#include "servconn.h" + +struct _MsnHttpConn +{ + MsnSession *session; + MsnServConn *servconn; + + char *full_session_id; + char *session_id; + + int timer; + + gboolean waiting_response; + gboolean dirty; /**< The flag that states if we should poll. */ + gboolean connected; + + char *host; + GList *queue; + + int fd; + int inpa; + + char *rx_buf; + int rx_len; + +#if 0 + GQueue *servconn_queue; +#endif + + gboolean virgin; +}; + +MsnHttpConn *msn_httpconn_new(MsnServConn *servconn); +void msn_httpconn_destroy(MsnHttpConn *httpconn); +size_t msn_httpconn_write(MsnHttpConn *httpconn, const char *buf, size_t size); + +gboolean msn_httpconn_connect(MsnHttpConn *httpconn, + const char *host, int port); +void msn_httpconn_disconnect(MsnHttpConn *httpconn); + +#if 0 +void msn_httpconn_queue_servconn(MsnHttpConn *httpconn, MsnServConn *servconn); +#endif + +#if 0 +/** + * Initializes the HTTP data for a session. + * + * @param session The session. + */ +void msn_http_session_init(MsnSession *session); + +/** + * Uninitializes the HTTP data for a session. + * + * @param session The session. + */ +void msn_http_session_uninit(MsnSession *session); + +/** + * 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 + +#endif /* _MSN_HTTPCONN_H_ */ diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/httpmethod.c --- a/src/protocols/msn/httpmethod.c Fri Dec 31 15:34:18 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,462 +0,0 @@ -/** - * @file httpmethod.c HTTP connection method - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * 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) -{ - MsnSession *session; - GList *l; - - session = data; - - for (l = session->switches; l != NULL; l = l->next) - { - MsnSwitchBoard *swboard; - - swboard = l->data; - - g_return_val_if_fail(swboard->servconn->http_data != NULL, FALSE); - - if (swboard->servconn->http_data->dirty) - { -#if 0 - gaim_debug_info("msn", "Polling server %s.\n", - servconn->http_data->gateway_host); -#endif - msn_http_servconn_poll(swboard->servconn); - } - } - - if (session->notification->servconn->http_data->dirty) - msn_http_servconn_poll(session->notification->servconn); - - return TRUE; -} - -static void -stop_timer(MsnSession *session) -{ - if (session->http_poll_timer) - { - gaim_timeout_remove(session->http_poll_timer); - session->http_poll_timer = 0; - } -} - -static void -start_timer(MsnSession *session) -{ - stop_timer(session); - - session->http_poll_timer = gaim_timeout_add(2000, http_poll, session); -} - -void -msn_http_session_init(MsnSession *session) -{ - g_return_if_fail(session != NULL); - - start_timer(session); -} - -void -msn_http_session_uninit(MsnSession *session) -{ - g_return_if_fail(session != NULL); - - stop_timer(session); -} - -size_t -msn_http_servconn_write(MsnServConn *servconn, const char *buf, size_t size, - const char *server_type) -{ - size_t s, needed; - char *params; - char *temp; - gboolean first; - int res; /* result of the write operation */ - - 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) - { - 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_host); - } - else - { - params = g_strdup_printf("Action=open&IP=%s", - servconn->http_data->gateway_host); - } - } - 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", - ((strcmp(server_type, "SB") == 0) && first - ? "gateway.messenger.hotmail.com" - : servconn->http_data->gateway_host), - params, - servconn->http_data->gateway_host, - (int)size, - buf); - - g_free(params); - -#if 0 - gaim_debug_misc("msn", "Writing HTTP to fd %d: {%s}\n", - servconn->fd, temp); -#endif - - s = 0; - needed = strlen(temp); - - do - { - res = write(servconn->fd, temp, needed); - if (res >= 0) - s += res; - else if (errno != EAGAIN) - { - char *msg = g_strdup_printf("Unable to write to MSN server via HTTP (error %d)", errno); - gaim_connection_error(servconn->session->account->gc, msg); - g_free(msg); - return -1; - } - } while (s < needed); - - g_free(temp); - - servconn->http_data->waiting_response = TRUE; - servconn->http_data->virgin = FALSE; - servconn->http_data->dirty = FALSE; - - 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_host, - servconn->http_data->session_id, - servconn->http_data->gateway_host); - -#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->dirty = FALSE; - - 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); - -#if 0 - gaim_debug_info("msn", "parsing data {%s} from fd %d\n", - buf, servconn->fd); -#endif - 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)) && - ((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) && - (strncmp(buf, "HTTP/1.0 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_host != NULL) - g_free(servconn->http_data->old_gateway_host); - - servconn->http_data->old_gateway_host = - servconn->http_data->gateway_host; - - servconn->http_data->session_id = session_id; - servconn->http_data->gateway_host = 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 - servconn->http_data->dirty = TRUE; - - return TRUE; -} - diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/httpmethod.h --- a/src/protocols/msn/httpmethod.h Fri Dec 31 15:34:18 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/** - * @file httpmethod.h HTTP connection method - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * 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_host; - char *gateway_host; - const char *server_type; - - int timer; - - gboolean virgin; - gboolean waiting_response; - gboolean dirty; - - GList *queue; -}; - -/** - * Initializes the HTTP data for a session. - * - * @param session The session. - */ -void msn_http_session_init(MsnSession *session); - -/** - * Uninitializes the HTTP data for a session. - * - * @param session The session. - */ -void msn_http_session_uninit(MsnSession *session); - -/** - * 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_ */ diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/msn.c --- a/src/protocols/msn/msn.c Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/msn.c Fri Dec 31 16:34:22 2004 +0000 @@ -621,13 +621,12 @@ show_send_to_mobile_cb, NULL); m = g_list_append(m, act); } - } if (g_ascii_strcasecmp(buddy->name, gaim_account_get_username(buddy->account))) { - act = gaim_blist_node_action_new(_("Initiate Chat"), + act = gaim_blist_node_action_new(_("Initiate _Chat"), initiate_chat_cb, NULL); m = g_list_append(m, act); } @@ -671,25 +670,13 @@ } if (gaim_account_get_bool(account, "http_method", FALSE)) - { http_method = TRUE; - gaim_debug_info("msn", "using http method\n"); - - host = "gateway.messenger.hotmail.com"; - port = 80; - } - else - { - host = gaim_account_get_string(account, "server", MSN_SERVER); - port = gaim_account_get_int(account, "port", MSN_PORT); - } + host = gaim_account_get_string(account, "server", MSN_SERVER); + port = gaim_account_get_int(account, "port", MSN_PORT); session = msn_session_new(account, host, port, http_method); - if (session->http_method) - msn_http_session_init(session); - gc->proto_data = session; gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_FORMATTING_WBFO | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_FONTSIZE | GAIM_CONNECTION_NO_URLDESC; @@ -713,9 +700,6 @@ g_return_if_fail(session != NULL); - if (session->http_method) - msn_http_session_uninit(session); - msn_session_destroy(session); gc->proto_data = NULL; @@ -1865,7 +1849,7 @@ NULL, /* warn */ NULL, /* join_chat */ NULL, /* reject chat invite */ - NULL, /* get_chat_name */ + NULL, /* get_chat_name */ msn_chat_invite, /* chat_invite */ msn_chat_leave, /* chat_leave */ NULL, /* chat_whisper */ diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/notification.c --- a/src/protocols/msn/notification.c Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/notification.c Fri Dec 31 16:34:22 2004 +0000 @@ -37,9 +37,124 @@ static MsnTable *cbs_table; /************************************************************************** + * Main + **************************************************************************/ +static void +destroy_cb(MsnServConn *servconn) +{ + MsnNotification *notification; + + notification = servconn->cmdproc->data; + g_return_if_fail(notification != NULL); + + msn_notification_destroy(notification); +} + +MsnNotification * +msn_notification_new(MsnSession *session) +{ + MsnNotification *notification; + MsnServConn *servconn; + + g_return_val_if_fail(session != NULL, NULL); + + notification = g_new0(MsnNotification, 1); + + notification->session = session; + notification->servconn = servconn = msn_servconn_new(session, MSN_SERVER_NS); + msn_servconn_set_destroy_cb(servconn, destroy_cb); + + notification->cmdproc = servconn->cmdproc; + notification->cmdproc->data = notification; + notification->cmdproc->cbs_table = cbs_table; + + return notification; +} + +void +msn_notification_destroy(MsnNotification *notification) +{ + if (notification->destroying) + return; + + notification->destroying = TRUE; + + msn_servconn_destroy(notification->servconn); + + notification->session->notification = NULL; + g_free(notification); +} + +/************************************************************************** + * Connect + **************************************************************************/ +static void +connect_cb(MsnServConn *servconn) +{ + MsnCmdProc *cmdproc; + MsnSession *session; + GaimAccount *account; + char **a, **c, *vers; + int i; + + g_return_if_fail(servconn != NULL); + + cmdproc = servconn->cmdproc; + session = servconn->session; + account = session->account; + + /* Allocate an array for CVR0, NULL, and all the versions */ + a = c = g_new0(char *, session->protocol_ver - 8 + 3); + + for (i = session->protocol_ver; i >= 8; i--) + *c++ = g_strdup_printf("MSNP%d", i); + + *c++ = g_strdup("CVR0"); + + vers = g_strjoinv(" ", a); + + msn_cmdproc_send(cmdproc, "VER", "%s", vers); + + g_strfreev(a); + g_free(vers); + + if (cmdproc->error) + return; + + if (session->user == NULL) + session->user = msn_user_new(session->userlist, + gaim_account_get_username(account), NULL); +} + +gboolean +msn_notification_connect(MsnNotification *notification, const char *host, int port) +{ + MsnServConn *servconn; + + g_return_val_if_fail(notification != NULL, FALSE); + + servconn = notification->servconn; + + msn_servconn_set_connect_cb(servconn, connect_cb); + notification->in_use = msn_servconn_connect(servconn, host, port); + + return notification->in_use; +} + +void +msn_notification_disconnect(MsnNotification *notification) +{ + g_return_if_fail(notification != NULL); + g_return_if_fail(notification->in_use); + + msn_servconn_disconnect(notification->servconn); + + notification->in_use = FALSE; +} + +/************************************************************************** * Util **************************************************************************/ - static void group_error_helper(MsnSession *session, const char *msg, int group_id, int error) { @@ -83,7 +198,6 @@ /************************************************************************** * Login **************************************************************************/ - void msn_got_login_params(MsnSession *session, const char *login_params) { @@ -266,6 +380,16 @@ msn_cmdproc_show_error(cmdproc, MSN_ERROR_SERVDOWN); } +void +msn_notification_close(MsnNotification *notification) +{ + g_return_if_fail(notification != NULL); + + msn_cmdproc_send_quick(notification->cmdproc, "OUT", NULL, NULL); + + msn_notification_disconnect(notification); +} + /************************************************************************** * Messages **************************************************************************/ @@ -1177,44 +1301,6 @@ g_hash_table_destroy(table); } -static void -connect_cb(MsnServConn *servconn) -{ - MsnCmdProc *cmdproc; - MsnSession *session; - GaimAccount *account; - char **a, **c, *vers; - int i; - - g_return_if_fail(servconn != NULL); - - cmdproc = servconn->cmdproc; - session = servconn->session; - account = session->account; - - /* Allocate an array for CVR0, NULL, and all the versions */ - a = c = g_new0(char *, session->protocol_ver - 8 + 3); - - for (i = session->protocol_ver; i >= 8; i--) - *c++ = g_strdup_printf("MSNP%d", i); - - *c++ = g_strdup("CVR0"); - - vers = g_strjoinv(" ", a); - - msn_cmdproc_send(cmdproc, "VER", "%s", vers); - - g_strfreev(a); - g_free(vers); - - if (cmdproc->error) - return; - - if (session->user == NULL) - session->user = msn_user_new(session->userlist, - gaim_account_get_username(account), NULL); -} - void msn_notification_add_buddy(MsnNotification *notification, const char *list, const char *who, const char *store_name, @@ -1254,6 +1340,9 @@ } } +/************************************************************************** + * Init + **************************************************************************/ void msn_notification_init(void) { @@ -1336,57 +1425,3 @@ { msn_table_destroy(cbs_table); } - -MsnNotification * -msn_notification_new(MsnSession *session) -{ - MsnNotification *notification; - MsnServConn *servconn; - - g_return_val_if_fail(session != NULL, NULL); - - notification = g_new0(MsnNotification, 1); - - notification->session = session; - notification->servconn = servconn = msn_servconn_new(session, MSN_SERVER_NS); - notification->cmdproc = servconn->cmdproc; - msn_servconn_set_connect_cb(servconn, connect_cb); - - if (session->http_method) - servconn->http_data->server_type = "NS"; - - servconn->cmdproc->cbs_table = cbs_table; - - return notification; -} - -void -msn_notification_destroy(MsnNotification *notification) -{ - msn_servconn_destroy(notification->servconn); - - g_free(notification); -} - -gboolean -msn_notification_connect(MsnNotification *notification, const char *host, int port) -{ - MsnServConn *servconn; - - g_return_val_if_fail(notification != NULL, FALSE); - - servconn = notification->servconn; - - return (notification->in_use = msn_servconn_connect(servconn, host, port)); -} - -void -msn_notification_disconnect(MsnNotification *notification) -{ - g_return_if_fail(notification != NULL); - - notification->in_use = FALSE; - - if (notification->servconn->connected) - msn_servconn_disconnect(notification->servconn); -} diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/notification.h --- a/src/protocols/msn/notification.h Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/notification.h Fri Dec 31 16:34:22 2004 +0000 @@ -36,6 +36,9 @@ MsnCmdProc *cmdproc; MsnServConn *servconn; + gboolean destroying; /**< A flag that states if the notification is on + the process of being destroyed. */ + gboolean in_use; }; @@ -56,6 +59,15 @@ const char *host, int port); void msn_notification_disconnect(MsnNotification *notification); +/** + * Closes a notification. + * + * It's first closed, and then disconnected. + * + * @param notification The notification object to close. + */ +void msn_notification_close(MsnNotification *notification); + void msn_got_login_params(MsnSession *session, const char *login_params); #endif /* _MSN_NOTIFICATION_H_ */ diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/servconn.c --- a/src/protocols/msn/servconn.c Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/servconn.c Fri Dec 31 16:34:22 2004 +0000 @@ -43,10 +43,7 @@ servconn->cmdproc->servconn = servconn; if (session->http_method) - { - servconn->http_data = g_new0(MsnHttpMethodData, 1); - servconn->http_data->virgin = TRUE; - } + servconn->httpconn = msn_httpconn_new(servconn); servconn->num = session->servconns_count++; @@ -64,11 +61,22 @@ return; } + if (servconn->destroying) + return; + + servconn->destroying = TRUE; + if (servconn->connected) msn_servconn_disconnect(servconn); - if (servconn->http_data != NULL) - g_free(servconn->http_data); + if (servconn->destroy_cb) + servconn->destroy_cb(servconn); + + if (servconn->httpconn != NULL) + msn_httpconn_destroy(servconn->httpconn); + + if (servconn->host != NULL) + g_free(servconn->host); msn_cmdproc_destroy(servconn->cmdproc); g_free(servconn); @@ -113,7 +121,7 @@ else { MsnSwitchBoard *swboard; - swboard = servconn->data; + swboard = servconn->cmdproc->data; swboard->error = MSN_SB_ERROR_CONNECTION; } @@ -167,12 +175,26 @@ if (servconn->connected) msn_servconn_disconnect(servconn); + if (servconn->host != NULL) + g_free(servconn->host); + + servconn->host = g_strdup(host); + if (session->http_method) { - if (servconn->http_data->gateway_host != NULL) - g_free(servconn->http_data->gateway_host); + /* HTTP Connection. */ + + if (!servconn->httpconn->connected) + msn_httpconn_connect(servconn->httpconn, host, port); - servconn->http_data->gateway_host = g_strdup(host); + servconn->connected = TRUE; + servconn->cmdproc->ready = TRUE; + servconn->httpconn->virgin = TRUE; + + /* Someone wants to know we connected. */ + servconn->connect_cb(servconn); + + return TRUE; } r = gaim_proxy_connect(session->account, host, port, connect_cb, @@ -200,6 +222,15 @@ return; } + if (servconn->session->http_method) + { + /* Fake disconnection */ + if (servconn->disconnect_cb != NULL) + servconn->disconnect_cb(servconn); + + return; + } + if (servconn->inpa > 0) { gaim_input_remove(servconn->inpa); @@ -208,21 +239,6 @@ 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_host != NULL) - g_free(servconn->http_data->old_gateway_host); - - if (servconn->http_data->gateway_host != NULL) - g_free(servconn->http_data->gateway_host); - - if (servconn->http_data->timer) - gaim_timeout_remove(servconn->http_data->timer); - } - servconn->rx_buf = NULL; servconn->rx_len = 0; servconn->payload_len = 0; @@ -235,20 +251,31 @@ } void -msn_servconn_set_connect_cb(MsnServConn *servconn, void (*connect_cb)(MsnServConn *)) +msn_servconn_set_connect_cb(MsnServConn *servconn, + void (*connect_cb)(MsnServConn *)) { g_return_if_fail(servconn != NULL); servconn->connect_cb = connect_cb; } void -msn_servconn_set_disconnect_cb(MsnServConn *servconn, void (*disconnect_cb)(MsnServConn *)) +msn_servconn_set_disconnect_cb(MsnServConn *servconn, + void (*disconnect_cb)(MsnServConn *)) { g_return_if_fail(servconn != NULL); servconn->disconnect_cb = disconnect_cb; } +void +msn_servconn_set_destroy_cb(MsnServConn *servconn, + void (*destroy_cb)(MsnServConn *)) +{ + g_return_if_fail(servconn != NULL); + + servconn->destroy_cb = destroy_cb; +} + static void failed_io(MsnServConn *servconn) { @@ -266,7 +293,7 @@ g_return_val_if_fail(servconn != NULL, 0); - if (servconn->http_data == NULL) + if (!servconn->session->http_method) { switch (servconn->type) { @@ -285,8 +312,7 @@ } else { - ret = msn_http_servconn_write(servconn, buf, len, - servconn->http_data->server_type); + ret = msn_httpconn_write(servconn->httpconn, buf, len); } if (ret == -1) @@ -327,69 +353,6 @@ memcpy(servconn->rx_buf + servconn->rx_len, buf, len + 1); servconn->rx_len += len; - if (session->http_method) - { - char *result_msg = NULL; - size_t result_len = 0; - gboolean error; - char *tmp; - - tmp = g_strndup(servconn->rx_buf, servconn->rx_len); - - if (!msn_http_servconn_parse_data(servconn, tmp, servconn->rx_len, - &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->host, - servconn->port, read_cb, servconn); - - if (i == 0) - servconn->connected = TRUE; - } -#endif - - g_free(servconn->rx_buf); - servconn->rx_buf = result_msg; - servconn->rx_len = result_len; - } - end = old_rx_buf = servconn->rx_buf; servconn->processing = TRUE; diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/servconn.h --- a/src/protocols/msn/servconn.h Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/servconn.h Fri Dec 31 16:34:22 2004 +0000 @@ -30,13 +30,11 @@ #include "cmdproc.h" #include "proxy.h" -#include "httpmethod.h" +#include "httpconn.h" /* -#include "msg.h" -#include "history.h" -*/ - + * Connection types + */ typedef enum { MSN_SERVER_NS, @@ -47,44 +45,107 @@ } MsnServConnType; +/* + * A Connection + */ struct _MsnServConn { - MsnServConnType type; - MsnSession *session; - MsnCmdProc *cmdproc; + MsnServConnType type; /**< The type of this connection. */ + MsnSession *session; /**< The MSN session of this connection. */ + MsnCmdProc *cmdproc; /**< The command processor of this connection. */ - gboolean connected; - gboolean processing; - gboolean wasted; + gboolean connected; /**< A flag that states if it's connected. */ + gboolean processing; /**< A flag that states if something is working + with this connection. */ + gboolean wasted; /**< A flag that states if it should be destroyed. */ + gboolean destroying; /**< A flag that states if the connection is on + the process of being destroyed. */ - int num; - - MsnHttpMethodData *http_data; + char *host; /**< The host this connection is connected or should be + connected to. */ + int num; /**< A number id of this connection. */ - int fd; - int inpa; + MsnHttpConn *httpconn; /**< The HTTP connection this connection should use. */ - char *rx_buf; - int rx_len; + int fd; /**< The connection's file descriptor. */ + int inpa; /**< The connection's input handler. */ + + char *rx_buf; /**< The receive buffer. */ + int rx_len; /**< The receive buffer lenght. */ - size_t payload_len; + size_t payload_len; /**< The length of the payload. + It's only set when we've received a command that + has a payload. */ - void (*connect_cb)(MsnServConn *); - void (*disconnect_cb)(MsnServConn *); - void (*data_free_cb)(void *data); - void *data; + void (*connect_cb)(MsnServConn *); /**< The callback to call when connecting. */ + void (*disconnect_cb)(MsnServConn *); /**< The callback to call when disconnecting. */ + void (*destroy_cb)(MsnServConn *); /**< The callback to call when destroying. */ }; +/** + * Creates a new connection object. + * + * @param session The session. + * @param type The type of the connection. + */ MsnServConn *msn_servconn_new(MsnSession *session, MsnServConnType type); + +/** + * Destroys a connection object. + * + * @param servconn The connection. + */ void msn_servconn_destroy(MsnServConn *servconn); +/** + * Connects to a host. + * + * @param servconn The connection. + * @param host The host. + * @param port The port. + */ gboolean msn_servconn_connect(MsnServConn *servconn, const char *host, int port); + +/** + * Disconnects. + * + * @param servconn The connection. + */ void msn_servconn_disconnect(MsnServConn *servconn); +/** + * Sets the connect callback. + * + * @param servconn The servconn. + * @param connect_cb The connect callback. + */ void msn_servconn_set_connect_cb(MsnServConn *servconn, void (*connect_cb)(MsnServConn *)); +/** + * Sets the disconnect callback. + * + * @param servconn The servconn. + * @param disconnect_cb The disconnect callback. + */ void msn_servconn_set_disconnect_cb(MsnServConn *servconn, void (*disconnect_cb)(MsnServConn *)); -size_t msn_servconn_write(MsnServConn *servconn, const char *buf, size_t size); +/** + * Sets the destroy callback. + * + * @param servconn The servconn that's being destroyed. + * @param destroy_cb The destroy callback. + */ +void msn_servconn_set_destroy_cb(MsnServConn *servconn, + void (*destroy_cb)(MsnServConn *)); + +/** + * Writes a chunck of data to the servconn. + * + * @param servconn The servconn. + * @param buf The data to write. + * @param size The size of the data. + */ +size_t msn_servconn_write(MsnServConn *servconn, const char *buf, + size_t size); #endif /* _MSN_SERVCONN_H_ */ diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/session.c --- a/src/protocols/msn/session.c Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/session.c Fri Dec 31 16:34:22 2004 +0000 @@ -113,6 +113,12 @@ session->connected = TRUE; + if (session->notification == NULL) + { + gaim_debug_error("msn", "This shouldn't happen\n"); + g_return_val_if_reached(FALSE); + } + if (msn_notification_connect(session->notification, session->dispatch_host, session->dispatch_port)) @@ -130,10 +136,12 @@ g_return_if_fail(session->connected); while (session->switches != NULL) - msn_switchboard_destroy(session->switches->data); + msn_switchboard_close(session->switches->data); if (session->notification != NULL) - msn_notification_disconnect(session->notification); + msn_notification_close(session->notification); + + session->connected = FALSE; } /* TODO: This must go away when conversation is redesigned */ diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/session.h --- a/src/protocols/msn/session.h Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/session.h Fri Dec 31 16:34:22 2004 +0000 @@ -35,6 +35,7 @@ #include "cmdproc.h" #include "nexus.h" +#include "httpconn.h" #include "userlist.h" #include "sync.h" diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/switchboard.c --- a/src/protocols/msn/switchboard.c Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/switchboard.c Fri Dec 31 16:34:22 2004 +0000 @@ -42,7 +42,6 @@ { MsnSwitchBoard *swboard; MsnServConn *servconn; - MsnCmdProc *cmdproc; g_return_val_if_fail(session != NULL, NULL); @@ -50,17 +49,16 @@ swboard->session = session; swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVER_SB); - cmdproc = servconn->cmdproc; + swboard->cmdproc = servconn->cmdproc; swboard->im_queue = g_queue_new(); swboard->empty = TRUE; - servconn->data = swboard; + swboard->cmdproc->data = swboard; + swboard->cmdproc->cbs_table = cbs_table; session->switches = g_list_append(session->switches, swboard); - cmdproc->cbs_table = cbs_table; - return swboard; } @@ -88,7 +86,7 @@ if (swboard->error != MSN_SB_ERROR_NONE) { /* The messages could not be sent due to a switchboard error */ - msg_error_helper(swboard->servconn->cmdproc, msg, + msg_error_helper(swboard->cmdproc, msg, MSN_MSG_ERROR_SB); } msn_message_unref(msg); @@ -199,8 +197,8 @@ g_return_if_fail(swboard != NULL); - cmdproc = swboard->servconn->cmdproc; - account = swboard->servconn->session->account; + cmdproc = swboard->cmdproc; + account = cmdproc->session->account; swboard->users = g_list_prepend(swboard->users, g_strdup(user)); swboard->current_users++; @@ -313,7 +311,7 @@ if (swboard->total_users == 0) { swboard->error = reason; - msn_switchboard_destroy(swboard); + msn_switchboard_close(swboard); } } @@ -346,7 +344,7 @@ if ((error != MSN_MSG_ERROR_SB) && (msg->nak_cb != NULL)) msg->nak_cb(msg, msg->ack_data); - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; if (msg->type == MSN_MSG_TEXT) { @@ -434,7 +432,7 @@ { MsnSwitchBoard *swboard; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; swboard->ready = TRUE; } @@ -444,7 +442,7 @@ MsnSwitchBoard *swboard; const char *user; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; user = cmd->params[0]; if (swboard->conv == NULL) @@ -509,7 +507,7 @@ account = cmdproc->session->account; gc = account->gc; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; swboard->total_users = atoi(cmd->params[2]); @@ -530,13 +528,14 @@ session = cmdproc->session; account = session->account; gc = account->gc; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; msn_switchboard_add_user(swboard, passport); msn_switchboard_process_queue(swboard); - send_clientcaps(swboard); + if (!session->http_method) + send_clientcaps(swboard); if (swboard->closed) msn_switchboard_close(swboard); @@ -590,7 +589,7 @@ if (msg->ack_cb != NULL) msg->ack_cb(msg, msg->ack_data); - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; swboard->ack_list = g_list_remove(swboard->ack_list, msg); msn_message_unref(msg); } @@ -602,7 +601,7 @@ MsnSwitchBoard *swboard; gc = cmdproc->session->account->gc; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; if (swboard->current_users > 1) serv_got_chat_left(gc, swboard->chat_id); @@ -615,7 +614,7 @@ { MsnSwitchBoard *swboard; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; #if 0 GList *l; @@ -650,7 +649,7 @@ const char *value; gc = cmdproc->session->account->gc; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; body = msn_message_get_bin_data(msg, &body_len); body_str = g_strndup(body, body_len); @@ -709,7 +708,7 @@ char *passport; gc = cmdproc->session->account->gc; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; passport = msg->remote_user; if (swboard->current_users == 1 && @@ -798,7 +797,7 @@ g_return_if_fail(swboard != NULL); g_return_if_fail(msg != NULL); - cmdproc = swboard->servconn->cmdproc; + cmdproc = swboard->cmdproc; payload = msn_message_gen_payload(msg, &payload_len); @@ -885,8 +884,8 @@ cmdproc->ready = TRUE; - account = servconn->session->account; - swboard = servconn->data; + account = cmdproc->session->account; + swboard = cmdproc->data; g_return_if_fail(swboard != NULL); if (msn_switchboard_is_invited(swboard)) @@ -910,7 +909,7 @@ { MsnSwitchBoard *swboard; - swboard = servconn->data; + swboard = servconn->cmdproc->data; g_return_if_fail(swboard != NULL); msn_switchboard_destroy(swboard); @@ -945,7 +944,7 @@ MsnSwitchBoard *swboard; const char *user; - swboard = cmdproc->servconn->data; + swboard = cmdproc->data; user = cmd->params[0]; @@ -985,7 +984,7 @@ g_return_if_fail(swboard != NULL); - cmdproc = swboard->servconn->cmdproc; + cmdproc = swboard->cmdproc; trans = msn_transaction_new(cmdproc, "CAL", "%s", user); /* this doesn't do anything, but users seem to think that @@ -1020,41 +1019,6 @@ msn_parse_socket(cmd->params[2], &host, &port); - if (swboard->session->http_method) - { - GaimAccount *account; - MsnSession *session; - MsnServConn *servconn; - - port = 80; - - session = swboard->session; - servconn = swboard->servconn; - account = session->account; - - swboard->empty = FALSE; - - servconn->http_data->gateway_host = g_strdup(host); - -#if 0 - servconn->connected = TRUE; - servconn->cmdproc->ready = TRUE; -#endif - - if (msn_switchboard_is_invited(swboard)) - { - msn_cmdproc_send(servconn->cmdproc, "ANS", "%s %s %s", - gaim_account_get_username(account), - swboard->auth_key, swboard->session_id); - } - else - { - msn_cmdproc_send(servconn->cmdproc, "USR", "%s %s", - gaim_account_get_username(account), - swboard->auth_key); - } - } - msn_switchboard_connect(swboard, host, port); g_free(host); @@ -1102,7 +1066,7 @@ { MsnCmdProc *cmdproc; - cmdproc = swboard->servconn->cmdproc; + cmdproc = swboard->cmdproc; msn_cmdproc_send_quick(cmdproc, "OUT", NULL, NULL); diff -r f7b32dd67bdf -r 9bed28273ec7 src/protocols/msn/switchboard.h --- a/src/protocols/msn/switchboard.h Fri Dec 31 15:34:18 2004 +0000 +++ b/src/protocols/msn/switchboard.h Fri Dec 31 16:34:22 2004 +0000 @@ -57,6 +57,7 @@ { MsnSession *session; MsnServConn *servconn; + MsnCmdProc *cmdproc; char *im_user; char *auth_key;