Mercurial > pidgin
annotate src/protocols/msn/httpconn.c @ 13253:87a7c3077c19
[gaim-migrate @ 15619]
More cleaning up of oscar. Renamed some functions to be more clear.
Got rid of some stuff that wasn't used. Inlined some small things
in conn.c that were only used once.
The goals of all this are
1. Non-blocking I/O for all connections
2. p2p stuff won't use the same struct as oscar connections, because
that's stupid
3. The oscar PRPL should be less scary
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Sun, 12 Feb 2006 21:27:04 +0000 |
| parents | 33bef17125c2 |
| 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 } |
