{"id":1053,"date":"2013-01-16T10:50:47","date_gmt":"2013-01-16T10:50:47","guid":{"rendered":"http:\/\/www.fbcs.co.uk\/wp\/?p=1053"},"modified":"2014-07-27T01:24:59","modified_gmt":"2014-07-27T00:24:59","slug":"using-nametrans-with-offlineimap","status":"publish","type":"post","link":"https:\/\/wp.fbcs.co.uk\/using-nametrans-with-offlineimap\/","title":{"rendered":"Using nametrans with offlineimap"},"content":{"rendered":"

(Originally posted on the offlineimap mailing list on 15 Jan 2012)<\/p>\n

I’ve finally got offlineimap’s ‘nametrans’ feature to do what I want.<\/p>\n

Part of the problem was that I found the documentation and examples to be somewhat ambiguous in terms of which direction the translation would happen.<\/p>\n

Anyway, I’ve got it working, so here are my notes which will hopefully be helpful to others.<\/p>\n

The ‘nametrans’ configuration option allows conversion between different folder names on the local and remote repositories.<\/p>\n

nametrans specifies a Python expression which, given each folder name from the repository in turn, returns the equivalent name on the other repository.<\/p>\n

In the configuration of the local repository, the nametrans code receives each local folder name, and returns the name of the equivalent remote folder.<\/p>\n

In the remote repository configuration, the nametrans code gets the remote folder names, one at a time, and returns the equivalent local names.<\/p>\n

Here’s a real example. My remote repository is on my ISP’s server. The ISP’s spam filter puts spam emails into a folder called ‘Spam’, and deleted emails into ‘Trash’. The local repository, on a Debian server running Dovecot IMAP, is accessed by users via Outlook, which likes to use the folder name ‘Junk E-mail’ for spam and ‘Deleted Items’ for deleted emails.<\/p>\n

So to avoid confusion, I’ve set up name translations:<\/p>\n

[Repository LocalIMAP]\ntype = IMAP\nremotehost = localhost\n...\nnametrans = lambda foldername: re.sub ('^Junk E-mail$', 'Spam',\nre.sub ('^Deleted Items$', 'Trash',\nfoldername))\n\n[Repository RemoteIMAP]\ntype = IMAP\nremotehost = isp.example.com\n...\nnametrans = lambda foldername: re.sub ('^Spam$', 'Junk E-mail',\nre.sub ('^Trash$', 'Deleted Items',\nfoldername))<\/code><\/pre>\n

I won’t explain Python lambdas and regular expressions here. But beginners should note<\/p>\n

    \n
  1. the variable name after the word ‘lambda’ can be anything you like, but must be the same as is used in the expression after the ‘:’; it makes sense to call it ‘foldername’, or just ‘f’ if you don’t like typing.<\/li>\n
  2. the re.sub function takes three arguments:\n
      \n
    1. regular expression to match against the third argument<\/li>\n
    2. the string to return if there’s a match<\/li>\n
    3. the value to match against — here the folder name.<\/li>\n<\/ol>\n<\/li>\n
    4. the use of ^ and $ to mark the beginning and end of the match, i.e. to make sure the whole folder name is matched.<\/li>\n
    5. if there is no match, re.sub() returns the folder name unchanged.<\/li>\n
    6. re.sub() can be nested to allow more than one translation.<\/li>\n<\/ol>\n

      With this configuration, offlineimap will synchronise the local ‘Junk E-mail’ folder with the remote ‘Spam’ folder, and local ‘Deleted Items’ with remote ‘Trash’ in both directions.<\/p>\n

      Problems will occur if the ‘foreign’ name exists as a folder. For example, if ‘Trash’ exists on the local repository, you’ll get this error message:<\/p>\n

      ERROR: INFINITE FOLDER CREATION DETECTED! Folder 'Trash' (repository\n'LocalIMAP') would be created as folder 'Trash' (repository\n'RemoteIMAP'). The latter becomes 'Deleted Items' in return, leading to\ninfinite folder creation cycles.\nSOLUTION: 1) Do set your nametrans rules on both repositories so they\nlead to identical names if applied back and forth. 2) Use folderfilter\nsettings on a repository to prevent some folders from being created on\nthe other side.<\/code><\/pre>\n

      I found that message only partially helpful: does it mean use both solutions 1) and 2), or either?<\/p>\n

      Solution 3) would be “Remove folder ‘Trash’ from the local repository”, but if you don’t want to do that, then solution 2) is required: add a folderfilter to stop the local ‘Trash’ from being copied to the remote side, like this (in the local repository configuration):<\/p>\n

      folderfilter = lambda foldername: foldername not in ['Trash']<\/code><\/pre>\n

      That folderfilter is only required, in this example, if ‘Trash’ already exists locally, or if there is any danger of it being created in the future. It’s always possible that a translated folder name could be created by the user, so it’s safest to add folderfilters for any translated folder names. To complete my real-world example from above, I need:<\/p>\n

      [Repository LocalIMAP]\n# Has folders: Inbox, Junk E-mail, Deleted Items, etc.\ntype = IMAP\nremotehost = localhost\n...\nnametrans = lambda foldername: re.sub ('^Junk E-mail$', 'Spam',\n                                re.sub ('^Deleted Items$', 'Trash',\n                                foldername))\nfolderfilter = lambda foldername: foldername not in ['Spam', 'Trash']\n\n[Repository RemoteIMAP]\n# Has folders: Inbox, Spam, Trash, etc.\ntype = IMAP\nremotehost = isp.example.com\n...\nnametrans = lambda foldername: re.sub ('^Spam$', 'Junk E-mail',\n                                re.sub ('^Trash$', 'Deleted Items',\n                                foldername))\nfolderfilter = lambda foldername: foldername not in ['Junk E-mail',\n                                                     'Deleted Items']\n<\/code><\/pre>\n

      I hope that’s clear, and that it’s helpful to people. Perhaps some of it could be included in the offlineimap documentation.<\/p>\n","protected":false},"excerpt":{"rendered":"

      (Originally posted on the offlineimap mailing list on 15 Jan 2012) I’ve finally got offlineimap’s ‘nametrans’ feature to do what I want. Part of the problem was that I found the documentation and examples to be somewhat ambiguous in terms of which direction the translation would happen. Anyway, I’ve got it working, so here are […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[42,29],"tags":[],"_links":{"self":[{"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/posts\/1053"}],"collection":[{"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/comments?post=1053"}],"version-history":[{"count":1,"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/posts\/1053\/revisions"}],"predecessor-version":[{"id":1284,"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/posts\/1053\/revisions\/1284"}],"wp:attachment":[{"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/media?parent=1053"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/categories?post=1053"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wp.fbcs.co.uk\/wp-json\/wp\/v2\/tags?post=1053"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}