source: wokkel/muc.py @ 107:c1566d326c58

wokkel-muc-client-support-24
Last change on this file since 107:c1566d326c58 was 107:c1566d326c58, checked in by Christopher Zorn <tofu@…>, 13 years ago

just saving what I started, still needs lots of work, needs message and iq support

File size: 5.7 KB
Line 
1# -*- test-case-name: wokkel.test.test_muc -*-
2#
3# Copyright (c) 2003-2008 Ralph Meijer
4# See LICENSE for details.
5
6"""
7XMPP Multi-User Chat protocol.
8
9This protocol is specified in
10U{XEP-0045<http://www.xmpp.org/extensions/xep-0045.html>}.
11"""
12
13from zope.interface import implements
14
15from twisted.internet import defer
16from twisted.words.protocols.jabber import jid, error, xmlstream
17from twisted.words.xish import domish
18
19from wokkel import disco, data_form, shim, xmppim
20from wokkel.subprotocols import IQHandlerMixin, XMPPHandler
21from wokkel.iwokkel import IMUCClient, IMUCService
22
23# Multi User Chat namespaces
24NS_MUC          = 'http://jabber.org/protocol/muc'
25NS_MUC_USER     = NS_MUC + '#user'
26NS_MUC_ADMIN    = NS_MUC + '#admin'
27NS_MUC_OWNER    = NS_MUC + '#owner'
28NS_MUC_ROOMINFO = NS_MUC + '#roominfo'
29NS_MUC_CONFIG   = NS_MUC + '#roomconfig'
30
31# ad hoc commands
32NS_AD_HOC       = "http://jabber.org/protocol/commands"
33
34
35# Iq get and set XPath queries
36IQ     = '/iq'
37IQ_GET = IQ+'[@type="get"]'
38IQ_SET = IQ+'[@type="set"]'
39
40IQ_RESULT = IQ+'[@type="result"]'
41IQ_ERROR  = IQ+'[@type="error"]'
42
43IQ_QUERY     = IQ+'/query'
44IQ_GET_QUERY = IQ_GET + '/query'
45IQ_SET_QUERY = IQ_SET + '/query'
46
47IQ_COMMAND   = IQ+'/command'
48
49MUC_ADMIN = IQ_QUERY+'[@xmlns="' + NS_MUC_ADMIN + '"]'
50MUC_OWNER = IQ_QUERY+'[@xmlns="' + NS_MUC_OWNER + '"]'
51
52MUC_AO = MUC_ADMIN + '|' + MUC_OWNER
53
54
55MESSAGE  = '/message'
56PRESENCE = '/presence'
57
58CHAT_BODY = MESSAGE +'[@type="chat"]/body'
59CHAT      = MESSAGE +'[@type="chat"]'
60
61GROUPCHAT    = MESSAGE +'[@type="groupchat"]'
62MESSAGE_ERROR = MESSAGE +'[@type="error"]'
63
64
65
66class MUCError(error.StanzaError):
67    """
68    Exception with muc specific condition.
69    """
70    def __init__(self, condition, mucCondition, feature=None, text=None):
71        appCondition = domish.Element((NS_MUC_ERRORS, mucCondition))
72        if feature:
73            appCondition['feature'] = feature
74        error.StanzaError.__init__(self, condition,
75                                         text=text,
76                                         appCondition=appCondition)
77
78
79class BadRequest(MUCError):
80    """
81    Bad request stanza error.
82    """
83    def __init__(self, mucCondition=None, text=None):
84        MUCError.__init__(self, 'bad-request', mucCondition, text)
85
86
87
88class Unsupported(MUCError):
89    def __init__(self, feature, text=None):
90        MUCError.__init__(self, 'feature-not-implemented',
91                          'unsupported',
92                          feature,
93                          text)
94
95
96class Room(object):
97    """
98    A Multi User Chat Room
99    """
100
101   
102    def __init__(self, name, server, nick, state=None):
103        """
104        """
105        self.state  = state
106        self.name   = name
107        self.server = server
108        self.nick   = nick
109       
110        self.entity_id = jid.internJID(name+'@'+server+'/'+nick)
111               
112        self.roster = {}
113
114       
115
116class BasicPresence(xmppim.Presence):
117    """
118    This behaves like an object providing L{domish.IElement}.
119
120    """
121
122    def __init__(self, to=None, type=None):
123        xmppim.Presence.__init__(self, to, type)
124       
125        # add muc elements
126        x = self.addElement('x', NS_MUC)
127
128
129class UserPresence(xmppim.Presence):
130    """
131    This behaves like an object providing L{domish.IElement}.
132
133    """
134
135    def __init__(self, to=None, type=None, frm=None, affiliation=None, role=None):
136        xmppim.Presence.__init__(self, to, type)
137        if frm:
138            self['from'] = frm
139        # add muc elements
140        x = self.addElement('x', NS_MUC_USER)
141        if affiliation:
142            x['affiliation'] = affiliation
143        if role:
144            x['role'] = role
145
146
147class PresenceError(BasicPresence):
148    """
149    This behaves like an object providing L{domish.IElement}.
150
151    """
152
153    def __init__(self, error, to=None):
154        BasicPresence.__init__(self, to, type='error')
155       
156        # add muc elements
157        x = self.addElement('x', NS_MUC)
158        # add error
159        self.addChild(error)
160       
161
162class MUCClient(XMPPHandler):
163    """
164    Multi-User chat client protocol.
165    """
166
167    implements(IMUCClient)
168
169
170    def connectionInitialized(self):
171        self.rooms = {}
172        self.xmlstream.addObserver(PRESENCE, self._onPresence)
173        self.xmlstream.addObserver(GROUPCHAT, self._onGroupChat)
174
175    def _setRoom(self, room):
176        self.rooms[room.entity_id.full().lower()] = room
177
178    def _getRoom(self, room_jid):
179        return self.rooms.get(room_jid.full().lower())
180
181    def _onGroupChat(self, msg):
182        """handle groupchat message stanzas
183        """
184
185
186    def _onPresence(self, prs):
187        """handle groupchat presence
188        """
189        x = getattr(prs, 'x', None)
190        if x.uri == NS_MUC_USER:
191            self.userPresence(prs)
192
193
194    def _joinedRoom(self, d, prs):
195        """We have presence that says we joined a room.
196        """
197        room_jid = jid.internJID(prs['from'])
198        print type(prs)
199        print type(d)
200        # check for errors
201        if prs.hasAttribute('type') and prs['type'] == 'error':           
202            print room_jid.full()
203        # change the state of the room
204        r = self._getRoom(room_jid)
205        r.state = 'joined'
206        d.callback(room_jid, r)
207
208    def userPresence(self, prs):
209        """User Presence has been received
210        """
211        pass
212       
213    def joinRoom(self, server, room, nick):
214        """
215        """
216        d = defer.Deferred()
217        r = Room(room, server, nick, state='joining')
218        self._setRoom(r)
219 
220        p = BasicPresence(to=r.entity_id)
221        # p['from'] = self.jid.full()
222        self.xmlstream.send(p)
223
224        # add observer for joining the room
225        self.xmlstream.addOnetimeObserver(PRESENCE+"[@from='%s']" % (r.entity_id.full()), 
226                                          self._joinedRoom, d)
227
228        return d
229   
230
Note: See TracBrowser for help on using the repository browser.