Add support for alternative message date synchronisation
Global or per-repository option utime_from_message tells OfflineIMAP to set file modification time of messages pushed from one repository to another basing on the message's "Date" header. This is useful if you are doing some processing/finding on your Maildir (for example, finding messages older than 3 months), without parsing each file/message content. From: Cyril RUSSO <boite.pour.spam@gmail.com> Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
This commit is contained in:
parent
e26827c1cb
commit
3bc66c0858
@ -21,6 +21,8 @@ WIP (add new stuff for the next release)
|
||||
(Steve Purcell)
|
||||
* Make the list of authentication mechanisms to be configurable.
|
||||
(Andreas Mack)
|
||||
* Allow to set message access and modification timestamps based
|
||||
on the "Date" header of the message itself. (Cyril Russo)
|
||||
|
||||
OfflineIMAP v6.5.5-rc1 (2012-09-05)
|
||||
===================================
|
||||
|
38
offlineimap/emailutil.py
Normal file
38
offlineimap/emailutil.py
Normal file
@ -0,0 +1,38 @@
|
||||
# Some useful functions to extract data out of emails
|
||||
# Copyright (C) 2002-2012 John Goerzen & contributors
|
||||
#
|
||||
# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import email
|
||||
from email.Parser import Parser as MailParser
|
||||
import time
|
||||
|
||||
def get_message_date(content, header='Date'):
|
||||
"""
|
||||
Parses mail and returns resulting timestamp.
|
||||
|
||||
:param header: the header to extract date from;
|
||||
:returns: timestamp or `None` in the case of failure.
|
||||
|
||||
"""
|
||||
message = MailParser().parsestr(content, True)
|
||||
dateheader = message.get(header)
|
||||
# parsedate_tz returns a 10-tuple that can be passed to mktime_tz
|
||||
# Will be None if missing or not in a valid format. Note that
|
||||
# indexes 6, 7, and 8 of the result tuple are not usable.
|
||||
datetuple = email.utils.parsedate_tz(dateheader)
|
||||
if datetuple is None:
|
||||
return None
|
||||
return email.utils.mktime_tz(datetuple)
|
@ -15,7 +15,7 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
from offlineimap import threadutil
|
||||
from offlineimap import threadutil, emailutil
|
||||
from offlineimap import globals
|
||||
from offlineimap.ui import getglobalui
|
||||
from offlineimap.error import OfflineImapError
|
||||
@ -48,6 +48,13 @@ class BaseFolder(object):
|
||||
if self.visiblename == self.getsep():
|
||||
self.visiblename = ''
|
||||
self.config = repository.getconfig()
|
||||
utime_from_message_global = \
|
||||
self.config.getdefaultboolean("general",
|
||||
"utime_from_message", False)
|
||||
repo = "Repository " + repository.name
|
||||
self._utime_from_message = \
|
||||
self.config.getdefaultboolean(repo,
|
||||
"utime_from_message", utime_from_message_global)
|
||||
|
||||
def getname(self):
|
||||
"""Returns name"""
|
||||
@ -66,6 +73,10 @@ class BaseFolder(object):
|
||||
"""Should this folder be synced or is it e.g. filtered out?"""
|
||||
return self._sync_this
|
||||
|
||||
@property
|
||||
def utime_from_message(self):
|
||||
return self._utime_from_message
|
||||
|
||||
def suggeststhreads(self):
|
||||
"""Returns true if this folder suggests using threads for actions;
|
||||
false otherwise. Probably only IMAP will return true."""
|
||||
@ -327,6 +338,9 @@ class BaseFolder(object):
|
||||
message = None
|
||||
flags = self.getmessageflags(uid)
|
||||
rtime = self.getmessagetime(uid)
|
||||
if dstfolder.utime_from_message:
|
||||
content = self.getmessage(uid)
|
||||
rtime = emailutil.get_message_date(content, 'Date')
|
||||
|
||||
if uid > 0 and dstfolder.uidexists(uid):
|
||||
# dst has message with that UID already, only update status
|
||||
|
@ -15,14 +15,13 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import email
|
||||
import random
|
||||
import binascii
|
||||
import re
|
||||
import time
|
||||
from sys import exc_info
|
||||
from .Base import BaseFolder
|
||||
from offlineimap import imaputil, imaplibutil, OfflineImapError
|
||||
from offlineimap import imaputil, imaplibutil, emailutil, OfflineImapError
|
||||
from offlineimap import globals
|
||||
from offlineimap.imaplib2 import MonthNames
|
||||
|
||||
@ -431,21 +430,12 @@ class IMAPFolder(BaseFolder):
|
||||
:returns: string in the form of "DD-Mmm-YYYY HH:MM:SS +HHMM"
|
||||
(including double quotes) or `None` in case of failure
|
||||
(which is fine as value for append)."""
|
||||
|
||||
if rtime is None:
|
||||
message = email.message_from_string(content)
|
||||
dateheader = message.get('Date')
|
||||
# parsedate_tz returns a 10-tuple that can be passed to mktime_tz;
|
||||
# Will be None if missing or not in a valid format. Note that
|
||||
# indexes 6, 7, and 8 of the result tuple are not usable.
|
||||
datetuple = email.utils.parsedate_tz(dateheader)
|
||||
if datetuple is None:
|
||||
#could not determine the date, use the local time.
|
||||
rtime = emailutil.get_message_date(content)
|
||||
if rtime == None:
|
||||
return None
|
||||
#make it a real struct_time, so we have named attributes
|
||||
datetuple = time.localtime(email.utils.mktime_tz(datetuple))
|
||||
else:
|
||||
#rtime is set, use that instead
|
||||
datetuple = time.localtime(rtime)
|
||||
datetuple = time.localtime(rtime)
|
||||
|
||||
try:
|
||||
# Check for invalid dates
|
||||
|
Loading…
Reference in New Issue
Block a user