comparison libpurple/protocols/jabber/presence.c @ 27501:6d26258e9f1d

propagate from branch 'im.pidgin.pidgin' (head ac87c285c7056f86005dc157b9870745de471f74) to branch 'im.pidgin.cpw.darkrain42.roster' (head 976d874853ac9745edb77d3cf107b92ebc037c10)
author Paul Aurich <paul@darkrain42.org>
date Mon, 06 Jul 2009 04:37:41 +0000
parents 9a5a9a4e7626 b41b69e8b341
children 3bb1085235d0
comparison
equal deleted inserted replaced
27500:b9da56683499 27501:6d26258e9f1d
249 249
250 xmlnode *jabber_presence_create_js(JabberStream *js, JabberBuddyState state, const char *msg, int priority) 250 xmlnode *jabber_presence_create_js(JabberStream *js, JabberBuddyState state, const char *msg, int priority)
251 { 251 {
252 xmlnode *show, *status, *presence, *pri, *c; 252 xmlnode *show, *status, *presence, *pri, *c;
253 const char *show_string = NULL; 253 const char *show_string = NULL;
254 #ifdef USE_VV
254 gboolean audio_enabled, video_enabled; 255 gboolean audio_enabled, video_enabled;
256 #endif
255 257
256 presence = xmlnode_new("presence"); 258 presence = xmlnode_new("presence");
257 259
258 if(state == JABBER_BUDDY_STATE_UNAVAILABLE) 260 if(state == JABBER_BUDDY_STATE_UNAVAILABLE)
259 xmlnode_set_attrib(presence, "type", "unavailable"); 261 xmlnode_set_attrib(presence, "type", "unavailable");
462 464
463 void jabber_presence_parse(JabberStream *js, xmlnode *packet) 465 void jabber_presence_parse(JabberStream *js, xmlnode *packet)
464 { 466 {
465 const char *from; 467 const char *from;
466 const char *type; 468 const char *type;
467 const char *real_jid = NULL;
468 const char *affiliation = NULL;
469 const char *role = NULL;
470 char *status = NULL; 469 char *status = NULL;
471 int priority = 0; 470 int priority = 0;
472 JabberID *jid; 471 JabberID *jid;
473 JabberChat *chat; 472 JabberChat *chat;
474 JabberBuddy *jb; 473 JabberBuddy *jb;
478 const gchar *stamp = NULL; /* from <delayed/> element */ 477 const gchar *stamp = NULL; /* from <delayed/> element */
479 PurpleBuddy *b = NULL; 478 PurpleBuddy *b = NULL;
480 char *buddy_name; 479 char *buddy_name;
481 JabberBuddyState state = JABBER_BUDDY_STATE_UNKNOWN; 480 JabberBuddyState state = JABBER_BUDDY_STATE_UNKNOWN;
482 xmlnode *y; 481 xmlnode *y;
483 gboolean muc = FALSE;
484 char *avatar_hash = NULL; 482 char *avatar_hash = NULL;
485 xmlnode *caps = NULL; 483 xmlnode *caps = NULL;
486 int idle = 0; 484 int idle = 0;
487 gchar *nickname = NULL; 485 gchar *nickname = NULL;
488 gboolean signal_return; 486 gboolean signal_return;
489 487
490 from = xmlnode_get_attrib(packet, "from"); 488 from = xmlnode_get_attrib(packet, "from");
491 type = xmlnode_get_attrib(packet, "type"); 489 type = xmlnode_get_attrib(packet, "type");
492 490
493 if(!(jb = jabber_buddy_find(js, from, TRUE))) 491 jb = jabber_buddy_find(js, from, TRUE);
494 return; 492 g_return_if_fail(jb != NULL);
495 493
496 signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, 494 signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin,
497 "jabber-receiving-presence", js->gc, type, from, packet)); 495 "jabber-receiving-presence", js->gc, type, from, packet));
498 if (signal_return) 496 if (signal_return)
499 return; 497 return;
500 498
501 if(!(jid = jabber_id_new(from))) 499 jid = jabber_id_new(from);
502 return; 500 if (jid == NULL) {
501 purple_debug_error("jabber", "Ignoring presence with malformed 'from' "
502 "JID: %s\n", from);
503 return;
504 }
503 505
504 if(jb->error_msg) { 506 if(jb->error_msg) {
505 g_free(jb->error_msg); 507 g_free(jb->error_msg);
506 jb->error_msg = NULL; 508 jb->error_msg = NULL;
507 } 509 }
508 510
509 if(type && !strcmp(type, "error")) { 511 if (type == NULL) {
512 xmlnode *show;
513 char *show_data = NULL;
514
515 state = JABBER_BUDDY_STATE_ONLINE;
516
517 show = xmlnode_get_child(packet, "show");
518 if (show) {
519 show_data = xmlnode_get_data(show);
520 if (show_data) {
521 state = jabber_buddy_show_get_state(show_data);
522 g_free(show_data);
523 } else
524 purple_debug_warning("jabber", "<show/> present on presence, "
525 "but no contents!\n");
526 }
527 } else if (g_str_equal(type, "error")) {
510 char *msg = jabber_parse_error(js, packet, NULL); 528 char *msg = jabber_parse_error(js, packet, NULL);
511 529
512 state = JABBER_BUDDY_STATE_ERROR; 530 state = JABBER_BUDDY_STATE_ERROR;
513 jb->error_msg = msg ? msg : g_strdup(_("Unknown Error in presence")); 531 jb->error_msg = msg ? msg : g_strdup(_("Unknown Error in presence"));
514 } else if(type && !strcmp(type, "subscribe")) { 532 } else if (g_str_equal(type, "subscribe")) {
515 struct _jabber_add_permit *jap = g_new0(struct _jabber_add_permit, 1); 533 struct _jabber_add_permit *jap = g_new0(struct _jabber_add_permit, 1);
516 gboolean onlist = FALSE; 534 gboolean onlist = FALSE;
517 PurpleBuddy *buddy = purple_find_buddy(purple_connection_get_account(js->gc), from); 535 PurpleAccount *account;
536 PurpleBuddy *buddy;
518 JabberBuddy *jb = NULL; 537 JabberBuddy *jb = NULL;
519 xmlnode *nick; 538 xmlnode *nick;
520 539
540 account = purple_connection_get_account(js->gc);
541 buddy = purple_find_buddy(account, from);
521 nick = xmlnode_get_child_with_namespace(packet, "nick", "http://jabber.org/protocol/nick"); 542 nick = xmlnode_get_child_with_namespace(packet, "nick", "http://jabber.org/protocol/nick");
522 if (nick) 543 if (nick)
523 nickname = xmlnode_get_data(nick); 544 nickname = xmlnode_get_data(nick);
524 545
525 if (buddy) { 546 if (buddy) {
530 551
531 jap->gc = js->gc; 552 jap->gc = js->gc;
532 jap->who = g_strdup(from); 553 jap->who = g_strdup(from);
533 jap->js = js; 554 jap->js = js;
534 555
535 purple_account_request_authorization(purple_connection_get_account(js->gc), from, NULL, nickname, NULL, onlist, 556 purple_account_request_authorization(account, from, NULL, nickname,
536 authorize_add_cb, deny_add_cb, jap); 557 NULL, onlist, authorize_add_cb, deny_add_cb, jap);
558
537 g_free(nickname); 559 g_free(nickname);
538 jabber_id_free(jid); 560 jabber_id_free(jid);
539 return; 561 return;
540 } else if(type && !strcmp(type, "subscribed")) { 562 } else if (g_str_equal(type, "subscribed")) {
541 /* we've been allowed to see their presence, but we don't care */ 563 /* we've been allowed to see their presence, but we don't care */
542 jabber_id_free(jid); 564 jabber_id_free(jid);
543 return; 565 return;
544 } else if(type && !strcmp(type, "unsubscribe")) { 566 } else if (g_str_equal(type, "unsubscribe")) {
545 /* XXX I'm not sure this is the right way to handle this, it 567 /* XXX I'm not sure this is the right way to handle this, it
546 * might be better to add "unsubscribe" to the presence status 568 * might be better to add "unsubscribe" to the presence status
547 * if lower down, but I'm not sure. */ 569 * if lower down, but I'm not sure. */
548 /* they are unsubscribing from our presence, we don't care */ 570 /* they are unsubscribing from our presence, we don't care */
549 /* Well, maybe just a little, we might want/need to start 571 /* Well, maybe just a little, we might want/need to start
550 * acknowledging this (and the others) at some point. */ 572 * acknowledging this (and the others) at some point. */
551 jabber_id_free(jid); 573 jabber_id_free(jid);
552 return; 574 return;
575 } else if (g_str_equal(type, "probe")) {
576 purple_debug_warning("jabber", "Ignoring presence probe\n");
577 jabber_id_free(jid);
578 return;
579 } else if (g_str_equal(type, "unavailable")) {
580 state = JABBER_BUDDY_STATE_UNAVAILABLE;
581 } else if (g_str_equal(type, "unsubscribed")) {
582 state = JABBER_BUDDY_STATE_UNKNOWN;
553 } else { 583 } else {
554 if((y = xmlnode_get_child(packet, "show"))) { 584 purple_debug_warning("jabber", "Ignoring presence with invalid type "
555 char *show = xmlnode_get_data(y); 585 "'%s'\n", type);
556 state = jabber_buddy_show_get_state(show); 586 jabber_id_free(jid);
557 g_free(show); 587 return;
558 } else {
559 state = JABBER_BUDDY_STATE_ONLINE;
560 }
561 } 588 }
562 589
563 590
564 for(y = packet->child; y; y = y->next) { 591 for(y = packet->child; y; y = y->next) {
565 const char *xmlns; 592 const char *xmlns;
590 } else if(!strcmp(y->name, "x")) { 617 } else if(!strcmp(y->name, "x")) {
591 if(!strcmp(xmlns, "jabber:x:delay")) { 618 if(!strcmp(xmlns, "jabber:x:delay")) {
592 /* XXX: compare the time. jabber:x:delay can happen on presence packets that aren't really and truly delayed */ 619 /* XXX: compare the time. jabber:x:delay can happen on presence packets that aren't really and truly delayed */
593 delayed = TRUE; 620 delayed = TRUE;
594 stamp = xmlnode_get_attrib(y, "stamp"); 621 stamp = xmlnode_get_attrib(y, "stamp");
595 } else if(!strcmp(xmlns, "http://jabber.org/protocol/muc#user")) { 622 } else if(!strcmp(xmlns, "vcard-temp:x:update")) {
596 xmlnode *z; 623 xmlnode *photo = xmlnode_get_child(y, "photo");
597 624 if(photo) {
598 muc = TRUE; 625 g_free(avatar_hash);
599 if((z = xmlnode_get_child(y, "status"))) { 626 avatar_hash = xmlnode_get_data(photo);
600 const char *code = xmlnode_get_attrib(z, "code"); 627 }
601 if(code && !strcmp(code, "201")) { 628 }
602 if((chat = jabber_chat_find(js, jid->node, jid->domain))) { 629 } else if (!strcmp(y->name, "query") &&
630 !strcmp(xmlnode_get_namespace(y), "jabber:iq:last")) {
631 /* resource has specified idle */
632 const gchar *seconds = xmlnode_get_attrib(y, "seconds");
633 if (seconds) {
634 /* we may need to take "delayed" into account here */
635 idle = atoi(seconds);
636 }
637 }
638 }
639
640 if (idle && delayed && stamp) {
641 /* if we have a delayed presence, we need to add the delay to the idle
642 value */
643 time_t offset = time(NULL) - purple_str_to_time(stamp, TRUE, NULL, NULL,
644 NULL);
645 purple_debug_info("jabber", "got delay %s yielding %ld s offset\n",
646 stamp, offset);
647 idle += offset;
648 }
649
650 if(jid->node && (chat = jabber_chat_find(js, jid->node, jid->domain))) {
651 static int i = 1;
652
653 if(state == JABBER_BUDDY_STATE_ERROR) {
654 char *title, *msg = jabber_parse_error(js, packet, NULL);
655
656 if (!chat->conv) {
657 title = g_strdup_printf(_("Error joining chat %s"), from);
658 purple_serv_got_join_chat_failed(js->gc, chat->components);
659 } else {
660 title = g_strdup_printf(_("Error in chat %s"), from);
661 if (g_hash_table_size(chat->members) == 0)
662 serv_got_chat_left(js->gc, chat->id);
663 }
664 purple_notify_error(js->gc, title, title, msg);
665 g_free(title);
666 g_free(msg);
667
668 if (g_hash_table_size(chat->members) == 0)
669 /* Only destroy the chat if the error happened while joining */
670 jabber_chat_destroy(chat);
671 jabber_id_free(jid);
672 g_free(status);
673 g_free(avatar_hash);
674 g_free(nickname);
675 return;
676 }
677
678 if (type == NULL) {
679 xmlnode *x;
680 const char *real_jid = NULL;
681 const char *affiliation = NULL;
682 const char *role = NULL;
683
684 /*
685 * XEP-0045 mandates the presence to include a resource (which is
686 * treated as the chat nick). Some non-compliant servers allow
687 * joining without a nick.
688 */
689 if (!jid->resource) {
690 jabber_id_free(jid);
691 g_free(avatar_hash);
692 g_free(nickname);
693 g_free(status);
694 return;
695 }
696
697 x = xmlnode_get_child_with_namespace(packet, "x",
698 "http://jabber.org/protocol/muc#user");
699 if (x) {
700 xmlnode *status_node;
701 xmlnode *item_node;
702
703 status_node = xmlnode_get_child(x, "status");
704 if (status_node) {
705 const char *code = xmlnode_get_attrib(status_node, "code");
706 if (purple_strequal(code, "201")) {
707 if ((chat = jabber_chat_find(js, jid->node, jid->domain))) {
603 chat->config_dialog_type = PURPLE_REQUEST_ACTION; 708 chat->config_dialog_type = PURPLE_REQUEST_ACTION;
604 chat->config_dialog_handle = 709 chat->config_dialog_handle =
605 purple_request_action(js->gc, 710 purple_request_action(js->gc,
606 _("Create New Room"), 711 _("Create New Room"),
607 _("Create New Room"), 712 _("Create New Room"),
612 purple_connection_get_account(js->gc), NULL, chat->conv, 717 purple_connection_get_account(js->gc), NULL, chat->conv,
613 chat, 2, 718 chat, 2,
614 _("_Configure Room"), G_CALLBACK(jabber_chat_request_room_configure), 719 _("_Configure Room"), G_CALLBACK(jabber_chat_request_room_configure),
615 _("_Accept Defaults"), G_CALLBACK(jabber_chat_create_instant_room)); 720 _("_Accept Defaults"), G_CALLBACK(jabber_chat_create_instant_room));
616 } 721 }
617 } else if(code && !strcmp(code, "210")) { 722 } else if (purple_strequal(code, "210")) {
618 /* server rewrote room-nick */ 723 /* server rewrote room-nick */
619 if((chat = jabber_chat_find(js, jid->node, jid->domain))) { 724 if((chat = jabber_chat_find(js, jid->node, jid->domain))) {
620 g_free(chat->handle); 725 g_free(chat->handle);
621 chat->handle = g_strdup(jid->resource); 726 chat->handle = g_strdup(jid->resource);
622 } 727 }
623 } 728 }
624 } 729 }
625 if((z = xmlnode_get_child(y, "item"))) { 730
626 real_jid = xmlnode_get_attrib(z, "jid"); 731 item_node = xmlnode_get_child(x, "item");
627 affiliation = xmlnode_get_attrib(z, "affiliation"); 732 if (item_node) {
628 role = xmlnode_get_attrib(z, "role"); 733 real_jid = xmlnode_get_attrib(item_node, "jid");
629 if(affiliation != NULL && !strcmp(affiliation, "owner")) 734 affiliation = xmlnode_get_attrib(item_node, "affiliation");
735 role = xmlnode_get_attrib(item_node, "role");
736
737 if (purple_strequal(affiliation, "owner"))
630 flags |= PURPLE_CBFLAGS_FOUNDER; 738 flags |= PURPLE_CBFLAGS_FOUNDER;
631 if (role != NULL) { 739 if (role) {
632 if (!strcmp(role, "moderator")) 740 if (g_str_equal(role, "moderator"))
633 flags |= PURPLE_CBFLAGS_OP; 741 flags |= PURPLE_CBFLAGS_OP;
634 else if (!strcmp(role, "participant")) 742 else if (g_str_equal(role, "participant"))
635 flags |= PURPLE_CBFLAGS_VOICE; 743 flags |= PURPLE_CBFLAGS_VOICE;
636 } 744 }
637 } 745 }
638 } else if(!strcmp(xmlns, "vcard-temp:x:update")) { 746 }
639 xmlnode *photo = xmlnode_get_child(y, "photo"); 747
640 if(photo) { 748 if(!chat->conv) {
641 g_free(avatar_hash); 749 char *room_jid = g_strdup_printf("%s@%s", jid->node, jid->domain);
642 avatar_hash = xmlnode_get_data(photo); 750 chat->id = i++;
643 } 751 chat->muc = (x != NULL);
644 } 752 chat->conv = serv_got_joined_chat(js->gc, chat->id, room_jid);
645 } else if (!strcmp(y->name, "query") && 753 purple_conv_chat_set_nick(PURPLE_CONV_CHAT(chat->conv), chat->handle);
646 !strcmp(xmlnode_get_namespace(y), "jabber:iq:last")) { 754
647 /* resource has specified idle */ 755 jabber_chat_disco_traffic(chat);
648 const gchar *seconds = xmlnode_get_attrib(y, "seconds"); 756 g_free(room_jid);
649 if (seconds) { 757 }
650 /* we may need to take "delayed" into account here */ 758
651 idle = atoi(seconds); 759 jabber_buddy_track_resource(jb, jid->resource, priority, state,
652 } 760 status);
653 } 761
654 } 762 jabber_chat_track_handle(chat, jid->resource, real_jid, affiliation, role);
655 763
656 if (idle && delayed && stamp) { 764 if(!jabber_chat_find_buddy(chat->conv, jid->resource))
657 /* if we have a delayed presence, we need to add the delay to the idle 765 purple_conv_chat_add_user(PURPLE_CONV_CHAT(chat->conv), jid->resource,
658 value */ 766 real_jid, flags, !delayed);
659 time_t offset = time(NULL) - purple_str_to_time(stamp, TRUE, NULL, NULL, 767 else
660 NULL); 768 purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(chat->conv), jid->resource,
661 purple_debug_info("jabber", "got delay %s yielding %ld s offset\n", 769 flags);
662 stamp, offset); 770 } else if (g_str_equal(type, "unavailable")) {
663 idle += offset;
664 }
665
666 if(jid->node && (chat = jabber_chat_find(js, jid->node, jid->domain))) {
667 static int i = 1;
668
669 if(state == JABBER_BUDDY_STATE_ERROR) {
670 char *title, *msg = jabber_parse_error(js, packet, NULL);
671
672 if (!chat->conv) {
673 title = g_strdup_printf(_("Error joining chat %s"), from);
674 purple_serv_got_join_chat_failed(js->gc, chat->components);
675 } else {
676 title = g_strdup_printf(_("Error in chat %s"), from);
677 if (g_hash_table_size(chat->members) == 0)
678 serv_got_chat_left(js->gc, chat->id);
679 }
680 purple_notify_error(js->gc, title, title, msg);
681 g_free(title);
682 g_free(msg);
683
684 if (g_hash_table_size(chat->members) == 0)
685 /* Only destroy the chat if the error happened while joining */
686 jabber_chat_destroy(chat);
687 jabber_id_free(jid);
688 g_free(status);
689 g_free(avatar_hash);
690 g_free(nickname);
691 return;
692 }
693
694
695 if(type && !strcmp(type, "unavailable")) {
696 gboolean nick_change = FALSE; 771 gboolean nick_change = FALSE;
772 gboolean kick = FALSE;
773 gboolean is_our_resource = FALSE; /* Is the presence about us? */
697 774
698 /* If the chat nick is invalid, we haven't yet joined, or we've 775 /* If the chat nick is invalid, we haven't yet joined, or we've
699 * already left (it was probably us leaving after we closed the 776 * already left (it was probably us leaving after we closed the
700 * chat), we don't care. 777 * chat), we don't care.
701 */ 778 */
708 g_free(avatar_hash); 785 g_free(avatar_hash);
709 g_free(nickname); 786 g_free(nickname);
710 return; 787 return;
711 } 788 }
712 789
790 is_our_resource = (0 == g_utf8_collate(jid->resource, chat->handle));
791
713 jabber_buddy_remove_resource(jb, jid->resource); 792 jabber_buddy_remove_resource(jb, jid->resource);
714 if(chat->muc) { 793 if(chat->muc) {
715 xmlnode *x; 794 xmlnode *x;
716 for(x = xmlnode_get_child(packet, "x"); x; x = xmlnode_get_next_twin(x)) { 795 for(x = xmlnode_get_child(packet, "x"); x; x = xmlnode_get_next_twin(x)) {
717 const char *xmlns, *nick, *code; 796 const char *xmlns, *nick, *code;
721 continue; 800 continue;
722 if(!(stat = xmlnode_get_child(x, "status"))) 801 if(!(stat = xmlnode_get_child(x, "status")))
723 continue; 802 continue;
724 if(!(code = xmlnode_get_attrib(stat, "code"))) 803 if(!(code = xmlnode_get_attrib(stat, "code")))
725 continue; 804 continue;
805
806 item = xmlnode_get_child(x, "item");
807
726 if(!strcmp(code, "301")) { 808 if(!strcmp(code, "301")) {
727 /* XXX: we got banned */ 809 /* XXX: we got banned */
728 } else if(!strcmp(code, "303")) { 810 } else if(!strcmp(code, "303")) {
729 if(!(item = xmlnode_get_child(x, "item"))) 811 if (!item)
730 continue; 812 continue;
731 if(!(nick = xmlnode_get_attrib(item, "nick"))) 813 if(!(nick = xmlnode_get_attrib(item, "nick")))
732 continue; 814 continue;
733 nick_change = TRUE; 815 nick_change = TRUE;
734 if(!strcmp(jid->resource, chat->handle)) { 816 if(!strcmp(jid->resource, chat->handle)) {
737 } 819 }
738 purple_conv_chat_rename_user(PURPLE_CONV_CHAT(chat->conv), jid->resource, nick); 820 purple_conv_chat_rename_user(PURPLE_CONV_CHAT(chat->conv), jid->resource, nick);
739 jabber_chat_remove_handle(chat, jid->resource); 821 jabber_chat_remove_handle(chat, jid->resource);
740 break; 822 break;
741 } else if(!strcmp(code, "307")) { 823 } else if(!strcmp(code, "307")) {
742 /* XXX: we got kicked */ 824 /* Someone was kicked from the room */
825 xmlnode *reason = NULL, *actor = NULL;
826 const char *actor_name = NULL;
827 char *reason_text = NULL;
828 char *tmp;
829
830 kick = TRUE;
831
832 if (item) {
833 reason = xmlnode_get_child(item, "reason");
834 actor = xmlnode_get_child(item, "actor");
835
836 if (reason != NULL)
837 reason_text = xmlnode_get_data(reason);
838 if (actor != NULL)
839 actor_name = xmlnode_get_attrib(actor, "jid");
840 }
841
842 if (reason_text == NULL)
843 reason_text = g_strdup(_("No reason"));
844
845 if (is_our_resource) {
846 if (actor_name != NULL)
847 tmp = g_strdup_printf(_("You have been kicked by %s: (%s)"),
848 actor_name, reason_text);
849 else
850 tmp = g_strdup_printf(_("You have been kicked: (%s)"),
851 reason_text);
852 } else {
853 if (actor_name != NULL)
854 tmp = g_strdup_printf(_("Kicked by %s (%s)"),
855 actor_name, reason_text);
856 else
857 tmp = g_strdup_printf(_("Kicked (%s)"),
858 reason_text);
859 }
860
861 g_free(reason_text);
862 g_free(status);
863 status = tmp;
743 } else if(!strcmp(code, "321")) { 864 } else if(!strcmp(code, "321")) {
744 /* XXX: removed due to an affiliation change */ 865 /* XXX: removed due to an affiliation change */
745 } else if(!strcmp(code, "322")) { 866 } else if(!strcmp(code, "322")) {
746 /* XXX: removed because room is now members-only */ 867 /* XXX: removed because room is now members-only */
747 } else if(!strcmp(code, "332")) { 868 } else if(!strcmp(code, "332")) {
748 /* XXX: removed due to system shutdown */ 869 /* XXX: removed due to system shutdown */
749 } 870 }
750 } 871 }
751 } 872 }
752 if(!nick_change) { 873 if(!nick_change) {
753 if(!g_utf8_collate(jid->resource, chat->handle)) { 874 if (is_our_resource) {
875 if (kick)
876 purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), jid->resource,
877 status, PURPLE_MESSAGE_SYSTEM, time(NULL));
878
754 serv_got_chat_left(js->gc, chat->id); 879 serv_got_chat_left(js->gc, chat->id);
755 jabber_chat_destroy(chat); 880 jabber_chat_destroy(chat);
756 } else { 881 } else {
757 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(chat->conv), jid->resource, 882 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(chat->conv), jid->resource,
758 status); 883 status);
759 jabber_chat_remove_handle(chat, jid->resource); 884 jabber_chat_remove_handle(chat, jid->resource);
760 } 885 }
761 } 886 }
762 } else { 887 } else {
763 /* 888 /* A type that isn't available or unavailable */
764 * XEP-0045 mandates the presence to include a resource (which is 889 purple_debug_error("jabber", "MUC presence with bad type: %s\n",
765 * treated as the chat nick). Some non-compliant servers allow 890 type);
766 * joining without a nick. 891
767 */ 892 jabber_id_free(jid);
768 if (!jid->resource) { 893 g_free(avatar_hash);
769 jabber_id_free(jid); 894 g_free(status);
770 g_free(avatar_hash); 895 g_free(nickname);
771 g_free(nickname); 896 g_return_if_reached();
772 g_free(status);
773 return;
774 }
775
776 if(!chat->conv) {
777 char *room_jid = g_strdup_printf("%s@%s", jid->node, jid->domain);
778 chat->id = i++;
779 chat->muc = muc;
780 chat->conv = serv_got_joined_chat(js->gc, chat->id, room_jid);
781 purple_conv_chat_set_nick(PURPLE_CONV_CHAT(chat->conv), chat->handle);
782
783 jabber_chat_disco_traffic(chat);
784 g_free(room_jid);
785 }
786
787 jabber_buddy_track_resource(jb, jid->resource, priority, state,
788 status);
789
790 jabber_chat_track_handle(chat, jid->resource, real_jid, affiliation, role);
791
792 if(!jabber_chat_find_buddy(chat->conv, jid->resource))
793 purple_conv_chat_add_user(PURPLE_CONV_CHAT(chat->conv), jid->resource,
794 real_jid, flags, !delayed);
795 else
796 purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(chat->conv), jid->resource,
797 flags);
798 } 897 }
799 } else { 898 } else {
800 buddy_name = g_strdup_printf("%s%s%s", jid->node ? jid->node : "", 899 buddy_name = g_strdup_printf("%s%s%s", jid->node ? jid->node : "",
801 jid->node ? "@" : "", jid->domain); 900 jid->node ? "@" : "", jid->domain);
802 if((b = purple_find_buddy(js->gc->account, buddy_name)) == NULL) { 901 if((b = purple_find_buddy(js->gc->account, buddy_name)) == NULL) {
839 } 938 }
840 } 939 }
841 } 940 }
842 941
843 if(state == JABBER_BUDDY_STATE_ERROR || 942 if(state == JABBER_BUDDY_STATE_ERROR ||
844 (type && (!strcmp(type, "unavailable") || 943 (type && (g_str_equal(type, "unavailable") ||
845 !strcmp(type, "unsubscribed")))) { 944 g_str_equal(type, "unsubscribed")))) {
846 PurpleConversation *conv; 945 PurpleConversation *conv;
847 946
848 jabber_buddy_remove_resource(jb, jid->resource); 947 jabber_buddy_remove_resource(jb, jid->resource);
849 if((conv = jabber_find_unnormalized_conv(from, js->gc->account))) 948 if((conv = jabber_find_unnormalized_conv(from, js->gc->account)))
850 purple_conversation_set_name(conv, buddy_name); 949 purple_conversation_set_name(conv, buddy_name);
869 purple_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL); 968 purple_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL);
870 } 969 }
871 g_free(buddy_name); 970 g_free(buddy_name);
872 } 971 }
873 972
874 if (caps && (!type || g_str_equal(type, "available"))) { 973 if (caps && !type) {
875 /* handle Entity Capabilities (XEP-0115) */ 974 /* handle Entity Capabilities (XEP-0115) */
876 const char *node = xmlnode_get_attrib(caps, "node"); 975 const char *node = xmlnode_get_attrib(caps, "node");
877 const char *ver = xmlnode_get_attrib(caps, "ver"); 976 const char *ver = xmlnode_get_attrib(caps, "ver");
878 const char *hash = xmlnode_get_attrib(caps, "hash"); 977 const char *hash = xmlnode_get_attrib(caps, "hash");
879 const char *ext = xmlnode_get_attrib(caps, "ext"); 978 const char *ext = xmlnode_get_attrib(caps, "ext");