class POPChannel(asynchat.async_chat): def __init__(self, conn, quit_after_one): logger.debug(locals()) self.quit_after_one = quit_after_one asynchat.async_chat.__init__(self, conn) self.__line = [] self.push('+OK %s %s' % (socket.getfqdn(), __version__)) self.set_terminator(TERMINATOR) self._activeDataChannel = None # Overrides base class for convenience def push(self, msg): logger.debug(locals()) asynchat.async_chat.push(self, msg + TERMINATOR) # Implementation of base class abstract method def collect_incoming_data(self, data): logger.debug(locals()) self.__line.append(data) # Implementation of base class abstract method def found_terminator(self): logger.debug(locals()) line = ''.join(self.__line) self.__line = [] if not line: self.push('500 Error: bad syntax') return method = None i = line.find(' ') if i < 0: command = line.upper() arg = None else: command = line[:i].upper() arg = line[i+1:].strip() print(' got: %s' % line) method = getattr(self, 'pop_' + command, None) if not method: self.push('-ERR Error : command "%s" not implemented' % command) return method(arg) return def pop_UIDL(self, which=None): logger.debug(locals()) """Return message digest (unique id) list. If 'which', result contains unique id for that message in the form 'response mesgnum uid', otherwise result is the list ['response', ['mesgnum uid', ...], octets] """ return self.pop_LIST(arg=which) def pop_USER(self, user): logger.debug(locals()) # Logs in any username. if not user: self.push('-ERR: Syntax: USER username') else: self.username = ''.join((USER_PREFIX,user)) # Store for later. logger.info("username=%s" % self.username) self.push('+OK Password required') def pop_PASS(self, password=''): logger.debug(locals()) self.scraper = OutlookWebScraper(WEBMAIL_SERVER, self.username, password) try: self.scraper.login() except InvalidLogin: self.push('-ERR Login failed. (Wrong username/password?)') else: self.push('+OK User logged in') self.inbox_cache = self.scraper.inbox() self.msg_cache = [self.scraper.get_message(msg_id) for msg_id in self.inbox_cache] def pop_STAT(self, arg): logger.debug(locals()) dropbox_size = sum([len(msg) for msg in self.msg_cache]) self.push('+OK %d %d' % (len(self.inbox_cache), dropbox_size)) def pop_NOOP(self, arg): self.push('+OK') def pop_LIST(self, arg): logger.debug(locals()) if not arg: num_messages = len(self.inbox_cache) self.push('+OK') for i, msg in enumerate(self.msg_cache): self.push('%d %d' % (i+1, len(msg))) self.push(".") else: # TODO: Handle per-msg LIST commands raise NotImplementedError def pop_UIDL(self, arg): if not arg: num_messages = len(self.inbox_cache) self.push('+OK') for i, msg in enumerate(self.msg_cache): self.push('%d %s' % (i+1, re.search(r"Message-ID: <(.*?)>", msg, re.S | re.I).group(1))) self.push(".") else: found = False for i, msg in enumerate(self.msg_cache): if (i+1) == int(arg): self.push('+OK %d %s' % (i+1, re.search(r"Message-ID: <(.*?)>", msg, re.S | re.I).group(1))) found = True if not found: self.push('-ERR no such message, only %d messages in maildrop' % (len(self.inbox_cache))) #self.push(".") def pop_RETR(self, arg): logger.debug(locals()) if not arg: self.push('-ERR: Syntax: RETR msg') print '-ERR: Syntax: RETR msg' else: # TODO: Check request is in range. msg_index = int(arg) - 1 msg = self.msg_cache[msg_index] msg_id = self.inbox_cache[msg_index] msg = msg.lstrip() + TERMINATOR self.push('+OK') print '+OK (pop_RETR l_138)' for line in quote_dots(msg.split(TERMINATOR)): self.push(line) self.push('.') # Delete the message self.scraper.delete_message(msg_id) self.push('+OK') # self.push(".") def pop_QUIT(self, arg): logger.debug(locals()) self.push('+OK Goodbye') self.close_when_done() if self.quit_after_one: # This SystemExit gets propogated to handle_error(), # which stops the program. Slightly hackish. raise SystemExit def handle_error(self): logger.debug(locals()) if self.quit_after_one: sys.exit(0) # Exit. else: asynchat.async_chat.handle_error(self)
class POPChannel(asynchat.async_chat): def __init__(self, conn, options): self.webmail_server = options.webmail_server self.unread_messages = options.unread is True asynchat.async_chat.__init__(self, conn) self.__line = [] self.push('+OK %s %s' % (socket.getfqdn(), __version__)) self.set_terminator(TERMINATOR) self._activeDataChannel = None # Overrides base class for convenience def push(self, msg): #print msg asynchat.async_chat.push(self, msg + TERMINATOR) # Implementation of base class abstract method def collect_incoming_data(self, data): self.__line.append(data) # Implementation of base class abstract method def found_terminator(self): line = ''.join(self.__line) self.__line = [] if not line: self.push('500 Error: bad syntax') return method = None i = line.find(' ') if i < 0: command = line.upper() arg = None else: command = line[:i].upper() arg = line[i+1:].strip() method = getattr(self, 'pop_' + command, None) if not method: self.push('-ERR Error : command "%s" not implemented' % command) return method(arg) return def pop_USER(self, user): # Logs in any username. if not user: self.push('-ERR: Syntax: USER username') else: self.username = user # Store for later. self.push('+OK Password required') def pop_PASS(self, password=''): self.scraper = OutlookWebScraper(self.webmail_server, self.username, password) try: self.scraper.login() except InvalidLogin: self.push('-ERR Login failed. (Wrong username/password?)') else: self.push('+OK User logged in') self.inbox_cache = self.scraper.inbox(self.unread_messages) self.msg_cache = [self.scraper.get_message(msg_id) for msg_id in self.inbox_cache] def pop_STAT(self, arg): dropbox_size = sum([len(msg) for msg in self.msg_cache]) self.push('+OK %d %d' % (len(self.inbox_cache), dropbox_size)) def pop_UIDL(self, arg): if not arg: self.push('+OK') for i, msg in enumerate(self.msg_cache): self.push('%d %d' % (i+1, i+1)) self.push(".") else: self.push('+OK %s %s' % (arg, arg)) def pop_LIST(self, arg): if not arg: self.push('+OK') for i, msg in enumerate(self.msg_cache): self.push('%d %d' % (i+1, len(msg))) self.push(".") else: # TODO: Handle per-msg LIST commands raise NotImplementedError def pop_RETR(self, arg): if not arg: self.push('-ERR: Syntax: RETR msg') else: # TODO: Check request is in range. msg_index = int(arg) - 1 msg_id = self.inbox_cache[msg_index] msg = self.msg_cache[msg_index] msg = msg.lstrip() + TERMINATOR self.push('+OK') for line in quote_dots(msg.split(TERMINATOR)): self.push(line) self.push('.') # Delete the message self.scraper.delete_message(msg_id) def pop_TOP(self, arg): if not arg: self.push('-ERR: Syntax: TOP msg') else: # TODO: Check request is in range. msg_index = int(arg.split(' ')[0]) - 1 msg = self.msg_cache[msg_index] msg = msg.split('\r\n\r\n')[0] msg = msg.lstrip() + TERMINATOR self.push('+OK') for line in quote_dots(msg.split(TERMINATOR)): self.push(line) self.push('.') def pop_QUIT(self, arg): self.push('+OK Goodbye') self.close_when_done() def handle_error(self): asynchat.async_chat.handle_error(self)
class POPChannel(asynchat.async_chat): def __init__(self, conn, options): self.webmail_server = options.webmail_server self.unread_messages = options.unread is True asynchat.async_chat.__init__(self, conn) self.__line = [] self.push('+OK %s %s' % (socket.getfqdn(), __version__)) self.set_terminator(TERMINATOR) self._activeDataChannel = None # Overrides base class for convenience def push(self, msg): #print msg asynchat.async_chat.push(self, msg + TERMINATOR) # Implementation of base class abstract method def collect_incoming_data(self, data): self.__line.append(data) # Implementation of base class abstract method def found_terminator(self): line = ''.join(self.__line) self.__line = [] if not line: self.push('500 Error: bad syntax') return method = None i = line.find(' ') if i < 0: command = line.upper() arg = None else: command = line[:i].upper() arg = line[i + 1:].strip() method = getattr(self, 'pop_' + command, None) if not method: self.push('-ERR Error : command "%s" not implemented' % command) return method(arg) return def pop_USER(self, user): # Logs in any username. if not user: self.push('-ERR: Syntax: USER username') else: self.username = user # Store for later. self.push('+OK Password required') def pop_PASS(self, password=''): self.scraper = OutlookWebScraper(self.webmail_server, self.username, password) try: self.scraper.login() except InvalidLogin: self.push('-ERR Login failed. (Wrong username/password?)') else: self.push('+OK User logged in') self.inbox_cache = self.scraper.inbox(self.unread_messages) self.msg_cache = [ self.scraper.get_message(msg_id) for msg_id in self.inbox_cache ] def pop_STAT(self, arg): dropbox_size = sum([len(msg) for msg in self.msg_cache]) self.push('+OK %d %d' % (len(self.inbox_cache), dropbox_size)) def pop_UIDL(self, arg): if not arg: self.push('+OK') for i, msg in enumerate(self.msg_cache): self.push('%d %d' % (i + 1, i + 1)) self.push(".") else: self.push('+OK %s %s' % (arg, arg)) def pop_LIST(self, arg): if not arg: self.push('+OK') for i, msg in enumerate(self.msg_cache): self.push('%d %d' % (i + 1, len(msg))) self.push(".") else: # TODO: Handle per-msg LIST commands raise NotImplementedError def pop_RETR(self, arg): if not arg: self.push('-ERR: Syntax: RETR msg') else: # TODO: Check request is in range. msg_index = int(arg) - 1 msg_id = self.inbox_cache[msg_index] msg = self.msg_cache[msg_index] msg = msg.lstrip() + TERMINATOR self.push('+OK') for line in quote_dots(msg.split(TERMINATOR)): self.push(line) self.push('.') # Delete the message self.scraper.delete_message(msg_id) def pop_TOP(self, arg): if not arg: self.push('-ERR: Syntax: TOP msg') else: # TODO: Check request is in range. msg_index = int(arg.split(' ')[0]) - 1 msg = self.msg_cache[msg_index] msg = msg.split('\r\n\r\n')[0] msg = msg.lstrip() + TERMINATOR self.push('+OK') for line in quote_dots(msg.split(TERMINATOR)): self.push(line) self.push('.') def pop_QUIT(self, arg): self.push('+OK Goodbye') self.close_when_done() def handle_error(self): asynchat.async_chat.handle_error(self)
class POPChannel(asynchat.async_chat): def __init__(self, conn, quit_after_one): logger.debug(locals()) self.quit_after_one = quit_after_one asynchat.async_chat.__init__(self, conn) self.__line = [] self.push('+OK %s %s' % (socket.getfqdn(), __version__)) self.set_terminator(TERMINATOR) self._activeDataChannel = None # Overrides base class for convenience def push(self, msg): logger.debug(locals()) asynchat.async_chat.push(self, msg + TERMINATOR) # Implementation of base class abstract method def collect_incoming_data(self, data): logger.debug(locals()) self.__line.append(data) # Implementation of base class abstract method def found_terminator(self): logger.debug(locals()) line = ''.join(self.__line) self.__line = [] if not line: self.push('500 Error: bad syntax') return method = None i = line.find(' ') if i < 0: command = line.upper() arg = None else: command = line[:i].upper() arg = line[i + 1:].strip() print(' got: %s' % line) method = getattr(self, 'pop_' + command, None) if not method: self.push('-ERR Error : command "%s" not implemented' % command) return method(arg) return def pop_UIDL(self, which=None): logger.debug(locals()) """Return message digest (unique id) list. If 'which', result contains unique id for that message in the form 'response mesgnum uid', otherwise result is the list ['response', ['mesgnum uid', ...], octets] """ return self.pop_LIST(arg=which) def pop_USER(self, user): logger.debug(locals()) # Logs in any username. if not user: self.push('-ERR: Syntax: USER username') else: self.username = ''.join((USER_PREFIX, user)) # Store for later. logger.info("username=%s" % self.username) self.push('+OK Password required') def pop_PASS(self, password=''): logger.debug(locals()) self.scraper = OutlookWebScraper(WEBMAIL_SERVER, self.username, password) try: self.scraper.login() except InvalidLogin: self.push('-ERR Login failed. (Wrong username/password?)') else: self.push('+OK User logged in') self.inbox_cache = self.scraper.inbox() self.msg_cache = [ self.scraper.get_message(msg_id) for msg_id in self.inbox_cache ] def pop_STAT(self, arg): logger.debug(locals()) dropbox_size = sum([len(msg) for msg in self.msg_cache]) self.push('+OK %d %d' % (len(self.inbox_cache), dropbox_size)) def pop_NOOP(self, arg): self.push('+OK') def pop_LIST(self, arg): logger.debug(locals()) if not arg: num_messages = len(self.inbox_cache) self.push('+OK') for i, msg in enumerate(self.msg_cache): self.push('%d %d' % (i + 1, len(msg))) self.push(".") else: # TODO: Handle per-msg LIST commands raise NotImplementedError def pop_UIDL(self, arg): if not arg: num_messages = len(self.inbox_cache) self.push('+OK') for i, msg in enumerate(self.msg_cache): self.push( '%d %s' % (i + 1, re.search(r"Message-ID: <(.*?)>", msg, re.S | re.I).group(1))) self.push(".") else: found = False for i, msg in enumerate(self.msg_cache): if (i + 1) == int(arg): self.push('+OK %d %s' % (i + 1, re.search(r"Message-ID: <(.*?)>", msg, re.S | re.I).group(1))) found = True if not found: self.push( '-ERR no such message, only %d messages in maildrop' % (len(self.inbox_cache))) #self.push(".") def pop_RETR(self, arg): logger.debug(locals()) if not arg: self.push('-ERR: Syntax: RETR msg') print '-ERR: Syntax: RETR msg' else: # TODO: Check request is in range. msg_index = int(arg) - 1 msg = self.msg_cache[msg_index] msg_id = self.inbox_cache[msg_index] msg = msg.lstrip() + TERMINATOR self.push('+OK') print '+OK (pop_RETR l_138)' for line in quote_dots(msg.split(TERMINATOR)): self.push(line) self.push('.') # Delete the message self.scraper.delete_message(msg_id) self.push('+OK') # self.push(".") def pop_QUIT(self, arg): logger.debug(locals()) self.push('+OK Goodbye') self.close_when_done() if self.quit_after_one: # This SystemExit gets propogated to handle_error(), # which stops the program. Slightly hackish. raise SystemExit def handle_error(self): logger.debug(locals()) if self.quit_after_one: sys.exit(0) # Exit. else: asynchat.async_chat.handle_error(self)