<DKIM> [PATCH] Write IMAP keyword changes (maildir file renames) back to the server

Nicolas Sebrecht nicolas.s-dev at laposte.net
Tue May 14 21:38:17 BST 2019


On Tue, May 14, 2019 at 12:16:19AM -0300, Igor Almeida wrote:

> Accomplish this by peeking at the source folder (which should be a Maildir) and
> reversing the keyword-to-maildirflag mapping to discover which IMAP keyword
> corresponds to which maildir flag.

Interesting.

> It's quite dirty right now.
> 
> Signed-off-by: Igor Almeida <igor.contato at gmail.com>
> ---
>  offlineimap/folder/IMAP.py | 21 ++++++++++++++++++++-
>  offlineimap/imaputil.py    | 10 +++++++++-
>  2 files changed, 29 insertions(+), 2 deletions(-)
> 
> diff --git a/offlineimap/folder/IMAP.py b/offlineimap/folder/IMAP.py
> index ead4396..12d9840 100644
> --- a/offlineimap/folder/IMAP.py
> +++ b/offlineimap/folder/IMAP.py
> @@ -899,6 +899,24 @@ class IMAPFolder(BaseFolder):
>          self.__processmessagesflags('-', uidlist, flags)
>  
>      def __processmessagesflags_real(self, operation, uidlist, flags):
> +        #before connecting, let us calculate the necessary flags & keywords to store/remove
> +        repo = self.getrepository()
> +        account = repo.getaccount()
> +        otherfolder = account.get_local_folder(self) #this is supposed to be maildir
> +        otherrepo = otherfolder.getrepository()

The looong logic just to access the paired repository. :-)

Of course, we should not try to go from one side to the other. This
makes this patch unlikely to get merged.... BUT OTOH I understand this
could help, offlineimap is getting old and Py2 will be deprecated soon
enough.

Actually, I wonder we could store patches like this in the repo. While
not applied to the mainline they could still be easily available for the
users who can go with dirty hacks. In this case we could drop a post on
the blog.

> +        try:
> +            keywordmap = otherrepo.getkeywordmap()
> +            #now flip the map, because we need to translate flags into IMAP keywords
> +            reversed_keywordmap = dict(zip(keywordmap.itervalues(), keywordmap.iterkeys()))
> +
> +            #TODO check other calls to imaputil.flagsmaildir2imap()
> +            flagstring = imaputil.flagsmaildir2imap(flags, reversed_keywordmap)
> +        except NotImplementedError:
> +            #are we doing IMAP-to-IMAP then? just fail
> +            raise OfflineImapError(
> +                'Error getting keywordmap', OfflineImapError.ERROR.MESSAGE)
> +

Why? Gmail/IMAP or IMAP/IMAP is valid. Will this error break the current
sync of the message or log offending lines? I wonder we should
intentionally ignore this error.

> +        #done, now connect and do it
>          imapobj = self.imapserver.acquireconnection()
>          try:
>              try:
> @@ -908,7 +926,7 @@ class IMAPFolder(BaseFolder):
>                  return
>              response = imapobj.uid('store',
>                  imaputil.uid_sequence(uidlist), operation + 'FLAGS',
> -                    imaputil.flagsmaildir2imap(flags))
> +                    flagstring)
>              if response[0] != 'OK':
>                  raise OfflineImapError(
>                      'Error with store: %s'% '. '.join(response[1]),
> @@ -932,6 +950,7 @@ class IMAPFolder(BaseFolder):
>              flagstr = attributehash['FLAGS']
>              uid = int(attributehash['UID'])
>              self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flagstr)
> +            self.messagelist[uid]['keywords'] = imaputil.flagsimap2keywords(flagstr)
>              try:
>                  needupdate.remove(uid)
>              except ValueError:  # Let it slide if it's not in the list.
> diff --git a/offlineimap/imaputil.py b/offlineimap/imaputil.py
> index 39bd8d4..28067ef 100644
> --- a/offlineimap/imaputil.py
> +++ b/offlineimap/imaputil.py
> @@ -211,13 +211,21 @@ def flagsimap2keywords(flagstring):
>      serverflagset = set([flag for (flag, c) in flagmap])
>      return imapflagset - serverflagset
>  
> -def flagsmaildir2imap(maildirflaglist):
> +def flagsmaildir2imap(maildirflaglist, letters_to_keywords_map=dict()):
>      """Convert set of flags ([DR]) into a string '(\\Deleted \\Draft)'."""
>  
>      retval = []
>      for imapflag, maildirflag in flagmap:
>          if maildirflag in maildirflaglist:
>              retval.append(imapflag)
> +
> +    #use the additional dict now
> +    if len(letters_to_keywords_map) > 0:
> +        for flag in maildirflaglist:
> +            if flag in letters_to_keywords_map:
> +                retval.append(letters_to_keywords_map[flag])
> +
> +    #NOTE there might be a problem with spaces in the keywordmap

Not very cool.

>      return '(' + ' '.join(sorted(retval)) + ')'
>  
>  def uid_sequence(uidlist):

Thanks!

-- 
Nicolas Sebrecht



More information about the OfflineIMAP-project mailing list