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... */