src/protocols/msn/httpmethod.c

changeset 10463
f2f97738b401
parent 10462
760c4796c9a9
child 10464
034b1b3ad2be
equal deleted inserted replaced
10462:760c4796c9a9 10463:f2f97738b401
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 "debug.h"
25 #include "httpmethod.h"
26
27 #define GET_NEXT(tmp) \
28 while (*(tmp) && *(tmp) != ' ' && *(tmp) != '\r') \
29 (tmp)++; \
30 if (*(tmp) != '\0') *(tmp)++ = '\0'; \
31 if (*(tmp) == '\n') (tmp)++; \
32 while (*(tmp) && *(tmp) == ' ') \
33 (tmp)++
34
35 #define GET_NEXT_LINE(tmp) \
36 while (*(tmp) && *(tmp) != '\r') \
37 (tmp)++; \
38 if (*(tmp) != '\0') *(tmp)++ = '\0'; \
39 if (*(tmp) == '\n') (tmp)++
40
41 typedef struct
42 {
43 MsnServConn *servconn;
44 char *buffer;
45 size_t size;
46 const char *server_type;
47
48 } MsnHttpQueueData;
49
50 static gboolean
51 http_poll(gpointer data)
52 {
53 MsnSession *session;
54 GList *l;
55
56 session = data;
57
58 for (l = session->switches; l != NULL; l = l->next)
59 {
60 MsnSwitchBoard *swboard;
61
62 swboard = l->data;
63
64 g_return_val_if_fail(swboard->servconn->http_data != NULL, FALSE);
65
66 if (swboard->servconn->http_data->dirty)
67 {
68 #if 0
69 gaim_debug_info("msn", "Polling server %s.\n",
70 servconn->http_data->gateway_host);
71 #endif
72 msn_http_servconn_poll(swboard->servconn);
73 }
74 }
75
76 if (session->notification->servconn->http_data->dirty)
77 msn_http_servconn_poll(session->notification->servconn);
78
79 return TRUE;
80 }
81
82 static void
83 stop_timer(MsnSession *session)
84 {
85 if (session->http_poll_timer)
86 {
87 gaim_timeout_remove(session->http_poll_timer);
88 session->http_poll_timer = 0;
89 }
90 }
91
92 static void
93 start_timer(MsnSession *session)
94 {
95 stop_timer(session);
96
97 session->http_poll_timer = gaim_timeout_add(2000, http_poll, session);
98 }
99
100 void
101 msn_http_session_init(MsnSession *session)
102 {
103 g_return_if_fail(session != NULL);
104
105 start_timer(session);
106 }
107
108 void
109 msn_http_session_uninit(MsnSession *session)
110 {
111 g_return_if_fail(session != NULL);
112
113 stop_timer(session);
114 }
115
116 size_t
117 msn_http_servconn_write(MsnServConn *servconn, const char *buf, size_t size,
118 const char *server_type)
119 {
120 size_t s, needed;
121 char *params;
122 char *temp;
123 gboolean first;
124 int res; /* result of the write operation */
125
126 g_return_val_if_fail(servconn != NULL, 0);
127 g_return_val_if_fail(buf != NULL, 0);
128 g_return_val_if_fail(size > 0, 0);
129 g_return_val_if_fail(servconn->http_data != NULL, 0);
130
131 if (servconn->http_data->waiting_response)
132 {
133 MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1);
134
135 queue_data->servconn = servconn;
136 queue_data->buffer = g_strdup(buf);
137 queue_data->size = size;
138 queue_data->server_type = server_type;
139
140 servconn->http_data->queue =
141 g_list_append(servconn->http_data->queue, queue_data);
142
143 return size;
144 }
145
146 first = servconn->http_data->virgin;
147
148 if (first)
149 {
150 if (server_type)
151 {
152 params = g_strdup_printf("Action=open&Server=%s&IP=%s",
153 server_type,
154 servconn->http_data->gateway_host);
155 }
156 else
157 {
158 params = g_strdup_printf("Action=open&IP=%s",
159 servconn->http_data->gateway_host);
160 }
161 }
162 else
163 {
164 params = g_strdup_printf("SessionID=%s",
165 servconn->http_data->session_id);
166 }
167
168 temp = g_strdup_printf(
169 "POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n"
170 "Accept: */*\r\n"
171 "Accept-Language: en-us\r\n"
172 "User-Agent: MSMSGS\r\n"
173 "Host: %s\r\n"
174 "Proxy-Connection: Keep-Alive\r\n"
175 "Connection: Keep-Alive\r\n"
176 "Pragma: no-cache\r\n"
177 "Content-Type: application/x-msn-messenger\r\n"
178 "Content-Length: %d\r\n"
179 "\r\n"
180 "%s",
181 ((strcmp(server_type, "SB") == 0) && first
182 ? "gateway.messenger.hotmail.com"
183 : servconn->http_data->gateway_host),
184 params,
185 servconn->http_data->gateway_host,
186 (int)size,
187 buf);
188
189 g_free(params);
190
191 #if 0
192 gaim_debug_misc("msn", "Writing HTTP to fd %d: {%s}\n",
193 servconn->fd, temp);
194 #endif
195
196 s = 0;
197 needed = strlen(temp);
198
199 do
200 {
201 res = write(servconn->fd, temp, needed);
202 if (res >= 0)
203 s += res;
204 else if (errno != EAGAIN)
205 {
206 char *msg = g_strdup_printf("Unable to write to MSN server via HTTP (error %d)", errno);
207 gaim_connection_error(servconn->session->account->gc, msg);
208 g_free(msg);
209 return -1;
210 }
211 } while (s < needed);
212
213 g_free(temp);
214
215 servconn->http_data->waiting_response = TRUE;
216 servconn->http_data->virgin = FALSE;
217 servconn->http_data->dirty = FALSE;
218
219 return s;
220 }
221
222 void
223 msn_http_servconn_poll(MsnServConn *servconn)
224 {
225 size_t s;
226 char *temp;
227
228 g_return_if_fail(servconn != NULL);
229 g_return_if_fail(servconn->http_data != NULL);
230
231 if (servconn->http_data->waiting_response ||
232 servconn->http_data->queue != NULL)
233 {
234 return;
235 }
236
237 temp = g_strdup_printf(
238 "POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n"
239 "Accept: */*\r\n"
240 "Accept-Language: en-us\r\n"
241 "User-Agent: MSMSGS\r\n"
242 "Host: %s\r\n"
243 "Proxy-Connection: Keep-Alive\r\n"
244 "Connection: Keep-Alive\r\n"
245 "Pragma: no-cache\r\n"
246 "Content-Type: application/x-msn-messenger\r\n"
247 "Content-Length: 0\r\n"
248 "\r\n",
249 servconn->http_data->gateway_host,
250 servconn->http_data->session_id,
251 servconn->http_data->gateway_host);
252
253 #if 0
254 gaim_debug_misc("msn", "Writing to HTTP: {%s}\n", temp);
255 #endif
256
257 s = write(servconn->fd, temp, strlen(temp));
258
259 g_free(temp);
260
261 servconn->http_data->waiting_response = TRUE;
262 servconn->http_data->dirty = FALSE;
263
264 if (s <= 0)
265 gaim_connection_error(servconn->session->account->gc,
266 _("Write error"));
267 }
268
269 gboolean
270 msn_http_servconn_parse_data(MsnServConn *servconn, const char *buf,
271 size_t size, char **ret_buf, size_t *ret_size,
272 gboolean *error)
273 {
274 GaimConnection *gc;
275 const char *s, *c;
276 char *headers, *body;
277 char *tmp;
278 size_t len = 0;
279
280 g_return_val_if_fail(servconn != NULL, FALSE);
281 g_return_val_if_fail(buf != NULL, FALSE);
282 g_return_val_if_fail(size > 0, FALSE);
283 g_return_val_if_fail(ret_buf != NULL, FALSE);
284 g_return_val_if_fail(ret_size != NULL, FALSE);
285 g_return_val_if_fail(error != NULL, FALSE);
286
287 #if 0
288 gaim_debug_info("msn", "parsing data {%s} from fd %d\n",
289 buf, servconn->fd);
290 #endif
291 servconn->http_data->waiting_response = FALSE;
292
293 gc = gaim_account_get_connection(servconn->session->account);
294
295 /* Healthy defaults. */
296 *ret_buf = NULL;
297 *ret_size = 0;
298 *error = FALSE;
299
300 /* First, some tests to see if we have a full block of stuff. */
301 if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) &&
302 (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) &&
303 ((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) &&
304 (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0)))
305 {
306 *error = TRUE;
307
308 return FALSE;
309 }
310
311 if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0)
312 {
313 if ((s = strstr(buf, "\r\n\r\n")) == NULL)
314 return FALSE;
315
316 s += 4;
317
318 if (*s == '\0')
319 {
320 *ret_buf = g_strdup("");
321 *ret_size = 0;
322
323 return TRUE;
324 }
325
326 buf = s;
327 size -= (s - buf);
328 }
329
330 if ((s = strstr(buf, "\r\n\r\n")) == NULL)
331 return FALSE;
332
333 headers = g_strndup(buf, s - buf);
334 s += 4; /* Skip \r\n */
335 body = g_strndup(s, size - (s - buf));
336
337 #if 0
338 gaim_debug_misc("msn", "Incoming HTTP buffer: {%s\r\n%s}", headers, body);
339 #endif
340
341 if ((s = strstr(headers, "Content-Length: ")) != NULL)
342 {
343 s += strlen("Content-Length: ");
344
345 if ((c = strchr(s, '\r')) == NULL)
346 {
347 g_free(headers);
348 g_free(body);
349
350 return FALSE;
351 }
352
353 tmp = g_strndup(s, c - s);
354 len = atoi(tmp);
355 g_free(tmp);
356
357 if (strlen(body) != len)
358 {
359 g_free(headers);
360 g_free(body);
361
362 gaim_debug_warning("msn",
363 "body length (%d) != content length (%d)\n",
364 strlen(body), len);
365 return FALSE;
366 }
367 }
368
369 /* Now we should be able to process the data. */
370 if ((s = strstr(headers, "X-MSN-Messenger: ")) != NULL)
371 {
372 char *session_id, *gw_ip;
373 char *c2, *s2;
374
375 s += strlen("X-MSN-Messenger: ");
376
377 if ((c = strchr(s, '\r')) == NULL)
378 {
379 gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
380 return FALSE;
381 }
382
383 tmp = g_strndup(s, c - s);
384
385 /* Find the value for the Session ID */
386 if ((s2 = strchr(tmp, '=')) == NULL)
387 {
388 gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
389 return FALSE;
390 }
391
392 s2++;
393
394 /* Terminate the ; so we can g_strdup it. */
395 if ((c2 = strchr(s2, ';')) == NULL)
396 {
397 gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
398 return FALSE;
399 }
400
401 *c2 = '\0';
402 c2++;
403
404 /* Now grab that session ID. */
405 session_id = g_strdup(s2);
406
407 /* Continue to the gateway IP */
408 if ((s2 = strchr(c2, '=')) == NULL)
409 {
410 gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
411 return FALSE;
412 }
413
414 s2++;
415
416 /* Grab the gateway IP */
417 gw_ip = g_strdup(s2);
418
419 g_free(tmp);
420
421 /* Set the new data. */
422 if (servconn->http_data->session_id != NULL)
423 g_free(servconn->http_data->session_id);
424
425 if (servconn->http_data->old_gateway_host != NULL)
426 g_free(servconn->http_data->old_gateway_host);
427
428 servconn->http_data->old_gateway_host =
429 servconn->http_data->gateway_host;
430
431 servconn->http_data->session_id = session_id;
432 servconn->http_data->gateway_host = gw_ip;
433 }
434
435 g_free(headers);
436
437 *ret_buf = body;
438 *ret_size = len;
439
440 if (servconn->http_data->queue != NULL)
441 {
442 MsnHttpQueueData *queue_data;
443
444 queue_data = (MsnHttpQueueData *)servconn->http_data->queue->data;
445
446 servconn->http_data->queue =
447 g_list_remove(servconn->http_data->queue, queue_data);
448
449 msn_http_servconn_write(queue_data->servconn,
450 queue_data->buffer,
451 queue_data->size,
452 queue_data->server_type);
453
454 g_free(queue_data->buffer);
455 g_free(queue_data);
456 }
457 else
458 servconn->http_data->dirty = TRUE;
459
460 return TRUE;
461 }
462

mercurial