mimeviewer.py
上传用户:gyjinxi
上传日期:2007-01-04
资源大小:159k
文件大小:10k
- import os, re, urllib
- from string import split, join, find, replace, lower, atoi
- from urlparse import urljoin
- from htmlentitydefs import entitydefs
- from htmllib import HTMLParser
- from sgmllib import SGMLParser
- from formatter import AbstractFormatter, DumbWriter, NullFormatter
- try: from cStringIO import StringIO
- except: from StringIO import StringIO
- from DocumentTemplate import *
- from gttag import *
- from Message import *
- from bobomailrc import *
- from fintl import gettext
- _ = gettext
- def urlquote(s): return urllib.quote(s, "")
- def urlunquote(s): return urllib.unquote(s)
- class Text2HTMLParser(HTMLParser):
- def handle_image(self, src, alt, *args):
- if alt == "(image)": alt = "[%s]" % os.path.basename(src)
- self.handle_data(alt)
- def anchor_end(self):
- if self.anchor: self.anchor = None
- def end_title(self):
- HTMLParser.end_title(self)
- self.formatter.add_literal_data(self.title)
- self.formatter.add_hor_rule()
- self.formatter.add_line_break()
- def start_tr(self, attrs): self.unknown_starttag("tr", attrs)
- def end_tr(self): self.do_br([])
- def quotedtext(text):
- def quotedline(line):
- return "> %s" % line
- return join(map(quotedline, split(text, "n")), "n")
- replace_char = {"n": "<br>"}
- for key, value in entitydefs.items():
- replace_char[value] = "&%s;" % key
- def escape(s, spaces=0):
- nbsp = entitydefs["nbsp"]
- new, last = "", ""
- for char in s:
- if spaces and char == " " and last in [" ", nbsp]:
- char = nbsp
- new = "%s%s" % (new, replace_char.get(char, char))
- last = char
- return new
-
- def path2pid(path):return join(map(str, path), ".")
- def pid2path(pid): return map(int, split(pid, "."))
-
- def getMIMEPart(msg, path=[]):
- if type(path) == type(""): path = pid2path(path)
- for p in path:
- if msg.gettype == "message/rfc822":
- msg = Message(StringIO(msg.decode()))
- msg = msg.parts[p]
- return msg
- class MIMEViewer:
- def __init__(self, msg, sid):
- self.msg = msg
- if not hasattr(self.msg, "path"):
- self.msg.path = []
- self.sid = sid
-
- def toHTML(self):
- html = HTMLFile(mime_template)
- return html(
- index=self.msg.unique_num, num=path2pid(self.msg.path), imagedir=image_dir,
- sid=self.sid, filename=self.msg.filename, mimetype=self.msg.gettype())
- def toText(self):
- o = StringIO()
- f = AbstractFormatter(DumbWriter(o))
- p = Text2HTMLParser(f)
- p.feed(str(self))
- p.close()
- return o.getvalue()
- def __repr__(self):
- return self.toText() or _("(no body)")
- def __str__(self):
- return self.toHTML() or _("(no body)")
- class MultiViewer(MIMEViewer):
-
- def toHTML(self):
- body = ""
- for i in range(len(self.msg.parts)):
- p = self.msg.parts[i]
- p.unique_num = self.msg.unique_num
- p.path = self.msg.path + [i]
- body = "%s%s" % (body, getBody(p, self.sid)) + '<br><hr height="3"><br>'
- return body
- class AlternativeViewer(MIMEViewer):
- prefer = ["text/html"]
-
- def toHTML(self):
- viewable = None
- for i in range(len(self.msg.parts)):
- p = self.msg.parts[i]
- p.unique_num = self.msg.unique_num
- p.path = self.msg.path + [i]
- ctype = p.gettype()
- if hasMIMEViewer(ctype):
- if ctype == "multipart/related":
- for x in p.parts:
- ct = x.gettype()
- if ct in self.prefer:
- ctype = ct
- break
- if not viewable or ctype in self.prefer:
- viewable = p
- if viewable:
- return getBody(viewable, self.sid)
- else:
- return MultiViewer(self.msg, self.sid)
- class RelatedViewer(MIMEViewer):
- handle = ["text/html"]
- def unquote(self, s):
- if len(s) > 2:
- if s[0] == "<" and s[-1] == ">":
- return s[1:-1]
- return s
- def toHTML(self):
- maindoc = None
- inline = {}
- for i in range(len(self.msg.parts)):
- p = self.msg.parts[i]
- p.unique_num = self.msg.unique_num
- p.path = self.msg.path + [i]
- cid = p.getheader("Content-Id", None)
- if cid: inline[self.unquote(cid)] = path2pid(p.path)
- ctype = p.gettype()
- if hasMIMEViewer(ctype):
- if not maindoc or ctype in self.handle:
- maindoc = p
- if maindoc:
- body = getBody(maindoc, self.sid)
- for key, value in inline.items():
- body = replace(body, "cid:%s" % key, "GetPart?index:int=%s&num=%s&sid=%s" % (
- self.msg.unique_num, value, self.sid))
- return body
- else:
- return MultiViewer(self.msg, self.sid)
- class MessageViewer(MIMEViewer):
- def toHTML(self):
- html = HTMLFile(message_template)
- if self.msg.gettype() == "message/rfc822":
- path = self.msg.path
- un = self.msg.unique_num
- self.msg = Message(StringIO(self.msg.decode()))
- self.msg.unique_num = un
- self.msg.path = path
- return html(msg=self.msg, body=getBody(self.msg, self.sid))
- urlpat = re.compile(r'(w+://[^>)s]+)')
- emailpat=re.compile(r'([-+,.w]+@[-+.w]+)')
- class TextViewer(MIMEViewer):
- def toHTML(self):
- html = HTMLFile(text_template)
- lines = split(self.msg.decode(), "n")
- for i in xrange(len(lines)):
- start, links, l = 0, {}, escape(lines[i])
- while 1:
- found = emailpat.search(l[start:])
- if found:
- url = found.group(1)
- links[url] = '<a href="Compose?sid=%s&To=%s">%s</a>' %
- (self.sid, urlquote(url), escape(url))
- else:
- found = urlpat.search(l[start:])
- if found:
- url = found.group(1)
- links[url] = '<a href="Goto?%s">%s</a>' % (urlquote(url), escape(url))
- else: break
- start = start + found.end()
- for old, new in links.items():
- l = replace(l, old, new)
- if len(l) > 1 and lines[i][0] in [">", ":", "|"]:
- lines[i] = '<i><font color="darkblue">%s</font></i>' % l
- else: lines[i] = l
- return html(text=join(lines, "<br>"))
- #XXX: translate mailto-links into Compose?to=..
- class HTMLMailParser(SGMLParser):
- def __init__(self, base=""):
- SGMLParser.__init__(self, NullFormatter())
- self.base = base
- self.data = self.title = ""
- self.titlestart = self.stopsave = 0
- self.linkcolor = self.vlink = self.alink = ""
- self.background = self.bgcolor = self.fgcolor = ""
- def fixlink(self, link):
- if self.base:
- link = urljoin(self.base, link)
- link = "Goto?%s" % urlquote(link)
- return link
-
- def makeattrs(self, attrs):
- r = ""
- for key, value in attrs:
- if key in ["src", "href", "background"]:
- if len(value) > 4 and lower(value[:4]) == "cid:":
- pass
- else: value = self.fixlink(value)
- r = '%s %s="%s"' % (r, key, value)
- return r
-
- def makedict(self, attrs):
- dict = {}
- for key, value in attrs:
- dict[lower(key)] = value
- return dict
-
- def save(self, data):
- if not self.stopsave:
- self.data = self.data + data
- def handle_comment(self, comment): self.save("<!--%s-->" % comment)
- def handle_entityref(self, name): self.save("&%s;" % name)
- def handle_charref(self, name): self.save("&#%s;" % name)
- def handle_data(self, data):self.save(data)
- def do_meta(self, attrs): pass
- def start_head(self, attrs): pass
- def end_head(self): pass
- def start_html(self, attrs): pass
- def end_html(self): pass
- def start_frameset(self, attrs): pass
- def end_frameset(self): pass
- def do_frame(self, attrs): pass
- def start_title(self, attrs): self.titlestart = len(self.data)
- def end_title(self): self.title = self.data[self.titlestart:]
- def start_a(self, attrs):
- html = "<a%s>" % self.makeattrs(attrs)
- if self.linkcolor:
- html = '%s<font color="%s">' % (html, self.linkcolor)
- self.save(html)
- def end_a(self):
- if self.linkcolor: self.save("</font>")
- self.save("</a>")
- def start_body(self, attrs):
- self.data = ""
- opts = self.makedict(attrs)
- self.background = opts.get("background", "")
- self.bgcolor = opts.get("bgcolor", "")
- self.fgcolor = opts.get("text", "")
- self.linkcolor = opts.get("link", "")
- self.vlink = opts.get("vlink", "")
- self.alink = opts.get("alink", "")
-
- def end_body(self): self.stopsave = 1
- def do_base(self, attrs):
- opts = self.makedict(attrs)
- if opts.has_key("href"):
- self.base = opts["href"]
- def unknown_starttag(self, tag, attrs):
- html = "<%s%s>" % (tag, self.makeattrs(attrs))
- self.save(html)
- def unknown_endtag(self, tag):
- html = "</%s>" % tag
- self.save(html)
- class HTMLViewer(MIMEViewer):
- def toHTML(self):
- parser = HTMLMailParser(self.msg.getheader("Content-Base", None))
- parser.feed(self.msg.decode())
- html = HTMLFile(html_template)
- return html(mail=parser)
- #XXX: Fix this hack. -> rfc2426
- # V-Cards are much more complex
- class VCardViewer(MIMEViewer):
- def toHTML(self):
- class VCard:
- def __init__(self, vc={}): self.__dict__ = vc
-
- data = self.msg.decode()
- lines = split(data, "n")
- entries = {}
- for l in lines:
- f = find(l, ":")
- entries[l[:f]] = l[f+1:]
- card = VCard(entries)
- card.street, card.city, card.state, card.zip,
- card.country = split(entries.get("adr", ""), ";")[2:]
- html = HTMLFile(vcard_template)
- return html(card=card, sid=self.sid)
- class ImageViewer(MIMEViewer):
- def toHTML(self):
- html = HTMLFile(image_template)
- return html(
- index=self.msg.unique_num, num=path2pid(self.msg.path),
- sid=self.sid, filename=self.msg.filename)
- mime_viewers = {
- "message/rfc822": MessageViewer,
- "message/delivery-status": TextViewer,
- "multipart/alternative": AlternativeViewer,
- "multipart/mixed": MultiViewer,
- "multipart/report": MultiViewer,
- "multipart/related": RelatedViewer,
- "text/plain": TextViewer,
- "text/html": HTMLViewer,
- "text/x-vcard": VCardViewer,
- "image/jpeg": ImageViewer,
- "image/png": ImageViewer,
- "image/x-xpixmap": ImageViewer,
- "image/gif": ImageViewer,
- }
- getMIMEViewer = mime_viewers.get
- hasMIMEViewer = mime_viewers.has_key
- def getBody(msg, sid):
- ctype = msg.gettype()
- MIMEViewerClass = getMIMEViewer(ctype, MIMEViewer)
- return str(MIMEViewerClass(msg, sid))
-
- if __name__ == "__main__":
- s = urlquote("Test/123!")
- print s, urlunquote(s)
- from fetchmail import MailSpool
- class Auth: userid = "henning"
- ml = MailSpool()
- ml.login(Auth())
- msg = ml[18]
- print MessageViewer(msg, 123)