Mercurial > pidgin
annotate src/protocols/msn/httpconn.c @ 13200:33bef17125c2
[gaim-migrate @ 15563]
This is the soon-to-be-infamous nonblocking network activity patch that I've been working on. Feel free to yell at me if this makes you unhappy.
committer: Tailor Script <tailor@pidgin.im>
| author | Daniel Atallah <daniel.atallah@gmail.com> |
|---|---|
| date | Thu, 09 Feb 2006 04:17:56 +0000 |
| parents | fc464a0abccc |
| children | 8754a0fe2297 |
| rev | line source |
|---|---|
| 10463 | 1 /** |
| 2 * @file httpmethod.c HTTP connection method | |
| 3 * | |
| 4 * gaim | |
| 5 * | |
| 6 * Gaim is the legal property of its developers, whose names are too numerous | |
| 7 * to list here. Please refer to the COPYRIGHT file distributed with this | |
| 8 * source distribution. | |
| 9 * | |
| 10 * This program is free software; you can redistribute it and/or modify | |
| 11 * it under the terms of the GNU General Public License as published by | |
| 12 * the Free Software Foundation; either version 2 of the License, or | |
| 13 * (at your option) any later version. | |
| 14 * | |
| 15 * This program is distributed in the hope that it will be useful, | |
| 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 * GNU General Public License for more details. | |
| 19 * | |
| 20 * You should have received a copy of the GNU General Public License | |
| 21 * along with this program; if not, write to the Free Software | |
| 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 23 */ | |
| 24 #include "msn.h" | |
| 25 #include "debug.h" | |
| 26 #include "httpconn.h" | |
| 27 | |
| 28 static void read_cb(gpointer data, gint source, GaimInputCondition cond); | |
| 29 gboolean msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf, | |
| 30 size_t size, char **ret_buf, size_t *ret_size, | |
| 31 gboolean *error); | |
| 32 | |
| 33 MsnHttpConn * | |
| 34 msn_httpconn_new(MsnServConn *servconn) | |
| 35 { | |
| 36 MsnHttpConn *httpconn; | |
| 37 | |
| 38 g_return_val_if_fail(servconn != NULL, NULL); | |
| 39 | |
| 40 httpconn = g_new0(MsnHttpConn, 1); | |
| 41 | |
| 10481 | 42 gaim_debug_info("msn", "new httpconn (%p)\n", httpconn); |
| 43 | |
| 10463 | 44 /* TODO: Remove this */ |
| 45 httpconn->session = servconn->session; | |
| 46 | |
| 47 httpconn->servconn = servconn; | |
| 48 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
49 httpconn->tx_buf = gaim_circ_buffer_new(MSN_BUF_LEN); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
50 httpconn->tx_handler = -1; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
51 |
| 10463 | 52 return httpconn; |
| 53 } | |
| 54 | |
| 55 void | |
| 56 msn_httpconn_destroy(MsnHttpConn *httpconn) | |
| 57 { | |
| 58 g_return_if_fail(httpconn != NULL); | |
| 59 | |
| 10481 | 60 gaim_debug_info("msn", "destroy httpconn (%p)\n", httpconn); |
| 61 | |
| 10463 | 62 if (httpconn->connected) |
| 63 msn_httpconn_disconnect(httpconn); | |
| 64 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
65 g_free(httpconn->full_session_id); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
66 |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
67 g_free(httpconn->session_id); |
| 10504 | 68 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
69 g_free(httpconn->host); |
| 10504 | 70 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
71 gaim_circ_buffer_destroy(httpconn->tx_buf); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
72 if (httpconn->tx_handler > 0) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
73 gaim_input_remove(httpconn->tx_handler); |
| 10504 | 74 |
| 10463 | 75 g_free(httpconn); |
| 76 } | |
| 77 | |
| 10568 | 78 static char * |
| 79 msn_httpconn_proxy_auth(MsnHttpConn *httpconn) | |
| 80 { | |
| 81 GaimAccount *account; | |
| 82 GaimProxyInfo *gpi; | |
| 83 const char *username, *password; | |
| 84 char *auth = NULL; | |
| 85 | |
| 86 account = httpconn->session->account; | |
| 87 | |
| 88 if (gaim_account_get_proxy_info(account) == NULL) | |
| 89 gpi = gaim_global_proxy_get_info(); | |
| 90 else | |
| 91 gpi = gaim_account_get_proxy_info(account); | |
| 92 | |
| 93 if (gpi == NULL || !(gaim_proxy_info_get_type(gpi) == GAIM_PROXY_HTTP || | |
| 94 gaim_proxy_info_get_type(gpi) == GAIM_PROXY_USE_ENVVAR)) | |
| 95 return NULL; | |
| 96 | |
| 97 username = gaim_proxy_info_get_username(gpi); | |
| 98 password = gaim_proxy_info_get_password(gpi); | |
| 99 | |
| 100 if (username != NULL) { | |
| 101 char *tmp; | |
| 102 auth = g_strdup_printf("%s:%s", username, password ? password : ""); | |
| 11137 | 103 tmp = gaim_base64_encode((const guchar *)auth, strlen(auth)); |
| 10568 | 104 g_free(auth); |
| 105 auth = g_strdup_printf("Proxy-Authorization: Basic %s\r\n", tmp); | |
| 106 g_free(tmp); | |
| 107 } | |
| 108 | |
| 109 return auth; | |
| 110 } | |
| 111 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
112 static void |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
113 httpconn_write_cb(gpointer data, gint source, GaimInputCondition cond) |
| 10463 | 114 { |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
115 MsnHttpConn *httpconn = data; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
116 int ret, writelen; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
117 |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
118 if (httpconn->waiting_response) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
119 return; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
120 |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
121 writelen = gaim_circ_buffer_get_max_read(httpconn->tx_buf); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
122 |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
123 if (writelen == 0) { |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
124 gaim_input_remove(httpconn->tx_handler); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
125 httpconn->tx_handler = -1; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
126 return; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
127 } |
| 10463 | 128 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
129 ret = write(httpconn->fd, httpconn->tx_buf->outptr, writelen); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
130 |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
131 if (ret < 0 && errno == EAGAIN) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
132 return; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
133 else if (ret <= 0) { |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
134 msn_servconn_got_error(httpconn->servconn, |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
135 MSN_SERVCONN_ERROR_WRITE); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
136 return; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
137 } |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
138 |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
139 gaim_circ_buffer_mark_read(httpconn->tx_buf, ret); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
140 } |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
141 |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
142 static ssize_t |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
143 write_raw(MsnHttpConn *httpconn, const char *data, size_t data_len) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
144 { |
| 10463 | 145 ssize_t res; /* result of the write operation */ |
| 146 | |
| 147 #ifdef MSN_DEBUG_HTTP | |
| 10481 | 148 gaim_debug_misc("msn", "Writing HTTP (header): {%s}\n", header); |
| 10463 | 149 #endif |
| 150 | |
| 10481 | 151 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
152 if (httpconn->tx_handler == -1 && !httpconn->waiting_response) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
153 res = write(httpconn->fd, data, data_len); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
154 else |
| 10481 | 155 { |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
156 res = -1; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
157 errno = EAGAIN; |
| 10481 | 158 } |
| 159 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
160 if (res <= 0 && errno != EAGAIN) |
| 10463 | 161 { |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
162 msn_servconn_got_error(httpconn->servconn, |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
163 MSN_SERVCONN_ERROR_WRITE); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
164 return -1; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
165 } else if (res < data_len) { |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
166 if (res < 0) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
167 res = 0; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
168 if (httpconn->tx_handler == -1) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
169 httpconn->tx_handler = gaim_input_add(httpconn->fd, |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
170 GAIM_INPUT_WRITE, httpconn_write_cb, httpconn); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
171 gaim_circ_buffer_append(httpconn->tx_buf, data + res, |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
172 data_len - res); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
173 } |
| 10481 | 174 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
175 return res; |
| 10463 | 176 } |
| 177 | |
|
12323
fc464a0abccc
[gaim-migrate @ 14627]
Richard Laager <rlaager@wiktel.com>
parents:
12213
diff
changeset
|
178 static void |
| 10463 | 179 msn_httpconn_poll(MsnHttpConn *httpconn) |
| 180 { | |
| 10481 | 181 char *header; |
| 10568 | 182 char *auth; |
| 10463 | 183 int r; |
| 184 | |
| 185 g_return_if_fail(httpconn != NULL); | |
| 186 | |
| 187 if (httpconn->waiting_response || | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
188 httpconn->tx_handler > 0) |
| 10463 | 189 { |
| 190 return; | |
| 191 } | |
| 192 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
193 /* It is OK if this is buffered because it will only be buffered if |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
194 nothing else is in the buffer */ |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
195 |
| 10568 | 196 auth = msn_httpconn_proxy_auth(httpconn); |
| 197 | |
| 10481 | 198 header = g_strdup_printf( |
| 10463 | 199 "POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n" |
| 200 "Accept: */*\r\n" | |
| 201 "Accept-Language: en-us\r\n" | |
| 202 "User-Agent: MSMSGS\r\n" | |
| 203 "Host: %s\r\n" | |
| 204 "Proxy-Connection: Keep-Alive\r\n" | |
| 10568 | 205 "%s" /* Proxy auth */ |
| 10463 | 206 "Connection: Keep-Alive\r\n" |
| 207 "Pragma: no-cache\r\n" | |
| 208 "Content-Type: application/x-msn-messenger\r\n" | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
209 "Content-Length: 0\r\n\r\n", |
| 10463 | 210 httpconn->host, |
| 211 httpconn->full_session_id, | |
| 10568 | 212 httpconn->host, |
| 213 auth ? auth : ""); | |
| 214 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
215 g_free(auth); |
| 10463 | 216 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
217 r = write_raw(httpconn, header, strlen(header)); |
| 10463 | 218 |
| 10481 | 219 g_free(header); |
| 10463 | 220 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
221 if (r >= 0) |
| 10463 | 222 { |
| 223 httpconn->waiting_response = TRUE; | |
| 224 httpconn->dirty = FALSE; | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 static gboolean | |
| 10543 | 229 do_poll(gpointer data) |
| 10463 | 230 { |
| 231 MsnHttpConn *httpconn; | |
| 232 | |
| 233 httpconn = data; | |
| 234 | |
| 10568 | 235 g_return_val_if_fail(httpconn != NULL, TRUE); |
| 236 | |
| 10463 | 237 #if 0 |
| 238 gaim_debug_info("msn", "polling from %s\n", httpconn->session_id); | |
| 239 #endif | |
| 240 | |
| 10568 | 241 if ((httpconn->host == NULL) || (httpconn->full_session_id == NULL)) |
| 242 { | |
| 243 gaim_debug_warning("msn", "Attempted HTTP poll before session is established\n"); | |
| 244 return TRUE; | |
| 245 } | |
| 246 | |
| 10463 | 247 if (httpconn->dirty) |
| 248 msn_httpconn_poll(httpconn); | |
| 249 | |
| 250 return TRUE; | |
| 251 } | |
| 252 | |
| 253 static void | |
| 254 connect_cb(gpointer data, gint source, GaimInputCondition cond) | |
| 255 { | |
| 256 MsnHttpConn *httpconn = data; | |
| 257 | |
| 258 httpconn->fd = source; | |
| 259 | |
| 260 if (source > 0) | |
| 261 { | |
| 262 httpconn->inpa = gaim_input_add(httpconn->fd, GAIM_INPUT_READ, | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
263 read_cb, data); |
| 10463 | 264 |
| 10543 | 265 httpconn->timer = gaim_timeout_add(2000, do_poll, httpconn); |
| 10463 | 266 |
| 267 httpconn->waiting_response = FALSE; | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
268 if (httpconn->tx_handler > 0) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
269 httpconn_write_cb(httpconn, source, GAIM_INPUT_WRITE); |
| 10463 | 270 } |
| 271 else | |
| 272 { | |
| 273 gaim_debug_error("msn", "HTTP: Connection error\n"); | |
| 10481 | 274 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_CONNECT); |
| 10463 | 275 } |
| 276 } | |
| 277 | |
| 278 gboolean | |
| 279 msn_httpconn_connect(MsnHttpConn *httpconn, const char *host, int port) | |
| 280 { | |
| 281 int r; | |
| 282 | |
| 283 g_return_val_if_fail(httpconn != NULL, FALSE); | |
| 284 g_return_val_if_fail(host != NULL, FALSE); | |
| 285 g_return_val_if_fail(port > 0, FALSE); | |
| 286 | |
| 287 if (httpconn->connected) | |
| 288 msn_httpconn_disconnect(httpconn); | |
| 289 | |
| 290 r = gaim_proxy_connect(httpconn->session->account, | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
291 "gateway.messenger.hotmail.com", 80, connect_cb, httpconn); |
| 10463 | 292 |
| 293 if (r == 0) | |
| 294 { | |
| 295 httpconn->waiting_response = TRUE; | |
| 296 httpconn->connected = TRUE; | |
| 297 } | |
| 298 | |
| 299 return httpconn->connected; | |
| 300 } | |
| 301 | |
| 302 void | |
| 303 msn_httpconn_disconnect(MsnHttpConn *httpconn) | |
| 304 { | |
| 305 g_return_if_fail(httpconn != NULL); | |
| 10481 | 306 |
| 307 if (!httpconn->connected) | |
| 308 return; | |
| 10463 | 309 |
| 310 if (httpconn->timer) | |
| 311 gaim_timeout_remove(httpconn->timer); | |
| 312 | |
| 313 httpconn->timer = 0; | |
| 314 | |
| 315 if (httpconn->inpa > 0) | |
| 316 { | |
| 317 gaim_input_remove(httpconn->inpa); | |
| 318 httpconn->inpa = 0; | |
| 319 } | |
| 320 | |
| 321 close(httpconn->fd); | |
| 322 | |
| 323 httpconn->rx_buf = NULL; | |
| 324 httpconn->rx_len = 0; | |
| 325 | |
| 326 httpconn->connected = FALSE; | |
| 327 | |
| 328 /* msn_servconn_disconnect(httpconn->servconn); */ | |
| 329 } | |
| 330 | |
| 331 static void | |
| 332 read_cb(gpointer data, gint source, GaimInputCondition cond) | |
| 333 { | |
| 334 MsnHttpConn *httpconn; | |
| 335 MsnServConn *servconn; | |
| 336 MsnSession *session; | |
| 337 char buf[MSN_BUF_LEN]; | |
| 338 char *cur, *end, *old_rx_buf; | |
| 339 int len, cur_len; | |
| 340 char *result_msg = NULL; | |
| 341 size_t result_len = 0; | |
| 342 gboolean error; | |
| 343 | |
| 344 httpconn = data; | |
| 345 servconn = NULL; | |
| 346 session = httpconn->session; | |
| 347 | |
| 348 len = read(httpconn->fd, buf, sizeof(buf) - 1); | |
| 349 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
350 if (len < 0 && errno == EAGAIN) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
351 return; |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
352 else if (len <= 0) |
| 10463 | 353 { |
| 354 gaim_debug_error("msn", "HTTP: Read error\n"); | |
| 10481 | 355 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ); |
| 10463 | 356 |
| 357 return; | |
| 358 } | |
| 359 | |
| 360 buf[len] = '\0'; | |
| 361 | |
| 362 httpconn->rx_buf = g_realloc(httpconn->rx_buf, len + httpconn->rx_len + 1); | |
| 363 memcpy(httpconn->rx_buf + httpconn->rx_len, buf, len + 1); | |
| 364 httpconn->rx_len += len; | |
| 365 | |
| 366 if (!msn_httpconn_parse_data(httpconn, httpconn->rx_buf, httpconn->rx_len, | |
| 367 &result_msg, &result_len, &error)) | |
| 368 { | |
| 10568 | 369 /* We must wait for more input, or something went wrong */ |
| 370 if (error) | |
| 371 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ); | |
| 10463 | 372 |
| 373 return; | |
| 374 } | |
| 375 | |
| 376 httpconn->servconn->processing = FALSE; | |
| 377 | |
| 378 servconn = httpconn->servconn; | |
| 379 | |
| 380 if (error) | |
| 381 { | |
| 382 gaim_debug_error("msn", "HTTP: Special error\n"); | |
| 10481 | 383 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ); |
| 10463 | 384 |
| 385 return; | |
| 386 } | |
| 387 | |
| 10533 | 388 if (httpconn->rx_buf != NULL) |
| 389 g_free(httpconn->rx_buf); | |
| 390 httpconn->rx_buf = NULL; | |
| 391 httpconn->rx_len = 0; | |
| 392 | |
| 10463 | 393 if (result_len == 0) |
| 394 { | |
| 395 /* Nothing to do here */ | |
| 396 #if 0 | |
| 397 gaim_debug_info("msn", "HTTP: nothing to do here\n"); | |
| 398 #endif | |
| 10481 | 399 g_free(result_msg); |
| 10463 | 400 return; |
| 401 } | |
| 402 | |
| 10533 | 403 if (servconn->rx_buf != NULL) |
| 404 g_free(servconn->rx_buf); | |
| 10463 | 405 servconn->rx_buf = result_msg; |
| 406 servconn->rx_len = result_len; | |
| 407 | |
| 408 end = old_rx_buf = servconn->rx_buf; | |
| 409 | |
| 410 servconn->processing = TRUE; | |
| 411 | |
| 412 do | |
| 413 { | |
| 414 cur = end; | |
| 415 | |
| 416 if (servconn->payload_len) | |
| 417 { | |
| 418 if (servconn->payload_len > servconn->rx_len) | |
| 419 /* The payload is still not complete. */ | |
| 420 break; | |
| 421 | |
| 422 cur_len = servconn->payload_len; | |
| 423 end += cur_len; | |
| 424 } | |
| 425 else | |
| 426 { | |
| 427 end = strstr(cur, "\r\n"); | |
| 428 | |
| 429 if (end == NULL) | |
| 430 /* The command is still not complete. */ | |
| 431 break; | |
| 432 | |
| 433 *end = '\0'; | |
| 434 end += 2; | |
| 435 cur_len = end - cur; | |
| 436 } | |
| 437 | |
| 438 servconn->rx_len -= cur_len; | |
| 439 | |
| 440 if (servconn->payload_len) | |
| 441 { | |
| 442 msn_cmdproc_process_payload(servconn->cmdproc, cur, cur_len); | |
| 443 servconn->payload_len = 0; | |
| 444 } | |
| 445 else | |
| 446 { | |
| 447 msn_cmdproc_process_cmd_text(servconn->cmdproc, cur); | |
| 448 } | |
| 449 } while (servconn->connected && servconn->rx_len > 0); | |
| 450 | |
| 451 if (servconn->connected) | |
| 452 { | |
| 453 if (servconn->rx_len > 0) | |
| 454 servconn->rx_buf = g_memdup(cur, servconn->rx_len); | |
| 455 else | |
| 456 servconn->rx_buf = NULL; | |
| 457 } | |
| 458 | |
| 459 servconn->processing = FALSE; | |
| 460 | |
| 461 if (servconn->wasted) | |
| 462 msn_servconn_destroy(servconn); | |
| 463 | |
| 464 g_free(old_rx_buf); | |
| 465 } | |
| 466 | |
| 467 size_t | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
468 msn_httpconn_write(MsnHttpConn *httpconn, const char *body, size_t size) |
| 10463 | 469 { |
| 470 char *params; | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
471 char *data; |
| 10568 | 472 char *auth; |
| 10463 | 473 const char *server_types[] = { "NS", "SB" }; |
| 474 const char *server_type; | |
| 475 size_t r; /* result of the write operation */ | |
| 476 char *host; | |
| 477 MsnServConn *servconn; | |
| 478 | |
| 479 /* TODO: remove http data from servconn */ | |
| 480 | |
| 481 g_return_val_if_fail(httpconn != NULL, 0); | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
482 g_return_val_if_fail(body != NULL, 0); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
483 g_return_val_if_fail(size > 0, 0); |
| 10463 | 484 |
| 485 servconn = httpconn->servconn; | |
| 486 | |
| 487 server_type = server_types[servconn->type]; | |
| 488 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
489 if (httpconn->virgin) |
| 10463 | 490 { |
| 491 host = "gateway.messenger.hotmail.com"; | |
| 492 | |
| 493 /* The first time servconn->host is the host we should connect to. */ | |
| 494 params = g_strdup_printf("Action=open&Server=%s&IP=%s", | |
| 495 server_type, | |
| 496 servconn->host); | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
497 httpconn->virgin = FALSE; |
| 10463 | 498 } |
| 499 else | |
| 500 { | |
| 501 /* The rest of the times servconn->host is the gateway host. */ | |
| 502 host = httpconn->host; | |
| 503 | |
| 10568 | 504 if (host == NULL || httpconn->full_session_id == NULL) |
| 505 { | |
| 506 gaim_debug_warning("msn", "Attempted HTTP write before session is established\n"); | |
| 507 return -1; | |
| 508 } | |
| 509 | |
| 10463 | 510 params = g_strdup_printf("SessionID=%s", |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
511 httpconn->full_session_id); |
| 10463 | 512 } |
| 513 | |
| 10568 | 514 auth = msn_httpconn_proxy_auth(httpconn); |
| 515 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
516 data = g_strdup_printf( |
| 10463 | 517 "POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n" |
| 518 "Accept: */*\r\n" | |
| 519 "Accept-Language: en-us\r\n" | |
| 520 "User-Agent: MSMSGS\r\n" | |
| 521 "Host: %s\r\n" | |
| 522 "Proxy-Connection: Keep-Alive\r\n" | |
| 10568 | 523 "%s" /* Proxy auth */ |
| 10463 | 524 "Connection: Keep-Alive\r\n" |
| 525 "Pragma: no-cache\r\n" | |
| 526 "Content-Type: application/x-msn-messenger\r\n" | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
527 "Content-Length: %d\r\n\r\n" |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
528 "%s", |
| 10463 | 529 host, |
| 530 params, | |
| 531 host, | |
| 10568 | 532 auth ? auth : "", |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
533 (int) size, |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
534 body ? body : ""); |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
535 |
| 10463 | 536 |
| 537 g_free(params); | |
| 538 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
539 g_free(auth); |
| 10568 | 540 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
541 r = write_raw(httpconn, data, strlen(data)); |
| 10463 | 542 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
543 g_free(data); |
| 10463 | 544 |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
545 if (r >= 0) |
| 10463 | 546 { |
| 547 httpconn->waiting_response = TRUE; | |
| 548 httpconn->dirty = FALSE; | |
| 549 } | |
| 550 | |
| 551 return r; | |
| 552 } | |
| 553 | |
| 554 gboolean | |
| 555 msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf, | |
| 556 size_t size, char **ret_buf, size_t *ret_size, | |
| 557 gboolean *error) | |
| 558 { | |
| 559 GaimConnection *gc; | |
| 560 const char *s, *c; | |
| 10481 | 561 char *header, *body; |
| 10463 | 562 const char *body_start; |
| 563 char *tmp; | |
| 564 size_t body_len = 0; | |
| 565 gboolean wasted = FALSE; | |
| 566 | |
| 567 g_return_val_if_fail(httpconn != NULL, FALSE); | |
| 568 g_return_val_if_fail(buf != NULL, FALSE); | |
| 569 g_return_val_if_fail(size > 0, FALSE); | |
| 570 g_return_val_if_fail(ret_buf != NULL, FALSE); | |
| 571 g_return_val_if_fail(ret_size != NULL, FALSE); | |
| 572 g_return_val_if_fail(error != NULL, FALSE); | |
| 573 | |
| 574 #if 0 | |
| 575 gaim_debug_info("msn", "HTTP: parsing data {%s}\n", buf); | |
| 576 #endif | |
| 577 | |
| 578 httpconn->waiting_response = FALSE; | |
| 579 | |
| 580 gc = gaim_account_get_connection(httpconn->session->account); | |
| 581 | |
| 582 /* Healthy defaults. */ | |
| 583 body = NULL; | |
| 584 | |
| 585 *ret_buf = NULL; | |
| 586 *ret_size = 0; | |
| 587 *error = FALSE; | |
| 588 | |
| 589 /* First, some tests to see if we have a full block of stuff. */ | |
| 590 if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) && | |
| 591 (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) && | |
| 592 ((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) && | |
| 593 (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0))) | |
| 594 { | |
| 595 *error = TRUE; | |
| 596 | |
| 597 return FALSE; | |
| 598 } | |
| 599 | |
| 600 if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0) | |
| 601 { | |
| 602 if ((s = strstr(buf, "\r\n\r\n")) == NULL) | |
| 603 return FALSE; | |
| 604 | |
| 605 s += 4; | |
| 606 | |
| 607 if (*s == '\0') | |
| 608 { | |
| 609 *ret_buf = g_strdup(""); | |
| 610 *ret_size = 0; | |
| 611 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
612 if (httpconn->tx_handler > 0) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
613 httpconn_write_cb(httpconn, httpconn->fd, |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
614 GAIM_INPUT_WRITE); |
| 10463 | 615 |
| 616 return TRUE; | |
| 617 } | |
| 618 | |
| 619 buf = s; | |
| 620 size -= (s - buf); | |
| 621 } | |
| 622 | |
| 623 if ((s = strstr(buf, "\r\n\r\n")) == NULL) | |
| 624 return FALSE; | |
| 625 | |
| 10718 | 626 s += 4; /* Skip \r\n */ |
| 10481 | 627 header = g_strndup(buf, s - buf); |
| 10463 | 628 body_start = s; |
| 629 body_len = size - (body_start - buf); | |
| 630 | |
| 12213 | 631 if ((s = gaim_strcasestr(header, "Content-Length: ")) != NULL) |
| 10463 | 632 { |
| 633 int tmp_len; | |
| 634 | |
| 635 s += strlen("Content-Length: "); | |
| 636 | |
| 637 if ((c = strchr(s, '\r')) == NULL) | |
| 638 { | |
| 10481 | 639 g_free(header); |
| 10463 | 640 |
| 641 return FALSE; | |
| 642 } | |
| 643 | |
| 644 tmp = g_strndup(s, c - s); | |
| 645 tmp_len = atoi(tmp); | |
| 646 g_free(tmp); | |
| 647 | |
| 648 if (body_len != tmp_len) | |
| 649 { | |
| 10481 | 650 g_free(header); |
| 10463 | 651 |
| 652 #if 0 | |
| 653 gaim_debug_warning("msn", | |
| 654 "body length (%d) != content length (%d)\n", | |
| 655 body_len, tmp_len); | |
| 656 #endif | |
| 657 | |
| 658 return FALSE; | |
| 659 } | |
| 660 } | |
| 661 | |
| 10481 | 662 body = g_malloc0(body_len + 1); |
| 663 memcpy(body, body_start, body_len); | |
| 10463 | 664 |
| 665 #ifdef MSN_DEBUG_HTTP | |
| 10481 | 666 gaim_debug_misc("msn", "Incoming HTTP buffer (header): {%s\r\n}\n", |
| 667 header); | |
| 10463 | 668 #endif |
| 669 | |
| 670 /* Now we should be able to process the data. */ | |
| 12213 | 671 if ((s = gaim_strcasestr(header, "X-MSN-Messenger: ")) != NULL) |
| 10463 | 672 { |
| 673 char *full_session_id, *gw_ip, *session_action; | |
| 674 char *t, *session_id; | |
| 675 char **elems, **cur, **tokens; | |
| 676 | |
| 677 full_session_id = gw_ip = session_action = NULL; | |
| 678 | |
| 679 s += strlen("X-MSN-Messenger: "); | |
| 680 | |
| 681 if ((c = strchr(s, '\r')) == NULL) | |
| 682 { | |
| 10481 | 683 msn_session_set_error(httpconn->session, |
| 684 MSN_ERROR_HTTP_MALFORMED, NULL); | |
| 10463 | 685 gaim_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}", |
| 686 buf); | |
| 687 | |
| 10481 | 688 g_free(body); |
| 10463 | 689 return FALSE; |
| 690 } | |
| 691 | |
| 692 tmp = g_strndup(s, c - s); | |
| 693 | |
| 694 elems = g_strsplit(tmp, "; ", 0); | |
| 695 | |
| 696 for (cur = elems; *cur != NULL; cur++) | |
| 697 { | |
| 698 tokens = g_strsplit(*cur, "=", 2); | |
| 699 | |
| 700 if (strcmp(tokens[0], "SessionID") == 0) | |
| 701 full_session_id = tokens[1]; | |
| 702 else if (strcmp(tokens[0], "GW-IP") == 0) | |
| 703 gw_ip = tokens[1]; | |
| 704 else if (strcmp(tokens[0], "Session") == 0) | |
| 705 session_action = tokens[1]; | |
| 706 | |
| 707 g_free(tokens[0]); | |
| 708 /* Don't free each of the tokens, only the array. */ | |
| 709 g_free(tokens); | |
| 710 } | |
| 711 | |
| 712 g_strfreev(elems); | |
| 713 | |
| 714 g_free(tmp); | |
| 715 | |
| 716 if ((session_action != NULL) && (strcmp(session_action, "close") == 0)) | |
| 717 wasted = TRUE; | |
| 718 | |
| 719 g_free(session_action); | |
| 720 | |
| 721 t = strchr(full_session_id, '.'); | |
| 722 session_id = g_strndup(full_session_id, t - full_session_id); | |
| 723 | |
| 724 if (!wasted) | |
| 725 { | |
| 10504 | 726 if (httpconn->full_session_id != NULL) |
| 10463 | 727 g_free(httpconn->full_session_id); |
| 728 | |
| 729 httpconn->full_session_id = full_session_id; | |
| 730 | |
| 10504 | 731 if (httpconn->session_id != NULL) |
| 10463 | 732 g_free(httpconn->session_id); |
| 733 | |
| 734 httpconn->session_id = session_id; | |
| 735 | |
| 10504 | 736 if (httpconn->host != NULL) |
| 10463 | 737 g_free(httpconn->host); |
| 738 | |
| 739 httpconn->host = gw_ip; | |
| 740 } | |
| 741 else | |
| 742 { | |
| 743 MsnServConn *servconn; | |
| 744 | |
| 745 /* It's going to die. */ | |
| 10504 | 746 /* poor thing */ |
| 10463 | 747 |
| 748 servconn = httpconn->servconn; | |
| 749 | |
| 10533 | 750 /* I'll be honest, I don't fully understand all this, but this |
| 751 * causes crashes, Stu. */ | |
| 752 /* if (servconn != NULL) | |
| 753 servconn->wasted = TRUE; */ | |
| 10463 | 754 |
| 755 g_free(full_session_id); | |
| 10504 | 756 g_free(session_id); |
| 10463 | 757 g_free(gw_ip); |
| 758 } | |
| 759 } | |
| 760 | |
| 10481 | 761 g_free(header); |
| 10463 | 762 |
| 763 *ret_buf = body; | |
| 764 *ret_size = body_len; | |
| 765 | |
|
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
766 if (httpconn->tx_handler > 0) |
|
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12323
diff
changeset
|
767 httpconn_write_cb(httpconn, httpconn->fd, GAIM_INPUT_WRITE); |
| 10463 | 768 |
| 769 return TRUE; | |
| 770 } |
