Mercurial > ~mikael > mcabber > hg
comparison mcabber/mcabber/xmpp_muc.c @ 1953:9f443617e96b
Improve MUC support (Myhailo Danylenko)
This patch should allow handling of multiple statuses in MUC rooms.
Patch merged from isbear's mcabber-experimental repository.
author | Mikael Berthe <mikael@lilotux.net> |
---|---|
date | Mon, 14 Mar 2011 13:17:17 +0100 |
parents | 1a01a7ef4e43 |
children | 6febc7d1f760 |
comparison
equal
deleted
inserted
replaced
1952:975f6f26b052 | 1953:9f443617e96b |
---|---|
399 void handle_muc_presence(const char *from, LmMessageNode *xmldata, | 399 void handle_muc_presence(const char *from, LmMessageNode *xmldata, |
400 const char *roomjid, const char *rname, | 400 const char *roomjid, const char *rname, |
401 enum imstatus ust, const char *ustmsg, | 401 enum imstatus ust, const char *ustmsg, |
402 time_t usttime, char bpprio) | 402 time_t usttime, char bpprio) |
403 { | 403 { |
404 LmMessageNode *y; | |
405 const char *p; | |
406 char *mbuf; | 404 char *mbuf; |
407 const char *ournick; | 405 const char *ournick; |
408 enum imrole mbrole = role_none; | 406 enum imrole mbrole = role_none; |
409 enum imaffiliation mbaffil = affil_none; | 407 enum imaffiliation mbaffil = affil_none; |
410 enum room_printstatus printstatus; | 408 enum room_printstatus printstatus; |
411 enum room_autowhois autowhois; | 409 enum room_autowhois autowhois; |
412 const char *mbjid = NULL, *mbnick = NULL; | 410 const char *mbjid = NULL, *mbnick = NULL; |
413 const char *actorjid = NULL, *reason = NULL; | 411 const char *actorjid = NULL, *reason = NULL; |
414 bool new_member = FALSE; // True if somebody else joins the room (not us) | 412 bool new_member = FALSE; // True if somebody else joins the room (not us) |
413 bool our_presence = FALSE; // True if this presence is from us (i.e. bears | |
414 // code 110) | |
415 guint statuscode = 0; | 415 guint statuscode = 0; |
416 guint nickchange = 0; | 416 guint nickchange = 0; |
417 GSList *room_elt; | 417 GSList *room_elt; |
418 int log_muc_conf; | 418 int log_muc_conf; |
419 guint msgflags; | 419 guint msgflags; |
440 // Get our room nickname | 440 // Get our room nickname |
441 ournick = buddy_getnickname(room_elt->data); | 441 ournick = buddy_getnickname(room_elt->data); |
442 | 442 |
443 if (!ournick) { | 443 if (!ournick) { |
444 // It shouldn't happen, probably a server issue | 444 // It shouldn't happen, probably a server issue |
445 mbuf = g_strdup_printf("Unexpected groupchat packet!"); | 445 const gchar msg[] = "Unexpected groupchat packet!"; |
446 | 446 scr_LogPrint(LPRINT_LOGNORM, msg); |
447 scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf); | 447 scr_WriteIncomingMessage(roomjid, msg, 0, HBB_PREFIX_INFO, 0); |
448 scr_WriteIncomingMessage(roomjid, mbuf, 0, HBB_PREFIX_INFO, 0); | |
449 g_free(mbuf); | |
450 // Send back an unavailable packet | 448 // Send back an unavailable packet |
451 xmpp_setstatus(offline, roomjid, "", TRUE); | 449 xmpp_setstatus(offline, roomjid, "", TRUE); |
452 scr_draw_roster(); | 450 scr_draw_roster(); |
453 return; | 451 return; |
454 } | 452 } |
455 | 453 |
456 // Get the status code | 454 #define SETSTATUSCODE(VALUE) \ |
457 // 201: a room has been created | 455 { \ |
458 // 301: the user has been banned from the room | 456 if (G_UNLIKELY(statuscode)) \ |
459 // 303: new room nickname | 457 scr_LogPrint(LPRINT_DEBUG, "handle_muc_presence: WARNING: " \ |
460 // 307: the user has been kicked from the room | 458 "replacing status code %u with %u.", statuscode, VALUE); \ |
461 // 321,322,332: the user has been removed from the room | 459 statuscode = VALUE; \ |
462 y = lm_message_node_find_child(xmldata, "status"); | 460 } |
463 if (y) { | 461 |
464 p = lm_message_node_get_attribute(y, "code"); | 462 { // Get the status code |
465 if (p) | 463 LmMessageNode *node; |
466 statuscode = atoi(p); | 464 for (node = xmldata -> children; node; node = node -> next) { |
467 } | 465 if (!g_strcmp0(node -> name, "status")) { |
466 const char *codestr = lm_message_node_get_attribute(node, "code"); | |
467 if (codestr) { | |
468 const char *mesg = NULL; | |
469 switch (atoi(codestr)) { | |
470 // initial | |
471 case 100: | |
472 mesg = "The room is not anonymous."; | |
473 break; | |
474 case 110: // It is our presence | |
475 our_presence = TRUE; | |
476 break; | |
477 // initial | |
478 case 170: | |
479 mesg = "The room is logged."; | |
480 break; | |
481 // initial | |
482 case 201: // Room created | |
483 SETSTATUSCODE(201); | |
484 break; | |
485 // initial | |
486 case 210: // Your nick change (on join) | |
487 // FIXME: print nick | |
488 mesg = "The room has changed your nick!"; | |
489 buddy_setnickname(room_elt->data, rname); | |
490 ournick = rname; | |
491 break; | |
492 case 301: // User banned | |
493 SETSTATUSCODE(301); | |
494 break; | |
495 case 303: // Nick change | |
496 SETSTATUSCODE(303); | |
497 break; | |
498 case 307: // User kicked | |
499 SETSTATUSCODE(307); | |
500 break; | |
501 // XXX (next three) | |
502 case 321: | |
503 mesg = "User leaves room due to affilation change."; | |
504 break; | |
505 case 322: | |
506 mesg = "User leaves room, as room is only for members now."; | |
507 break; | |
508 case 332: | |
509 mesg = "User leaves room due to system shutdown."; | |
510 break; | |
511 default: | |
512 scr_LogPrint(LPRINT_DEBUG, | |
513 "handle_muc_presence: Unknown MUC status code: %s.", | |
514 codestr); | |
515 break; | |
516 } | |
517 if (mesg) { | |
518 scr_WriteIncomingMessage(roomjid, mesg, usttime, | |
519 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
520 if (log_muc_conf) | |
521 hlog_write_message(roomjid, 0, -1, mesg); | |
522 } | |
523 } | |
524 } | |
525 } | |
526 } | |
527 | |
528 #undef SETSTATUSCODE | |
529 | |
530 if (!our_presence) | |
531 if (ournick && !strcmp(ournick, rname)) | |
532 our_presence = TRUE; | |
468 | 533 |
469 // Get the room's "print_status" settings | 534 // Get the room's "print_status" settings |
470 printstatus = buddy_getprintstatus(room_elt->data); | 535 printstatus = buddy_getprintstatus(room_elt->data); |
471 if (printstatus == status_default) { | 536 if (printstatus == status_default) { |
472 printstatus = (guint) settings_opt_get_int("muc_print_status"); | 537 printstatus = (guint) settings_opt_get_int("muc_print_status"); |
486 if (log_muc_conf) | 551 if (log_muc_conf) |
487 hlog_write_message(roomjid, 0, -1, mbuf); | 552 hlog_write_message(roomjid, 0, -1, mbuf); |
488 g_free(mbuf); | 553 g_free(mbuf); |
489 buddy_resource_setname(room_elt->data, rname, mbnick); | 554 buddy_resource_setname(room_elt->data, rname, mbnick); |
490 // Maybe it's _our_ nickname... | 555 // Maybe it's _our_ nickname... |
491 if (ournick && !strcmp(rname, ournick)) | 556 if (our_presence) |
492 buddy_setnickname(room_elt->data, mbnick); | 557 buddy_setnickname(room_elt->data, mbnick); |
493 nickchange = TRUE; | 558 nickchange = TRUE; |
494 } | 559 } |
495 | 560 |
496 // Check for departure/arrival | 561 // Check for departure/arrival |
497 if (statuscode != 303 && ust == offline) { | 562 if (statuscode != 303 && ust == offline) { |
498 // Somebody is leaving | 563 // Somebody is leaving |
499 enum { leave=0, kick, ban } how = leave; | 564 enum { leave=0, kick, ban } how = leave; |
500 bool we_left = FALSE; | |
501 | 565 |
502 if (statuscode == 307) | 566 if (statuscode == 307) |
503 how = kick; | 567 how = kick; |
504 else if (statuscode == 301) | 568 else if (statuscode == 301) |
505 how = ban; | 569 how = ban; |
506 | 570 |
507 // If this is a leave, check if it is ourself | 571 // If this is a leave, check if it is ourself |
508 if (ournick && !strcmp(rname, ournick)) { | 572 if (our_presence) { |
509 we_left = TRUE; // _We_ have left! (kicked, banned, etc.) | |
510 buddy_setinsideroom(room_elt->data, FALSE); | 573 buddy_setinsideroom(room_elt->data, FALSE); |
511 buddy_setnickname(room_elt->data, NULL); | 574 buddy_setnickname(room_elt->data, NULL); |
512 buddy_del_all_resources(room_elt->data); | 575 buddy_del_all_resources(room_elt->data); |
513 buddy_settopic(room_elt->data, NULL); | 576 buddy_settopic(room_elt->data, NULL); |
514 scr_update_chat_status(FALSE); | 577 scr_update_chat_status(FALSE); |
529 (how == ban ? "banned" : "kicked"), | 592 (how == ban ? "banned" : "kicked"), |
530 roomjid); | 593 roomjid); |
531 } | 594 } |
532 if (reason) | 595 if (reason) |
533 reason_msg = g_strdup_printf("\nReason: %s", reason); | 596 reason_msg = g_strdup_printf("\nReason: %s", reason); |
534 if (we_left) | 597 if (our_presence) |
535 mbuf = g_strdup_printf("You have been %s%s", mbuf_end, | 598 mbuf = g_strdup_printf("You have been %s%s", mbuf_end, |
536 reason_msg ? reason_msg : ""); | 599 reason_msg ? reason_msg : ""); |
537 else | 600 else |
538 mbuf = g_strdup_printf("%s has been %s%s", rname, mbuf_end, | 601 mbuf = g_strdup_printf("%s has been %s%s", rname, mbuf_end, |
539 reason_msg ? reason_msg : ""); | 602 reason_msg ? reason_msg : ""); |
540 | 603 |
541 g_free(reason_msg); | 604 g_free(reason_msg); |
542 g_free(mbuf_end); | 605 g_free(mbuf_end); |
543 } else { | 606 } else { |
544 // Natural leave | 607 // Natural leave |
545 if (we_left) { | 608 if (our_presence) { |
546 LmMessageNode *destroynode = lm_message_node_find_child(xmldata, | 609 LmMessageNode *destroynode = lm_message_node_find_child(xmldata, |
547 "destroy"); | 610 "destroy"); |
548 if (destroynode) { | 611 if (destroynode) { |
549 reason = lm_message_node_get_child_value(destroynode, "reason"); | 612 reason = lm_message_node_get_child_value(destroynode, "reason"); |
550 if (reason && *reason) { | 613 if (reason && *reason) { |
573 } | 636 } |
574 } | 637 } |
575 | 638 |
576 // Display the mbuf message if we're concerned | 639 // Display the mbuf message if we're concerned |
577 // or if the print_status isn't set to none. | 640 // or if the print_status isn't set to none. |
578 if (we_left || printstatus != status_none) { | 641 if (our_presence || printstatus != status_none) { |
579 msgflags = HBB_PREFIX_INFO; | 642 msgflags = HBB_PREFIX_INFO; |
580 if (!we_left && settings_opt_get_int("muc_flag_joins") != 2) | 643 if (!our_presence && settings_opt_get_int("muc_flag_joins") != 2) |
581 msgflags |= HBB_PREFIX_NOFLAG; | 644 msgflags |= HBB_PREFIX_NOFLAG; |
582 scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0); | 645 scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0); |
583 } | 646 } |
584 | 647 |
585 if (log_muc_conf) | 648 if (log_muc_conf) |
586 hlog_write_message(roomjid, 0, -1, mbuf); | 649 hlog_write_message(roomjid, 0, -1, mbuf); |
587 | 650 |
588 if (we_left) { | 651 if (our_presence) { |
589 scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf); | 652 scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf); |
590 g_free(mbuf); | 653 g_free(mbuf); |
591 return; | 654 return; |
592 } | 655 } |
593 g_free(mbuf); | 656 g_free(mbuf); |
594 } else if (buddy_getstatus(room_elt->data, rname) == offline && | |
595 ust != offline) { | |
596 // Somebody is joining | |
597 new_member = muc_handle_join(room_elt, rname, roomjid, ournick, | |
598 printstatus, usttime, log_muc_conf); | |
599 } else { | 657 } else { |
600 // This is a simple member status change | 658 enum imstatus old_ust = buddy_getstatus(room_elt->data, rname); |
601 | 659 if (old_ust == offline && ust != offline) { |
602 if (printstatus == status_all && !nickchange) { | 660 // Somebody is joining |
603 mbuf = g_strdup_printf("Member status has changed: %s [%c] %s", rname, | 661 new_member = muc_handle_join(room_elt, rname, roomjid, ournick, |
604 imstatus2char[ust], ((ustmsg) ? ustmsg : "")); | 662 printstatus, usttime, log_muc_conf); |
605 scr_WriteIncomingMessage(roomjid, mbuf, usttime, | 663 } else { |
606 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | 664 // This is a simple member status change |
607 g_free(mbuf); | 665 |
666 if (printstatus == status_all && !nickchange) { | |
667 const char *old_ustmsg = buddy_getstatusmsg(room_elt->data, rname); | |
668 if (old_ust != ust || g_strcmp0(old_ustmsg, ustmsg)) { | |
669 mbuf = g_strdup_printf("Member status has changed: %s [%c] %s", rname, | |
670 imstatus2char[ust], ((ustmsg) ? ustmsg : "")); | |
671 scr_WriteIncomingMessage(roomjid, mbuf, usttime, | |
672 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
673 g_free(mbuf); | |
674 } | |
675 } | |
608 } | 676 } |
609 } | 677 } |
610 | 678 |
611 // Sanity check, shouldn't happen... | 679 // Sanity check, shouldn't happen... |
612 if (!rname) | 680 if (!rname) |
725 g_free(barejid); | 793 g_free(barejid); |
726 } | 794 } |
727 | 795 |
728 | 796 |
729 // Specific MUC message handling (for example invitation processing) | 797 // Specific MUC message handling (for example invitation processing) |
730 void got_muc_message(const char *from, LmMessageNode *x) | 798 void got_muc_message(const char *from, LmMessageNode *x, time_t timestamp) |
731 { | 799 { |
732 LmMessageNode *invite = lm_message_node_get_child(x, "invite"); | 800 LmMessageNode *node; |
733 if (invite) | 801 // invitation |
734 { | 802 node = lm_message_node_get_child(x, "invite"); |
803 if (node) { | |
735 const char *invite_from; | 804 const char *invite_from; |
736 const char *reason = NULL; | 805 const char *reason = NULL; |
737 const char *password = NULL; | 806 const char *password = NULL; |
738 | 807 |
739 invite_from = lm_message_node_get_attribute(invite, "from"); | 808 invite_from = lm_message_node_get_attribute(node, "from"); |
740 reason = lm_message_node_get_child_value(invite, "reason"); | 809 reason = lm_message_node_get_child_value(node, "reason"); |
741 password = lm_message_node_get_child_value(invite, "password"); | 810 password = lm_message_node_get_child_value(node, "password"); |
742 if (invite_from) | 811 if (invite_from) |
743 got_invite(invite_from, from, reason, password, TRUE); | 812 got_invite(invite_from, from, reason, password, TRUE); |
744 } | 813 } |
745 // TODO | 814 |
746 // handle status code = 100 ( not anonymous ) | |
747 // handle status code = 170 ( changement de config ) | |
748 // 10.2.1 Notification of Configuration Changes | |
749 // declined invitation | 815 // declined invitation |
816 node = lm_message_node_get_child(x, "decline"); | |
817 if (node) { | |
818 const char *decline_from = lm_message_node_get_attribute(node, "from"); | |
819 const char *reason = lm_message_node_get_child_value(node, "reason"); | |
820 if (decline_from) { | |
821 if (reason) | |
822 scr_LogPrint(LPRINT_LOGNORM, "<%s> declines your invitation: %s.", | |
823 from, reason); | |
824 else | |
825 scr_LogPrint(LPRINT_LOGNORM, "<%s> declines your invitation.", from); | |
826 } | |
827 } | |
828 | |
829 // status codes | |
830 for (node = x -> children; node; node = node -> next) { | |
831 if (!g_strcmp0(node -> name, "status")) { | |
832 const char *codestr = lm_message_node_get_attribute(node, "code"); | |
833 if (codestr) { | |
834 const char *mesg = NULL; | |
835 switch (atoi(codestr)) { | |
836 // initial | |
837 case 100: | |
838 mesg = "The room is not anonymous."; | |
839 break; | |
840 case 101: | |
841 mesg = "Your affilation has changed while absent."; | |
842 break; | |
843 case 102: | |
844 mesg = "The room shows unavailable members."; | |
845 break; | |
846 case 103: | |
847 mesg = "The room does not show unavailable members."; | |
848 break; | |
849 case 104: | |
850 mesg = "The room configuration has changed."; | |
851 break; | |
852 case 170: | |
853 mesg = "The room is logged."; | |
854 break; | |
855 case 171: | |
856 mesg = "The room is not logged."; | |
857 break; | |
858 case 172: | |
859 mesg = "The room is not anonymous."; | |
860 break; | |
861 case 173: | |
862 mesg = "The room is semi-anonymous."; | |
863 break; | |
864 case 174: | |
865 mesg = "The room is anonymous."; | |
866 break; | |
867 default: | |
868 scr_LogPrint(LPRINT_DEBUG, | |
869 "got_muc_message: Unknown MUC status code: %s.", | |
870 codestr); | |
871 break; | |
872 } | |
873 if (mesg) { | |
874 scr_WriteIncomingMessage(from, mesg, timestamp, | |
875 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
876 if (settings_opt_get_int("log_muc_conf")) | |
877 hlog_write_message(from, 0, -1, mesg); | |
878 } | |
879 } | |
880 } | |
881 } | |
750 } | 882 } |
751 | 883 |
752 /* vim: set et cindent cinoptions=>2\:2(0 ts=2 sw=2: For Vim users... */ | 884 /* vim: set et cindent cinoptions=>2\:2(0 ts=2 sw=2: For Vim users... */ |