Created
September 23, 2009 21:09
-
-
Save WorldMaker/192277 to your computer and use it in GitHub Desktop.
Revisions
-
WorldMaker revised this gist
Sep 23, 2009 . 1 changed file with 63 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,66 @@ # # textapp -- Combined SMS and IM dispatching # Copyright 2009 Max Battcher. All Rights Reserved. # # Microsoft Public License (Ms-PL) # # This license governs use of the accompanying software. If you use the # software, you accept this license. If you do not accept the license, # do not use the software. # # 1. Definitions # # The terms “reproduce,” “reproduction,” “derivative works,” and # “distribution” have the same meaning here as under U.S. copyright # law. A “contribution” is the original software, or any additions or # changes to the software. A “contributor” is any person that # distributes its contribution under this license. “Licensed patents” # are a contributor’s patent claims that read directly on its # contribution. # # 2. Grant of Rights # # (A) Copyright Grant- Subject to the terms of this license, including # the license conditions and limitations in section 3, each contributor # grants you a non-exclusive, worldwide, royalty-free copyright license # to reproduce its contribution, prepare derivative works of its # contribution, and distribute its contribution or any derivative works # that you create. # # (B) Patent Grant- Subject to the terms of this license, including the # license conditions and limitations in section 3, each contributor # grants you a non-exclusive, worldwide, royalty-free license under its # licensed patents to make, have made, use, sell, offer for sale, # import, and/or otherwise dispose of its contribution in the software # or derivative works of the contribution in the software. # # 3. Conditions and Limitations # # (A) No Trademark License- This license does not grant you rights to # use any contributors’ name, logo, or trademarks. # # (B) If you bring a patent claim against any contributor over patents # that you claim are infringed by the software, your patent license from # such contributor to the software ends automatically. # # (C) If you distribute any portion of the software, you must retain all # copyright, patent, trademark, and attribution notices that are present # in the software. # # (D) If you distribute any portion of the software in source code form, # you may do so only under this license by including a complete copy of # this license with your distribution. If you distribute any portion of # the software in compiled or object code form, you may only do so under # a license that complies with this license. # # (E) The software is licensed “as-is.” You bear the risk of using it. # The contributors give no express warranties, guarantees or conditions. # You may have additional consumer rights under your local laws which # this license cannot change. To the extent permitted under your local # laws, the contributors exclude the implied warranties of # merchantability, fitness for a particular purpose and # non-infringement. # from google.appengine.api import xmpp from google.appengine.ext.webapp.xmpp_handlers import BaseHandler from models import Player -
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,224 @@ from google.appengine.api import xmpp from google.appengine.ext.webapp.xmpp_handlers import BaseHandler from models import Player from webappfb import FacebookRequestHandler import logging import re class Error(Exception): """Text application error base class.""" pass class NoHandlerError(Error): """No matching regex/handler error.""" pass class UnregisteredJidError(Error): """Unregisted JID.""" pass # Based on, for instance, Django's RegexURLPattern or webapps WSGIApplication class TextApplication(object): def __init__(self, mapping): compiled = [] for regex, handler in mapping: if not regex.startswith('^'): regex = '^' + regex if not regex.endswith('$'): regex = regex + '$' compiled.append((re.compile(regex, re.IGNORECASE | re.UNICODE), handler)) self._mapping = compiled def __call__(self, message): for regex, handler in self._mapping: match = regex.match(message.body.strip()) if match: # If the groups are named, use kwargs, otherwise args args, kwargs = (), match.groupdict() if not kwargs: args = match.groups() return handler(message, *args, **kwargs) raise NoHandlerError # Borrowed from google.appengine.api.xmpp, replaced __'s for subclasses class Message(object): """Encapsulates an XMPP message received by the application.""" def __init__(self, vars): """Constructs a new XMPP Message from an HTTP request. Args: vars: A dict-like object to extract message arguments from. """ try: self._sender = vars["from"] self._to = vars["to"] self._body = vars["body"] except KeyError, e: raise xmpp.InvalidMessageError(e[0]) self._command = None self._arg = None @property def sender(self): return self._sender @property def to(self): return self._to @property def body(self): return self._body def __parse_command(self): if self._arg != None: return body = self._body if body.startswith('\\'): body = '/' + body[1:] self._arg = '' if body.startswith('/'): parts = body.split(' ', 1) self._command = parts[0][1:] if len(parts) > 1: self._arg = parts[1].strip() else: self._arg = self._body.strip() @property def command(self): self._parse_command() return self._command @property def arg(self): self._parse_command() return self._arg def reply(self, body, message_type=xmpp.MESSAGE_TYPE_CHAT, raw_xml=False, send_message=xmpp.send_message): """Convenience function to reply to a message. Args: body: str: The body of the message message_type, raw_xml: As per send_message. send_message: Used for testing. Returns: A status code as per send_message. Raises: See send_message. """ return send_message([self.sender], body, from_jid=self.to, message_type=message_type, raw_xml=raw_xml) class FacebookXmppMessage(Message): def __init__(self, vars, facebook): self._facebook = facebook super(FacebookXmppMessage, self).__init__(vars) barejid = self._sender slash = barejid.find('/') if slash >= 0: barejid = barejid[:slash] players = list(Player.all().filter('jid =', barejid)) self._senderuid = None if len(players) == 1: self._senderuid = players[0].uid @property def facebook(self): return self._facebook @property def senderuid(self): if self._senderuid is None: raise UnregisteredJidError return self._senderuid class FacebookSmsMessage(FacebookXmppMessage): def __init__(self, vars, facebook): self._facebook = facebook self._sender = 'facebook-sms' self._to = 'facebook-sms' try: self._sid = vars['fb_sig_sms_sid'] self._senderuid = vars['fb_sig_user'] self._body = vars['fb_sig_message'] except KeyError, e: raise xmpp.InvalidMessageError(e[0]) self._command = None self._arg = None def reply(self, body, **kwargs): return self.facebook.sms.send(self._senderuid, body, self._sid, False, ) class XmppHandler(BaseHandler): def message_received(self, message): self.application(message) class FacebookXmppHandler(FacebookRequestHandler): def handle_exception(self, exception, debug_mode): if self.message: if isinstance(exception, UnregisteredJidError): self.message.reply("""You need to register first: http://apps.facebook.com/enlark-assassins/my/settings""") elif isinstance(exception, NoHandlerError): self.message.reply("Unrecognized command.") else: self.message.reply('An error occurred processing your message.') else: super(FacebookXmppHandler, self).handle_exception(exception, debug_mode) def post(self): if self.redirecting: return # Unlikely, but... try: self.message = FacebookXmppMessage(self.request.POST, self.facebook) except xmpp.InvalidMessageError, e: logging.error("Invalid XMPP request: %s", e[0]) return reply = self.application(self.message) if reply: self.message.reply(reply) class FacebookSmsHandler(FacebookRequestHandler): def canvas(self): raise NotImplementedError() def handle_exception(self, exception, debug_mode): if self.message: if isinstance(exception, NoHandlerError): self.message.reply('Unrecognized command.') else: self.message.reply('An error occurred processing your message.') else: super(FacebookSmsHandler, self).handle_exception(exception, debug_mode) def post(self): if self.redirecting: return sms = self.request.get('fb_sig_sms') if sms and int(sms) == 1: try: self.message = FacebookSmsMessage(self.request.POST, self.facebook) except xmpp.InvalidMessageError, e: logging.error("Invalid SMS request: %s", e[0]) return reply = self.application(self.message) if reply: self.message.reply(reply) else: self.canvas() # vim: ai et ts=4 sts=4 sw=4