Mercurial > pidgin.yaz
comparison libgaim/protocols/msn/switchboard.c @ 14192:60b1bc8dbf37
[gaim-migrate @ 16863]
Renamed 'core' to 'libgaim'
committer: Tailor Script <tailor@pidgin.im>
author | Evan Schoenberg <evan.s@dreskin.net> |
---|---|
date | Sat, 19 Aug 2006 01:50:10 +0000 |
parents | |
children | f71894e1700d |
comparison
equal
deleted
inserted
replaced
14191:009db0b357b5 | 14192:60b1bc8dbf37 |
---|---|
1 /** | |
2 * @file switchboard.c MSN switchboard functions | |
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 "prefs.h" | |
26 #include "switchboard.h" | |
27 #include "notification.h" | |
28 #include "msn-utils.h" | |
29 | |
30 #include "error.h" | |
31 | |
32 static MsnTable *cbs_table; | |
33 | |
34 static void msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, | |
35 MsnMsgErrorType error); | |
36 | |
37 /************************************************************************** | |
38 * Main | |
39 **************************************************************************/ | |
40 | |
41 MsnSwitchBoard * | |
42 msn_switchboard_new(MsnSession *session) | |
43 { | |
44 MsnSwitchBoard *swboard; | |
45 MsnServConn *servconn; | |
46 | |
47 g_return_val_if_fail(session != NULL, NULL); | |
48 | |
49 swboard = g_new0(MsnSwitchBoard, 1); | |
50 | |
51 swboard->session = session; | |
52 swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVCONN_SB); | |
53 swboard->cmdproc = servconn->cmdproc; | |
54 | |
55 swboard->msg_queue = g_queue_new(); | |
56 swboard->empty = TRUE; | |
57 | |
58 swboard->cmdproc->data = swboard; | |
59 swboard->cmdproc->cbs_table = cbs_table; | |
60 | |
61 session->switches = g_list_append(session->switches, swboard); | |
62 | |
63 return swboard; | |
64 } | |
65 | |
66 void | |
67 msn_switchboard_destroy(MsnSwitchBoard *swboard) | |
68 { | |
69 MsnSession *session; | |
70 MsnMessage *msg; | |
71 GList *l; | |
72 | |
73 #ifdef MSN_DEBUG_SB | |
74 gaim_debug_info("msn", "switchboard_destroy: swboard(%p)\n", swboard); | |
75 #endif | |
76 | |
77 g_return_if_fail(swboard != NULL); | |
78 | |
79 if (swboard->destroying) | |
80 return; | |
81 | |
82 swboard->destroying = TRUE; | |
83 | |
84 /* If it linked us is because its looking for trouble */ | |
85 while (swboard->slplinks != NULL) | |
86 msn_slplink_destroy(swboard->slplinks->data); | |
87 | |
88 /* Destroy the message queue */ | |
89 while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL) | |
90 { | |
91 if (swboard->error != MSN_SB_ERROR_NONE) | |
92 { | |
93 /* The messages could not be sent due to a switchboard error */ | |
94 msg_error_helper(swboard->cmdproc, msg, | |
95 MSN_MSG_ERROR_SB); | |
96 } | |
97 msn_message_unref(msg); | |
98 } | |
99 | |
100 g_queue_free(swboard->msg_queue); | |
101 | |
102 /* msg_error_helper will both remove the msg from ack_list and | |
103 unref it, so we don't need to do either here */ | |
104 while ((l = swboard->ack_list) != NULL) | |
105 msg_error_helper(swboard->cmdproc, l->data, MSN_MSG_ERROR_SB); | |
106 | |
107 g_free(swboard->im_user); | |
108 g_free(swboard->auth_key); | |
109 g_free(swboard->session_id); | |
110 | |
111 for (l = swboard->users; l != NULL; l = l->next) | |
112 g_free(l->data); | |
113 | |
114 session = swboard->session; | |
115 session->switches = g_list_remove(session->switches, swboard); | |
116 | |
117 #if 0 | |
118 /* This should never happen or we are in trouble. */ | |
119 if (swboard->servconn != NULL) | |
120 msn_servconn_destroy(swboard->servconn); | |
121 #endif | |
122 | |
123 swboard->cmdproc->data = NULL; | |
124 | |
125 msn_servconn_set_disconnect_cb(swboard->servconn, NULL); | |
126 | |
127 msn_servconn_destroy(swboard->servconn); | |
128 | |
129 g_free(swboard); | |
130 } | |
131 | |
132 void | |
133 msn_switchboard_set_auth_key(MsnSwitchBoard *swboard, const char *key) | |
134 { | |
135 g_return_if_fail(swboard != NULL); | |
136 g_return_if_fail(key != NULL); | |
137 | |
138 swboard->auth_key = g_strdup(key); | |
139 } | |
140 | |
141 const char * | |
142 msn_switchboard_get_auth_key(MsnSwitchBoard *swboard) | |
143 { | |
144 g_return_val_if_fail(swboard != NULL, NULL); | |
145 | |
146 return swboard->auth_key; | |
147 } | |
148 | |
149 void | |
150 msn_switchboard_set_session_id(MsnSwitchBoard *swboard, const char *id) | |
151 { | |
152 g_return_if_fail(swboard != NULL); | |
153 g_return_if_fail(id != NULL); | |
154 | |
155 if (swboard->session_id != NULL) | |
156 g_free(swboard->session_id); | |
157 | |
158 swboard->session_id = g_strdup(id); | |
159 } | |
160 | |
161 const char * | |
162 msn_switchboard_get_session_id(MsnSwitchBoard *swboard) | |
163 { | |
164 g_return_val_if_fail(swboard != NULL, NULL); | |
165 | |
166 return swboard->session_id; | |
167 } | |
168 | |
169 void | |
170 msn_switchboard_set_invited(MsnSwitchBoard *swboard, gboolean invited) | |
171 { | |
172 g_return_if_fail(swboard != NULL); | |
173 | |
174 swboard->invited = invited; | |
175 } | |
176 | |
177 gboolean | |
178 msn_switchboard_is_invited(MsnSwitchBoard *swboard) | |
179 { | |
180 g_return_val_if_fail(swboard != NULL, FALSE); | |
181 | |
182 return swboard->invited; | |
183 } | |
184 | |
185 /************************************************************************** | |
186 * Utility | |
187 **************************************************************************/ | |
188 | |
189 static void | |
190 send_clientcaps(MsnSwitchBoard *swboard) | |
191 { | |
192 MsnMessage *msg; | |
193 | |
194 msg = msn_message_new(MSN_MSG_CAPS); | |
195 msn_message_set_content_type(msg, "text/x-clientcaps"); | |
196 msn_message_set_flag(msg, 'U'); | |
197 msn_message_set_bin_data(msg, MSN_CLIENTINFO, strlen(MSN_CLIENTINFO)); | |
198 | |
199 msn_switchboard_send_msg(swboard, msg, TRUE); | |
200 | |
201 msn_message_destroy(msg); | |
202 } | |
203 | |
204 static void | |
205 msn_switchboard_add_user(MsnSwitchBoard *swboard, const char *user) | |
206 { | |
207 MsnCmdProc *cmdproc; | |
208 GaimAccount *account; | |
209 | |
210 g_return_if_fail(swboard != NULL); | |
211 | |
212 cmdproc = swboard->cmdproc; | |
213 account = cmdproc->session->account; | |
214 | |
215 swboard->users = g_list_prepend(swboard->users, g_strdup(user)); | |
216 swboard->current_users++; | |
217 swboard->empty = FALSE; | |
218 | |
219 #ifdef MSN_DEBUG_CHAT | |
220 gaim_debug_info("msn", "user=[%s], total=%d\n", user, | |
221 swboard->current_users); | |
222 #endif | |
223 | |
224 if (!(swboard->flag & MSN_SB_FLAG_IM) && (swboard->conv != NULL)) | |
225 { | |
226 /* This is a helper switchboard. */ | |
227 gaim_debug_error("msn", "switchboard_add_user: conv != NULL\n"); | |
228 return; | |
229 } | |
230 | |
231 if ((swboard->conv != NULL) && | |
232 (gaim_conversation_get_type(swboard->conv) == GAIM_CONV_TYPE_CHAT)) | |
233 { | |
234 gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), user, NULL, | |
235 GAIM_CBFLAGS_NONE, TRUE); | |
236 } | |
237 else if (swboard->current_users > 1 || swboard->total_users > 1) | |
238 { | |
239 if (swboard->conv == NULL || | |
240 gaim_conversation_get_type(swboard->conv) != GAIM_CONV_TYPE_CHAT) | |
241 { | |
242 GList *l; | |
243 | |
244 #ifdef MSN_DEBUG_CHAT | |
245 gaim_debug_info("msn", "[chat] Switching to chat.\n"); | |
246 #endif | |
247 | |
248 #if 0 | |
249 /* this is bad - it causes msn_switchboard_close to be called on the | |
250 * switchboard we're in the middle of using :( */ | |
251 if (swboard->conv != NULL) | |
252 gaim_conversation_destroy(swboard->conv); | |
253 #endif | |
254 | |
255 cmdproc->session->conv_seq++; | |
256 swboard->chat_id = cmdproc->session->conv_seq; | |
257 swboard->flag |= MSN_SB_FLAG_IM; | |
258 swboard->conv = serv_got_joined_chat(account->gc, | |
259 swboard->chat_id, | |
260 "MSN Chat"); | |
261 | |
262 for (l = swboard->users; l != NULL; l = l->next) | |
263 { | |
264 const char *tmp_user; | |
265 | |
266 tmp_user = l->data; | |
267 | |
268 #ifdef MSN_DEBUG_CHAT | |
269 gaim_debug_info("msn", "[chat] Adding [%s].\n", tmp_user); | |
270 #endif | |
271 | |
272 gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), | |
273 tmp_user, NULL, GAIM_CBFLAGS_NONE, TRUE); | |
274 } | |
275 | |
276 #ifdef MSN_DEBUG_CHAT | |
277 gaim_debug_info("msn", "[chat] We add ourselves.\n"); | |
278 #endif | |
279 | |
280 gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), | |
281 gaim_account_get_username(account), | |
282 NULL, GAIM_CBFLAGS_NONE, TRUE); | |
283 | |
284 g_free(swboard->im_user); | |
285 swboard->im_user = NULL; | |
286 } | |
287 } | |
288 else if (swboard->conv == NULL) | |
289 { | |
290 swboard->conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, | |
291 user, account); | |
292 } | |
293 else | |
294 { | |
295 gaim_debug_warning("msn", "switchboard_add_user: This should not happen!\n"); | |
296 } | |
297 } | |
298 | |
299 static GaimConversation * | |
300 msn_switchboard_get_conv(MsnSwitchBoard *swboard) | |
301 { | |
302 GaimAccount *account; | |
303 | |
304 g_return_val_if_fail(swboard != NULL, NULL); | |
305 | |
306 if (swboard->conv != NULL) | |
307 return swboard->conv; | |
308 | |
309 gaim_debug_error("msn", "Switchboard with unassigned conversation\n"); | |
310 | |
311 account = swboard->session->account; | |
312 | |
313 return (swboard->conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, | |
314 account, swboard->im_user)); | |
315 } | |
316 | |
317 static void | |
318 msn_switchboard_report_user(MsnSwitchBoard *swboard, GaimMessageFlags flags, const char *msg) | |
319 { | |
320 GaimConversation *conv; | |
321 | |
322 g_return_if_fail(swboard != NULL); | |
323 g_return_if_fail(msg != NULL); | |
324 | |
325 if ((conv = msn_switchboard_get_conv(swboard)) != NULL) | |
326 { | |
327 gaim_conversation_write(conv, NULL, msg, flags, time(NULL)); | |
328 } | |
329 } | |
330 | |
331 static void | |
332 swboard_error_helper(MsnSwitchBoard *swboard, int reason, const char *passport) | |
333 { | |
334 g_return_if_fail(swboard != NULL); | |
335 | |
336 gaim_debug_warning("msg", "Error: Unable to call the user %s for reason %i\n", | |
337 passport ? passport : "(null)", reason); | |
338 | |
339 /* TODO: if current_users > 0, this is probably a chat and an invite failed, | |
340 * we should report that in the chat or something */ | |
341 if (swboard->current_users == 0) | |
342 { | |
343 swboard->error = reason; | |
344 msn_switchboard_close(swboard); | |
345 } | |
346 } | |
347 | |
348 static void | |
349 cal_error_helper(MsnTransaction *trans, int reason) | |
350 { | |
351 MsnSwitchBoard *swboard; | |
352 const char *passport; | |
353 char **params; | |
354 | |
355 params = g_strsplit(trans->params, " ", 0); | |
356 | |
357 passport = params[0]; | |
358 | |
359 swboard = trans->data; | |
360 | |
361 gaim_debug_warning("msn", "cal_error_helper: command %s failed for reason %i\n",trans->command,reason); | |
362 | |
363 swboard_error_helper(swboard, reason, passport); | |
364 | |
365 g_strfreev(params); | |
366 } | |
367 | |
368 static void | |
369 msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, MsnMsgErrorType error) | |
370 { | |
371 MsnSwitchBoard *swboard; | |
372 | |
373 g_return_if_fail(cmdproc != NULL); | |
374 g_return_if_fail(msg != NULL); | |
375 | |
376 if ((error != MSN_MSG_ERROR_SB) && (msg->nak_cb != NULL)) | |
377 msg->nak_cb(msg, msg->ack_data); | |
378 | |
379 swboard = cmdproc->data; | |
380 | |
381 /* This is not good, and should be fixed somewhere else. */ | |
382 g_return_if_fail(swboard != NULL); | |
383 | |
384 if (msg->type == MSN_MSG_TEXT) | |
385 { | |
386 const char *format, *str_reason; | |
387 char *body_str, *body_enc, *pre, *post; | |
388 | |
389 #if 0 | |
390 if (swboard->conv == NULL) | |
391 { | |
392 if (msg->ack_ref) | |
393 msn_message_unref(msg); | |
394 | |
395 return; | |
396 } | |
397 #endif | |
398 | |
399 if (error == MSN_MSG_ERROR_TIMEOUT) | |
400 { | |
401 str_reason = _("Message may have not been sent " | |
402 "because a timeout occurred:"); | |
403 } | |
404 else if (error == MSN_MSG_ERROR_SB) | |
405 { | |
406 switch (swboard->error) | |
407 { | |
408 case MSN_SB_ERROR_OFFLINE: | |
409 str_reason = _("Message could not be sent, " | |
410 "not allowed while invisible:"); | |
411 break; | |
412 case MSN_SB_ERROR_USER_OFFLINE: | |
413 str_reason = _("Message could not be sent " | |
414 "because the user is offline:"); | |
415 break; | |
416 case MSN_SB_ERROR_CONNECTION: | |
417 str_reason = _("Message could not be sent " | |
418 "because a connection error occurred:"); | |
419 break; | |
420 case MSN_SB_ERROR_TOO_FAST: | |
421 str_reason = _("Message could not be sent " | |
422 "because we are sending too quickly:"); | |
423 break; | |
424 default: | |
425 str_reason = _("Message could not be sent " | |
426 "because an error with " | |
427 "the switchboard occurred:"); | |
428 break; | |
429 } | |
430 } | |
431 else | |
432 { | |
433 str_reason = _("Message may have not been sent " | |
434 "because an unknown error occurred:"); | |
435 } | |
436 | |
437 body_str = msn_message_to_string(msg); | |
438 body_enc = g_markup_escape_text(body_str, -1); | |
439 g_free(body_str); | |
440 | |
441 format = msn_message_get_attr(msg, "X-MMS-IM-Format"); | |
442 msn_parse_format(format, &pre, &post); | |
443 body_str = g_strdup_printf("%s%s%s", pre ? pre : "", | |
444 body_enc ? body_enc : "", post ? post : ""); | |
445 g_free(body_enc); | |
446 g_free(pre); | |
447 g_free(post); | |
448 | |
449 msn_switchboard_report_user(swboard, GAIM_MESSAGE_ERROR, | |
450 str_reason); | |
451 msn_switchboard_report_user(swboard, GAIM_MESSAGE_RAW, | |
452 body_str); | |
453 | |
454 g_free(body_str); | |
455 } | |
456 | |
457 /* If a timeout occures we will want the msg around just in case we | |
458 * receive the ACK after the timeout. */ | |
459 if (msg->ack_ref && error != MSN_MSG_ERROR_TIMEOUT) | |
460 { | |
461 swboard->ack_list = g_list_remove(swboard->ack_list, msg); | |
462 msn_message_unref(msg); | |
463 } | |
464 } | |
465 | |
466 /************************************************************************** | |
467 * Message Stuff | |
468 **************************************************************************/ | |
469 | |
470 /** Called when a message times out. */ | |
471 static void | |
472 msg_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans) | |
473 { | |
474 MsnMessage *msg; | |
475 | |
476 msg = trans->data; | |
477 | |
478 msg_error_helper(cmdproc, msg, MSN_MSG_ERROR_TIMEOUT); | |
479 } | |
480 | |
481 /** Called when we receive an error of a message. */ | |
482 static void | |
483 msg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) | |
484 { | |
485 msg_error_helper(cmdproc, trans->data, MSN_MSG_ERROR_UNKNOWN); | |
486 } | |
487 | |
488 #if 0 | |
489 /** Called when we receive an ack of a special message. */ | |
490 static void | |
491 msg_ack(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
492 { | |
493 MsnMessage *msg; | |
494 | |
495 msg = cmd->trans->data; | |
496 | |
497 if (msg->ack_cb != NULL) | |
498 msg->ack_cb(msg->ack_data); | |
499 | |
500 msn_message_unref(msg); | |
501 } | |
502 | |
503 /** Called when we receive a nak of a special message. */ | |
504 static void | |
505 msg_nak(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
506 { | |
507 MsnMessage *msg; | |
508 | |
509 msg = cmd->trans->data; | |
510 | |
511 msn_message_unref(msg); | |
512 } | |
513 #endif | |
514 | |
515 static void | |
516 release_msg(MsnSwitchBoard *swboard, MsnMessage *msg) | |
517 { | |
518 MsnCmdProc *cmdproc; | |
519 MsnTransaction *trans; | |
520 char *payload; | |
521 gsize payload_len; | |
522 | |
523 g_return_if_fail(swboard != NULL); | |
524 g_return_if_fail(msg != NULL); | |
525 | |
526 cmdproc = swboard->cmdproc; | |
527 | |
528 payload = msn_message_gen_payload(msg, &payload_len); | |
529 | |
530 #ifdef MSN_DEBUG_SB | |
531 msn_message_show_readable(msg, "SB SEND", FALSE); | |
532 #endif | |
533 | |
534 trans = msn_transaction_new(cmdproc, "MSG", "%c %d", | |
535 msn_message_get_flag(msg), payload_len); | |
536 | |
537 /* Data for callbacks */ | |
538 msn_transaction_set_data(trans, msg); | |
539 | |
540 if (msg->type == MSN_MSG_TEXT) | |
541 { | |
542 msg->ack_ref = TRUE; | |
543 msn_message_ref(msg); | |
544 swboard->ack_list = g_list_append(swboard->ack_list, msg); | |
545 msn_transaction_set_timeout_cb(trans, msg_timeout); | |
546 } | |
547 else if (msg->type == MSN_MSG_SLP) | |
548 { | |
549 msg->ack_ref = TRUE; | |
550 msn_message_ref(msg); | |
551 swboard->ack_list = g_list_append(swboard->ack_list, msg); | |
552 msn_transaction_set_timeout_cb(trans, msg_timeout); | |
553 #if 0 | |
554 if (msg->ack_cb != NULL) | |
555 { | |
556 msn_transaction_add_cb(trans, "ACK", msg_ack); | |
557 msn_transaction_add_cb(trans, "NAK", msg_nak); | |
558 } | |
559 #endif | |
560 } | |
561 | |
562 trans->payload = payload; | |
563 trans->payload_len = payload_len; | |
564 | |
565 msg->trans = trans; | |
566 | |
567 msn_cmdproc_send_trans(cmdproc, trans); | |
568 } | |
569 | |
570 static void | |
571 queue_msg(MsnSwitchBoard *swboard, MsnMessage *msg) | |
572 { | |
573 g_return_if_fail(swboard != NULL); | |
574 g_return_if_fail(msg != NULL); | |
575 | |
576 gaim_debug_info("msn", "Appending message to queue.\n"); | |
577 | |
578 g_queue_push_tail(swboard->msg_queue, msg); | |
579 | |
580 msn_message_ref(msg); | |
581 } | |
582 | |
583 static void | |
584 process_queue(MsnSwitchBoard *swboard) | |
585 { | |
586 MsnMessage *msg; | |
587 | |
588 g_return_if_fail(swboard != NULL); | |
589 | |
590 gaim_debug_info("msn", "Processing queue\n"); | |
591 | |
592 while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL) | |
593 { | |
594 gaim_debug_info("msn", "Sending message\n"); | |
595 release_msg(swboard, msg); | |
596 msn_message_unref(msg); | |
597 } | |
598 } | |
599 | |
600 gboolean | |
601 msn_switchboard_can_send(MsnSwitchBoard *swboard) | |
602 { | |
603 g_return_val_if_fail(swboard != NULL, FALSE); | |
604 | |
605 if (swboard->empty || !g_queue_is_empty(swboard->msg_queue)) | |
606 return FALSE; | |
607 | |
608 return TRUE; | |
609 } | |
610 | |
611 void | |
612 msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg, | |
613 gboolean queue) | |
614 { | |
615 g_return_if_fail(swboard != NULL); | |
616 g_return_if_fail(msg != NULL); | |
617 | |
618 if (msn_switchboard_can_send(swboard)) | |
619 release_msg(swboard, msg); | |
620 else if (queue) | |
621 queue_msg(swboard, msg); | |
622 } | |
623 | |
624 /************************************************************************** | |
625 * Switchboard Commands | |
626 **************************************************************************/ | |
627 | |
628 static void | |
629 ans_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
630 { | |
631 MsnSwitchBoard *swboard; | |
632 | |
633 swboard = cmdproc->data; | |
634 swboard->ready = TRUE; | |
635 } | |
636 | |
637 static void | |
638 bye_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
639 { | |
640 MsnSwitchBoard *swboard; | |
641 const char *user; | |
642 | |
643 swboard = cmdproc->data; | |
644 user = cmd->params[0]; | |
645 | |
646 if (!(swboard->flag & MSN_SB_FLAG_IM) && (swboard->conv != NULL)) | |
647 gaim_debug_error("msn_switchboard", "bye_cmd: helper bug\n"); | |
648 | |
649 if (swboard->conv == NULL) | |
650 { | |
651 /* This is a helper switchboard */ | |
652 msn_switchboard_destroy(swboard); | |
653 } | |
654 else if ((swboard->current_users > 1) || | |
655 (gaim_conversation_get_type(swboard->conv) == GAIM_CONV_TYPE_CHAT)) | |
656 { | |
657 /* This is a switchboard used for a chat */ | |
658 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(swboard->conv), user, NULL); | |
659 swboard->current_users--; | |
660 if (swboard->current_users == 0) | |
661 msn_switchboard_destroy(swboard); | |
662 } | |
663 else | |
664 { | |
665 /* This is a switchboard used for a im session */ | |
666 msn_switchboard_destroy(swboard); | |
667 } | |
668 } | |
669 | |
670 static void | |
671 iro_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
672 { | |
673 GaimAccount *account; | |
674 GaimConnection *gc; | |
675 MsnSwitchBoard *swboard; | |
676 | |
677 account = cmdproc->session->account; | |
678 gc = account->gc; | |
679 swboard = cmdproc->data; | |
680 | |
681 swboard->total_users = atoi(cmd->params[2]); | |
682 | |
683 msn_switchboard_add_user(swboard, cmd->params[3]); | |
684 } | |
685 | |
686 static void | |
687 joi_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
688 { | |
689 MsnSession *session; | |
690 GaimAccount *account; | |
691 GaimConnection *gc; | |
692 MsnSwitchBoard *swboard; | |
693 const char *passport; | |
694 | |
695 passport = cmd->params[0]; | |
696 | |
697 session = cmdproc->session; | |
698 account = session->account; | |
699 gc = account->gc; | |
700 swboard = cmdproc->data; | |
701 | |
702 msn_switchboard_add_user(swboard, passport); | |
703 | |
704 process_queue(swboard); | |
705 | |
706 if (!session->http_method) | |
707 send_clientcaps(swboard); | |
708 | |
709 if (swboard->closed) | |
710 msn_switchboard_close(swboard); | |
711 } | |
712 | |
713 static void | |
714 msg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) | |
715 { | |
716 MsnMessage *msg; | |
717 | |
718 msg = msn_message_new_from_cmd(cmdproc->session, cmd); | |
719 | |
720 msn_message_parse_payload(msg, payload, len); | |
721 #ifdef MSN_DEBUG_SB | |
722 msn_message_show_readable(msg, "SB RECV", FALSE); | |
723 #endif | |
724 | |
725 if (msg->remote_user != NULL) | |
726 g_free (msg->remote_user); | |
727 | |
728 msg->remote_user = g_strdup(cmd->params[0]); | |
729 msn_cmdproc_process_msg(cmdproc, msg); | |
730 | |
731 msn_message_destroy(msg); | |
732 } | |
733 | |
734 static void | |
735 msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
736 { | |
737 cmdproc->servconn->payload_len = atoi(cmd->params[2]); | |
738 cmdproc->last_cmd->payload_cb = msg_cmd_post; | |
739 } | |
740 | |
741 static void | |
742 nak_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
743 { | |
744 MsnMessage *msg; | |
745 | |
746 msg = cmd->trans->data; | |
747 g_return_if_fail(msg != NULL); | |
748 | |
749 msg_error_helper(cmdproc, msg, MSN_MSG_ERROR_NAK); | |
750 } | |
751 | |
752 static void | |
753 ack_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
754 { | |
755 MsnSwitchBoard *swboard; | |
756 MsnMessage *msg; | |
757 | |
758 msg = cmd->trans->data; | |
759 | |
760 if (msg->ack_cb != NULL) | |
761 msg->ack_cb(msg, msg->ack_data); | |
762 | |
763 swboard = cmdproc->data; | |
764 swboard->ack_list = g_list_remove(swboard->ack_list, msg); | |
765 msn_message_unref(msg); | |
766 } | |
767 | |
768 static void | |
769 out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
770 { | |
771 GaimConnection *gc; | |
772 MsnSwitchBoard *swboard; | |
773 | |
774 gc = cmdproc->session->account->gc; | |
775 swboard = cmdproc->data; | |
776 | |
777 if (swboard->current_users > 1) | |
778 serv_got_chat_left(gc, swboard->chat_id); | |
779 | |
780 msn_switchboard_disconnect(swboard); | |
781 } | |
782 | |
783 static void | |
784 usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
785 { | |
786 MsnSwitchBoard *swboard; | |
787 | |
788 swboard = cmdproc->data; | |
789 | |
790 #if 0 | |
791 GList *l; | |
792 | |
793 for (l = swboard->users; l != NULL; l = l->next) | |
794 { | |
795 const char *user; | |
796 user = l->data; | |
797 | |
798 msn_cmdproc_send(cmdproc, "CAL", "%s", user); | |
799 } | |
800 #endif | |
801 | |
802 swboard->ready = TRUE; | |
803 msn_cmdproc_process_queue(cmdproc); | |
804 } | |
805 | |
806 /************************************************************************** | |
807 * Message Handlers | |
808 **************************************************************************/ | |
809 static void | |
810 plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | |
811 { | |
812 GaimConnection *gc; | |
813 MsnSwitchBoard *swboard; | |
814 const char *body; | |
815 char *body_str; | |
816 char *body_enc; | |
817 char *body_final; | |
818 size_t body_len; | |
819 const char *passport; | |
820 const char *value; | |
821 | |
822 gc = cmdproc->session->account->gc; | |
823 swboard = cmdproc->data; | |
824 | |
825 body = msn_message_get_bin_data(msg, &body_len); | |
826 body_str = g_strndup(body, body_len); | |
827 body_enc = g_markup_escape_text(body_str, -1); | |
828 g_free(body_str); | |
829 | |
830 passport = msg->remote_user; | |
831 | |
832 if (!strcmp(passport, "messenger@microsoft.com") && | |
833 strstr(body, "immediate security update")) | |
834 { | |
835 return; | |
836 } | |
837 | |
838 #if 0 | |
839 if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL) | |
840 { | |
841 gaim_debug_misc("msn", "User-Agent = '%s'\n", value); | |
842 } | |
843 #endif | |
844 | |
845 if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) | |
846 { | |
847 char *pre, *post; | |
848 | |
849 msn_parse_format(value, &pre, &post); | |
850 | |
851 body_final = g_strdup_printf("%s%s%s", pre ? pre : "", | |
852 body_enc ? body_enc : "", post ? post : ""); | |
853 | |
854 g_free(pre); | |
855 g_free(post); | |
856 g_free(body_enc); | |
857 } | |
858 else | |
859 { | |
860 body_final = body_enc; | |
861 } | |
862 | |
863 swboard->flag |= MSN_SB_FLAG_IM; | |
864 | |
865 if (swboard->current_users > 1 || | |
866 ((swboard->conv != NULL) && | |
867 gaim_conversation_get_type(swboard->conv) == GAIM_CONV_TYPE_CHAT)) | |
868 { | |
869 /* If current_users is always ok as it should then there is no need to | |
870 * check if this is a chat. */ | |
871 if (swboard->current_users <= 1) | |
872 gaim_debug_misc("msn", "plain_msg: current_users(%d)\n", | |
873 swboard->current_users); | |
874 | |
875 serv_got_chat_in(gc, swboard->chat_id, passport, 0, body_final, | |
876 time(NULL)); | |
877 if (swboard->conv == NULL) | |
878 { | |
879 swboard->conv = gaim_find_chat(gc, swboard->chat_id); | |
880 swboard->flag |= MSN_SB_FLAG_IM; | |
881 } | |
882 } | |
883 else | |
884 { | |
885 serv_got_im(gc, passport, body_final, 0, time(NULL)); | |
886 if (swboard->conv == NULL) | |
887 { | |
888 swboard->conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, | |
889 passport, gaim_connection_get_account(gc)); | |
890 swboard->flag |= MSN_SB_FLAG_IM; | |
891 } | |
892 } | |
893 | |
894 g_free(body_final); | |
895 } | |
896 | |
897 static void | |
898 control_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | |
899 { | |
900 GaimConnection *gc; | |
901 MsnSwitchBoard *swboard; | |
902 char *passport; | |
903 | |
904 gc = cmdproc->session->account->gc; | |
905 swboard = cmdproc->data; | |
906 passport = msg->remote_user; | |
907 | |
908 if (swboard->current_users == 1 && | |
909 msn_message_get_attr(msg, "TypingUser") != NULL) | |
910 { | |
911 serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, | |
912 GAIM_TYPING); | |
913 } | |
914 } | |
915 | |
916 static void | |
917 clientcaps_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | |
918 { | |
919 #if 0 | |
920 MsnSession *session; | |
921 MsnSwitchBoard *swboard; | |
922 MsnUser *user; | |
923 GHashTable *clientcaps; | |
924 const char *value; | |
925 | |
926 char *passport = msg->sender; | |
927 | |
928 session = cmdproc->session; | |
929 swboard = cmdproc->servconn->swboard; | |
930 | |
931 clientcaps = msn_message_get_hashtable_from_body(msg); | |
932 #endif | |
933 } | |
934 | |
935 static void | |
936 nudge_msg(MsnCmdProc *cmdproc, MsnMessage *msg) | |
937 { | |
938 MsnSwitchBoard *swboard; | |
939 char *username, *str; | |
940 GaimAccount *account; | |
941 GaimBuddy *buddy; | |
942 const char *user; | |
943 | |
944 swboard = cmdproc->data; | |
945 account = cmdproc->session->account; | |
946 user = msg->remote_user; | |
947 | |
948 if ((buddy = gaim_find_buddy(account, user)) != NULL) | |
949 username = g_markup_escape_text(gaim_buddy_get_alias(buddy), -1); | |
950 else | |
951 username = g_markup_escape_text(user, -1); | |
952 | |
953 str = g_strdup_printf(_("%s just sent you a Nudge!"), username); | |
954 g_free(username); | |
955 msn_switchboard_report_user(swboard, GAIM_MESSAGE_SYSTEM, str); | |
956 g_free(str); | |
957 } | |
958 | |
959 /************************************************************************** | |
960 * Connect stuff | |
961 **************************************************************************/ | |
962 static void | |
963 connect_cb(MsnServConn *servconn) | |
964 { | |
965 MsnSwitchBoard *swboard; | |
966 MsnCmdProc *cmdproc; | |
967 GaimAccount *account; | |
968 | |
969 cmdproc = servconn->cmdproc; | |
970 g_return_if_fail(cmdproc != NULL); | |
971 | |
972 account = cmdproc->session->account; | |
973 swboard = cmdproc->data; | |
974 g_return_if_fail(swboard != NULL); | |
975 | |
976 if (msn_switchboard_is_invited(swboard)) | |
977 { | |
978 swboard->empty = FALSE; | |
979 | |
980 msn_cmdproc_send(cmdproc, "ANS", "%s %s %s", | |
981 gaim_account_get_username(account), | |
982 swboard->auth_key, swboard->session_id); | |
983 } | |
984 else | |
985 { | |
986 msn_cmdproc_send(cmdproc, "USR", "%s %s", | |
987 gaim_account_get_username(account), | |
988 swboard->auth_key); | |
989 } | |
990 } | |
991 | |
992 static void | |
993 disconnect_cb(MsnServConn *servconn) | |
994 { | |
995 MsnSwitchBoard *swboard; | |
996 | |
997 swboard = servconn->cmdproc->data; | |
998 g_return_if_fail(swboard != NULL); | |
999 | |
1000 msn_servconn_set_disconnect_cb(swboard->servconn, NULL); | |
1001 | |
1002 msn_switchboard_destroy(swboard); | |
1003 } | |
1004 | |
1005 gboolean | |
1006 msn_switchboard_connect(MsnSwitchBoard *swboard, const char *host, int port) | |
1007 { | |
1008 g_return_val_if_fail(swboard != NULL, FALSE); | |
1009 | |
1010 msn_servconn_set_connect_cb(swboard->servconn, connect_cb); | |
1011 msn_servconn_set_disconnect_cb(swboard->servconn, disconnect_cb); | |
1012 | |
1013 return msn_servconn_connect(swboard->servconn, host, port); | |
1014 } | |
1015 | |
1016 void | |
1017 msn_switchboard_disconnect(MsnSwitchBoard *swboard) | |
1018 { | |
1019 g_return_if_fail(swboard != NULL); | |
1020 | |
1021 msn_servconn_disconnect(swboard->servconn); | |
1022 } | |
1023 | |
1024 /************************************************************************** | |
1025 * Call stuff | |
1026 **************************************************************************/ | |
1027 static void | |
1028 got_cal(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
1029 { | |
1030 #if 0 | |
1031 MsnSwitchBoard *swboard; | |
1032 const char *user; | |
1033 | |
1034 swboard = cmdproc->data; | |
1035 | |
1036 user = cmd->params[0]; | |
1037 | |
1038 msn_switchboard_add_user(swboard, user); | |
1039 #endif | |
1040 } | |
1041 | |
1042 static void | |
1043 cal_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans) | |
1044 { | |
1045 gaim_debug_warning("msn", "cal_timeout: command %s timed out\n", trans->command); | |
1046 | |
1047 cal_error_helper(trans, MSN_SB_ERROR_UNKNOWN); | |
1048 } | |
1049 | |
1050 static void | |
1051 cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) | |
1052 { | |
1053 int reason = MSN_SB_ERROR_UNKNOWN; | |
1054 | |
1055 if (error == 215) | |
1056 { | |
1057 gaim_debug_info("msn", "Invited user already in switchboard\n"); | |
1058 return; | |
1059 } | |
1060 else if (error == 217) | |
1061 { | |
1062 reason = MSN_SB_ERROR_USER_OFFLINE; | |
1063 } | |
1064 | |
1065 gaim_debug_warning("msn", "cal_error: command %s gave error %i\n", trans->command, error); | |
1066 | |
1067 cal_error_helper(trans, reason); | |
1068 } | |
1069 | |
1070 void | |
1071 msn_switchboard_request_add_user(MsnSwitchBoard *swboard, const char *user) | |
1072 { | |
1073 MsnTransaction *trans; | |
1074 MsnCmdProc *cmdproc; | |
1075 | |
1076 g_return_if_fail(swboard != NULL); | |
1077 | |
1078 cmdproc = swboard->cmdproc; | |
1079 | |
1080 trans = msn_transaction_new(cmdproc, "CAL", "%s", user); | |
1081 /* this doesn't do anything, but users seem to think that | |
1082 * 'Unhandled command' is some kind of error, so we don't report it */ | |
1083 msn_transaction_add_cb(trans, "CAL", got_cal); | |
1084 | |
1085 msn_transaction_set_data(trans, swboard); | |
1086 msn_transaction_set_timeout_cb(trans, cal_timeout); | |
1087 | |
1088 if (swboard->ready) | |
1089 msn_cmdproc_send_trans(cmdproc, trans); | |
1090 else | |
1091 msn_cmdproc_queue_trans(cmdproc, trans); | |
1092 } | |
1093 | |
1094 /************************************************************************** | |
1095 * Create & Transfer stuff | |
1096 **************************************************************************/ | |
1097 | |
1098 static void | |
1099 got_swboard(MsnCmdProc *cmdproc, MsnCommand *cmd) | |
1100 { | |
1101 MsnSwitchBoard *swboard; | |
1102 char *host; | |
1103 int port; | |
1104 swboard = cmd->trans->data; | |
1105 | |
1106 if (g_list_find(cmdproc->session->switches, swboard) == NULL) | |
1107 /* The conversation window was closed. */ | |
1108 return; | |
1109 | |
1110 msn_switchboard_set_auth_key(swboard, cmd->params[4]); | |
1111 | |
1112 msn_parse_socket(cmd->params[2], &host, &port); | |
1113 | |
1114 if (!msn_switchboard_connect(swboard, host, port)) | |
1115 msn_switchboard_destroy(swboard); | |
1116 | |
1117 g_free(host); | |
1118 } | |
1119 | |
1120 static void | |
1121 xfr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) | |
1122 { | |
1123 MsnSwitchBoard *swboard; | |
1124 int reason = MSN_SB_ERROR_UNKNOWN; | |
1125 | |
1126 if (error == 913) | |
1127 reason = MSN_SB_ERROR_OFFLINE; | |
1128 else if (error == 800) | |
1129 reason = MSN_SB_ERROR_TOO_FAST; | |
1130 | |
1131 swboard = trans->data; | |
1132 | |
1133 gaim_debug_info("msn", "xfr_error %i for %s: trans %x, command %s, reason %i\n", | |
1134 error, (swboard->im_user ? swboard->im_user : "(null)"), trans, | |
1135 (trans->command ? trans->command : "(null)"), reason); | |
1136 | |
1137 swboard_error_helper(swboard, reason, swboard->im_user); | |
1138 } | |
1139 | |
1140 void | |
1141 msn_switchboard_request(MsnSwitchBoard *swboard) | |
1142 { | |
1143 MsnCmdProc *cmdproc; | |
1144 MsnTransaction *trans; | |
1145 | |
1146 g_return_if_fail(swboard != NULL); | |
1147 | |
1148 cmdproc = swboard->session->notification->cmdproc; | |
1149 | |
1150 trans = msn_transaction_new(cmdproc, "XFR", "%s", "SB"); | |
1151 msn_transaction_add_cb(trans, "XFR", got_swboard); | |
1152 | |
1153 msn_transaction_set_data(trans, swboard); | |
1154 msn_transaction_set_error_cb(trans, xfr_error); | |
1155 | |
1156 msn_cmdproc_send_trans(cmdproc, trans); | |
1157 } | |
1158 | |
1159 void | |
1160 msn_switchboard_close(MsnSwitchBoard *swboard) | |
1161 { | |
1162 g_return_if_fail(swboard != NULL); | |
1163 | |
1164 if (swboard->error != MSN_SB_ERROR_NONE) | |
1165 { | |
1166 msn_switchboard_destroy(swboard); | |
1167 } | |
1168 else if (g_queue_is_empty(swboard->msg_queue) || | |
1169 !swboard->session->connected) | |
1170 { | |
1171 MsnCmdProc *cmdproc; | |
1172 cmdproc = swboard->cmdproc; | |
1173 msn_cmdproc_send_quick(cmdproc, "OUT", NULL, NULL); | |
1174 | |
1175 msn_switchboard_destroy(swboard); | |
1176 } | |
1177 else | |
1178 { | |
1179 swboard->closed = TRUE; | |
1180 } | |
1181 } | |
1182 | |
1183 gboolean | |
1184 msn_switchboard_release(MsnSwitchBoard *swboard, MsnSBFlag flag) | |
1185 { | |
1186 g_return_val_if_fail(swboard != NULL, FALSE); | |
1187 | |
1188 swboard->flag &= ~flag; | |
1189 | |
1190 if (flag == MSN_SB_FLAG_IM) | |
1191 /* Forget any conversation that used to be associated with this | |
1192 * swboard. */ | |
1193 swboard->conv = NULL; | |
1194 | |
1195 if (swboard->flag == 0) | |
1196 { | |
1197 msn_switchboard_close(swboard); | |
1198 return TRUE; | |
1199 } | |
1200 | |
1201 return FALSE; | |
1202 } | |
1203 | |
1204 /************************************************************************** | |
1205 * Init stuff | |
1206 **************************************************************************/ | |
1207 | |
1208 void | |
1209 msn_switchboard_init(void) | |
1210 { | |
1211 cbs_table = msn_table_new(); | |
1212 | |
1213 msn_table_add_cmd(cbs_table, "ANS", "ANS", ans_cmd); | |
1214 msn_table_add_cmd(cbs_table, "ANS", "IRO", iro_cmd); | |
1215 | |
1216 msn_table_add_cmd(cbs_table, "MSG", "ACK", ack_cmd); | |
1217 msn_table_add_cmd(cbs_table, "MSG", "NAK", nak_cmd); | |
1218 | |
1219 msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd); | |
1220 | |
1221 msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd); | |
1222 msn_table_add_cmd(cbs_table, NULL, "JOI", joi_cmd); | |
1223 msn_table_add_cmd(cbs_table, NULL, "BYE", bye_cmd); | |
1224 msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd); | |
1225 | |
1226 #if 0 | |
1227 /* They might skip the history */ | |
1228 msn_table_add_cmd(cbs_table, NULL, "ACK", NULL); | |
1229 #endif | |
1230 | |
1231 msn_table_add_error(cbs_table, "MSG", msg_error); | |
1232 msn_table_add_error(cbs_table, "CAL", cal_error); | |
1233 | |
1234 /* Register the message type callbacks. */ | |
1235 msn_table_add_msg_type(cbs_table, "text/plain", | |
1236 plain_msg); | |
1237 msn_table_add_msg_type(cbs_table, "text/x-msmsgscontrol", | |
1238 control_msg); | |
1239 msn_table_add_msg_type(cbs_table, "text/x-clientcaps", | |
1240 clientcaps_msg); | |
1241 msn_table_add_msg_type(cbs_table, "text/x-clientinfo", | |
1242 clientcaps_msg); | |
1243 msn_table_add_msg_type(cbs_table, "application/x-msnmsgrp2p", | |
1244 msn_p2p_msg); | |
1245 msn_table_add_msg_type(cbs_table, "text/x-mms-emoticon", | |
1246 msn_emoticon_msg); | |
1247 msn_table_add_msg_type(cbs_table, "text/x-mms-animemoticon", | |
1248 msn_emoticon_msg); | |
1249 msn_table_add_msg_type(cbs_table, "text/x-msnmsgr-datacast", | |
1250 nudge_msg); | |
1251 #if 0 | |
1252 msn_table_add_msg_type(cbs_table, "text/x-msmmsginvite", | |
1253 msn_invite_msg); | |
1254 #endif | |
1255 } | |
1256 | |
1257 void | |
1258 msn_switchboard_end(void) | |
1259 { | |
1260 msn_table_destroy(cbs_table); | |
1261 } |