1.1 --- a/MoinRemoteSupport.py Wed Jan 29 18:22:58 2014 +0100
1.2 +++ b/MoinRemoteSupport.py Wed Jan 29 19:22:48 2014 +0100
1.3 @@ -8,8 +8,15 @@
1.4
1.5 from ContentTypeSupport import getContentTypeAndEncoding
1.6 from MoinMoin.action import cache
1.7 -from MoinMoin import caching
1.8 +from MoinMoin import caching, log
1.9 +from email.parser import Parser
1.10 +from email.mime.multipart import MIMEMultipart
1.11 +from urllib import splithost, splitpasswd, splitport, splituser, unquote_plus
1.12 +from urlparse import urlsplit
1.13 import urllib2, time
1.14 +import imaplib
1.15 +
1.16 +logging = log.getLogger(__name__)
1.17
1.18 def getCachedResource(request, url, arena, scope, max_cache_age, reader=None):
1.19
1.20 @@ -56,16 +63,20 @@
1.21 cache_entry.open(mode="w")
1.22
1.23 try:
1.24 - # Read from the source and write to the cache.
1.25 + try:
1.26 + # Read from the source and write to the cache.
1.27
1.28 - reader(url, cache_entry)
1.29 + reader(url, cache_entry)
1.30 +
1.31 + # In case of an exception, return None.
1.32
1.33 - # In case of an exception, return None.
1.34 + except IOError:
1.35 + if cache_entry.exists():
1.36 + cache_entry.remove()
1.37 + return None
1.38
1.39 - except IOError:
1.40 - if cache_entry.exists():
1.41 - cache_entry.remove()
1.42 - return None
1.43 + finally:
1.44 + cache_entry.close()
1.45
1.46 # Open the cache entry and read it.
1.47
1.48 @@ -81,17 +92,105 @@
1.49
1.50 f = urllib2.urlopen(url)
1.51 try:
1.52 - cache_entry.write(url + "\n")
1.53 - cache_entry.write((f.headers.get("content-type") or "") + "\n")
1.54 - for key, value in f.headers.items():
1.55 - if key.lower() != "content-type":
1.56 - cache_entry.write("%s: %s\n" % (key, value))
1.57 - cache_entry.write("\n")
1.58 + writeCacheHeaders(url, f.headers, cache_entry)
1.59 cache_entry.write(f.read())
1.60 finally:
1.61 - cache_entry.close()
1.62 f.close()
1.63
1.64 +def imapreader(url, cache_entry):
1.65 +
1.66 + """
1.67 + Retrieve data associated with the given 'url' using the IMAP protocol
1.68 + specifically, writing it to the 'cache_entry'.
1.69 + """
1.70 +
1.71 + # NOTE: Should use something like pykolab.imap_utf7.encode here.
1.72 +
1.73 + enc = lambda s: s.encode("utf-7")
1.74 +
1.75 + # The URL maps to credentials and folder details.
1.76 +
1.77 + scheme, netloc, path, query, fragment = urlsplit(url)
1.78 + credentials, location = splituser(netloc)
1.79 + username, password = map(unquote_plus, splitpasswd(credentials))
1.80 + host, port = splitport(location)
1.81 + folders = map(unquote_plus, path.split("/")[1:])
1.82 +
1.83 + # Connect and log in to the IMAP server.
1.84 +
1.85 + cls = scheme == "imaps" and imaplib.IMAP4_SSL or imaplib.IMAP4
1.86 +
1.87 + if port is None:
1.88 + i = cls(host)
1.89 + else:
1.90 + i = cls(host, int(port))
1.91 +
1.92 + i.login(username, password)
1.93 +
1.94 + try:
1.95 + # Descend to the desired folder.
1.96 +
1.97 + for folder in folders:
1.98 + code, response = i.select(enc(folder), readonly=True)
1.99 + if code != "OK":
1.100 + logging.warning("Could not enter folder: %s" % folder)
1.101 + raise IOError
1.102 +
1.103 + # Search for all messages.
1.104 + # NOTE: This could also be parameterised.
1.105 +
1.106 + code, response = i.search(None, "(ALL)")
1.107 +
1.108 + if code != "OK":
1.109 + logging.warning("Could not enter folder: %s" % folder)
1.110 + raise IOError
1.111 +
1.112 + # For each result, obtain the full message, but embed it in a larger
1.113 + # multipart message.
1.114 +
1.115 + message = MIMEMultipart()
1.116 +
1.117 + writeCacheHeaders(url, message, cache_entry)
1.118 +
1.119 + numbers = response and response[0].split(" ") or []
1.120 +
1.121 + for n in numbers:
1.122 + code, response = i.fetch(n, "(RFC822.PEEK)")
1.123 +
1.124 + if code == "OK" and response:
1.125 +
1.126 + # Write the message payload into the cache entry for later
1.127 + # processing.
1.128 +
1.129 + for data in response:
1.130 + try:
1.131 + envelope, body = data
1.132 + message.attach(Parser().parsestr(body))
1.133 + except ValueError:
1.134 + pass
1.135 + else:
1.136 + logging.warning("Could not obtain message %d from folder %s" % (n, folder))
1.137 +
1.138 + cache_entry.write(message.as_string())
1.139 +
1.140 + finally:
1.141 + i.logout()
1.142 + del i
1.143 +
1.144 +def writeCacheHeaders(url, headers, cache_entry):
1.145 +
1.146 + """
1.147 + For the given 'url', write it and the given 'headers' to the given
1.148 + 'cache_entry'.
1.149 + """
1.150 +
1.151 + cache_entry.write(url + "\n")
1.152 + cache_entry.write((headers.get("content-type") or "") + "\n")
1.153 + for key, value in headers.items():
1.154 + if key.lower() != "content-type":
1.155 + cache_entry.write("%s: %s\n" % (key, value))
1.156 + cache_entry.write("\n")
1.157 +
1.158 def getCachedResourceMetadata(f):
1.159
1.160 "Return a metadata dictionary for the given resource file-like object 'f'."