Mercurial > pidgin
annotate src/protocols/msn/switchboard.c @ 4634:d19872836812
[gaim-migrate @ 4941]
This will let you set up different proxy settings for different accounts.
Mainly useful to the corporate users that need to connect to an internal
jabber server, and still want to connect to "external" stuff through a
proxy, or something along those lines. I'm sure someone will come up with
another use for it.
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Sun, 02 Mar 2003 18:48:02 +0000 |
parents | a951bb590857 |
children | 283fb289c510 |
rev | line source |
---|---|
4542 | 1 /** |
2 * @file switchboard.c MSN switchboard functions | |
3 * | |
4 * gaim | |
5 * | |
6 * Copyright (C) 2003, Christian Hammond <chipx86@gnupdate.org> | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
23 #include "msn.h" | |
24 | |
4546
a951bb590857
[gaim-migrate @ 4825]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4542
diff
changeset
|
25 #ifdef _WIN32 |
a951bb590857
[gaim-migrate @ 4825]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4542
diff
changeset
|
26 #include "win32dep.h" |
a951bb590857
[gaim-migrate @ 4825]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4542
diff
changeset
|
27 #endif |
a951bb590857
[gaim-migrate @ 4825]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4542
diff
changeset
|
28 |
a951bb590857
[gaim-migrate @ 4825]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4542
diff
changeset
|
29 G_MODULE_IMPORT GSList *connections; |
a951bb590857
[gaim-migrate @ 4825]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4542
diff
changeset
|
30 |
4542 | 31 static char * |
32 msn_parse_format(char *mime) | |
33 { | |
34 char *cur; | |
35 GString *ret = g_string_new(NULL); | |
36 guint colorbuf; | |
37 char *colors = (char *)(&colorbuf); | |
38 | |
39 | |
40 cur = strstr(mime, "FN="); | |
41 if (cur && (*(cur = cur + 3) != ';')) { | |
42 ret = g_string_append(ret, "<FONT FACE=\""); | |
43 while (*cur && *cur != ';') { | |
44 ret = g_string_append_c(ret, *cur); | |
45 cur++; | |
46 } | |
47 ret = g_string_append(ret, "\">"); | |
48 } | |
49 | |
50 cur = strstr(mime, "EF="); | |
51 if (cur && (*(cur = cur + 3) != ';')) { | |
52 while (*cur && *cur != ';') { | |
53 ret = g_string_append_c(ret, '<'); | |
54 ret = g_string_append_c(ret, *cur); | |
55 ret = g_string_append_c(ret, '>'); | |
56 cur++; | |
57 } | |
58 } | |
59 | |
60 cur = strstr(mime, "CO="); | |
61 if (cur && (*(cur = cur + 3) != ';')) { | |
62 if (sscanf (cur, "%x;", &colorbuf) == 1) { | |
63 char tag[64]; | |
64 g_snprintf(tag, sizeof(tag), "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">", colors[0], colors[1], colors[2]); | |
65 ret = g_string_append(ret, tag); | |
66 } | |
67 } | |
68 | |
69 cur = url_decode(ret->str); | |
70 g_string_free(ret, TRUE); | |
71 return cur; | |
72 } | |
73 | |
74 static int | |
75 msn_process_switch(struct msn_switchboard *ms, char *buf) | |
76 { | |
77 struct gaim_connection *gc = ms->gc; | |
78 char sendbuf[MSN_BUF_LEN]; | |
79 static int id = 0; | |
80 | |
81 if (!g_strncasecmp(buf, "ACK", 3)) { | |
82 } else if (!g_strncasecmp(buf, "ANS", 3)) { | |
83 if (ms->chat) | |
84 gaim_chat_add_user(GAIM_CHAT(ms->chat), gc->username, NULL); | |
85 } else if (!g_strncasecmp(buf, "BYE", 3)) { | |
86 char *user, *tmp = buf; | |
87 GET_NEXT(tmp); | |
88 user = tmp; | |
89 | |
90 if (ms->chat) { | |
91 gaim_chat_remove_user(GAIM_CHAT(ms->chat), user, NULL); | |
92 } else { | |
93 char msgbuf[256]; | |
94 const char *username; | |
95 struct gaim_conversation *cnv; | |
96 struct buddy *b; | |
97 | |
98 if ((b = find_buddy(gc->account, user)) != NULL) | |
99 username = get_buddy_alias(b); | |
100 else | |
101 username = user; | |
102 | |
103 g_snprintf(msgbuf, sizeof(msgbuf), | |
104 _("%s has closed the conversation window"), username); | |
105 | |
106 if ((cnv = gaim_find_conversation(user))) | |
107 gaim_conversation_write(cnv, NULL, msgbuf, -1, | |
108 WFLAG_SYSTEM, time(NULL)); | |
109 | |
110 msn_kill_switch(ms); | |
111 return 0; | |
112 } | |
113 } else if (!g_strncasecmp(buf, "CAL", 3)) { | |
114 } else if (!g_strncasecmp(buf, "IRO", 3)) { | |
115 char *tot, *user, *tmp = buf; | |
116 | |
117 GET_NEXT(tmp); | |
118 GET_NEXT(tmp); | |
119 GET_NEXT(tmp); | |
120 tot = tmp; | |
121 GET_NEXT(tmp); | |
122 ms->total = atoi(tot); | |
123 user = tmp; | |
124 GET_NEXT(tmp); | |
125 | |
126 if (ms->total > 1) { | |
127 if (!ms->chat) | |
128 ms->chat = serv_got_joined_chat(gc, ++id, "MSN Chat"); | |
129 | |
130 gaim_chat_add_user(GAIM_CHAT(ms->chat), user, NULL); | |
131 } | |
132 } else if (!g_strncasecmp(buf, "JOI", 3)) { | |
133 char *user, *tmp = buf; | |
134 GET_NEXT(tmp); | |
135 user = tmp; | |
136 GET_NEXT(tmp); | |
137 | |
138 if (ms->total == 1) { | |
139 ms->chat = serv_got_joined_chat(gc, ++id, "MSN Chat"); | |
140 gaim_chat_add_user(GAIM_CHAT(ms->chat), ms->user, NULL); | |
141 gaim_chat_add_user(GAIM_CHAT(ms->chat), gc->username, NULL); | |
142 g_free(ms->user); | |
143 ms->user = NULL; | |
144 } | |
145 if (ms->chat) | |
146 gaim_chat_add_user(GAIM_CHAT(ms->chat), user, NULL); | |
147 ms->total++; | |
148 while (ms->txqueue) { | |
149 char *send = add_cr(ms->txqueue->data); | |
150 g_snprintf(sendbuf, sizeof(sendbuf), | |
151 "MSG %u N %d\r\n%s%s", ++ms->trId, | |
152 strlen(MIME_HEADER) + strlen(send), | |
153 MIME_HEADER, send); | |
154 | |
155 g_free(ms->txqueue->data); | |
156 ms->txqueue = g_slist_remove(ms->txqueue, ms->txqueue->data); | |
157 | |
158 if (msn_write(ms->fd, sendbuf, strlen(sendbuf)) < 0) { | |
159 msn_kill_switch(ms); | |
160 return 0; | |
161 } | |
162 | |
163 debug_printf("\n"); | |
164 } | |
165 } else if (!g_strncasecmp(buf, "MSG", 3)) { | |
166 char *user, *tmp = buf; | |
167 int length; | |
168 | |
169 GET_NEXT(tmp); | |
170 user = tmp; | |
171 | |
172 GET_NEXT(tmp); | |
173 | |
174 GET_NEXT(tmp); | |
175 length = atoi(tmp); | |
176 | |
177 ms->msg = TRUE; | |
178 ms->msguser = g_strdup(user); | |
179 ms->msglen = length; | |
180 } else if (!g_strncasecmp(buf, "NAK", 3)) { | |
181 do_error_dialog(_("An MSN message may not have been received."), NULL, GAIM_ERROR); | |
182 } else if (!g_strncasecmp(buf, "NLN", 3)) { | |
183 } else if (!g_strncasecmp(buf, "OUT", 3)) { | |
184 if (ms->chat) | |
185 serv_got_chat_left(gc, gaim_chat_get_id(GAIM_CHAT(ms->chat))); | |
186 msn_kill_switch(ms); | |
187 return 0; | |
188 } else if (!g_strncasecmp(buf, "USR", 3)) { | |
189 /* good, we got USR, now we need to find out who we want to talk to */ | |
190 struct msn_switchboard *ms = msn_find_writable_switch(gc); | |
191 | |
192 if (!ms) | |
193 return 0; | |
194 | |
195 g_snprintf(sendbuf, sizeof(sendbuf), "CAL %u %s\r\n", | |
196 ++ms->trId, ms->user); | |
197 | |
198 if (msn_write(ms->fd, sendbuf, strlen(sendbuf)) < 0) { | |
199 msn_kill_switch(ms); | |
200 return 0; | |
201 } | |
202 } else if (isdigit(*buf)) { | |
203 handle_errcode(buf, TRUE); | |
204 | |
205 if (atoi(buf) == 217) | |
206 msn_kill_switch(ms); | |
207 | |
208 } else { | |
209 debug_printf("Unhandled message!\n"); | |
210 } | |
211 | |
212 return 1; | |
213 } | |
214 | |
215 static void | |
216 msn_process_switch_msg(struct msn_switchboard *ms, char *msg) | |
217 { | |
218 char *content, *agent, *format; | |
219 char *message = NULL; | |
220 int flags = 0; | |
221 | |
222 agent = strstr(msg, "User-Agent: "); | |
223 if (agent) { | |
224 if (!g_strncasecmp(agent, "User-Agent: Gaim", | |
225 strlen("User-Agent: Gaim"))) | |
226 flags |= IM_FLAG_GAIMUSER; | |
227 } | |
228 | |
229 format = strstr(msg, "X-MMS-IM-Format: "); | |
230 if (format) { | |
231 format = msn_parse_format(format); | |
232 } else { | |
233 format = NULL; | |
234 } | |
235 | |
236 content = strstr(msg, "Content-Type: "); | |
237 if (!content) | |
238 return; | |
239 if (!g_strncasecmp(content, "Content-Type: text/x-msmsgscontrol\r\n", | |
240 strlen( "Content-Type: text/x-msmsgscontrol\r\n"))) { | |
241 if (strstr(content,"TypingUser: ") && !ms->chat) { | |
242 serv_got_typing(ms->gc, ms->msguser, | |
243 MSN_TYPING_RECV_TIMEOUT, TYPING); | |
244 return; | |
245 } | |
246 | |
247 } else if (!g_strncasecmp(content, "Content-Type: text/x-msmsgsinvite;", | |
248 strlen("Content-Type: text/x-msmsgsinvite;"))) { | |
249 | |
250 /* | |
251 * NOTE: Other things, such as voice communication, would go in | |
252 * here too (since they send the same Content-Type). However, | |
253 * this is the best check for file transfer messages, so I'm | |
254 * calling msn_process_ft_invite_msg(). If anybody adds support | |
255 * for anything else that sends a text/x-msmsgsinvite, perhaps | |
256 * this should be changed. For now, it stays. | |
257 */ | |
258 msn_process_ft_msg(ms, content); | |
259 | |
260 } else if (!g_strncasecmp(content, "Content-Type: text/plain", | |
261 strlen("Content-Type: text/plain"))) { | |
262 | |
263 char *skiphead = strstr(msg, "\r\n\r\n"); | |
264 | |
265 if (!skiphead || !skiphead[4]) { | |
266 return; | |
267 } | |
268 | |
269 skiphead += 4; | |
270 strip_linefeed(skiphead); | |
271 | |
272 if (format) { | |
273 message = g_strdup_printf("%s%s", format, skiphead); | |
274 } else { | |
275 message = g_strdup(skiphead); | |
276 } | |
277 | |
278 if (ms->chat) | |
279 serv_got_chat_in(ms->gc, gaim_chat_get_id(GAIM_CHAT(ms->chat)), | |
280 ms->msguser, flags, message, time(NULL)); | |
281 else | |
282 serv_got_im(ms->gc, ms->msguser, message, flags, time(NULL), -1); | |
283 | |
284 g_free(message); | |
285 } | |
286 } | |
287 | |
288 static void | |
289 msn_switchboard_callback(gpointer data, gint source, GaimInputCondition cond) | |
290 { | |
291 struct msn_switchboard *ms = data; | |
292 char buf[MSN_BUF_LEN]; | |
293 int cont = 1; | |
294 int len; | |
295 | |
296 ms->fd = source; | |
297 len = read(ms->fd, buf, sizeof(buf)); | |
298 if (len <= 0) { | |
299 msn_kill_switch(ms); | |
300 return; | |
301 } | |
302 | |
303 ms->rxqueue = g_realloc(ms->rxqueue, len + ms->rxlen); | |
304 memcpy(ms->rxqueue + ms->rxlen, buf, len); | |
305 ms->rxlen += len; | |
306 | |
307 while (cont) { | |
308 if (!ms->rxlen) | |
309 return; | |
310 | |
311 if (ms->msg) { | |
312 char *msg; | |
313 if (ms->msglen > ms->rxlen) | |
314 return; | |
315 msg = ms->rxqueue; | |
316 ms->rxlen -= ms->msglen; | |
317 if (ms->rxlen) { | |
318 ms->rxqueue = g_memdup(msg + ms->msglen, ms->rxlen); | |
319 } else { | |
320 ms->rxqueue = NULL; | |
321 msg = g_realloc(msg, ms->msglen + 1); | |
322 } | |
323 msg[ms->msglen] = 0; | |
324 ms->msglen = 0; | |
325 ms->msg = FALSE; | |
326 | |
327 msn_process_switch_msg(ms, msg); | |
328 | |
329 g_free(ms->msguser); | |
330 g_free(msg); | |
331 } else { | |
332 char *end = ms->rxqueue; | |
333 int cmdlen; | |
334 char *cmd; | |
335 int i = 0; | |
336 | |
337 while (i + 1 < ms->rxlen) { | |
338 if (*end == '\r' && end[1] == '\n') | |
339 break; | |
340 end++; i++; | |
341 } | |
342 if (i + 1 == ms->rxlen) | |
343 return; | |
344 | |
345 cmdlen = end - ms->rxqueue + 2; | |
346 cmd = ms->rxqueue; | |
347 ms->rxlen -= cmdlen; | |
348 if (ms->rxlen) { | |
349 ms->rxqueue = g_memdup(cmd + cmdlen, ms->rxlen); | |
350 } else { | |
351 ms->rxqueue = NULL; | |
352 cmd = g_realloc(cmd, cmdlen + 1); | |
353 } | |
354 cmd[cmdlen] = 0; | |
355 | |
356 debug_printf("MSN S: %s", cmd); | |
357 g_strchomp(cmd); | |
358 cont = msn_process_switch(ms, cmd); | |
359 | |
360 g_free(cmd); | |
361 } | |
362 } | |
363 } | |
364 | |
365 void | |
366 msn_rng_connect(gpointer data, gint source, GaimInputCondition cond) | |
367 { | |
368 struct msn_switchboard *ms = data; | |
369 struct gaim_connection *gc = ms->gc; | |
370 struct msn_data *md; | |
371 char buf[MSN_BUF_LEN]; | |
372 | |
373 if (source == -1 || !g_slist_find(connections, gc)) { | |
374 close(source); | |
375 g_free(ms->sessid); | |
376 g_free(ms->auth); | |
377 g_free(ms); | |
378 return; | |
379 } | |
380 | |
381 md = gc->proto_data; | |
382 | |
383 if (ms->fd != source) | |
384 ms->fd = source; | |
385 | |
386 g_snprintf(buf, sizeof(buf), "ANS %u %s %s %s\r\n", ++ms->trId, gc->username, ms->auth, ms->sessid); | |
387 if (msn_write(ms->fd, buf, strlen(buf)) < 0) { | |
388 close(ms->fd); | |
389 g_free(ms->sessid); | |
390 g_free(ms->auth); | |
391 g_free(ms); | |
392 return; | |
393 } | |
394 | |
395 md->switches = g_slist_append(md->switches, ms); | |
396 ms->inpa = gaim_input_add(ms->fd, GAIM_INPUT_READ, | |
397 msn_switchboard_callback, ms); | |
398 } | |
399 | |
400 static void | |
401 msn_ss_xfr_connect(gpointer data, gint source, GaimInputCondition cond) | |
402 { | |
403 struct msn_switchboard *ms = data; | |
404 struct gaim_connection *gc = ms->gc; | |
405 char buf[MSN_BUF_LEN]; | |
406 | |
407 if (source == -1 || !g_slist_find(connections, gc)) { | |
408 close(source); | |
409 if (g_slist_find(connections, gc)) { | |
410 msn_kill_switch(ms); | |
411 do_error_dialog(_("Gaim was unable to send an MSN message"), | |
412 _("Gaim encountered an error communicating with the " | |
413 "MSN switchboard server. Please try again later."), | |
414 GAIM_ERROR); | |
415 } | |
416 | |
417 return; | |
418 } | |
419 | |
420 if (ms->fd != source) | |
421 ms->fd = source; | |
422 | |
423 g_snprintf(buf, sizeof(buf), "USR %u %s %s\r\n", | |
424 ++ms->trId, gc->username, ms->auth); | |
425 | |
426 if (msn_write(ms->fd, buf, strlen(buf)) < 0) { | |
427 g_free(ms->auth); | |
428 g_free(ms); | |
429 return; | |
430 } | |
431 | |
432 ms->inpa = gaim_input_add(ms->fd, GAIM_INPUT_READ, | |
433 msn_switchboard_callback, ms); | |
434 } | |
435 | |
436 struct msn_switchboard * | |
437 msn_find_switch(struct gaim_connection *gc, const char *username) | |
438 { | |
439 struct msn_data *md = (struct msn_data *)gc->proto_data; | |
440 GSList *m = md->switches; | |
441 | |
442 for (m = md->switches; m != NULL; m = m->next) { | |
443 struct msn_switchboard *ms = (struct msn_switchboard *)m->data; | |
444 | |
445 if (ms->total <= 1 && !g_strcasecmp(ms->user, username)) | |
446 return ms; | |
447 } | |
448 | |
449 return NULL; | |
450 } | |
451 | |
452 struct msn_switchboard * | |
453 msn_find_switch_by_id(struct gaim_connection *gc, int chat_id) | |
454 { | |
455 struct msn_data *md = (struct msn_data *)gc->proto_data; | |
456 GSList *m; | |
457 | |
458 for (m = md->switches; m != NULL; m = m->next) { | |
459 struct msn_switchboard *ms = (struct msn_switchboard *)m->data; | |
460 | |
461 if (ms->chat && gaim_chat_get_id(GAIM_CHAT(ms->chat)) == chat_id) | |
462 return ms; | |
463 } | |
464 | |
465 return NULL; | |
466 } | |
467 | |
468 struct msn_switchboard * | |
469 msn_find_writable_switch(struct gaim_connection *gc) | |
470 { | |
471 struct msn_data *md = (struct msn_data *)gc->proto_data; | |
472 GSList *m; | |
473 | |
474 for (m = md->switches; m != NULL; m = m->next) { | |
475 struct msn_switchboard *ms = (struct msn_switchboard *)m->data; | |
476 | |
477 if (ms->txqueue != NULL) | |
478 return ms; | |
479 } | |
480 | |
481 return NULL; | |
482 } | |
483 | |
484 void | |
485 msn_kill_switch(struct msn_switchboard *ms) | |
486 { | |
487 struct gaim_connection *gc = ms->gc; | |
488 struct msn_data *md = gc->proto_data; | |
489 | |
490 if (ms->inpa) | |
491 gaim_input_remove(ms->inpa); | |
492 | |
493 close(ms->fd); | |
494 g_free(ms->rxqueue); | |
495 | |
496 if (ms->msg) g_free(ms->msguser); | |
497 if (ms->user) g_free(ms->user); | |
498 if (ms->sessid) g_free(ms->sessid); | |
499 | |
500 g_free(ms->auth); | |
501 | |
502 while (ms->txqueue) { | |
503 g_free(ms->txqueue->data); | |
504 ms->txqueue = g_slist_remove(ms->txqueue, ms->txqueue->data); | |
505 } | |
506 | |
507 if (ms->chat) | |
508 serv_got_chat_left(gc, gaim_chat_get_id(GAIM_CHAT(ms->chat))); | |
509 | |
510 md->switches = g_slist_remove(md->switches, ms); | |
511 | |
512 g_free(ms); | |
513 } | |
514 | |
515 struct msn_switchboard * | |
516 msn_switchboard_connect(struct gaim_connection *gc, const char *host, int port) | |
517 { | |
518 struct msn_switchboard *ms; | |
519 | |
520 if (host == NULL || port == 0) | |
521 return NULL; | |
522 | |
523 ms = msn_find_writable_switch(gc); | |
524 | |
525 if (ms == NULL) | |
526 return NULL; | |
527 | |
4634 | 528 if (proxy_connect(gc->account, (char *)host, port, msn_ss_xfr_connect, |
529 ms) != 0) { | |
4542 | 530 msn_kill_switch(ms); |
531 | |
532 return NULL; | |
533 } | |
534 | |
535 return ms; | |
536 } |