|
1 #!/usr/bin/env python |
|
2 # |
|
3 # Copyright 2007 Google Inc. |
|
4 # |
|
5 # Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 # you may not use this file except in compliance with the License. |
|
7 # You may obtain a copy of the License at |
|
8 # |
|
9 # http://www.apache.org/licenses/LICENSE-2.0 |
|
10 # |
|
11 # Unless required by applicable law or agreed to in writing, software |
|
12 # distributed under the License is distributed on an "AS IS" BASIS, |
|
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 # See the License for the specific language governing permissions and |
|
15 # limitations under the License. |
|
16 # |
|
17 |
|
18 """Stub version of the XMPP API, writes messages to logs.""" |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 import logging |
|
25 import os |
|
26 |
|
27 from google.appengine.api import apiproxy_stub |
|
28 from google.appengine.api import xmpp |
|
29 from google.appengine.api.xmpp import xmpp_service_pb |
|
30 |
|
31 |
|
32 class XmppServiceStub(apiproxy_stub.APIProxyStub): |
|
33 """Python only xmpp service stub. |
|
34 |
|
35 This stub does not use an XMPP network. It prints messages to the console |
|
36 instead of sending any stanzas. |
|
37 """ |
|
38 |
|
39 def __init__(self, log=logging.info, service_name='xmpp'): |
|
40 """Initializer. |
|
41 |
|
42 Args: |
|
43 log: A logger, used for dependency injection. |
|
44 service_name: Service name expected for all calls. |
|
45 """ |
|
46 super(XmppServiceStub, self).__init__(service_name) |
|
47 self.log = log |
|
48 |
|
49 def _Dynamic_GetPresence(self, request, response): |
|
50 """Implementation of XmppService::GetPresence. |
|
51 |
|
52 Returns online if the first character of the JID comes before 'm' in the |
|
53 alphabet, otherwise returns offline. |
|
54 |
|
55 Args: |
|
56 request: A PresenceRequest. |
|
57 response: A PresenceResponse. |
|
58 """ |
|
59 jid = request.jid() |
|
60 self._GetFrom(request.from_jid()) |
|
61 if jid[0] < 'm': |
|
62 response.set_is_available(True) |
|
63 else: |
|
64 response.set_is_available(False) |
|
65 |
|
66 def _Dynamic_SendMessage(self, request, response): |
|
67 """Implementation of XmppService::SendMessage. |
|
68 |
|
69 Args: |
|
70 request: An XmppMessageRequest. |
|
71 response: An XmppMessageResponse . |
|
72 """ |
|
73 from_jid = self._GetFrom(request.from_jid()) |
|
74 self.log('Sending an XMPP Message:') |
|
75 self.log(' From:') |
|
76 self.log(' ' + from_jid) |
|
77 self.log(' Body:') |
|
78 self.log(' ' + request.body()) |
|
79 self.log(' Type:') |
|
80 self.log(' ' + request.type()) |
|
81 self.log(' Raw Xml:') |
|
82 self.log(' ' + str(request.raw_xml())) |
|
83 self.log(' To JIDs:') |
|
84 for jid in request.jid_list(): |
|
85 self.log(' ' + jid) |
|
86 |
|
87 for jid in request.jid_list(): |
|
88 response.add_status(xmpp_service_pb.XmppMessageResponse.NO_ERROR) |
|
89 |
|
90 def _Dynamic_SendInvite(self, request, response): |
|
91 """Implementation of XmppService::SendInvite. |
|
92 |
|
93 Args: |
|
94 request: An XmppInviteRequest. |
|
95 response: An XmppInviteResponse . |
|
96 """ |
|
97 from_jid = self._GetFrom(request.from_jid()) |
|
98 self.log('Sending an XMPP Invite:') |
|
99 self.log(' From:') |
|
100 self.log(' ' + from_jid) |
|
101 self.log(' To: ' + request.jid()) |
|
102 |
|
103 def _GetFrom(self, requested): |
|
104 """Validates that the from JID is valid. |
|
105 |
|
106 Args: |
|
107 requested: The requested from JID. |
|
108 |
|
109 Returns: |
|
110 string, The from JID. |
|
111 |
|
112 Raises: |
|
113 xmpp.InvalidJidError if the requested JID is invalid. |
|
114 """ |
|
115 |
|
116 appid = os.environ.get('APPLICATION_ID', '') |
|
117 if requested == None or requested == '': |
|
118 return appid + '@appspot.com/bot' |
|
119 |
|
120 node, domain, resource = ('', '', '') |
|
121 at = requested.find('@') |
|
122 if at == -1: |
|
123 self.log('Invalid From JID: No \'@\' character found. JID: %s', requested) |
|
124 raise xmpp.InvalidJidError() |
|
125 |
|
126 node = requested[:at] |
|
127 rest = requested[at+1:] |
|
128 |
|
129 if rest.find('@') > -1: |
|
130 self.log('Invalid From JID: Second \'@\' character found. JID: %s', |
|
131 requested) |
|
132 raise xmpp.InvalidJidError() |
|
133 |
|
134 slash = rest.find('/') |
|
135 if slash == -1: |
|
136 domain = rest |
|
137 resource = 'bot' |
|
138 else: |
|
139 domain = rest[:slash] |
|
140 resource = rest[slash+1:] |
|
141 |
|
142 if resource.find('/') > -1: |
|
143 self.log('Invalid From JID: Second \'/\' character found. JID: %s', |
|
144 requested) |
|
145 raise xmpp.InvalidJidError() |
|
146 |
|
147 if domain == 'appspot.com' and node == appid: |
|
148 return node + '@' + domain + '/' + resource |
|
149 elif domain == appid + '.appspotchat.com': |
|
150 return node + '@' + domain + '/' + resource |
|
151 |
|
152 self.log('Invalid From JID: Must be appid@appspot.com[/resource] or ' |
|
153 'node@appid.appspotchat.com[/resource]. JID: %s', requested) |
|
154 raise xmpp.InvalidJidError() |