Index: third_party/twisted_8_1/twisted/mail/maildir.py |
diff --git a/third_party/twisted_8_1/twisted/mail/maildir.py b/third_party/twisted_8_1/twisted/mail/maildir.py |
deleted file mode 100644 |
index 439e92e38a383257d69c1750c21ef88bb069bb45..0000000000000000000000000000000000000000 |
--- a/third_party/twisted_8_1/twisted/mail/maildir.py |
+++ /dev/null |
@@ -1,459 +0,0 @@ |
-# -*- test-case-name: twisted.mail.test.test_mail -*- |
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories. |
-# See LICENSE for details. |
- |
- |
-"""Maildir-style mailbox support |
-""" |
- |
-from __future__ import generators |
- |
-import os |
-import stat |
-import socket |
-import time |
-import md5 |
-import cStringIO |
- |
-from zope.interface import implements |
- |
-try: |
- import cStringIO as StringIO |
-except ImportError: |
- import StringIO |
- |
-from twisted.mail import pop3 |
-from twisted.mail import smtp |
-from twisted.protocols import basic |
-from twisted.persisted import dirdbm |
-from twisted.python import log, failure |
-from twisted.mail import mail |
-from twisted.mail import alias |
-from twisted.internet import interfaces, defer, reactor |
- |
-from twisted import cred |
-import twisted.cred.portal |
-import twisted.cred.credentials |
-import twisted.cred.checkers |
-import twisted.cred.error |
- |
-INTERNAL_ERROR = '''\ |
-From: Twisted.mail Internals |
-Subject: An Error Occurred |
- |
- An internal server error has occurred. Please contact the |
- server administrator. |
-''' |
- |
-class _MaildirNameGenerator: |
- """Utility class to generate a unique maildir name |
- """ |
- n = 0 |
- p = os.getpid() |
- s = socket.gethostname().replace('/', r'\057').replace(':', r'\072') |
- |
- def generate(self): |
- self.n = self.n + 1 |
- t = time.time() |
- seconds = str(int(t)) |
- microseconds = str(int((t-int(t))*10e6)) |
- return '%s.M%sP%sQ%s.%s' % (seconds, microseconds, |
- self.p, self.n, self.s) |
- |
-_generateMaildirName = _MaildirNameGenerator().generate |
- |
-def initializeMaildir(dir): |
- if not os.path.isdir(dir): |
- os.mkdir(dir, 0700) |
- for subdir in ['new', 'cur', 'tmp', '.Trash']: |
- os.mkdir(os.path.join(dir, subdir), 0700) |
- for subdir in ['new', 'cur', 'tmp']: |
- os.mkdir(os.path.join(dir, '.Trash', subdir), 0700) |
- # touch |
- open(os.path.join(dir, '.Trash', 'maildirfolder'), 'w').close() |
- |
- |
-class MaildirMessage(mail.FileMessage): |
- size = None |
- |
- def __init__(self, address, fp, *a, **kw): |
- header = "Delivered-To: %s\n" % address |
- fp.write(header) |
- self.size = len(header) |
- mail.FileMessage.__init__(self, fp, *a, **kw) |
- |
- def lineReceived(self, line): |
- mail.FileMessage.lineReceived(self, line) |
- self.size += len(line)+1 |
- |
- def eomReceived(self): |
- self.finalName = self.finalName+',S=%d' % self.size |
- return mail.FileMessage.eomReceived(self) |
- |
-class AbstractMaildirDomain: |
- """Abstract maildir-backed domain. |
- """ |
- alias = None |
- root = None |
- |
- def __init__(self, service, root): |
- """Initialize. |
- """ |
- self.root = root |
- |
- def userDirectory(self, user): |
- """Get the maildir directory for a given user |
- |
- Override to specify where to save mails for users. |
- Return None for non-existing users. |
- """ |
- return None |
- |
- ## |
- ## IAliasableDomain |
- ## |
- |
- def setAliasGroup(self, alias): |
- self.alias = alias |
- |
- ## |
- ## IDomain |
- ## |
- def exists(self, user, memo=None): |
- """Check for existence of user in the domain |
- """ |
- if self.userDirectory(user.dest.local) is not None: |
- return lambda: self.startMessage(user) |
- try: |
- a = self.alias[user.dest.local] |
- except: |
- raise smtp.SMTPBadRcpt(user) |
- else: |
- aliases = a.resolve(self.alias, memo) |
- if aliases: |
- return lambda: aliases |
- log.err("Bad alias configuration: " + str(user)) |
- raise smtp.SMTPBadRcpt(user) |
- |
- def startMessage(self, user): |
- """Save a message for a given user |
- """ |
- if isinstance(user, str): |
- name, domain = user.split('@', 1) |
- else: |
- name, domain = user.dest.local, user.dest.domain |
- dir = self.userDirectory(name) |
- fname = _generateMaildirName() |
- filename = os.path.join(dir, 'tmp', fname) |
- fp = open(filename, 'w') |
- return MaildirMessage('%s@%s' % (name, domain), fp, filename, |
- os.path.join(dir, 'new', fname)) |
- |
- def willRelay(self, user, protocol): |
- return False |
- |
- def addUser(self, user, password): |
- raise NotImplementedError |
- |
- def getCredentialsCheckers(self): |
- raise NotImplementedError |
- ## |
- ## end of IDomain |
- ## |
- |
-class _MaildirMailboxAppendMessageTask: |
- implements(interfaces.IConsumer) |
- |
- osopen = staticmethod(os.open) |
- oswrite = staticmethod(os.write) |
- osclose = staticmethod(os.close) |
- osrename = staticmethod(os.rename) |
- |
- def __init__(self, mbox, msg): |
- self.mbox = mbox |
- self.defer = defer.Deferred() |
- self.openCall = None |
- if not hasattr(msg, "read"): |
- msg = StringIO.StringIO(msg) |
- self.msg = msg |
- # This is needed, as this startup phase might call defer.errback and zero out self.defer |
- # By doing it on the reactor iteration appendMessage is able to use .defer without problems. |
- reactor.callLater(0, self.startUp) |
- |
- def startUp(self): |
- self.createTempFile() |
- if self.fh != -1: |
- self.filesender = basic.FileSender() |
- self.filesender.beginFileTransfer(self.msg, self) |
- |
- def registerProducer(self, producer, streaming): |
- self.myproducer = producer |
- self.streaming = streaming |
- if not streaming: |
- self.prodProducer() |
- |
- def prodProducer(self): |
- self.openCall = None |
- if self.myproducer is not None: |
- self.openCall = reactor.callLater(0, self.prodProducer) |
- self.myproducer.resumeProducing() |
- |
- def unregisterProducer(self): |
- self.myproducer = None |
- self.streaming = None |
- self.osclose(self.fh) |
- self.moveFileToNew() |
- |
- def write(self, data): |
- try: |
- self.oswrite(self.fh, data) |
- except: |
- self.fail() |
- |
- def fail(self, err=None): |
- if err is None: |
- err = failure.Failure() |
- if self.openCall is not None: |
- self.openCall.cancel() |
- self.defer.errback(err) |
- self.defer = None |
- |
- def moveFileToNew(self): |
- while True: |
- newname = os.path.join(self.mbox.path, "new", _generateMaildirName()) |
- try: |
- self.osrename(self.tmpname, newname) |
- break |
- except OSError, (err, estr): |
- import errno |
- # if the newname exists, retry with a new newname. |
- if err != errno.EEXIST: |
- self.fail() |
- newname = None |
- break |
- if newname is not None: |
- self.mbox.list.append(newname) |
- self.defer.callback(None) |
- self.defer = None |
- |
- def createTempFile(self): |
- attr = (os.O_RDWR | os.O_CREAT | os.O_EXCL |
- | getattr(os, "O_NOINHERIT", 0) |
- | getattr(os, "O_NOFOLLOW", 0)) |
- tries = 0 |
- self.fh = -1 |
- while True: |
- self.tmpname = os.path.join(self.mbox.path, "tmp", _generateMaildirName()) |
- try: |
- self.fh = self.osopen(self.tmpname, attr, 0600) |
- return None |
- except OSError: |
- tries += 1 |
- if tries > 500: |
- self.defer.errback(RuntimeError("Could not create tmp file for %s" % self.mbox.path)) |
- self.defer = None |
- return None |
- |
-class MaildirMailbox(pop3.Mailbox): |
- """Implement the POP3 mailbox semantics for a Maildir mailbox |
- """ |
- AppendFactory = _MaildirMailboxAppendMessageTask |
- |
- def __init__(self, path): |
- """Initialize with name of the Maildir mailbox |
- """ |
- self.path = path |
- self.list = [] |
- self.deleted = {} |
- initializeMaildir(path) |
- for name in ('cur', 'new'): |
- for file in os.listdir(os.path.join(path, name)): |
- self.list.append((file, os.path.join(path, name, file))) |
- self.list.sort() |
- self.list = [e[1] for e in self.list] |
- |
- def listMessages(self, i=None): |
- """Return a list of lengths of all files in new/ and cur/ |
- """ |
- if i is None: |
- ret = [] |
- for mess in self.list: |
- if mess: |
- ret.append(os.stat(mess)[stat.ST_SIZE]) |
- else: |
- ret.append(0) |
- return ret |
- return self.list[i] and os.stat(self.list[i])[stat.ST_SIZE] or 0 |
- |
- def getMessage(self, i): |
- """Return an open file-pointer to a message |
- """ |
- return open(self.list[i]) |
- |
- def getUidl(self, i): |
- """Return a unique identifier for a message |
- |
- This is done using the basename of the filename. |
- It is globally unique because this is how Maildirs are designed. |
- """ |
- # Returning the actual filename is a mistake. Hash it. |
- base = os.path.basename(self.list[i]) |
- return md5.md5(base).hexdigest() |
- |
- def deleteMessage(self, i): |
- """Delete a message |
- |
- This only moves a message to the .Trash/ subfolder, |
- so it can be undeleted by an administrator. |
- """ |
- trashFile = os.path.join( |
- self.path, '.Trash', 'cur', os.path.basename(self.list[i]) |
- ) |
- os.rename(self.list[i], trashFile) |
- self.deleted[self.list[i]] = trashFile |
- self.list[i] = 0 |
- |
- def undeleteMessages(self): |
- """Undelete any deleted messages it is possible to undelete |
- |
- This moves any messages from .Trash/ subfolder back to their |
- original position, and empties out the deleted dictionary. |
- """ |
- for (real, trash) in self.deleted.items(): |
- try: |
- os.rename(trash, real) |
- except OSError, (err, estr): |
- import errno |
- # If the file has been deleted from disk, oh well! |
- if err != errno.ENOENT: |
- raise |
- # This is a pass |
- else: |
- try: |
- self.list[self.list.index(0)] = real |
- except ValueError: |
- self.list.append(real) |
- self.deleted.clear() |
- |
- def appendMessage(self, txt): |
- """Appends a message into the mailbox.""" |
- task = self.AppendFactory(self, txt) |
- return task.defer |
- |
-class StringListMailbox: |
- implements(pop3.IMailbox) |
- |
- def __init__(self, msgs): |
- self.msgs = msgs |
- |
- def listMessages(self, i=None): |
- if i is None: |
- return map(len, self.msgs) |
- return len(self.msgs[i]) |
- |
- def getMessage(self, i): |
- return StringIO.StringIO(self.msgs[i]) |
- |
- def getUidl(self, i): |
- return md5.new(self.msgs[i]).hexdigest() |
- |
- def deleteMessage(self, i): |
- pass |
- |
- def undeleteMessages(self): |
- pass |
- |
- def sync(self): |
- pass |
- |
-class MaildirDirdbmDomain(AbstractMaildirDomain): |
- """A Maildir Domain where membership is checked by a dirdbm file |
- """ |
- |
- implements(cred.portal.IRealm, mail.IAliasableDomain) |
- |
- portal = None |
- _credcheckers = None |
- |
- def __init__(self, service, root, postmaster=0): |
- """Initialize |
- |
- The first argument is where the Domain directory is rooted. |
- The second is whether non-existing addresses are simply |
- forwarded to postmaster instead of outright bounce |
- |
- The directory structure of a MailddirDirdbmDomain is: |
- |
- /passwd <-- a dirdbm file |
- /USER/{cur,new,del} <-- each user has these three directories |
- """ |
- AbstractMaildirDomain.__init__(self, service, root) |
- dbm = os.path.join(root, 'passwd') |
- if not os.path.exists(dbm): |
- os.makedirs(dbm) |
- self.dbm = dirdbm.open(dbm) |
- self.postmaster = postmaster |
- |
- def userDirectory(self, name): |
- """Get the directory for a user |
- |
- If the user exists in the dirdbm file, return the directory |
- os.path.join(root, name), creating it if necessary. |
- Otherwise, returns postmaster's mailbox instead if bounces |
- go to postmaster, otherwise return None |
- """ |
- if not self.dbm.has_key(name): |
- if not self.postmaster: |
- return None |
- name = 'postmaster' |
- dir = os.path.join(self.root, name) |
- if not os.path.exists(dir): |
- initializeMaildir(dir) |
- return dir |
- |
- ## |
- ## IDomain |
- ## |
- def addUser(self, user, password): |
- self.dbm[user] = password |
- # Ensure it is initialized |
- self.userDirectory(user) |
- |
- def getCredentialsCheckers(self): |
- if self._credcheckers is None: |
- self._credcheckers = [DirdbmDatabase(self.dbm)] |
- return self._credcheckers |
- |
- ## |
- ## IRealm |
- ## |
- def requestAvatar(self, avatarId, mind, *interfaces): |
- if pop3.IMailbox not in interfaces: |
- raise NotImplementedError("No interface") |
- if avatarId == cred.checkers.ANONYMOUS: |
- mbox = StringListMailbox([INTERNAL_ERROR]) |
- else: |
- mbox = MaildirMailbox(os.path.join(self.root, avatarId)) |
- |
- return ( |
- pop3.IMailbox, |
- mbox, |
- lambda: None |
- ) |
- |
-class DirdbmDatabase: |
- implements(cred.checkers.ICredentialsChecker) |
- |
- credentialInterfaces = ( |
- cred.credentials.IUsernamePassword, |
- cred.credentials.IUsernameHashedPassword |
- ) |
- |
- def __init__(self, dbm): |
- self.dirdbm = dbm |
- |
- def requestAvatarId(self, c): |
- if c.username in self.dirdbm: |
- if c.checkPassword(self.dirdbm[c.username]): |
- return c.username |
- raise cred.error.UnauthorizedLogin() |