# python imports import re # TAM imports import util from query import Query # website listed in response email URL = 'http://bilumi.org' class Asker: """ Asker of a L{Query}. Intended to be subclassed. """ #: @type: L{Query} query = None def reply(self, response): """ Prints response to standard out. @type response: L{Response} @param response: Response to Asker's query @rtype: int @returns: exit code """ print response return 0 class EmailAsker(Asker): """ Asker over email """ #: asker name in email's From: sender = None #: asker domain name in email's From: domain = None #: email To: recipient = None #: email To: recipient_domain = None def __extract_message(self, node): """ @type node: L{Node} @param node: @rtype: String @returns: String """ ret = self.__extract_ratings_message(node) for p in node.parents: ret += "\n" + self.__extract_ratings_message(p) ret += "Add more %s" % (URL) return ret def __extract_ratings_message(self, node): """ @type node: L{Node} @param node: @rtype: String @returns: String """ ret = "" behaviors = node.behaviors for b in behaviors: if b.average_rating != -1: ret += b.dimension.label ret += ": " ret += "%1.1f" % b.average_rating ret += "\n" return ret def __construct_msgsubject(self, response): """ @type response: L{Response} @param response: Response to Asker's query @rtype: String (whitespace includes spaces only) @returns: Message subject line """ if self.query.product_id == None: return 'Problem parsing your request' elif response.node == None and response.upcdb_dict == None: return str(self.query.product_id)+' is not yet in our database' elif response.node != None: return str(self.query.product_id)+' is '+response.node.label elif response.upcdb_dict != None: return str(self.query.product_id)+' is '+response.upcdb_dict['description'] else: return 'http://BILUMI.org' def __construct_msgbody(self, response): """ @type response: L{Response} @param response: Response to Asker's query @rtype: String (includes all kinds of whitespace) @returns: Message body """ if self.query.product_id == None: return 'Please send a 8 or 13 digit barcode. For help email info@bilumi.org\n'+URL elif response.node == None and response.upcdb_dict == None: return self.query.product_id+' is not yet in our database. Please help us grow our community effort '+URL elif response.node != None: return response.node.label+'\n'+self.__extract_ratings_message(response.node) elif response.upcdb_dict != None: return """%s: Size: %s Origin: %s Please review this product at %s""" % \ (str(response.upcdb_dict['description']).title(), str(response.upcdb_dict['size']), str(response.upcdb_dict['issuerCountryCode']).upper(), str(URL)) else: return 'Buy It Like You Mean It\nhttp://BILUMI.org' def reply(self, response): """ Sends email reply. Somewhat verbose. """ return util.sendmail(str(self.sender)+"@"+str(self.domain), str(self.recipient)+"@"+str(self.recipient_domain), self.__construct_msgsubject(response), self.__construct_msgbody(response)) def __eq__(self, other): """ @type other: L{Asker} @rtype: boolean @returns: """ if other == None: return False return self.query == other.query and \ self.sender == other.sender and \ self.domain == other.domain and \ self.recipient == other.recipient and \ self.recipient_domain == other.recipient_domain def __str__(self): return 'query:%s\nsender:%s\ndomain:%s\nrecipient:%s\nrecipient_domain:%s\n' % (str(self.query), str(self.sender), str(self.domain), str(self.recipient), str(self.recipient_domain)) class SMSAsker(EmailAsker): """ Asker over SMS (cellphone) (or...MMS, right?) We can't actually send SMS back to phone number. Instead, we use email via carrier. Thus, FOR NOW, PhoneAsker inherits from EmailAsker and does not override methods. """ #: @type: long phnumber = None class SmartPhoneAsker(EmailAsker): """ Asker over email via phone, not desktop. Reply might be formatted differently. For now, SmartPhoneAsker does not override methods. """ pass class TestSuiteAsker(Asker): """ Replies by writing log messages. Not yet implemented """ #: """ list of lines of mail """ mail = [] def reply(self, response): print "log me" return 0 def parse_email(lines_in): """ Parses an email, including constructing a Query object @type lines_in: list @param lines_in: List of input lines from email @rtype: L{Asker} @returns: Asker """ """ sender_regex matches: From @ Sun May 11 20:13:42 2008\n type of stuff. sometimes \n is right after domain. #don't we want to end this with [\s\n\r\f]+ ? to not get partial domain? recip_regex is like sender_regex by for To instead of From. sender_isphone will be true if the matched string contains only numbers. product_id_regex matches: Subject """ sender_regex = re.compile('^Return-Path:\s*\<*(?P[A-Za-z0-9_\.\-]+)\@(?P[A-Za-z0-9_\.\-]+)\>*\s*') recipient_regex = re.compile('^Delivered-To:\s*\<*(?P[A-Za-z0-9_\.\-]+)\@(?P[A-Za-z0-9_\.\-]+)\>*\s*') # this pattern only supports EAN, eventually this will need to be smarter # to support all product descriptions # product_id_regex = re.compile('.*[E|e][A|a][N|n]\s*(?P[0-9]+)\s*') product_id_regex = re.compile('.*Subject.\s(?P[0-9]+)\s*') bkup_product_id_regex = re.compile('\s*(?P[0-9]+)\s*') # initialize query = Query() sender_isphone = False sender = None domain = None recipient = None recipient_domain = None for s in lines_in: sender_expr = sender_regex.match(s) if sender is None and sender_expr: sender = sender_expr.group('name') sender_isphone = (re.match(r'^\d+$',sender)!=None) domain = sender_expr.group('domain') recip_expr = recipient_regex.match(s) if recipient is None and recip_expr: recipient = recip_expr.group('name') recipient_domain = recip_expr.group('domain') prod_expr = product_id_regex.match(s) if prod_expr: query.product_id = prod_expr.group('product_id') if sender and recipient and query.product_id: break if query.product_id is None: for s in reversed(lines_in): expr = bkup_product_id_regex.match(s) if expr: query.product_id = expr.group('product_id') break if sender_isphone: asker = SMSAsker() else: asker = EmailAsker() asker.query = query asker.sender = sender asker.domain = domain asker.recipient = recipient asker.recipient_domain = recipient_domain return asker