Changeset 145:216c953d8ecd for wokkel/muc.py
- Timestamp:
- Aug 8, 2011, 1:43:09 PM (11 years ago)
- Branch:
- wokkel-muc-client-support-24
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
wokkel/muc.py
r144 r145 10 10 U{XEP-0045<http://www.xmpp.org/extensions/xep-0045.html>}. 11 11 """ 12 import datetime13 12 from dateutil.tz import tzutc 14 13 15 14 from zope.interface import implements 16 15 17 from twisted.internet import defer , reactor16 from twisted.internet import defer 18 17 from twisted.words.protocols.jabber import jid, error, xmlstream 19 18 from twisted.words.xish import domish … … 39 38 PRESENCE = '/presence' 40 39 41 GROUPCHAT = MESSAGE +'[@type="groupchat"]/body' 42 SUBJECT = MESSAGE +'[@type="groupchat"]/subject' 40 GROUPCHAT = MESSAGE +'[@type="groupchat"]' 43 41 44 42 DEFER_TIMEOUT = 30 # basic timeout is 30 seconds … … 263 261 def toElement(self): 264 262 """ 265 Returns a L{domish.Element} representing the xml for thehistory options.263 Returns a L{domish.Element} representing the history options. 266 264 """ 267 265 element = domish.Element((NS_MUC, 'history')) … … 315 313 @type state: L{int} 316 314 317 @ivar occupantJID: The JID of the occupant in the room. Generated from roomIdentifier, service, and nick. 315 @ivar occupantJID: The JID of the occupant in the room. Generated from 316 roomIdentifier, service, and nick. 318 317 @type occupantJID: L{jid.JID} 319 318 """ … … 460 459 timeout = None 461 460 462 def __init__(self):463 XMPPHandler.__init__(self)464 465 self._rooms = {}466 self._deferreds = []467 468 461 presenceTypeParserMap = { 469 462 'error': generic.ErrorStanza, … … 472 465 } 473 466 467 def __init__(self, reactor=None): 468 XMPPHandler.__init__(self) 469 470 self._rooms = {} 471 self._deferreds = [] 472 473 if reactor: 474 self._reactor = reactor 475 else: 476 from twisted.internet import reactor 477 self._reactor = reactor 478 479 474 480 def connectionInitialized(self): 475 481 """ … … 481 487 """ 482 488 xmppim.BasePresenceProtocol.connectionInitialized(self) 483 484 489 self.xmlstream.addObserver(GROUPCHAT, self._onGroupChat) 485 self.xmlstream.addObserver(SUBJECT, self._onSubject)486 # TODO: add history487 488 490 self.initialized() 489 491 … … 502 504 503 505 504 def _getRoom(self, occupantJID):506 def _getRoom(self, roomJID): 505 507 """ 506 508 Grab a room from the room collection. … … 511 513 @type occupantJID: L{jid.JID} 512 514 """ 513 roomJID = occupantJID.userhostJID()514 515 return self._rooms.get(roomJID) 515 516 … … 550 551 self._userLeavesRoom(occupantJID) 551 552 553 552 554 def _userLeavesRoom(self, occupantJID): 553 555 # when a user leaves a room we need to update it 554 room = self._getRoom(occupantJID )556 room = self._getRoom(occupantJID.userhostJID()) 555 557 if room is None: 556 558 # not in the room yet … … 576 578 577 579 # grab room 578 room = self._getRoom(occupantJID )580 room = self._getRoom(occupantJID.userhostJID()) 579 581 if room is None: 580 582 # not in the room yet … … 600 602 A group chat message has been received from a MUC room. 601 603 602 There are a few event methods that may get called here. receviedGroupChat and receivedHistory 604 There are a few event methods that may get called here. 605 L{receivedGroupChat}, L{receivedHistory} or L{receivedHistory}. 603 606 """ 604 607 message = GroupChat.fromElement(element) 605 608 606 609 occupantJID = message.sender 607 608 610 if not occupantJID: 609 # need to return an error here XXX610 611 return 611 612 612 room = self._getRoom(occupantJID) 613 roomJID = occupantJID.userhostJID() 614 615 room = self._getRoom(roomJID) 613 616 if room is None: 614 617 # not in the room yet … … 621 624 user = None 622 625 623 if message.delay is None: 626 if message.subject: 627 self.receivedSubject(room, user, message.subject) 628 elif message.delay is None: 624 629 self.receivedGroupChat(room, user, message) 625 630 else: … … 627 632 628 633 629 def _onSubject(self, msg): 630 """ 631 A subject has been sent from a MUC room. 632 """ 633 if not msg.hasAttribute('from'): 634 return 635 occupantJID = jid.internJID(msg['from']) 636 637 # grab room 638 room = self._getRoom(occupantJID) 639 if room is None: 640 # not in the room yet 641 return 642 643 self.receivedSubject(occupantJID, unicode(msg.subject)) 644 645 646 def _makeTimeStamp(self, stamp=None): 647 # create a timestamp 648 if stamp is None: 649 stamp = datetime.datetime.now() 650 651 return stamp.strftime('%Y%m%dT%H:%M:%S') 652 653 654 def _joinedRoom(self, d, prs): 634 def _joinedRoom(self, presence): 655 635 """ 656 636 We have presence that says we joined a room. 657 637 """ 658 occupantJID = jid.internJID(prs['from']) 659 660 # check for errors 661 if prs.hasAttribute('type') and prs['type'] == 'error': 662 d.errback(error.exceptionFromStanza(prs)) 663 else: 664 # change the state of the room 665 room = self._getRoom(occupantJID) 666 room.state = 'joined' 667 668 # grab status 669 status = getattr(prs.x, 'status', None) 670 if status: 671 room.status = status.getAttribute('code', None) 672 673 d.callback(room) 674 675 676 def _leftRoom(self, d, prs): 638 roomJID = presence.sender.userhostJID() 639 640 # change the state of the room 641 room = self._getRoom(roomJID) 642 room.state = 'joined' 643 644 # grab status 645 if presence.statusCode: 646 room.status = presence.statusCode 647 648 return room 649 650 651 def _leftRoom(self, presence): 677 652 """ 678 653 We have presence that says we left a room. 679 654 """ 680 occupantJID = jid.internJID(prs['from']) 681 682 # check for errors 683 if prs.hasAttribute('type') and prs['type'] == 'error': 684 d.errback(error.exceptionFromStanza(prs)) 685 else: 686 # change the state of the room 687 self._removeRoom(occupantJID) 688 689 d.callback(True) 655 occupantJID = presence.sender 656 657 # change the state of the room 658 self._removeRoom(occupantJID) 659 660 return True 690 661 691 662 … … 785 756 786 757 787 def sendDeferred(self, obj, timeout): 788 """ 789 Send data or a domish element, adding a deferred with a timeout. 790 791 @param obj: The object to send over the wire. 792 @type obj: L{domish.Element} or C{unicode} 793 794 @param timeout: The number of seconds to wait before the deferred is timed out. 758 def sendDeferred(self, stanza): 759 """ 760 Send presence stanza, adding a deferred with a timeout. 761 762 @param stanza: The presence stanza to send over the wire. 763 @type stanza: L{generic.Stanza} 764 765 @param timeout: The number of seconds to wait before the deferred is 766 timed out. 795 767 @type timeout: L{int} 796 768 … … 798 770 """ 799 771 d = defer.Deferred() 800 self._deferreds.append(d) 801 772 773 def onResponse(element): 774 if element.getAttribute('type') == 'error': 775 d.errback(error.exceptionFromStanza(element)) 776 else: 777 d.callback(UserPresence.fromElement(element)) 802 778 803 779 def onTimeout(): 804 i = 0 805 for xd in self._deferreds: 806 if d == xd: 807 self._deferreds.pop(i) 808 d.errback(xmlstream.TimeoutError("Timeout waiting for response.")) 809 i += 1 810 811 call = reactor.callLater(timeout, onTimeout) 780 d.errback(xmlstream.TimeoutError("Timeout waiting for response.")) 781 782 call = self._reactor.callLater(DEFER_TIMEOUT, onTimeout) 812 783 813 784 def cancelTimeout(result): … … 819 790 d.addBoth(cancelTimeout) 820 791 821 self.xmlstream.send(obj) 792 query = "/presence[@from='%s' or (@from='%s' and @type='error')]" % ( 793 stanza.recipient.full(), stanza.recipient.userhost()) 794 self.xmlstream.addOnetimeObserver(query, onResponse, priority=1) 795 self.xmlstream.send(stanza.toElement()) 822 796 return d 823 797 … … 841 815 def getConfigureForm(self, roomJID): 842 816 """ 843 Grab the configuration form from the room. This sends an iq request to the room. 817 Grab the configuration form from the room. 818 819 This sends an iq request to the room. 844 820 845 821 @param roomJID: The bare JID of the room. … … 876 852 presence.history = HistoryOptions(maxstanzas=history) 877 853 878 d = self.sendDeferred(presence.toElement(), timeout=DEFER_TIMEOUT) 879 880 # add observer for joining the room 881 query = PRESENCE + u"[@from='%s']" % room.occupantJID 882 self.xmlstream.addOnetimeObserver(query, self._joinedRoom, 1, d) 883 854 d = self.sendDeferred(presence) 855 d.addCallback(self._joinedRoom) 884 856 return d 885 857 … … 903 875 904 876 905 def _changed(self, d, occupantJID, prs):877 def _changed(self, presence, occupantJID): 906 878 """ 907 879 Callback for changing the nick and status. 908 880 """ 909 910 status = getattr(prs, 'status', None) 911 show = getattr(prs, 'show', None) 912 913 room = self._getRoom(occupantJID) 914 915 user = self._changeUserStatus(room, occupantJID, status, show) 916 917 d.callback(room) 881 room = self._getRoom(occupantJID.userhostJID()) 882 self._changeUserStatus(room, occupantJID, presence.status, presence.show) 883 884 return room 918 885 919 886 … … 930 897 @type nick: C{unicode} 931 898 """ 932 933 934 899 room = self._getRoom(roomJID) 935 900 … … 939 904 # Create presence 940 905 presence = BasicPresence(recipient=room.occupantJID) 941 d = self.sendDeferred(presence.toElement(), timeout=DEFER_TIMEOUT) 942 943 # Add observer for joining the room 944 query = PRESENCE+"[@from='%s']" % (room.occupantJID.full()) 945 self.xmlstream.addOnetimeObserver(query, self._changed, 1, d, roomJID) 946 906 907 d = self.sendDeferred(presence) 908 d.addCallback(self._changed, room.occupantJID) 947 909 return d 948 910 949 911 950 def leave(self, occupantJID):912 def leave(self, roomJID): 951 913 """ 952 914 Leave a MUC room. … … 954 916 See: http://xmpp.org/extensions/xep-0045.html#exit 955 917 956 @param occupantJID: The Room JID of the room to leave.957 @type occupantJID: L{jid.JID}958 """ 959 room = self._getRoom( occupantJID)918 @param roomJID: The Room JID of the room to leave. 919 @type roomJID: L{jid.JID} 920 """ 921 room = self._getRoom(roomJID) 960 922 961 923 presence = xmppim.AvailabilityPresence(recipient=room.occupantJID, 962 924 available=False) 963 925 964 d = self.sendDeferred(presence.toElement(), timeout=DEFER_TIMEOUT) 965 # add observer for joining the room 966 query = PRESENCE + u"[@from='%s' and @type='unavailable']" % (room.occupantJID) 967 self.xmlstream.addOnetimeObserver(query, self._leftRoom, 1, d) 968 926 d = self.sendDeferred(presence) 927 d.addCallback(self._leftRoom) 969 928 return d 970 929 971 930 972 def status(self, occupantJID, show=None, status=None):931 def status(self, roomJID, show=None, status=None): 973 932 """ 974 933 Change user status. … … 976 935 See: http://xmpp.org/extensions/xep-0045.html#changepres 977 936 978 @param occupantJID: The room jabber/xmpp entity id for the requested configuration form. 979 @type occupantJID: L{jid.JID} 980 981 @param show: The availability of the entity. Common values are xa, available, etc 937 @param roomJID: The Room JID of the room. 938 @type roomJID: L{jid.JID} 939 940 @param show: The availability of the entity. Common values are xa, 941 available, etc 982 942 @type show: C{unicode} 983 943 … … 985 945 @type show: C{unicode} 986 946 """ 987 room = self._getRoom( occupantJID)947 room = self._getRoom(roomJID) 988 948 989 949 presence = BasicPresence(recipient=room.occupantJID, 990 950 show=show, status=status) 991 951 992 d = self.sendDeferred(presence.toElement(), timeout=DEFER_TIMEOUT) 993 994 # add observer for joining the room 995 query = PRESENCE + u"[@from='%s']" % room.occupantJID 996 self.xmlstream.addOnetimeObserver(query, self._changed, 1, d, occupantJID) 997 952 d = self.sendDeferred(presence) 953 d.addCallback(self._changed, room.occupantJID) 998 954 return d 999 955 … … 1177 1133 Get an owner list from a room. 1178 1134 1179 @param roomJID: The room jabber/xmpp entity id for the requested member list. 1135 @param roomJID: The room jabber/xmpp entity id for the requested member 1136 list. 1180 1137 @type roomJID: L{jid.JID} 1181 1138 """ … … 1189 1146 Grab the registration form for a MUC room. 1190 1147 1191 @param room: The room jabber/xmpp entity id for the requested registration form. 1148 @param room: The room jabber/xmpp entity id for the requested 1149 registration form. 1192 1150 @type room: L{jid.JID} 1193 1151 """
Note: See TracChangeset
for help on using the changeset viewer.