|
/
Zope
/
gocept svn checkins
/
Archive
/
2010
/
2010-02
/
SVN: r30566 - webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail
[
SVN: r30532 - gocept.paltrydirectory / Christian ... ]
[
SVN: r30586 - webmailer/mytum.webmail/trunk / ... ]
SVN: r30566 - webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail
Thomas Lotze <tl(at)gocept.com> |
2010-02-01 17:22:13 |
[ FULL ]
|
Author: thomas
Date: Mon Feb 1 17:22:11 2010
New Revision: 30566
Log:
log an error whenever an invalid message sort criterion is requested by the UI
Modified:
webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail/draft.py
webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail/imapaccount.py
Modified:
webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail/draft.py
==============================================================================
---
webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail/draft.py (original)
+++ webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail/draft.py Mon
Feb 1 17:22:11 2010
(at)(at) -11,6 +11,7 (at)(at)
import email.MIMEBase
import email.Parser
import email.Utils
+import logging
import os
import os.path
import shutil
(at)(at) -38,6 +39,8 (at)(at)
parser = email.Parser.Parser()
+log = logging.getLogger('gocept.restmail')
+
def split(line):
r"""Split an address line into words and chunks of non-word characters.
(at)(at) -94,6 +97,8 (at)(at)
if sort_by in ('to', 'subject', 'date'):
messages = sorted(messages, key=lambda x:getattr(x, sort_by),
reverse=sort_dir == 'desc')
+ else:
+ log.error('Invalid sort criterion (drafts): %r' % sort_by)
return [message for message in messages[i:j]]
Modified:
webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail/imapaccount.py
==============================================================================
---
webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail/imapaccount.py (original)
+++
webmailer/gocept.restmail/branches/4892-jquery/gocept/restmail/imapaccount.py Mon
Feb 1 17:22:11 2010
(at)(at) -15,6 +15,7 (at)(at)
import gocept.imapapi.folder
import gocept.imapapi.interfaces
import gocept.restmail.interfaces
+import logging
import pytz
import tempfile
import transaction
(at)(at) -22,6 +23,9 (at)(at)
import zope.interface
+log = logging.getLogger('gocept.restmail')
+
+
class IMAPAccount(ObjectManager, PropertyManager, Item):
"""A delegate for the gocept.imapapi account object."""
(at)(at) -258,6 +262,7 (at)(at)
def filtered_messages(self, sort_by, sort_dir='asc', i=0, j=None):
if sort_by not in ('from_name', 'subject', 'date'):
+ log.error('Invalid sort criterion (imap): %r' % sort_by)
sort_by = ''
messages = self.folder.messages.filtered(sort_by, sort_dir)
return [Message(message).__of__(self.aq_inner)
|
SVN: r30567 - webmailer/gocept.restmail/trunk/gocept/restmail
Thomas Lotze <tl(at)gocept.com> |
2010-02-01 17:27:57 |
[ FULL ]
|
Author: thomas
Date: Mon Feb 1 17:27:56 2010
New Revision: 30567
Log:
log an error whenever an invalid message sort criterion is requested by the UI
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/draft.py
webmailer/gocept.restmail/trunk/gocept/restmail/imapaccount.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/draft.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/draft.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/draft.py Mon Feb 1
17:27:56 2010
(at)(at) -11,6 +11,7 (at)(at)
import email.MIMEBase
import email.Parser
import email.Utils
+import logging
import os
import os.path
import shutil
(at)(at) -38,6 +39,8 (at)(at)
parser = email.Parser.Parser()
+log = logging.getLogger('gocept.restmail')
+
def split(line):
r"""Split an address line into words and chunks of non-word characters.
(at)(at) -94,6 +97,8 (at)(at)
if sort_by in ('to', 'subject', 'date'):
messages = sorted(messages, key=lambda x:getattr(x, sort_by),
reverse=sort_dir == 'desc')
+ else:
+ log.error('Invalid sort criterion (drafts): %r' % sort_by)
return [message for message in messages[i:j]]
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/imapaccount.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/imapaccount.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/imapaccount.py Mon Feb 1
17:27:56 2010
(at)(at) -15,6 +15,7 (at)(at)
import gocept.imapapi.folder
import gocept.imapapi.interfaces
import gocept.restmail.interfaces
+import logging
import pytz
import tempfile
import transaction
(at)(at) -22,6 +23,9 (at)(at)
import zope.interface
+log = logging.getLogger('gocept.restmail')
+
+
class IMAPAccount(ObjectManager, PropertyManager, Item):
"""A delegate for the gocept.imapapi account object."""
(at)(at) -258,6 +262,7 (at)(at)
def filtered_messages(self, sort_by, sort_dir='asc', i=0, j=None):
if sort_by not in ('from_name', 'subject', 'date'):
+ log.error('Invalid sort criterion (imap): %r' % sort_by)
sort_by = ''
messages = self.folder.messages.filtered(sort_by, sort_dir)
return [Message(message).__of__(self.aq_inner)
|
SVN: r30568 - webmailer/gocept.imapapi/trunk/gocept/imapapi
Thomas Lotze <tl(at)gocept.com> |
2010-02-02 16:53:34 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 2 16:53:32 2010
New Revision: 30568
Log:
caught a certain case of an empty IMAP response that could cause a
StopIteration traceback, added some traceback info to track down another
Modified:
webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py
Modified: webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py
==============================================================================
--- webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py (original)
+++ webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py Tue Feb 2
16:53:32 2010
(at)(at) -559,7 +559,9 (at)(at)
self._store(flag, '-')
def _update(self, data=None):
- if data is None:
+ if data is None or data == [None]:
+ # None: called without a previous FETCH or STORE
+ # [None]: empty FETCH response
code, data = self.server.uid('FETCH', self.message.UID, 'FLAGS')
assert code == 'OK'
__traceback_info__ = 'Server response: %s, %r' % (code, data)
(at)(at) -591,6 +593,7 (at)(at)
data_item_req = '(%s)' % data_item_req
code, data = server.uid('FETCH', msg_uid, data_item_req)
assert code == 'OK'
+ __traceback_info__ = 'Server response to FETCH uid %s: %s, %r' %
(data_item_req, code, data)
data = gocept.imapapi.parser.fetch(data)
return data[data_item_resp]
|
SVN: r30569 - webmailer/gocept.imapapi/trunk/gocept/imapapi
Thomas Lotze <tl(at)gocept.com> |
2010-02-02 17:46:51 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 2 17:46:49 2010
New Revision: 30569
Log:
don't call SORT on the IMAP server if the sort criterion is empty
Modified:
webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py
Modified: webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py
==============================================================================
--- webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py (original)
+++ webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py Tue Feb 2
17:46:49 2010
(at)(at) -454,6 +454,10 (at)(at)
self.container._select()
if sort_criterion == 'FROM_NAME':
uids = self._filtered_by_header('FROM', self.from_name, sort_dir)
+ elif not sort_criterion:
+ uids = [gocept.imapapi.parser.fetch(line)['UID']
+ for line in self._fetch_lines('%s:%s' % (1, len(self)),
+ '(UID)')]
else:
uids = self._filtered_by_imap(sort_criterion, sort_dir)
uids = [self._key(uid) for uid in uids]
|
SVN: r30570 - webmailer/gocept.imapapi/trunk/gocept/imapapi
Thomas Lotze <tl(at)gocept.com> |
2010-02-02 18:24:35 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 2 18:24:34 2010
New Revision: 30570
Log:
added a test for sorting on an empty key
Modified:
webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.txt
Modified: webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.txt
==============================================================================
--- webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.txt (original)
+++ webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.txt Tue Feb 2
18:24:34 2010
(at)(at) -188,6 +188,18 (at)(at)
u'Thomas Lotze <tl(at)gocept.com>',
u'Zaphod <admin(at)example.com>']
+Calling the ``filtered`` method with an empty sort key returns the messages in
+the order they have inside the folder:
+
+>>> messages = INBOX.messages.filtered(sort_by='')
+>>> [m.headers['From'] for m in messages]
+[u'test(at)localhost',
+ u'',
+ u'Zaphod <admin(at)example.com>',
+ u'Christian Zagrodnick <cz(at)gocept.com>',
+ u'Thomas Lotze <tl(at)gocept.com>',
+ u'Thomas Lotze <tl(at)gocept.com>']
+
Appending messages to folders
=============================
|
SVN: r30571 - webmailer/gocept.imapapi/trunk/gocept/imapapi
Thomas Lotze <tl(at)gocept.com> |
2010-02-02 18:41:18 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 2 18:41:17 2010
New Revision: 30571
Log:
when setting or unsetting a flag, no longer fetch new flags from IMAP at all
Modified:
webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py
webmailer/gocept.imapapi/trunk/gocept/imapapi/message.txt
Modified: webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py
==============================================================================
--- webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py (original)
+++ webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py Tue Feb 2
18:41:17 2010
(at)(at) -576,8 +576,10 (at)(at)
code, data = self.server.uid(
'STORE', '%s' % self.message.UID, '%sFLAGS' % sign, '(%s)' % flag)
assert code == 'OK'
- __traceback_info__ = 'Server response to STORE uid %sFLAGS (%s): %s,
%r' % (sign, flag, code, data)
- self._update(data)
+ if sign == '+':
+ self.flags.add(flag)
+ else:
+ self.flags.discard(flag)
def _fetch(server, mailbox, msg_uid, data_item, chunk_no=None):
Modified: webmailer/gocept.imapapi/trunk/gocept/imapapi/message.txt
==============================================================================
--- webmailer/gocept.imapapi/trunk/gocept/imapapi/message.txt (original)
+++ webmailer/gocept.imapapi/trunk/gocept/imapapi/message.txt Tue Feb 2
18:41:17 2010
(at)(at) -259,7 +259,7 (at)(at)
>>> message.flags.add(r'\Answered')
>>> message.flags
-flags(['\\Seen', '\\Answered'])
+flags(['\\Answered', '\\Seen'])
>>> message.server.uid('FETCH', str(message.UID), 'FLAGS')
('OK', ['4 (UID ... FLAGS (\\Answered \\Seen))'])
|
SVN: r30572 - webmailer/gocept.restmail/trunk/gocept/restmail
Thomas Lotze <tl(at)gocept.com> |
2010-02-03 07:59:43 |
[ FULL ]
|
Author: thomas
Date: Wed Feb 3 07:59:41 2010
New Revision: 30572
Log:
no longer log an error when an invalid sort key is provided
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/imapaccount.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/imapaccount.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/imapaccount.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/imapaccount.py Wed Feb 3
07:59:41 2010
(at)(at) -15,7 +15,6 (at)(at)
import gocept.imapapi.folder
import gocept.imapapi.interfaces
import gocept.restmail.interfaces
-import logging
import pytz
import tempfile
import transaction
(at)(at) -23,9 +22,6 (at)(at)
import zope.interface
-log = logging.getLogger('gocept.restmail')
-
-
class IMAPAccount(ObjectManager, PropertyManager, Item):
"""A delegate for the gocept.imapapi account object."""
(at)(at) -262,7 +258,6 (at)(at)
def filtered_messages(self, sort_by, sort_dir='asc', i=0, j=None):
if sort_by not in ('from_name', 'subject', 'date'):
- log.error('Invalid sort criterion (imap): %r' % sort_by)
sort_by = ''
messages = self.folder.messages.filtered(sort_by, sort_dir)
return [Message(message).__of__(self.aq_inner)
|
SVN: r30573 - webmailer/gocept.imapapi/trunk/gocept/imapapi
Thomas Lotze <tl(at)gocept.com> |
2010-02-03 08:12:34 |
[ FULL ]
|
Author: thomas
Date: Wed Feb 3 08:12:33 2010
New Revision: 30573
Log:
when asking the server for a certain header line, interpret a response missing
the corresponding line as indicating an empty value
Modified:
webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py
Modified: webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py
==============================================================================
--- webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py (original)
+++ webmailer/gocept.imapapi/trunk/gocept/imapapi/message.py Wed Feb 3
08:12:33 2010
(at)(at) -478,7 +478,7 (at)(at)
assert code == 'OK'
items = gocept.imapapi.parser.fetch(data, fetch_all=True)
for item in items:
- lines = item['BODY[HEADER.FIELDS (%s)]' % field]
+ lines = item.get('BODY[HEADER.FIELDS (%s)]' % field, '')
line = lines.splitlines()[0]
if line:
assert line.upper().startswith(field.upper() + ':'), \
|
SVN: r30574 - webmailer/gocept.restmail/trunk/gocept/restmail
Thomas Lotze <tl(at)gocept.com> |
2010-02-03 08:32:09 |
[ FULL ]
|
Author: thomas
Date: Wed Feb 3 08:32:08 2010
New Revision: 30574
Log:
display a raw message even if no sender identity has ever been selected for it,
or its sender identity can no longer be resolved
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/draft.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/draft.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/draft.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/draft.py Wed Feb 3
08:32:08 2010
(at)(at) -166,7 +166,10 (at)(at)
def raw(self, headers=None):
profile = gocept.restmail.interfaces.IProfile(self)
- identity = profile.get_identity(self.identity)
+ try:
+ identity = profile.get_identity(self.identity)
+ except KeyError:
+ identity = None
# 1. Convert to RFC 822 message
# XXX We really want to use MIMEText, which unfortunately treats the
(at)(at) -209,7 +212,8 (at)(at)
else:
message = text_part
- message['From'] = quote_names(identity.From())
+ if identity:
+ message['From'] = quote_names(identity.From())
message['To'] = quote_names(self.to)
if self.cc:
message['CC'] = quote_names(self.cc)
|
SVN: r30575 - webmailer/gocept.restmail/trunk/gocept/restmail
Thomas Lotze <tl(at)gocept.com> |
2010-02-03 16:57:50 |
[ FULL ]
|
Author: thomas
Date: Wed Feb 3 16:57:47 2010
New Revision: 30575
Log:
added traceback info to track down a mysterious XML error
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/render.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/render.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/render.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/render.py Wed Feb 3
16:57:47 2010
(at)(at) -312,6 +312,7 (at)(at)
pre = lxml.html.Element('pre')
block.append(pre)
pre.text = ''
+ __traceback_info__ = 'Offending line: %r' % line
pre.text += line + '\n'
last_level = level
body = root.getchildren()[0]
|
SVN: r30576 - webmailer/gocept.restmail/trunk/gocept/restmail/browser
Thomas Lotze <tl(at)gocept.com> |
2010-02-03 17:43:45 |
[ FULL ]
|
Author: thomas
Date: Wed Feb 3 17:43:45 2010
New Revision: 30576
Log:
users have been observed to include a port in the host name; strip it as we
never wanted it in the ID and as a : cannot be part of a name
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/profile.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/profile.py
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/profile.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/profile.py Wed Feb
3 17:43:45 2010
(at)(at) -89,7 +89,8 (at)(at)
self.context)
mailhost_id = self.add_mailhost(
smtp_host, smtp_port, smtp_user, smtp_password)
- account_id = name_chooser.chooseName('%s-%s' % (user, host), None)
+ account_id = name_chooser.chooseName(
+ '%s-%s' % (user, host.split(':')[0]), None)
identity_id = self.add_identity(
name, address, account_id, mailhost_id)
sent_folder = tuple(unicode(name) for name in sent_folder)
(at)(at) -113,7 +114,7 (at)(at)
name_chooser = zope.app.container.interfaces.INameChooser(
self.context)
mailhost_id = name_chooser.chooseName(
- '%s-%s' % (smtp_user, smtp_host), None)
+ '%s-%s' % (smtp_user, smtp_host.split(':')[0]), None)
mailhost = Products.MailHost.MailHost.MailHost(
id=mailhost_id,
smtp_host=smtp_host,
|
SVN: r30577 - webmailer/gocept.imapapi/trunk/gocept/imapapi
Thomas Lotze <tl(at)gocept.com> |
2010-02-03 22:59:08 |
[ FULL ]
|
Author: thomas
Date: Wed Feb 3 22:59:07 2010
New Revision: 30577
Log:
added debug info
Modified:
webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.py
Modified: webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.py
==============================================================================
--- webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.py (original)
+++ webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.py Wed Feb 3 22:59:07
2010
(at)(at) -118,7 +118,7 (at)(at)
"""
if self._message_count_cache is None:
code, data = self.server.status(self.encoded_path, "(MESSAGES)")
- assert code == 'OK'
+ assert code == 'OK', '%s %r' % (code, data)
self._message_count_cache = (
gocept.imapapi.parser.status(data[0])['MESSAGES'])
return self._message_count_cache
|
SVN: r30578 - webmailer/gocept.webmail/trunk/gocept/webmail/browser
Thomas Lotze <tl(at)gocept.com> |
2010-02-04 07:28:06 |
[ FULL ]
|
Author: thomas
Date: Thu Feb 4 07:28:04 2010
New Revision: 30578
Log:
translated composer template to German, made the label of the save-as-draft
button clearer
Modified:
webmailer/gocept.webmail/trunk/gocept/webmail/browser/composer.pt
Modified: webmailer/gocept.webmail/trunk/gocept/webmail/browser/composer.pt
==============================================================================
---
webmailer/gocept.webmail/trunk/gocept/webmail/browser/composer.pt (original)
+++ webmailer/gocept.webmail/trunk/gocept/webmail/browser/composer.pt Thu Feb
4 07:28:04 2010
(at)(at) -7,26 +7,26 (at)(at)
<div metal:fill-slot="layout">
<div class="menubar" id="menubar-composer">
- <button id="menuitem-send">Send</button>
- <button id="menuitem-save">Save</button>
+ <button id="menuitem-send">Abschicken</button>
+ <button id="menuitem-save">Entwurf speichern</button>
</div>
<div id="yui-layout-center">
<div id="composeBarWrap">
<ul id="composeBarTabs" class="yui-nav">
- <li class="selected"><a
href="#tab1">Message</a></li>
- <li><a id="composeBarTabAttachments"
href="#tab2">Attachments</a></li>
+ <li class="selected"><a
href="#tab1">Nachricht</a></li>
+ <li><a id="composeBarTabAttachments"
href="#tab2">Anhänge</a></li>
</ul>
<div class="yui-content">
<div>
<div id="composeAddr">
<div id="composeIdentity">
- <label for="composeFrom">From:</label>
+ <label for="composeFrom">Von:</label>
<select id="composeFrom" name="composeFrom">
</select>
</div>
<div>
- <label for="composeTo">To:</label>
+ <label for="composeTo">An:</label>
<input type="text" name="composeTo" id="composeTo"/>
</div>
<div>
(at)(at) -38,7 +38,7 (at)(at)
<input type="text" name="composeBCC" id="composeBCC"/>
</div>
<div>
- <label for="composeSubject">Subject:</label>
+ <label for="composeSubject">Betreff:</label>
<input type="text" name="composeSubject"
id="composeSubject"/>
</div>
</div>
(at)(at) -48,9 +48,10 (at)(at)
<div id="attachments">
<form id="composeAttachments" method="post"
enctype="multipart/form-data">
<ul id="composeAttachmentsList"></ul>
- <strong>Add new attachment:</strong>
+ <strong>Neuen Anhang hinzufügen:</strong>
<input type="file" name="file"
id="composeAttachmentsFile"/>
- <span id="composeAttachmentsUploading" style="display:
none">uploading...</span>
+ <span id="composeAttachmentsUploading"
+ style="display: none">lade hoch...</span>
</form>
</div>
</div>
|
SVN: r30579 - webmailer/gocept.restmail/trunk/gocept/restmail
Thomas Lotze <tl(at)gocept.com> |
2010-02-08 16:51:17 |
[ FULL ]
|
Author: thomas
Date: Mon Feb 8 16:51:14 2010
New Revision: 30579
Log:
added debug info to track down a system error
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/render.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/render.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/render.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/render.py Mon Feb 8
16:51:14 2010
(at)(at) -249,6 +249,7 (at)(at)
(at)classmethod
def parse(cls, text, encoding):
+ __traceback_info__ = 'Encoding: %s' % encoding
try:
parser = lxml.html.HTMLParser(encoding=encoding)
except LookupError:
|
SVN: r30580 - webmailer/gocept.restmail/trunk/gocept/restmail
Thomas Lotze <tl(at)gocept.com> |
2010-02-08 17:42:28 |
[ FULL ]
|
Author: thomas
Date: Mon Feb 8 17:42:27 2010
New Revision: 30580
Log:
replace any control chars except tabs and line breaks when putting text inside
an HTML element
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/render.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/render.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/render.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/render.py Mon Feb 8
17:42:27 2010
(at)(at) -289,11 +289,13 (at)(at)
Make sure we don't fail if the input text contains a null byte:
- >>> BodyTextPlain.requote(u'asd\x00f').text
- 'asdf\n'
+ >>> BodyTextPlain.requote(u'a\x07s\x0ad\x00f').text
+ 'as\ndf\n'
"""
- text = text.replace('\x00', '')
+ for i in xrange(32):
+ if i not in (9, 10, 13):
+ text = text.replace(chr(i), '')
if not text:
return
# XXX try to rewrite in a way that doesn't blow one's mind
|
SVN: r30581 - webmailer/gocept.restmail/trunk/gocept/restmail/browser
Thomas Lotze <tl(at)gocept.com> |
2010-02-08 19:55:39 |
[ FULL ]
|
Author: thomas
Date: Mon Feb 8 19:55:38 2010
New Revision: 30581
Log:
make sure folder renaming works with non-ASCII characters this side of the REST
interface
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/folder.txt
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/folder.txt
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/folder.txt (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/folder.txt Mon Feb
8 19:55:38 2010
(at)(at) -97,20 +97,28 (at)(at)
Rename folders
--------------
+Let's create a folder which we are going to rename. We make a point of using
+non-ASCII characters all over the place:
+
>>> json_request('http://localhost/profile/test-localhost/(at)(at)create_folder',
-... name=u'Knuddelwurz')
-{'status': 'OK', 'url': 'http://localhost/profile/test-localhost/+Knuddelwurz'}
+... name=u'Knuddelw\xfcrz')
+{'status': 'OK', 'url': 'http://localhost/profile/test-localhost/+Knuddelw%C3%BCrz'}
Folders can be renamed:
->>> json_request('http://localhost/profile/test-localhost/+Knuddelwurz/(at)(at)rename',
-... name=u'Wulliknurz')
-{'status': 'OK', 'url': 'http://localhost/profile/test-localhost/+Wulliknurz'}
+>>> json_request('http://localhost/profile/test-localhost/+Knuddelw%C3%BCrz/(at)(at)rename',
+... name=u'Wullikn\xfcrz')
+{'status': 'OK', 'url': 'http://localhost/profile/test-localhost/+Wullikn%C3%BCrz'}
>>> json_request(
-... 'http://localhost/profile/test-localhost/+Wulliknurz/(at)(at)has_content')
+... 'http://localhost/profile/test-localhost/+Wullikn%C3%BCrz/(at)(at)has_content')
{'message': False}
-Renaming to a mailbox, which already exists nearby, results into an error:
+>>> json_request('http://localhost/profile/test-localhost/+Wullikn%C3%BCrz/(at)(at)rename',
+... name=u'Wulliknurz')
+{'status': 'OK', 'url': 'http://localhost/profile/test-localhost/+Wulliknurz'}
+
+Trying to change the name of a folder into one that is already used for a
+folder at the same location results in an error:
>>> json_request('http://localhost/profile/test-localhost/+Testmessages/(at)(at)rename',
... name=u'Bar')
|
SVN: r30582 - webmailer/gocept.imapapi/trunk/gocept/imapapi
Thomas Lotze <tl(at)gocept.com> |
2010-02-09 07:25:22 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 9 07:25:20 2010
New Revision: 30582
Log:
fixed a silly bug that caused folder names with an umlaut somewhere after a
dash to be decoded wrong from modified UTF7
Modified:
webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.py
Modified: webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.py
==============================================================================
--- webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.py (original)
+++ webmailer/gocept.imapapi/trunk/gocept/imapapi/folder.py Tue Feb 9 07:25:20
2010
(at)(at) -272,6 +272,9 (at)(at)
>>> encode_modified_utf7(u'\xe4\xf6\xfc')
'&AOQA9gD8-'
+ >>> encode_modified_utf7(u'as-d\xe4f')
+ 'as-d&AOQ-f'
+
"""
def encode_buffer(buffer):
return buffer.encode('utf7').replace('/', ',').replace('+', '&')
(at)(at) -305,6 +308,12 (at)(at)
>>> decode_modified_utf7('\xef')
u'\\xef'
+ Regression: Strings which contain a UTF7-encoded character somewhere after
+ a dash used to be decoded wrong:
+
+ >>> decode_modified_utf7('as-d&AOQ-f')
+ u'as-d\xe4f'
+
"""
def decode_utf7(buffer):
return buffer.replace('&', '+').replace(',', '/').decode('utf7')
(at)(at) -320,7 +329,7 (at)(at)
start = bytes.index('&')
text += decode_ascii(bytes[:start])
- stop = bytes.index('-') + 1
+ stop = bytes.index('-', start) + 1
if stop == start + 2:
text += u'&'
else:
|
SVN: r30583 - webmailer/gocept.restmail/trunk/gocept/restmail/browser
Thomas Lotze <tl(at)gocept.com> |
2010-02-09 07:29:06 |
[ FULL ]
|
SVN: r30584 - in webmailer/gocept.restmail/trunk/gocept/restmail: . browser
Thomas Lotze <tl(at)gocept.com> |
2010-02-09 08:16:57 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 9 08:16:56 2010
New Revision: 30584
Log:
use the date formatter utility instead of applying ISO format to draft dates
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft.py
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft_snippet_header.pt
webmailer/gocept.restmail/trunk/gocept/restmail/browser/profile.py
webmailer/gocept.restmail/trunk/gocept/restmail/draft.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft.py Tue Feb 9
08:16:56 2010
(at)(at) -13,7 +13,7 (at)(at)
def data(self):
"""Return data of the draft message."""
return {'identity': self.context.identity,
- 'date': self.context.date.isoformat(' '),
+ 'date': self.context.formatted_date,
'to': self.context.to,
'cc': self.context.cc,
'bcc': self.context.bcc,
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft_snippet_header.pt
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft_snippet_header.pt (original)
+++
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft_snippet_header.pt Tue
Feb 9 08:16:56 2010
(at)(at) -16,7 +16,7 (at)(at)
</tal:block>
<dt>Date:</dt>
- <dd tal:content="draft/date"></dd>
+ <dd tal:content="draft/formatted_date"></dd>
</dl>
<div class="novisclear"></div>
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/profile.py
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/profile.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/profile.py Tue Feb
9 08:16:56 2010
(at)(at) -146,7 +146,7 (at)(at)
'url': zope.app.zapi.absoluteURL(message, self.request),
'to': message.to,
'subject': message.subject,
- 'date': message.date.isoformat(' '),
+ 'date': message.formatted_date,
} for message in messages]
data = {
'messages': messages,
(at)(at) -183,7 +183,7 (at)(at)
num_attachments=0), # XXX this should not be 0
message.to,
message.subject,
- message.date.isoformat(' '), # XXX use date utility
+ message.formatted_date,
],
))
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/draft.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/draft.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/draft.py Tue Feb 9
08:16:56 2010
(at)(at) -290,6 +290,17 (at)(at)
def add_attachment(self):
return new_attachment(self)
+ (at)property
+ def formatted_date(self):
+ # Try to format the time according to site configuration, fall back to
+ # ISO format.
+ format = zope.component.queryUtility(
+ gocept.restmail.interfaces.IDateFormatter)
+ if format:
+ return format(self.date)
+ else:
+ return self.date.isoformat(' ')
+
def new_draft(container, message=None, forward=False):
id = str(uuid.uuid1())
|
SVN: r30585 - webmailer/gocept.restmail/trunk/gocept/restmail/browser
Thomas Lotze <tl(at)gocept.com> |
2010-02-09 18:21:53 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 9 18:21:52 2010
New Revision: 30585
Log:
validate address lists (to, cc, bcc) syntactically before passing them to the
MailHost
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft.py
webmailer/gocept.restmail/trunk/gocept/restmail/browser/tests.py
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft.py Tue Feb 9
18:21:52 2010
(at)(at) -6,6 +6,53 (at)(at)
import gocept.restmail.browser.json
+def generate_addresses(line):
+ r"""Split a text line into email addresses that may come with real names.
+
+ The line is split on commas with anything between pairs of double quotes
+ being considered atomic. Double quotes may be escaped in turn.
+
+ >>> list(generate_addresses(
+ ... '"foo, bar" <baz(at)example.org>, foo\\", \\"bar
<baz(at)example.com>'))
+ ['"foo, bar" <baz(at)example.org>', ' foo\\"', ' \\"bar
<baz(at)example.com>']
+
+ """
+ inside_quote = False
+ bs = False
+ item = ''
+ for c in line:
+ if c == ',' and not inside_quote:
+ yield item
+ bs = False
+ item = ''
+ continue
+ if c == '"' and not bs:
+ inside_quote = not inside_quote
+ bs = (c == '\\')
+ item += c
+ yield item
+
+
+def validate_address_list(line):
+ r"""Check the syntax of a list of email addresses including real names.
+
+ See RfC 2822, A.1.2.
+
+ >>> validate_address_list(
+ ... '"foo, bar" <baz(at)example.org>, "foo\\", \\"bar"
<baz(at)example.com>')
+ True
+
+ >>> validate_address_list(
+ ... '"foo, bar" <baz(at)example.org>, foo\\", \\"bar
<baz(at)example.com>')
+ False
+
+ """
+ for item in generate_addresses(line):
+ if '(at)' not in item:
+ return False
+ return True
+
+
class WebAPI(object):
"""Web API for drafts."""
(at)(at) -40,6 +87,15 (at)(at)
if not self.context.to:
return {'status': 'ValidationError',
'message': u'Bitte Empfänger angeben.'}
+ if not validate_address_list(self.context.to):
+ return {'status': 'ValidationError',
+ 'message': u'Die Empfängerliste ist fehlerhaft.'}
+ if self.context.cc and not validate_address_list(self.context.cc):
+ return {'status': 'ValidationError',
+ 'message': u'Die Cc-Empfängerliste ist fehlerhaft.'}
+ if self.context.bcc and not validate_address_list(self.context.bcc):
+ return {'status': 'ValidationError',
+ 'message': u'Die BCc-Empfängerliste ist fehlerhaft.'}
error = self.context.send()
if error:
return {'status': 'SentError', 'message': str(error)}
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/tests.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/browser/tests.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/tests.py Tue Feb 9
18:21:52 2010
(at)(at) -3,6 +3,7 (at)(at)
# See also LICENSE.txt
"""Test harness for gocept.restmail."""
+from zope.testing import doctest
import cjson
import gocept.restmail.tests
import unittest
(at)(at) -120,6 +121,8 (at)(at)
def test_suite():
patch_zpublisher_response_for_iteration()
suite = unittest.TestSuite()
+ suite.addTest(doctest.DocTestSuite(
+ 'gocept.restmail.browser.draft'))
suite.addTest(gocept.restmail.tests.FunctionalDocFileSuite(
'README.txt',
'profile.txt',
|
SVN: r30589 - webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles
Thomas Lotze <tl(at)gocept.com> |
2010-02-11 17:16:13 |
[ FULL ]
|
Author: thomas
Date: Thu Feb 11 17:16:13 2010
New Revision: 30589
Log:
added some styles for the render-error page
Modified:
webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles/webmail.css
Modified:
webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles/webmail.css
==============================================================================
---
webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles/webmail.css (original)
+++
webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles/webmail.css Thu
Feb 11 17:16:13 2010
(at)(at) -90,6 +90,33 (at)(at)
padding: 10px;
}
+.render-error {
+ margin:10%;
+ padding:5%;
+ background-color:white;
+ border:1px solid red;
+}
+
+.render-error h1 {
+ font-size: 200%;
+ font-weight: bold;
+ margin-bottom: 1em;
+}
+
+.render-error table {
+ margin-top: 20px;
+}
+
+.render-error th {
+ text-align: right;
+ padding-right: 0.5em;
+ font-weight: bold;
+}
+
+html.webmailer .yui-layout-bd .render-error pre {
+ padding: 0px;
+}
+
html.webmailer .yui-layout-bd dl dt {
width: 7em;
padding-right: 0.5em;
|
SVN: r30595 - in webmailer/gocept.restmail/trunk/gocept/restmail: . browser
Thomas Lotze <tl(at)gocept.com> |
2010-02-16 00:03:32 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 16 00:03:30 2010
New Revision: 30595
Log:
show a gravatar for the from address of a message on display, floating right of
the headers
Added:
webmailer/gocept.restmail/trunk/gocept/restmail/avatar.py (contents, props
changed)
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft_snippet_header.pt
webmailer/gocept.restmail/trunk/gocept/restmail/browser/inline.txt
webmailer/gocept.restmail/trunk/gocept/restmail/browser/snippet_header.pt
webmailer/gocept.restmail/trunk/gocept/restmail/draft.py
webmailer/gocept.restmail/trunk/gocept/restmail/render.py
Added: webmailer/gocept.restmail/trunk/gocept/restmail/avatar.py
==============================================================================
--- (empty file)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/avatar.py Tue Feb 16
00:03:30 2010
(at)(at) -0,0 +1,15 (at)(at)
+# Copyright (c) 2010 gocept gmbh & co. kg
+# See also LICENSE.txt
+
+import md5
+
+
+def avatar(line):
+ if not(line and '(at)' in line):
+ return None
+
+ for split_char in '\t\n\x0b\x0c\r <>()"\'':
+ line = [item for item in line.split(split_char) if '(at)' in item][0]
+
+ return ('https://secure.gravatar.com/avatar/%s.jpg?s=64&d=404&r=pg'
%
+ md5.new(line.lower()).hexdigest())
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft_snippet_header.pt
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft_snippet_header.pt (original)
+++
webmailer/gocept.restmail/trunk/gocept/restmail/browser/draft_snippet_header.pt Tue
Feb 16 00:03:30 2010
(at)(at) -1,3 +1,7 (at)(at)
+<div class="header">
+ <img class="sender-avatar" alt=""
+ tal:condition="context/sender_avatar"
+ tal:attributes="src context/sender_avatar" />
<dl tal:define="draft context/context">
<dt>Subject:</dt>
<dd tal:content="draft/subject"></dd>
(at)(at) -20,3 +24,4 (at)(at)
</dl>
<div class="novisclear"></div>
+</div>
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/inline.txt
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/inline.txt (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/inline.txt Tue Feb
16 00:03:30 2010
(at)(at) -75,6 +75,7 (at)(at)
>>> r = render_message(folder, '09 - AppleMail, Simple HTML with
image')
>>> print r['header']
<div class="header">
+ <img class="sender-avatar" alt="" src="..." />
<dl>
<dt>Subject:</dt>
<dd>09 - AppleMail, Simple HTML with image</dd>
(at)(at) -116,6 +117,7 (at)(at)
>>> r = render_message(folder, '10 - Claws, Signed, Text attachment')
>>> print r['header']
<div class="header">
+ <img class="sender-avatar" alt="" src="..." />
<dl>
<dt>Subject:</dt>
<dd>10 - Claws, Signed, Text attachment</dd>
(at)(at) -170,6 +172,7 (at)(at)
>>> r = render_message(folder, '11 - AppleMail, Complex HTML with
many images')
>>> print r['header']
<div class="header">
+ <img class="sender-avatar" alt="" src="..." />
<dl>
<dt>Subject:</dt>
<dd>11 - AppleMail, Complex HTML with many images</dd>
(at)(at) -252,6 +255,7 (at)(at)
>>> r = render_message(folder, '12 - Evolution, multipart/mixed,
inline image, gzip attachment')
>>> print r['header']
<div class="header">
+ <img class="sender-avatar" alt="" src="..." />
<dl>
<dt>Subject:</dt>
<dd>12 - Evolution, multipart/mixed, inline image, gzip
attachment</dd>
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/snippet_header.pt
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/snippet_header.pt (original)
+++
webmailer/gocept.restmail/trunk/gocept/restmail/browser/snippet_header.pt Tue
Feb 16 00:03:30 2010
(at)(at) -1,4 +1,7 (at)(at)
<div class="header">
+ <img class="sender-avatar" alt=""
+ tal:condition="context/sender_avatar"
+ tal:attributes="src context/sender_avatar" />
<dl>
<tal:block repeat="header python:['Subject', 'From', 'To', 'CC',
'Date']">
<tal:block tal:define="header_content context/headers/?header |
nothing"
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/draft.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/draft.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/draft.py Tue Feb 16
00:03:30 2010
(at)(at) -1,4 +1,4 (at)(at)
-# Copyright (c) 2007-2009 gocept gmbh & co. kg
+# Copyright (c) 2007-2010 gocept gmbh & co. kg
# See also LICENSE.txt
import datetime
(at)(at) -29,6 +29,7 (at)(at)
import Products.MailHost.interfaces
import gocept.imapapi.interfaces
+import gocept.restmail.avatar
import gocept.restmail.interfaces
import gocept.restmail.render
(at)(at) -455,6 +456,14 (at)(at)
super(RenderedDraftMessage, self).__init__(
context, rendered_body)
+ profile = gocept.restmail.interfaces.IProfile(context)
+ try:
+ identity = profile.get_identity(context.identity)
+ self.sender_avatar = gocept.restmail.avatar.avatar(
+ identity.address)
+ except KeyError:
+ self.sender_avatar = None
+
class RenderedAttachment(gocept.restmail.render.RenderedBase):
"""A structured rendition of an attached message body part."""
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/render.py
==============================================================================
--- webmailer/gocept.restmail/trunk/gocept/restmail/render.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/render.py Tue Feb 16
00:03:30 2010
(at)(at) -1,4 +1,4 (at)(at)
-# Copyright (c) 2008-2009 gocept gmbh & co. kg
+# Copyright (c) 2008-2010 gocept gmbh & co. kg
# See also LICENSE.txt
"""Rendering messages"""
(at)(at) -15,6 +15,7 (at)(at)
import gocept.imapapi.interfaces
import gocept.imapapi.message
+import gocept.restmail.avatar
import gocept.restmail.interfaces
import gocept.restmail.imapaccount
(at)(at) -112,6 +113,8 (at)(at)
super(RenderedMessage, self).__init__(context, body)
self.headers = self.context.headers
self.body.parent = self
+ self.sender_avatar = gocept.restmail.avatar.avatar(
+ self.headers.get('From'))
class RenderedBroken(RenderedInline):
|
SVN: r30596 - webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles
Thomas Lotze <tl(at)gocept.com> |
2010-02-16 00:04:18 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 16 00:04:17 2010
New Revision: 30596
Log:
added some styling for sender avatars
Modified:
webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles/webmail.css
Modified:
webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles/webmail.css
==============================================================================
---
webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles/webmail.css (original)
+++
webmailer/gocept.webmail/trunk/gocept/webmail/browser/resources/styles/webmail.css Tue
Feb 16 00:04:17 2010
(at)(at) -131,6 +131,11 (at)(at)
padding:1em;
}
+html.webmailer .header .sender-avatar {
+ float: right;
+ padding: 1em;
+}
+
html.webmailer .yui-layout-bd div.messagepart {
clear:both;
background-color: white;
|
SVN: r30600 - in webmailer/gocept.restmail/trunk: . gocept/restmail/browser
Thomas Lotze <tl(at)gocept.com> |
2010-02-16 20:12:24 |
[ FULL ]
|
Author: thomas
Date: Tue Feb 16 20:12:22 2010
New Revision: 30600
Log:
re #4932: merged the multiselection features from the 4892-jquery branch
Modified:
webmailer/gocept.restmail/trunk/ (props changed)
webmailer/gocept.restmail/trunk/gocept/restmail/browser/configure.zcml
webmailer/gocept.restmail/trunk/gocept/restmail/browser/message.py
webmailer/gocept.restmail/trunk/gocept/restmail/browser/message.txt
(contents, props changed)
Modified:
webmailer/gocept.restmail/trunk/gocept/restmail/browser/configure.zcml
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/configure.zcml (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/configure.zcml Tue
Feb 16 20:12:22 2010
(at)(at) -277,6 +277,18 (at)(at)
name="clear"
attribute="clear"
/>
+ <browser:page
+ name="delete_messages"
+ attribute="delete_messages"
+ />
+ <browser:page
+ name="copy_messages"
+ attribute="copy_messages"
+ />
+ <browser:page
+ name="move_messages"
+ attribute="move_messages"
+ />
</browser:pages>
<browser:pages
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/message.py
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/message.py (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/message.py Tue Feb
16 20:12:22 2010
(at)(at) -100,6 +100,51 (at)(at)
self.context.delete_messages()
return {}
+ (at)gocept.restmail.browser.json.view
+ def delete_messages(self, message_urls):
+ """Delete messages.
+ """
+ messages = self._get_messages(message_urls)
+
+ account = gocept.restmail.interfaces.IIMAPAccount(self.context)
+ trash = account.get_function_folder('trash', create=True)
+
+ for message in messages:
+ parent = message.getParentNode()
+ if parent != self.context:
+ continue
+ if self.context != trash:
+ trash.add_message(message)
+ # XXX for some reason self.context.delete_message results
+ # in a TypeError in imapapi, while parent.delete_message DOES
+ # work!
+ parent.delete_message(message)
+ return {}
+
+ (at)gocept.restmail.browser.json.view
+ def copy_messages(self, message_urls):
+ """Copy messages to this folder"""
+ messages = self._get_messages(message_urls)
+ for message in messages:
+ self.context.add_message(message)
+ return {}
+
+ (at)gocept.restmail.browser.json.view
+ def move_messages(self, message_urls):
+ """Move messages to this folder"""
+ messages = self._get_messages(message_urls)
+ for message in messages:
+ previous_container = message.getParentNode()
+ self.context.add_message(message)
+ previous_container.delete_message(message)
+ return {}
+
+ def _get_messages(self, message_urls):
+ """Turn list of submitted message_urls into messages.
+ """
+ return [gocept.restmail.browser.traversal.traverse(
+ url, self.context, self.request) for
+ url in message_urls]
def from_name(value):
name, addr = email.Utils.parseaddr(value)
(at)(at) -182,6 +227,9 (at)(at)
folder.add_message(self.context.aq_inner)
return {}
+ # XXX This method is not tested anymore since multiselection made it
+ # obsolete (at least for the time being). It should either be removed or
+ # consciously kept and tested.
(at)gocept.restmail.browser.json.view
def move(self, folder_url):
"""Move message to target folder"""
Modified: webmailer/gocept.restmail/trunk/gocept/restmail/browser/message.txt
==============================================================================
---
webmailer/gocept.restmail/trunk/gocept/restmail/browser/message.txt (original)
+++ webmailer/gocept.restmail/trunk/gocept/restmail/browser/message.txt Tue Feb
16 20:12:22 2010
(at)(at) -104,10 +104,13 (at)(at)
Copying and moving messages
---------------------------
-Messages can be copied and moved using the `(at)(at)copy` and `(at)(at)move`
views,
-respectively. You must pass the url of the target folder. Let's copy a message
-to a folder with a non-ASCII name, copy it back and move it back and forth
-between that folder and another.
+Messages can be copied and moved using the `(at)(at)copy_messages` and
+`(at)(at)move_messages` views, respectively. These views exist on the target
+folder, and you must pass one or more urls of the messages you want to
+copy or move to it.
+
+Let's copy a message to a folder with a non-ASCII name, copy it back
+and move it back and forth between that folder and another.
When copying, the source message will not be deleted:
(at)(at) -120,7 +123,8 (at)(at)
>>> other_messages['total']
0
->>> json_request(messages['messages'][-1]['url']+'/(at)(at)copy',
folder_url=other_url, post=True)
+>>> json_request(other_url + '/(at)(at)copy_messages',
+... message_urls=[messages['messages'][-1]['url']])
{}
>>> messages = json_request(INBOX_url + '/(at)(at)messages')
>>> messages['total']
(at)(at) -129,8 +133,8 (at)(at)
>>> other_messages['total']
1
->>>
json_request(other_messages['messages'][-1]['url']+'/(at)(at)copy',
-... folder_url=INBOX_url, post=True)
+>>> json_request(INBOX_url + '/(at)(at)copy_messages',
+... message_urls=[other_messages['messages'][-1]['url']], post=True)
{}
>>> messages = json_request(INBOX_url + '/(at)(at)messages')
>>> messages['total']
(at)(at) -141,8 +145,8 (at)(at)
Moving messages implies the deletion of the source message:
->>>
json_request(other_messages['messages'][-1]['url']+'/(at)(at)move',
-... folder_url=INBOX_url, post=True)
+>>> json_request(INBOX_url + '/(at)(at)move_messages',
+... message_urls=[other_messages['messages'][-1]['url']], post=True)
{}
>>> messages = json_request(INBOX_url + '/(at)(at)messages')
>>> messages['total']
(at)(at) -151,7 +155,8 (at)(at)
>>> other_messages['total']
0
->>> json_request(messages['messages'][-1]['url']+'/(at)(at)move',
folder_url=other_url, post=True)
+>>> json_request(other_url + '/(at)(at)move_messages',
+... message_urls=[messages['messages'][-1]['url']], post=True)
{}
>>> messages = json_request(INBOX_url + '/(at)(at)messages')
>>> messages['total']
(at)(at) -164,27 +169,30 (at)(at)
Deleting messages
-----------------
-Messages can be deleted using the `(at)(at)delete` view. We demonstrate this
both
-for a folder with more than one message in it and for a folder with a
-non-ASCII name.
+Messages can be deleted using the `(at)(at)delete_messages` view on folders.
We
+demonstrate this both for a folder with more than one message in it
+and for a folder with a non-ASCII name.
Messages that are deleted are moved to the trash, which is empty at first. The
trash folder is identified as a `function folder` in the account information
(see above):
->>> trash = json_request('http://localhost/profile/test-localhost/+Trash/(at)(at)messages')
+>>> trash_url = 'http://localhost/profile/test-localhost/+Trash'
+>>> trash = json_request(trash_url + '/(at)(at)messages')
>>> trash['total']
0
We delete two messages:
->>> json_request(messages['messages'][-1]['url']+'/(at)(at)delete',
post=True)
+>>> json_request(INBOX_url + '/(at)(at)delete_messages',
+... message_urls=[messages['messages'][-1]['url']], post=True)
{}
>>> messages = json_request(INBOX_url + '/(at)(at)messages')
>>> messages['total']
2
->>>
json_request(other_messages['messages'][-1]['url']+'/(at)(at)delete',
post=True)
+>>> json_request(other_url + '/(at)(at)delete_messages',
+... message_urls=[other_messages['messages'][-1]['url']], post=True)
{}
>>> other_messages = json_request(other_url + '/(at)(at)messages')
>>> other_messages['total']
(at)(at) -192,18 +200,69 (at)(at)
And find them in the trash now:
->>> trash = json_request('http://localhost/profile/test-localhost/+Trash/(at)(at)messages')
+>>> trash = json_request(trash_url + '/(at)(at)messages')
>>> trash['total']
2
Deleting messages in the trash makes them go away completely:
->>> json_request(trash['messages'][0]['url']+'/(at)(at)delete',
post=True)
+>>> json_request(trash_url + '/(at)(at)delete_messages',
+... message_urls=[trash['messages'][0]['url']], post=True)
{}
->>> trash = json_request('http://localhost/profile/test-localhost/+Trash/(at)(at)messages')
+>>> trash = json_request(trash_url + '/(at)(at)messages')
>>> trash['total']
1
+Copying, moving and and deleting multiple messages at once
+----------------------------------------------------------
+
+XXX these tests fail due to some issue in imapapi which in some cases
+raises a TypeError, trying to do addition or substraction with "None".
+
+We can also copy, move and delete multiple messages at the same time.
+
+We copy both messages into the other folder::
+
+>>> messages = json_request(INBOX_url + '/(at)(at)messages')
+>>> messages['total']
+2
+>>> json_request(other_url + '/(at)(at)copy_messages',
+... message_urls=[message['url'] for message in messages['messages']],
+... post=True)
+{}
+>>> other_messages = json_request(other_url + '/(at)(at)messages')
+>>> other_messages['total']
+2
+
+Let's move them back again::
+
+>>> json_request(INBOX_url + '/(at)(at)move_messages',
+... message_urls=[message['url'] for message in other_messages['messages']],
+... post=True)
+{}
+>>> other_messages = json_request(other_url + '/(at)(at)messages')
+>>> other_messages['total']
+0
+>>> messages = json_request(INBOX_url + '/(at)(at)messages')
+>>> messages['total']
+4
+
+We remove the last two messages by deleting them (but first, we clear the
+trash folder to make the outcome more obvious)::
+
+>>> json_request(trash_url + '/(at)(at)clear')
+{}
+
+>>> json_request(INBOX_url + '/(at)(at)delete_messages',
+... message_urls=[message['url'] for message in messages['messages'][-2:]],
+... post=True)
+{}
+>>> messages = json_request(INBOX_url + '/(at)(at)messages')
+>>> messages['total']
+2
+>>> trash = json_request(trash_url + '/(at)(at)messages')
+>>> trash['total']
+2
Sending messages
================
|
|