[Mailman-checkins] [Branch ~mailman-coders/mailman/3.0] (no title)

2007-08-01 Thread noreply

revno: 6536
committer: Barry Warsaw [EMAIL PROTECTED]
branch nick: 3.0
timestamp: Mon 2007-07-23 17:52:39 -0400
message:
  Remove an empty file
removed:
  Mailman/Site.py

=== removed file 'Mailman/Site.py'


--
(no title)
https://code.launchpad.net/~mailman-coders/mailman/3.0

You are receiving this branch notification because you are subscribed to it.
To unsubscribe from this branch go to 
https://code.launchpad.net/~mailman-coders/mailman/3.0/+subscription/mailman-checkins.
___
Mailman-checkins mailing list
Mailman-checkins@python.org
Unsubscribe: 
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org



[Mailman-checkins] [Branch ~mailman-coders/mailman/3.0] (no title)

2007-08-01 Thread noreply
1 revision was removed from the branch.


--
(no title)
https://code.launchpad.net/~mailman-coders/mailman/3.0

You are receiving this branch notification because you are subscribed to it.
To unsubscribe from this branch go to 
https://code.launchpad.net/~mailman-coders/mailman/3.0/+subscription/mailman-checkins.
___
Mailman-checkins mailing list
Mailman-checkins@python.org
Unsubscribe: 
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org



[Mailman-checkins] [Branch ~mailman-coders/mailman/3.0] (no title)

2007-08-01 Thread noreply

revno: 6538
committer: Barry Warsaw [EMAIL PROTECTED]
branch nick: 3.0
timestamp: Wed 2007-08-01 17:05:06 -0400
message:
  Repair some test suite regressions.
modified:
  Mailman/Handlers/Hold.py
  Mailman/LockFile.py
  Mailman/Message.py
  Mailman/Queue/NewsRunner.py
  Mailman/docs/addresses.txt
  Mailman/docs/hold.txt
  Mailman/docs/news-runner.txt
  Mailman/docs/pending.txt

=== modified file 'Mailman/Handlers/Hold.py'
--- a/Mailman/Handlers/Hold.py  2007-08-01 20:11:08 +
+++ b/Mailman/Handlers/Hold.py  2007-08-01 21:05:06 +
@@ -35,12 +35,14 @@
 from email.mime.message import MIMEMessage
 from email.mime.text import MIMEText
 from types import ClassType
+from zope.interface import implements
 
 from Mailman import Errors
 from Mailman import Message
-from Mailman import Pending
 from Mailman import Utils
 from Mailman import i18n
+from Mailman.configuration import config
+from Mailman.interfaces import IPendable, IPending
 
 log = logging.getLogger('mailman.vette')
 
@@ -129,6 +131,12 @@
 
 
 
+class HeldMessagePendable(dict):
+implements(IPendable)
+PEND_KEY = 'held message'
+
+
+
 def process(mlist, msg, msgdata):
 if msgdata.get('approved'):
 return
@@ -239,7 +247,9 @@
 #
 # This message should appear to come from list-admin so as to handle any
 # bounce processing that might be needed.
-cookie = mlist.pend_new(Pending.HELD_MESSAGE, id)
+pendable = HeldMessagePendable(type=HeldMessagePendable.PEND_KEY,
+   id=str(id))
+token = IPending(config.db).add(pendable)
 # Get the language to send the response in.  If the sender is a member,
 # then send it in the member's language, otherwise send it in the mailing
 # list's preferred language.
@@ -247,9 +257,9 @@
 lang = (member.preferred_language if member else mlist.preferred_language)
 if not fromusenet and ackp(msg) and mlist.respond_to_post_requests and \
mlist.autorespondToSender(sender, lang):
-# Get a confirmation cookie
+# Get a confirmation token
 d['confirmurl'] = '%s/%s' % (mlist.GetScriptURL('confirm', absolute=1),
- cookie)
+ token)
 lang = msgdata.get('lang', lang)
 subject = _('Your message to $listname awaits moderator approval')
 text = Utils.maketext('postheld.txt', d, lang=lang, mlist=mlist)
@@ -284,7 +294,7 @@
 message will be approved for posting to the list.  The Approved: header can
 also appear in the first line of the body of the reply.)),
 _charset=Utils.GetCharSet(lang))
-dmsg['Subject'] = 'confirm ' + cookie
+dmsg['Subject'] = 'confirm ' + token
 dmsg['Sender'] = requestaddr
 dmsg['From'] = requestaddr
 dmsg['Date'] = email.utils.formatdate(localtime=True)

=== modified file 'Mailman/LockFile.py'
--- a/Mailman/LockFile.py   2007-05-28 20:21:41 +
+++ b/Mailman/LockFile.py   2007-08-01 21:05:06 +
@@ -59,12 +59,13 @@
 import random
 import socket
 import logging
+import datetime
 import traceback
 
 # Units are floating-point seconds.
-DEFAULT_LOCK_LIFETIME  = 15
+DEFAULT_LOCK_LIFETIME  = datetime.timedelta(seconds=15)
 # Allowable a bit of clock skew
-CLOCK_SLOP = 10
+CLOCK_SLOP = datetime.timedelta(seconds=10)
 # This is appropriate for Mailman, but you may want to change this if you're
 # using this code outside Mailman.
 log = logging.getLogger('mailman.locks')
@@ -95,8 +96,8 @@
 Create the resource lock using lockfile as the global lock file.  Each
 process laying claim to this resource lock will create their own
 temporary lock files based on the path specified by lockfile.
-Optional lifetime is the number of seconds the process expects to hold
-the lock.
+Optional lifetime is a timedelta specifying the number of seconds the
+process expects to hold the lock.
 
 set_lifetime(lifetime):
 Set a new lock lifetime.  This takes affect the next time the file is
@@ -155,7 +156,7 @@
 self._owned = True
 
 def __repr__(self):
-return 'LockFile %s: %s [%s: %ssec] pid=%s' % (
+return 'LockFile %s: %s [%s: %s] pid=%s' % (
 id(self), self._lockfile,
 self.locked() and 'locked' or 'unlocked',
 self._lifetime, os.getpid())
@@ -400,7 +401,8 @@
 return None
 
 def _touch(self, filename=None):
-t = time.time() + self._lifetime
+expiration_date = datetime.datetime.now() + self._lifetime
+t = time.mktime(expiration_date.timetuple())
 try:
 # XXX We probably don't need to modify atime, but this is easier.
 os.utime(filename or self._tmpfname, (t, t))

=== modified file 'Mailman/Message.py'
--- a/Mailman/Message.py2007-08-01 20:11:08 +
+++ 

[Mailman-checkins] [Branch ~mailman-coders/mailman/3.0] (no title)

2007-08-01 Thread noreply

revno: 6534
committer: Barry Warsaw [EMAIL PROTECTED]
branch nick: 3.0
timestamp: Sun 2007-07-22 19:52:34 -0400
message:
  The start of a message store definition.  Whether this will end up being used
  for the archive or not is left to be seen.
  
  Define an interface, test, and implementation of a basic message store using
  globally unique identifiers of the form: archive/hash/seqno
  
  - archive is the base url of the archive, e.g. http://archives.example.com.
This is available in the List-Archive header.
  - hash is the base32 encoded sha1 hash of the message's Message-ID and Date
headers, which it must have.  This is available in the X-List-ID-Hash
header.
  - seqno is a sequence number specific to the archive which will uniquely
identify the message should there be a Message-ID/Date collision.  this is
available in the X-List-Sequence-Number header.
  
  Added a MESSAGES_DIR variable to the config.
  
  Added a .message_store attribute to the config.
added:
  Mailman/database/messagestore.py
  Mailman/database/model/message.py
  Mailman/docs/messagestore.txt
  Mailman/interfaces/messagestore.py
modified:
  Mailman/configuration.py
  Mailman/database/__init__.py
  Mailman/database/model/__init__.py
  Mailman/docs/archives.txt

=== added file 'Mailman/database/messagestore.py'
--- a/Mailman/database/messagestore.py  1970-01-01 00:00:00 +
+++ b/Mailman/database/messagestore.py  2007-07-22 23:52:34 +
@@ -0,0 +1,140 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+from __future__ import with_statement
+
+__metaclass__ = type
+__all__ = [
+'MessageStore',
+]
+
+import os
+import errno
+import base64
+import hashlib
+import cPickle as pickle
+
+from zope.interface import implements
+
+from Mailman import Utils
+from Mailman.configuration import config
+from Mailman.database.model import Message
+from Mailman.interfaces import IMessageStore
+
+# It could be very bad if you have already stored files and you change this
+# value.  We'd need a script to reshuffle and resplit.
+MAX_SPLITS = 2
+EMPTYSTRING = ''
+
+
+
+class MessageStore:
+implements(IMessageStore)
+
+def add(self, message):
+# Ensure that the message has the requisite headers.
+message_ids = message.get_all('message-id', [])
+dates = message.get_all('date', [])
+if not (len(message_ids) == 1 and len(dates) == 1):
+raise ValueError(
+'Exactly one Message-ID and one Date header required')
+# Calculate and insert the X-List-ID-Hash.
+message_id = message_ids[0]
+date = dates[0]
+shaobj = hashlib.sha1(message_id)
+shaobj.update(date)
+hash32 = base64.b32encode(shaobj.digest())
+del message['X-List-ID-Hash']
+message['X-List-ID-Hash'] = hash32
+# Calculate the path on disk where we're going to store this message
+# object, in pickled format.
+parts = []
+split = list(hash32)
+while split and len(parts)  MAX_SPLITS:
+parts.append(split.pop(0) + split.pop(0))
+parts.append(EMPTYSTRING.join(split))
+relpath = os.path.join(*parts)
+# Store the message in the database.  This relies on the database
+# providing a unique serial number, but to get this information, we
+# have to use a straight insert instead of relying on Elixir to create
+# the object.
+result = Message.table.insert().execute(
+hash=hash32, path=relpath, message_id=message_id)
+# Add the additional header.
+seqno = result.last_inserted_ids()[0]
+del message['X-List-Sequence-Number']
+message['X-List-Sequence-Number'] = str(seqno)
+# Now calculate the full file system path.
+path = os.path.join(config.MESSAGES_DIR, relpath, str(seqno))
+# Write the file to the path, but catch the appropriate exception in
+# case the parent directories don't yet exist.  In that case, create
+# them and try again.
+while True:
+try:
+with open(path, 'w') as fp:
+# -1 says to use the highest protocol available.
+ 

[Mailman-checkins] [Branch ~mailman-coders/mailman/3.0] (no title)

2007-08-01 Thread noreply

revno: 6535
committer: Barry Warsaw [EMAIL PROTECTED]
branch nick: 3.0
timestamp: Mon 2007-07-23 01:57:48 -0400
message:
  Remove last vestiges of dbcontext
removed:
  Mailman/database/dbcontext.py
modified:
  Mailman/bin/testall.py

=== removed file 'Mailman/database/dbcontext.py'
--- a/Mailman/database/dbcontext.py 2007-05-28 20:21:41 +
+++ b/Mailman/database/dbcontext.py 1970-01-01 00:00:00 +
@@ -1,174 +0,0 @@
-# Copyright (C) 2006-2007 by the Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-import os
-import sys
-import logging
-import weakref
-
-from elixir import create_all, metadata, objectstore
-from sqlalchemy import create_engine
-from string import Template
-from urlparse import urlparse
-
-from Mailman import Version
-from Mailman.configuration import config
-from Mailman.database.txnsupport import txn
-
-
-
-class MlistRef(weakref.ref):
-def __init__(self, mlist, callback):
-super(MlistRef, self).__init__(mlist, callback)
-self.fqdn_listname = mlist.fqdn_listname
-
-
-
-class DBContext(object):
-def __init__(self):
-# Special transaction used only for MailList.Lock() .Save() and
-# .Unlock() interface.
-self._mlist_txns = {}
-
-def connect(self):
-# Calculate the engine url
-url = Template(config.SQLALCHEMY_ENGINE_URL).safe_substitute(
-config.paths)
-# XXX By design of SQLite, database file creation does not honor
-# umask.  See their ticket #1193:
-# http://www.sqlite.org/cvstrac/tktview?tn=1193,31
-#
-# This sucks for us because the mailman.db file /must/ be group
-# writable, however even though we guarantee our umask is 002 here, it
-# still gets created without the necessary g+w permission, due to
-# SQLite's policy.  This should only affect SQLite engines because its
-# the only one that creates a little file on the local file system.
-# This kludges around their bug by touching the database file before
-# SQLite has any chance to create it, thus honoring the umask and
-# ensuring the right permissions.  We only try to do this for SQLite
-# engines, and yes, we could have chmod'd the file after the fact, but
-# half dozen and all...
-self._touch(url)
-engine = create_engine(url)
-engine.echo = config.SQLALCHEMY_ECHO
-metadata.connect(engine)
-# Load and create the Elixir active records.  This works by
-# side-effect.
-import Mailman.database.model
-create_all()
-# Validate schema version.
-v = Mailman.database.model.Version.get_by(component='schema')
-if not v:
-# Database has not yet been initialized
-v = Mailman.database.model.Version(
-component='schema',
-version=Version.DATABASE_SCHEMA_VERSION)
-objectstore.flush()
-elif v.version  Version.DATABASE_SCHEMA_VERSION:
-# XXX Update schema
-raise SchemaVersionMismatchError(v.version)
-
-def _touch(self, url):
-parts = urlparse(url)
-if parts.scheme  'sqlite':
-return
-path = os.path.normpath(parts.path)
-fd = os.open(path, os.O_WRONLY |  os.O_NONBLOCK | os.O_CREAT, 0666)
-# Ignore errors
-if fd  0:
-os.close(fd)
-
-# Cooperative method for use with @txn decorator
-def _withtxn(self, meth, *args, **kws):
-try:
-txn = objectstore.session.current.create_transaction()
-rtn = meth(*args, **kws)
-except:
-txn.rollback()
-raise
-else:
-txn.commit()
-return rtn
-
-def _unlock_mref(self, mref):
-txn = self._mlist_txns.pop(mref.fqdn_listname, None)
-if txn is not None:
-txn.rollback()
-
-# Higher level interface
-def api_lock(self, mlist):
-# Don't try to re-lock a list
-if mlist.fqdn_listname in self._mlist_txns:
-return
-txn = objectstore.session.current.create_transaction()
-mref = MlistRef(mlist, self._unlock_mref)
-# If