home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / Calibre / calibre-0.8.18.msi / file_262 / smtpd.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-09-09  |  13.2 KB  |  483 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.7)
  3.  
  4. import sys
  5. import os
  6. import errno
  7. import getopt
  8. import time
  9. import socket
  10. import asyncore
  11. import asynchat
  12. __all__ = [
  13.     'SMTPServer',
  14.     'DebuggingServer',
  15.     'PureProxy',
  16.     'MailmanProxy']
  17. program = sys.argv[0]
  18. __version__ = 'Python SMTP proxy version 0.2'
  19.  
  20. class Devnull:
  21.     
  22.     def write(self, msg):
  23.         pass
  24.  
  25.     
  26.     def flush(self):
  27.         pass
  28.  
  29.  
  30. DEBUGSTREAM = Devnull()
  31. NEWLINE = '\n'
  32. EMPTYSTRING = ''
  33. COMMASPACE = ', '
  34.  
  35. def usage(code, msg = ''):
  36.     print >>sys.stderr, __doc__ % globals()
  37.     if msg:
  38.         print >>sys.stderr, msg
  39.     sys.exit(code)
  40.  
  41.  
  42. class SMTPChannel(asynchat.async_chat):
  43.     COMMAND = 0
  44.     DATA = 1
  45.     
  46.     def __init__(self, server, conn, addr):
  47.         asynchat.async_chat.__init__(self, conn)
  48.         self._SMTPChannel__server = server
  49.         self._SMTPChannel__conn = conn
  50.         self._SMTPChannel__addr = addr
  51.         self._SMTPChannel__line = []
  52.         self._SMTPChannel__state = self.COMMAND
  53.         self._SMTPChannel__greeting = 0
  54.         self._SMTPChannel__mailfrom = None
  55.         self._SMTPChannel__rcpttos = []
  56.         self._SMTPChannel__data = ''
  57.         self._SMTPChannel__fqdn = socket.getfqdn()
  58.         
  59.         try:
  60.             self._SMTPChannel__peer = conn.getpeername()
  61.         except socket.error:
  62.             err = None
  63.             self.close()
  64.             if err[0] != errno.ENOTCONN:
  65.                 raise 
  66.             return None
  67.  
  68.         print >>DEBUGSTREAM, 'Peer:', repr(self._SMTPChannel__peer)
  69.         self.push('220 %s %s' % (self._SMTPChannel__fqdn, __version__))
  70.         self.set_terminator('\r\n')
  71.  
  72.     
  73.     def push(self, msg):
  74.         asynchat.async_chat.push(self, msg + '\r\n')
  75.  
  76.     
  77.     def collect_incoming_data(self, data):
  78.         self._SMTPChannel__line.append(data)
  79.  
  80.     
  81.     def found_terminator(self):
  82.         line = EMPTYSTRING.join(self._SMTPChannel__line)
  83.         print >>DEBUGSTREAM, 'Data:', repr(line)
  84.         self._SMTPChannel__line = []
  85.         if self._SMTPChannel__state == self.COMMAND:
  86.             if not line:
  87.                 self.push('500 Error: bad syntax')
  88.                 return None
  89.             method = None
  90.             i = line.find(' ')
  91.             if i < 0:
  92.                 command = line.upper()
  93.                 arg = None
  94.             else:
  95.                 command = line[:i].upper()
  96.                 arg = line[i + 1:].strip()
  97.             method = getattr(self, 'smtp_' + command, None)
  98.             if not method:
  99.                 self.push('502 Error: command "%s" not implemented' % command)
  100.                 return None
  101.             None(arg)
  102.             return None
  103.         if None._SMTPChannel__state != self.DATA:
  104.             self.push('451 Internal confusion')
  105.             return None
  106.         data = None
  107.         for text in line.split('\r\n'):
  108.             if text and text[0] == '.':
  109.                 data.append(text[1:])
  110.                 continue
  111.             data.append(text)
  112.         
  113.         self._SMTPChannel__data = NEWLINE.join(data)
  114.         status = self._SMTPChannel__server.process_message(self._SMTPChannel__peer, self._SMTPChannel__mailfrom, self._SMTPChannel__rcpttos, self._SMTPChannel__data)
  115.         self._SMTPChannel__rcpttos = []
  116.         self._SMTPChannel__mailfrom = None
  117.         self._SMTPChannel__state = self.COMMAND
  118.         self.set_terminator('\r\n')
  119.         if not status:
  120.             self.push('250 Ok')
  121.         else:
  122.             self.push(status)
  123.  
  124.     
  125.     def smtp_HELO(self, arg):
  126.         if not arg:
  127.             self.push('501 Syntax: HELO hostname')
  128.             return None
  129.         if None._SMTPChannel__greeting:
  130.             self.push('503 Duplicate HELO/EHLO')
  131.         else:
  132.             self._SMTPChannel__greeting = arg
  133.             self.push('250 %s' % self._SMTPChannel__fqdn)
  134.  
  135.     
  136.     def smtp_NOOP(self, arg):
  137.         if arg:
  138.             self.push('501 Syntax: NOOP')
  139.         else:
  140.             self.push('250 Ok')
  141.  
  142.     
  143.     def smtp_QUIT(self, arg):
  144.         self.push('221 Bye')
  145.         self.close_when_done()
  146.  
  147.     
  148.     def __getaddr(self, keyword, arg):
  149.         address = None
  150.         keylen = len(keyword)
  151.         if arg[:keylen].upper() == keyword:
  152.             address = arg[keylen:].strip()
  153.             if not address:
  154.                 pass
  155.             elif address[0] == '<' and address[-1] == '>' and address != '<>':
  156.                 address = address[1:-1]
  157.             
  158.         return address
  159.  
  160.     
  161.     def smtp_MAIL(self, arg):
  162.         print >>DEBUGSTREAM, '===> MAIL', arg
  163.         address = self._SMTPChannel__getaddr('FROM:', arg) if arg else None
  164.         if not address:
  165.             self.push('501 Syntax: MAIL FROM:<address>')
  166.             return None
  167.         if None._SMTPChannel__mailfrom:
  168.             self.push('503 Error: nested MAIL command')
  169.             return None
  170.         self._SMTPChannel__mailfrom = None
  171.         print >>DEBUGSTREAM, 'sender:', self._SMTPChannel__mailfrom
  172.         self.push('250 Ok')
  173.  
  174.     
  175.     def smtp_RCPT(self, arg):
  176.         print >>DEBUGSTREAM, '===> RCPT', arg
  177.         if not self._SMTPChannel__mailfrom:
  178.             self.push('503 Error: need MAIL command')
  179.             return None
  180.         address = self._SMTPChannel__getaddr('TO:', arg) if None else None
  181.         if not address:
  182.             self.push('501 Syntax: RCPT TO: <address>')
  183.             return None
  184.         None._SMTPChannel__rcpttos.append(address)
  185.         print >>DEBUGSTREAM, 'recips:', self._SMTPChannel__rcpttos
  186.         self.push('250 Ok')
  187.  
  188.     
  189.     def smtp_RSET(self, arg):
  190.         if arg:
  191.             self.push('501 Syntax: RSET')
  192.             return None
  193.         self._SMTPChannel__mailfrom = None
  194.         self._SMTPChannel__rcpttos = []
  195.         self._SMTPChannel__data = ''
  196.         self._SMTPChannel__state = self.COMMAND
  197.         self.push('250 Ok')
  198.  
  199.     
  200.     def smtp_DATA(self, arg):
  201.         if not self._SMTPChannel__rcpttos:
  202.             self.push('503 Error: need RCPT command')
  203.             return None
  204.         if None:
  205.             self.push('501 Syntax: DATA')
  206.             return None
  207.         self._SMTPChannel__state = None.DATA
  208.         self.set_terminator('\r\n.\r\n')
  209.         self.push('354 End data with <CR><LF>.<CR><LF>')
  210.  
  211.  
  212.  
  213. class SMTPServer(asyncore.dispatcher):
  214.     
  215.     def __init__(self, localaddr, remoteaddr):
  216.         self._localaddr = localaddr
  217.         self._remoteaddr = remoteaddr
  218.         asyncore.dispatcher.__init__(self)
  219.         
  220.         try:
  221.             self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
  222.             self.set_reuse_addr()
  223.             self.bind(localaddr)
  224.             self.listen(5)
  225.         except:
  226.             self.close()
  227.             raise 
  228.  
  229.         print >>DEBUGSTREAM, '%s started at %s\n\tLocal addr: %s\n\tRemote addr:%s' % (self.__class__.__name__, time.ctime(time.time()), localaddr, remoteaddr)
  230.  
  231.     
  232.     def handle_accept(self):
  233.         pair = self.accept()
  234.         if pair is not None:
  235.             (conn, addr) = pair
  236.             print >>DEBUGSTREAM, 'Incoming connection from %s' % repr(addr)
  237.             channel = SMTPChannel(self, conn, addr)
  238.  
  239.     
  240.     def process_message(self, peer, mailfrom, rcpttos, data):
  241.         raise NotImplementedError
  242.  
  243.  
  244.  
  245. class DebuggingServer(SMTPServer):
  246.     
  247.     def process_message(self, peer, mailfrom, rcpttos, data):
  248.         inheaders = 1
  249.         lines = data.split('\n')
  250.         print '---------- MESSAGE FOLLOWS ----------'
  251.         for line in lines:
  252.             if inheaders and not line:
  253.                 print 'X-Peer:', peer[0]
  254.                 inheaders = 0
  255.             print line
  256.         
  257.         print '------------ END MESSAGE ------------'
  258.  
  259.  
  260.  
  261. class PureProxy(SMTPServer):
  262.     
  263.     def process_message(self, peer, mailfrom, rcpttos, data):
  264.         lines = data.split('\n')
  265.         i = 0
  266.         for line in lines:
  267.             if not line:
  268.                 break
  269.             i += 1
  270.         
  271.         lines.insert(i, 'X-Peer: %s' % peer[0])
  272.         data = NEWLINE.join(lines)
  273.         refused = self._deliver(mailfrom, rcpttos, data)
  274.         print >>DEBUGSTREAM, 'we got some refusals:', refused
  275.  
  276.     
  277.     def _deliver(self, mailfrom, rcpttos, data):
  278.         import smtplib
  279.         refused = { }
  280.         
  281.         try:
  282.             s = smtplib.SMTP()
  283.             s.connect(self._remoteaddr[0], self._remoteaddr[1])
  284.             
  285.             try:
  286.                 refused = s.sendmail(mailfrom, rcpttos, data)
  287.             finally:
  288.                 s.quit()
  289.  
  290.         except smtplib.SMTPRecipientsRefused:
  291.             e = None
  292.             print >>DEBUGSTREAM, 'got SMTPRecipientsRefused'
  293.             refused = e.recipients
  294.         except (socket.error, smtplib.SMTPException):
  295.             e = None
  296.             print >>DEBUGSTREAM, 'got', e.__class__
  297.             errcode = getattr(e, 'smtp_code', -1)
  298.             errmsg = getattr(e, 'smtp_error', 'ignore')
  299.             for r in rcpttos:
  300.                 refused[r] = (errcode, errmsg)
  301.             
  302.  
  303.         return refused
  304.  
  305.  
  306.  
  307. class MailmanProxy(PureProxy):
  308.     
  309.     def process_message(self, peer, mailfrom, rcpttos, data):
  310.         StringIO = StringIO
  311.         import cStringIO
  312.         Utils = Utils
  313.         import Mailman
  314.         Message = Message
  315.         import Mailman
  316.         MailList = MailList
  317.         import Mailman
  318.         listnames = []
  319.         for rcpt in rcpttos:
  320.             local = rcpt.lower().split('@')[0]
  321.             parts = local.split('-')
  322.             if len(parts) > 2:
  323.                 continue
  324.             listname = parts[0]
  325.             if len(parts) == 2:
  326.                 command = parts[1]
  327.             else:
  328.                 command = ''
  329.             if not Utils.list_exists(listname) or command not in ('', 'admin', 'owner', 'request', 'join', 'leave'):
  330.                 continue
  331.             listnames.append((rcpt, listname, command))
  332.         
  333.         for rcpt, listname, command in listnames:
  334.             rcpttos.remove(rcpt)
  335.         
  336.         print >>DEBUGSTREAM, 'forwarding recips:', ' '.join(rcpttos)
  337.         if rcpttos:
  338.             refused = self._deliver(mailfrom, rcpttos, data)
  339.             print >>DEBUGSTREAM, 'we got refusals:', refused
  340.         mlists = { }
  341.         s = StringIO(data)
  342.         msg = Message.Message(s)
  343.         if not msg.getheader('from'):
  344.             msg['From'] = mailfrom
  345.         if not msg.getheader('date'):
  346.             msg['Date'] = time.ctime(time.time())
  347.         for rcpt, listname, command in listnames:
  348.             print >>DEBUGSTREAM, 'sending message to', rcpt
  349.             mlist = mlists.get(listname)
  350.             if not mlist:
  351.                 mlist = MailList.MailList(listname, lock = 0)
  352.                 mlists[listname] = mlist
  353.             if command == '':
  354.                 msg.Enqueue(mlist, tolist = 1)
  355.                 continue
  356.             if command == 'admin':
  357.                 msg.Enqueue(mlist, toadmin = 1)
  358.                 continue
  359.             if command == 'owner':
  360.                 msg.Enqueue(mlist, toowner = 1)
  361.                 continue
  362.             if command == 'request':
  363.                 msg.Enqueue(mlist, torequest = 1)
  364.                 continue
  365.             if command in ('join', 'leave') or command == 'join':
  366.                 msg['Subject'] = 'subscribe'
  367.             else:
  368.                 msg['Subject'] = 'unsubscribe'
  369.             msg.Enqueue(mlist, torequest = 1)
  370.         
  371.  
  372.  
  373.  
  374. class Options:
  375.     setuid = 1
  376.     classname = 'PureProxy'
  377.  
  378.  
  379. def parseargs():
  380.     global DEBUGSTREAM
  381.     
  382.     try:
  383.         (opts, args) = getopt.getopt(sys.argv[1:], 'nVhc:d', [
  384.             'class=',
  385.             'nosetuid',
  386.             'version',
  387.             'help',
  388.             'debug'])
  389.     except getopt.error:
  390.         e = None
  391.         usage(1, e)
  392.  
  393.     options = Options()
  394.     for opt, arg in opts:
  395.         if opt in ('-h', '--help'):
  396.             usage(0)
  397.             continue
  398.         if opt in ('-V', '--version'):
  399.             print >>sys.stderr, __version__
  400.             sys.exit(0)
  401.             continue
  402.         if opt in ('-n', '--nosetuid'):
  403.             options.setuid = 0
  404.             continue
  405.         if opt in ('-c', '--class'):
  406.             options.classname = arg
  407.             continue
  408.         if opt in ('-d', '--debug'):
  409.             DEBUGSTREAM = sys.stderr
  410.             continue
  411.     if len(args) < 1:
  412.         localspec = 'localhost:8025'
  413.         remotespec = 'localhost:25'
  414.     elif len(args) < 2:
  415.         localspec = args[0]
  416.         remotespec = 'localhost:25'
  417.     elif len(args) < 3:
  418.         localspec = args[0]
  419.         remotespec = args[1]
  420.     else:
  421.         usage(1, 'Invalid arguments: %s' % COMMASPACE.join(args))
  422.     i = localspec.find(':')
  423.     if i < 0:
  424.         usage(1, 'Bad local spec: %s' % localspec)
  425.     options.localhost = localspec[:i]
  426.     
  427.     try:
  428.         options.localport = int(localspec[i + 1:])
  429.     except ValueError:
  430.         usage(1, 'Bad local port: %s' % localspec)
  431.  
  432.     i = remotespec.find(':')
  433.     if i < 0:
  434.         usage(1, 'Bad remote spec: %s' % remotespec)
  435.     options.remotehost = remotespec[:i]
  436.     
  437.     try:
  438.         options.remoteport = int(remotespec[i + 1:])
  439.     except ValueError:
  440.         usage(1, 'Bad remote port: %s' % remotespec)
  441.  
  442.     return options
  443.  
  444. if __name__ == '__main__':
  445.     options = parseargs()
  446.     if options.setuid:
  447.         
  448.         try:
  449.             import pwd
  450.         except ImportError:
  451.             print >>sys.stderr, 'Cannot import module "pwd"; try running with -n option.'
  452.             sys.exit(1)
  453.  
  454.         nobody = pwd.getpwnam('nobody')[2]
  455.         
  456.         try:
  457.             os.setuid(nobody)
  458.         except OSError:
  459.             e = None
  460.             if e.errno != errno.EPERM:
  461.                 raise 
  462.             print >>sys.stderr, 'Cannot setuid "nobody"; try running with -n option.'
  463.             sys.exit(1)
  464.         
  465.  
  466.     classname = options.classname
  467.     if '.' in classname:
  468.         lastdot = classname.rfind('.')
  469.         mod = __import__(classname[:lastdot], globals(), locals(), [
  470.             ''])
  471.         classname = classname[lastdot + 1:]
  472.     else:
  473.         import __main__ as mod
  474.     class_ = getattr(mod, classname)
  475.     proxy = class_((options.localhost, options.localport), (options.remotehost, options.remoteport))
  476.     
  477.     try:
  478.         asyncore.loop()
  479.     except KeyboardInterrupt:
  480.         pass
  481.     
  482.  
  483.