2013년 12월 17일 화요일

[Python] Mime Mail 클래스

#! /usr/bin/python
# Copyright (C) 2000 Mag. Christian Tanzer. All rights reserved
# Glasauergasse 32, A--1130 Wien, Austria. tanzer@swing.co.at
# ****************************************************************************
#

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#

# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free
# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# ****************************************************************************
#
#++
# Name
#    Mime Mail
#
# Purpose
#    Model a MIME mail
#
# Revision Dates
#    10-Jan-2000 (CT) Creation
#    11-Jan-2000 (CT) Creation continued
#     1-Feb-2000 (CT) `formatted': don't format parts with subtype `html'

#
#--

import mimetools
import quopri
import re
import string
from   binascii  import a2b uu, a2b base64, a2b hqx
from   mimify    import *
from   multifile import MultiFile
from   cStringIO import StringIO

def a2b qp (data) :
    """Return a block of binary quoted `data' as string"""
    result = StringIO      ()
    quopri.decode          (StringIO (data), result)
    return result.getvalue ()
# end def a2b qp

class Mime Mail (mimetools.Message) :
    """MIME mail: represents the headers and parts of a mime mail"""
   

    file name  = ""

    def   init   (self, file, seekable = 0) :
        """Create a new message instance from `file'.

           `file' can be the name of a file or any input object supporting
           the `readline' method (see documentation rfc822.Message).
        """
        if type (file) == type ("") :
            self.file name  = file
            file            = open (file, "r")
            seekable        = 1
        mimetools.Message.  init   (self, file, seekable)
        self.parts   = []
        self. leader = ""
        self.mfile   = mfile = MultiFile (file, seekable)
        if self.maintype == "multipart" :
            self.multipart = 1
            self.boundary  = boundary = self.getparam ("boundary")
            mfile.push               (boundary)
            head = mfile.read        ()
            if self. add part (head) :
                self. leader = ""
            else :
                self. leader = head
            mfile.next ()               

            while not mfile.last :
                self. add part (mfile.read ())
                mfile.next     ()
        else :
            self.multipart = 0
            self.boundary  = ""
            text = mfile.read ()
            if string.strip (text) :
                self.parts.append (text)
        if self.file name :
            self.fp.close ()
    # end def   init 

    def   getattr   (self, name) :
        if   name == "attachement name" :
            return self. attachement name ()
        elif name == "encoding" :
            return self.getencoding ()
        elif name == "receiver address" :
            return self. address (self.receiver header name) [1]
        elif name == "receiver name" :
            return mime decode header (self. address
                                           (self.receiver header name) [0]
                                      )
        elif name == "sender address" :
            return self. address (self.sender header name) [1]
        elif name == "sender name" :
            return mime decode header (self. address
                                           (self.sender header name) [0]
                                      )
        else :
            raise AttributeError, name
    # end def   getattr 
   

    def  add part (self, text) :
        msg = Mime Mail (StringIO (text))
        if msg.type == "message/rfc822" and len (msg.parts) == 1:

            msg.parts [0] = Mime Mail (StringIO (msg.parts [0]))
            msg.multipart = 1
            msg.boundary  = msg.getparam ("boundary") or ""
            msg. leader   = ""
        if msg :
            self.parts.append (msg)
        return msg
    # end def  add part

    def write (self, file, write headers = 1, as bindary = 0) :
        """Write message `self' to `file', which must be a writable object
           with file-semantic or a filename.
        """
        if type (file) == type ("") :
            file = open        (file, "w")
        if write headers and self.headers :
            file.write         (string.join (self.headers, ""))
            file.write         ("\n")
        if self.multipart :
            file.write         (self. leader)
            for p in self.parts :
                if not p : continue
                if self.boundary :
                    file.write (self.mfile.section divider (self.boundary))
                file.write     ("\n")
                p.write        (file)
            if self.boundary :
                file.write     (self.mfile.end marker (self.boundary))
            file.write         ("\n")
        else :
            if as bindary :
                file.write     (self.as binary ())
            else :
                file.write     (self.parts [0])
    # end def write

    date header name     = ("date", "delivery-date")
    sender header name   = ("from", "reply-to", "return-path")
    receiver header name = ("to",   "cc")

    def  address (self, header names) :
        for n in header names :
            result = self.getaddr (n)
            if type (result [0]) == type ("") : return result
        return (None, None)
    # end def  sender

    def  all headers (self, header names) :
        for n in header names :
            result = self.getallmatchingheaders (n)
            if result :
                pat    = re.compile (r"^%s\s*:\s*" % re.escape (n), re.I)
                result = map (lambda h, p = pat : p.sub ("", h), result)
                return (n, result)
        return ("", ())
    # end def  all headers

    def  first header (self, header names) :
        for n in header names :
            result = self.getheader (n)
            if result : return (n, result)
        return ("", "")
    # end def  first header
   

    name pat = re.compile ('''name="(?P<name> [^"]+)"''', re.X)

    def  attachement name (self) :
        result = self.getparam ("name")
        if not result :
            for h in self.headers :
                match = self.name pat.search (h)
                if match :
                    return match.group  ("name")
        return result
    # end def  attachement name
   

    def   nonzero   (self) :
        return len (self.headers) or (self.parts and len (self.parts [0])) or 0
    # end def   nonzero 
   

    def   str   (self) :
        if self.multipart :
            return "Multipart message from %s" % self.getheader ("From")
        else :
            return self.parts [0]
    # end def   str 

    def   repr   (self) :
        return self.type
    # end def   repr 

    a2b converter = { "base64"           : a2b base64
                    , "binhex4"          : a2b hqx
                    , "quoted-printable" : a2b qp
                    , "uuencode"         : a2b uu
                    , "x-uuencode"       : a2b uu
                    }

    def as binary (self) :
        """Returns all parts converted from mime encodings to binary strings."""
        if self.multipart :
            return map (lambda p : p.as binary (), self.parts)
        else :
            if not self.parts : return ""
            converter = self.a2b converter.get (self.encoding)
            if converter :
                return converter (self.parts [0])
        return self.parts [0]
    # end def convert to binary

    def formatted (self, separator length = 79, n = "") :
        """Returns a string containing the mail in a format suitable for
           printing.
        """
        result = []
        header = self. formatted headers ()
        if header :
            result.append  (header)
        leader = string.strip (self. leader)
        if leader :
            if header :
                result.append  ("\n" + ("-" * separator length) + "\n")
            result.append  (a2b qp (leader))
        if self.multipart :
            i = 0
            for p in self.parts :
                i = i + 1
                if n :
                    pn = "%s.%s" % (n, i)
                else :
                    pn = i
                if (  p.maintype not in ("text", "message", "multipart")
                   or p.subtype in ("html", )) :
                    r = string.join (p.headers, "")
                else :
                    r = p.formatted (separator length, pn)
                r = string.strip (r)
                if r :
                    ph = "\n%s part %s "   % ("-" * 5, pn)
                    result.append ("%s-%s" % (ph, "-" * (separator length - len (ph))))
                    result.append (r)
        else :
            if header or leader :
                result.append  ("\n" + ("-" * separator length) + "\n")
            result.append  (self.as binary ())
        return string.join (filter (None, result) or "", "\n")
    # end def formatted

    def  formatted headers (self) :
        result = []
        (dn, date) = self. first header        (self.date header name)
        (fn, snd)  = self. all headers         (self.sender header name)
        (tn, rcv)  = self. all headers         (self.receiver header name)
        subject    = self.getheader            ("subject")
        result.append (self. formatted header  ("Date",    "", date))
        result.append (self. formatted address ("From",    snd))
        result.append (self. formatted address ("To",      rcv))
        result.append (self. formatted header  ("Subject", "", subject))
        return string.join (filter (None, result) or "", "\n")
    # end def  formatted headers

    label width = 8
    ws pat      = re.compile (r"\s+")
   

    def  formatted header (self, label, continuation tail, * lines) :
        if not (lines and lines [0]) : return
        if len (label) > self.label width :
            print "Label `%s' too long: %s > %s" % \
                  (label [:40], len (label), self.label width)
            return
        lines  = map (mime decode header, lines)
        head   = "%-*s: " % (self.label width, label)
        tail   = self. break lines ( 79 - len (head) - len (continuation tail), lines)
        result = "%s%s" % (head, string.join ( tail or ""
                                             , "%s\n%*s"
                                             % ( continuation tail
                                               , len (head), " "
                                               )
                                             )
                          )
        return result
    # end def  formatted header

    def  formatted address (self, label, lines) :
        line  = self.ws pat.sub (" ", string.strip (string.join (lines, " ")))
        lines = tuple           (string.split (line, ","))
        return apply (self. formatted header, (label, ",") + lines)
    # end def  formatted address

    def  break lines (self, space, lines) :
        result = []
        for l in lines :
            l = self.ws pat.sub (" ", string.strip (l))
            if not l : continue
            while len (l) > space :
                i = string.rfind (l, " ", 0, space)
                if i < 0 : i = len (l)
                result.append (l [:i])
                l = l [i + 1:]
            if l :
                result.append (l)
        return result
    # end def  break lines
   

# end class Mime Mail
-------------------------------------------------------------------------------

댓글 없음:

댓글 쓰기