Initial commit
Benjamin Renard

Benjamin Renard commited on 2013-12-25 20:10:39
Showing 6 changed files, with 684 additions and 0 deletions.

... ...
@@ -0,0 +1,2 @@
1
+*.pyc
2
+*~
... ...
@@ -0,0 +1,96 @@
1
+Thunderbird to SOGo scripts
2
+===========================
3
+
4
+Convert Thunderbird mail directory to Maildir format
5
+----------------------------------------------------
6
+
7
+The thunderbird2maildir script permit to transform Thunderbird mail
8
+directory in Maildir format. This script take Thunderbird mail
9
+directory path (-m parameter) and inspect content to find mbox file
10
+and convert relative path in maildir hierarchic path. You could use
11
+-r parameter to replace accents in maildir path to avoid encoding
12
+problems. It use perfect_maildir.pl [1] script (path could be specify
13
+by using -P parameter) to convert mbox file to Maildir.
14
+
15
+[1] perfect_maildir.pl : http://perfectmaildir.home-dn.net/
16
+
17
+    Usage: thunderbird2maildir [options]
18
+    
19
+    Options:
20
+      -h, --help            show this help message and exit
21
+      -m MBDIR              The Mbox Thunderbird mail directory
22
+      -M MDDIR              The maildir directory
23
+      -P PERFECTMAILDIR     The perfect_maildir.pl script path
24
+      -t, --just-try        
25
+      -r, --replace-accents
26
+                            Remove accent in folder names
27
+      -v, --verbose         
28
+      -d, --debug
29
+
30
+Convert Thunderbird mail filters to SOGo JSON format
31
+----------------------------------------------------
32
+
33
+The convertFilters script permit to convert Thunderbird mail filters
34
+to SOGo filters. It take as input msgFilterRules.dat path (-f parameter),
35
+parse file and try to convert filters in SOGo equivalent. Some filters
36
+conditions or actions can't be converted as SOGo filters, so warning or
37
+critical messages will be inform you of possible conversions problems.
38
+Output is in JSON format. By default, JSON string is write and stdout
39
+but you could provide with -o parameter a file path where JSON have to
40
+be write.
41
+
42
+    Usage: convertFilters [options]
43
+    
44
+    Options:
45
+      -h, --help            show this help message and exit
46
+      -f FILE               The msgFilterRules.dat path
47
+      -o OUT                Output path (default : '-' => stdout)
48
+      -p, --pretty          Pretty JSON output
49
+      -j, --just-try        Just-try mode (no output)
50
+      --dont-warn-cc        Don't warn about cc -> to_or_cc convertion
51
+      -r, --replace-accents
52
+                            Remove accent in folder names
53
+      -v, --verbose         
54
+      -d, --debug
55
+
56
+The thunderbirdFilters.py library is inspired by tbprocmailconv.py script :
57
+
58
+http://sourceforge.net/projects/tbprocmailconv/
59
+
60
+Load JSON in SOGo profile
61
+~~~~~~~~~~~~~~~~~~~~~~~~~
62
+
63
+Run as sogo user :
64
+
65
+  echo "[USER]:[PASS]" > /tmp/[USER].pass
66
+  /usr/sbin/sogo-tool user-preferences set defaults [USER] -p /tmp/[USER].pass \
67
+  SOGoSieveFilters -f /tmp/[USER].json
68
+  rm [USER].pass
69
+
70
+With :
71
+
72
+  * [USER] : user's login
73
+  * [PASS] : user's password
74
+
75
+The JSON file must be /tmp/[USER].json.
76
+
77
+Copyright
78
+=========
79
+
80
+Copyright (c) 2013 Benjamin Renard
81
+
82
+License
83
+=======
84
+
85
+This program is free software; you can redistribute it and/or
86
+modify it under the terms of the GNU General Public License version 2
87
+as published by the Free Software Foundation.
88
+
89
+This program is distributed in the hope that it will be useful,
90
+but WITHOUT ANY WARRANTY; without even the implied warranty of
91
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
92
+GNU General Public License for more details.
93
+
94
+You should have received a copy of the GNU General Public License
95
+along with this program; if not, write to the Free Software
96
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
... ...
@@ -0,0 +1,221 @@
1
+#!/usr/bin/python
2
+# -*- coding: utf-8 -*-
3
+#
4
+# This script permit to convert Thunderbird mail filters to SOGo
5
+# filters. It take as input msgFilterRules.dat path (-f parameter),
6
+# parse file and try to convert filters in SOGo equivalent. Some 
7
+# filters conditions or actions can't be converted as SOGo filters,
8
+# so warning or critical messages will be inform you of possible
9
+# conversions problems. Output is in JSON format. By default, JSON
10
+# string is write and stdout but you could provide with -o parameter
11
+# a file path where JSON have to be write.
12
+#
13
+# To know how to load JSON in SOGo, see README file.
14
+#
15
+# Author : Benjamin Renard <brenard@zionetrix.net>
16
+# Date : Wed, 25 Dec 2013 20:41:39 +0100
17
+# Source : http://git.zionetrix.net/thunderbird2sogo
18
+
19
+from optparse import OptionParser
20
+import sys
21
+import thunderbirdFilters
22
+import logging
23
+import json
24
+import re
25
+
26
+parser = OptionParser()
27
+
28
+parser.add_option('-f',
29
+                  action="store",
30
+                  type="string",
31
+                  dest="file",
32
+                  help="The msgFilterRules.dat path",
33
+                  default=None)
34
+parser.add_option('-o',
35
+                  action="store",
36
+                  type="string",
37
+                  dest="out",
38
+                  help="Output path (default : '-' => stdout) ",
39
+                  default='-')
40
+parser.add_option('-p','--pretty',
41
+                  action="store_true",
42
+                  dest="pretty",
43
+                  help="Pretty JSON output")
44
+parser.add_option('-j','--just-try',
45
+                  action="store_true",
46
+                  dest="justtry",
47
+                  help="Just-try mode (no output)")
48
+parser.add_option('--dont-warn-cc',
49
+                  action="store_true",
50
+                  dest="dontwarncc",
51
+                  help="Don't warn about cc -> to_or_cc convertion",
52
+		  default=False)
53
+parser.add_option('-r',
54
+                  '--replace-accents',
55
+		  help='Remove accent in folder names',
56
+                  action="store_true",
57
+                  dest="replaceaccents")
58
+parser.add_option('-v',
59
+                  '--verbose',
60
+                  action="store_true",
61
+                  dest="verbose")
62
+parser.add_option('-d',
63
+                  '--debug',
64
+                  action="store_true",
65
+                  dest="debug")
66
+
67
+(options, args) = parser.parse_args()
68
+
69
+if options.debug:
70
+	loglevel=logging.DEBUG
71
+elif options.verbose:
72
+        loglevel=logging.INFO
73
+else:  
74
+        loglevel=logging.WARNING
75
+
76
+logging.basicConfig(level=loglevel,format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
77
+
78
+if options.file is None:
79
+	logging.fatal('You must provide msgFilterRules.dat path (-f)')
80
+	sys.exit(1)
81
+
82
+if options.out!='-':
83
+	try:
84
+		output_file=open(options.out,'w')
85
+	except Exception,e:
86
+		logging.fatal('Error opening output file %s : %s' % (options.out,e))
87
+		sys.exit(2)
88
+
89
+(tbf,warning)=thunderbirdFilters.read_from_file(options.file)
90
+if len(warning)!=0:
91
+	logging.warning('Parsing msgFilterRules.dat return warnings :\n - %s' % '\n - '.join(warning))
92
+logging.debug('Parsing return :\n%s' % tbf)
93
+sfs=[]
94
+
95
+for f in tbf:
96
+	if f['type'] != "17":
97
+		logging.error("Filter type '%s' no recognized, pass this filter" % f['type'])
98
+		continue
99
+	try:
100
+		sf={}
101
+		if f["enabled"]=='yes':	
102
+			sf["active"]=1
103
+		else:
104
+			sf["active"]=0
105
+		if 'name' not in f:
106
+			logging.error('Thunderbird filter does not have name ! Pass this filter : %s' % f)
107
+			continue
108
+		sf['name']=f['name']
109
+		fc=thunderbirdFilters.convert_conditions(f["condition"])
110
+		bool_ops=[]
111
+		sfr=[]
112
+		for c in fc:
113
+			r={}
114
+			if c['bool_operator'] not in bool_ops:
115
+				bool_ops.append(c['bool_operator'])
116
+
117
+			if c['cri_operator']=='contains' or c['cri_operator']=='is':
118
+				r['operator']=c['cri_operator']
119
+			elif c['cri_operator']=="isn't":
120
+				r['operator']='is_not'
121
+			else:
122
+				raise Exception('Condition operator "%s" not recognized. Pass' % c['cri_operator'])
123
+			if c['cri_operand'] in ['subject','to','from']:
124
+				r['field']=c['cri_operand']
125
+			elif c['cri_operand']=='cc':
126
+				r['field']='to_or_cc'
127
+				if not options.dontwarncc:
128
+					logging.warning('Filter %s : Condition operator cc convert to to_or_cc' % f['name'])
129
+			elif c['cri_operand'].startswith('"') and c['cri_operand'].endswith('"'):
130
+				r['field']='header'
131
+				r['custom_header']=re.sub('^"(.*)"$',r'\1',c['cri_operand'],count=1)
132
+			else:
133
+				raise Exception('Condition operand "%s" not recognized. Pass' % c['cri_operand'])
134
+			r['value']=c['value']
135
+			sfr.append(r)
136
+		if len(sfr)==0:
137
+			logging.error('Filter %s : No condition found ! Pass this filter' % f['name'])
138
+			continue
139
+		sf['rules']=sfr
140
+
141
+		if len(bool_ops)==1:
142
+			if bool_ops[0]=='AND':
143
+				sf['match']='all'
144
+			elif bool_ops[0]=='OR':
145
+				sf['match']='any'
146
+			else:
147
+				logging.error("Filter %s : Boolean operator not recognized %s, pass this filter." % (f['name'],bool_ops[0]))
148
+				continue
149
+		else:
150
+			logging.error('Filter %s : Multiple boolean operator not supported (%s). Pass this filter.' % (f['name'],','.join(bool_ops)))
151
+			continue
152
+		sfa=[]
153
+		for a in f['actions']:
154
+			if a[0]=='Move to folder':
155
+				sa={
156
+					'method': 'fileinto',
157
+					'argument': thunderbirdFilters.convert_uri_path_to_maildir(a[1],separator='/',replaceaccents=options.replaceaccents)
158
+				}
159
+			elif a[0]=='Forward':
160
+				sa={
161
+					'method': 'redirect',
162
+					'argument': a[1]
163
+				}
164
+			elif a[0]=='Mark read':
165
+				sa={
166
+					'method': 'addflag',
167
+					'argument': 'seen'
168
+				}
169
+			elif a[0]=='JunkScore':
170
+				if a[1]==0:
171
+					argument='not_junk'
172
+				else:
173
+					argument='junk'
174
+				sa={
175
+					'method': 'addflag',
176
+					'argument': argument
177
+				}
178
+			elif a[0]=='Mark flagged':
179
+				sa={
180
+					'method': 'addflag',
181
+					'argument': 'flagged'
182
+				}
183
+			elif a[0]=='Stop execution':
184
+				sa={
185
+					'method': 'stop',
186
+					'argument': None
187
+				}
188
+			elif a[0] in ['Mark unread','Copy to folder','Change priority','Reply']:
189
+				raise Exception("Action %s doesn't have equivalent in SOGo" % a[0])
190
+			else:
191
+				raise Exception('Filter %s : Action %s not supported' % (f['name'],a[0]))
192
+			sfa.append(sa)
193
+		if len(sfa)==0:
194
+			logging.error('Filter %s : no action found ! Pass this filter.' % f['name'])
195
+			continue
196
+		sf['actions']=sfa
197
+		sfs.append(sf)
198
+	except Exception,e:
199
+		if 'name' in f:
200
+			name=f['name']
201
+		else:
202
+			name=f
203
+		logging.fatal('Failed to convert filter %s, pass : %s' % (name,e))
204
+		continue
205
+
206
+output_data={'SOGoSieveFilters': sfs}
207
+
208
+if options.justtry:
209
+	sys.exit(0)
210
+
211
+if options.pretty:
212
+	output_text=json.dumps(output_data,indent=4, separators=(',', ': '))
213
+else:
214
+	output_text=json.dumps(output_data)
215
+
216
+if options.out=='-':
217
+	print output_text
218
+else:
219
+	logging.info('Write SOGo filters on %s file' % options.out)
220
+	output_file.write(output_text)
221
+	output_file.close()
... ...
@@ -0,0 +1,73 @@
1
+#!/usr/bin/python
2
+# -*- coding: utf-8 -*-
3
+#
4
+# This simple library provide function to replace accents
5
+# in string. It's part of thunderbird2sogo scripts.
6
+#
7
+# Author : Benjamin Renard <brenard@zionetrix.net>
8
+# Date : Wed, 25 Dec 2013 20:41:39 +0100
9
+# Source : http://git.zionetrix.net/thunderbird2sogo
10
+
11
+import string
12
+
13
+def replace_accents(s):
14
+	replacements={
15
+		"à": "a",
16
+		"á": "a",
17
+		"â": "a",
18
+		"ã": "a",
19
+		"ä": "a",
20
+		"ç": "c",
21
+		"è": "e",
22
+		"é": "e",
23
+		"ê": "e",
24
+		"ë": "e",
25
+		"ì": "i",
26
+		"í": "i",
27
+		"î": "i",
28
+		"ï": "i",
29
+		"ñ": "n",
30
+		"ò": "o",
31
+		"ó": "o",
32
+		"ô": "o",
33
+		"õ": "o",
34
+		"ö": "o",
35
+		"ù": "u",
36
+		"ú": "u",
37
+		"û": "u",
38
+		"ü": "u",
39
+		"ý": "y",
40
+		"ÿ": "y",
41
+		"À": "A",
42
+		"Á": "A",
43
+		"Â": "A",
44
+		"Ã": "A",
45
+		"Ä": "A",
46
+		"Ç": "C",
47
+		"È": "E",
48
+		"É": "E",
49
+		"Ê": "E",
50
+		"Ë": "E",
51
+		"Ì": "I",
52
+		"Í": "I",
53
+		"Î": "I",
54
+		"Ï": "I",
55
+		"Ñ": "N",
56
+		"Ò": "O",
57
+		"Ó": "O",
58
+		"Ô": "O",
59
+		"Õ": "O",
60
+		"Ö": "O",
61
+		"Ù": "U",
62
+		"Ú": "U",
63
+		"Û": "U",
64
+		"Ü": "U",
65
+		"Ý": "Y"
66
+	}
67
+	for f in replacements:
68
+		s=s.replace(f,replacements[f])
69
+	return s
70
+
71
+if __name__ == '__main__':
72
+	test='éàèôù'
73
+	print '%s -> %s' % (test,replace_accents(test))
... ...
@@ -0,0 +1,168 @@
1
+#!/usr/bin/python
2
+# -*- coding: utf-8 -*-
3
+#
4
+# This script permit to transform Thunderbird mail directory in
5
+# Maildir format. This script take Thunderbird mail directory path
6
+# (-m parameter) and inspect content to find mbox file and convert
7
+# relative path in maildir hierarchic path. You could use -r
8
+# parameter to replace accents in maildir path to avoid encoding
9
+# problems. It use perfect_maildir.pl [1] script (path could be
10
+# specify by using -P parameter) to convert mbox file to Maildir.
11
+#
12
+# Author : Benjamin Renard <brenard@zionetrix.net>
13
+# Date : Wed, 25 Dec 2013 20:41:39 +0100
14
+# Source : http://git.zionetrix.net/thunderbird2sogo
15
+
16
+from optparse import OptionParser
17
+
18
+import os
19
+import re
20
+import logging
21
+import sys
22
+import subprocess
23
+from replace_accents import replace_accents
24
+
25
+parser = OptionParser()
26
+
27
+parser.add_option('-m',
28
+                  action="store",
29
+                  type="string",
30
+                  dest="mbdir",
31
+                  help="The Mbox Thunderbird mail directory",
32
+                  default=None)
33
+
34
+parser.add_option('-M',
35
+                  action="store",
36
+                  type="string",
37
+                  dest="mddir",
38
+                  help="The maildir directory",
39
+                  default=None)
40
+
41
+parser.add_option('-P',
42
+                  action="store",
43
+                  type="string",
44
+                  dest="perfectmaildir",
45
+                  help="The perfect_maildir.pl script path",
46
+                  default='perfect_maildir.pl')
47
+
48
+parser.add_option('-t',
49
+                  '--just-try',
50
+                  action="store_true",
51
+                  dest="justtry")
52
+
53
+parser.add_option('-r',
54
+                  '--replace-accents',
55
+		  help='Remove accent in folder names',
56
+                  action="store_true",
57
+                  dest="replaceaccents")
58
+
59
+parser.add_option('-v',
60
+                  '--verbose',
61
+                  action="store_true",
62
+                  dest="verbose")
63
+
64
+parser.add_option('-d',
65
+                  '--debug',
66
+                  action="store_true",
67
+                  dest="debug")
68
+
69
+(options, args) = parser.parse_args()
70
+
71
+if options.debug:
72
+        loglevel=logging.DEBUG
73
+elif options.verbose:
74
+        loglevel=logging.INFO
75
+else:  
76
+        loglevel=logging.WARNING
77
+
78
+logging.basicConfig(level=loglevel,format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
79
+
80
+if not options.mbdir or not options.mddir:
81
+	logging.fatal('You must provide Mbox directory and Maildir directory')
82
+	sys.exit(1)
83
+
84
+if not os.path.isdir(options.mbdir):
85
+	logging.fatal('The directory %s does not exists' % options.mbdir)
86
+	sys.exit(1)
87
+
88
+options.mbdir=os.path.abspath(options.mbdir)
89
+
90
+if os.path.exists(options.mddir):
91
+	logging.fatal('The destination Maildir directory already exists')
92
+	sys.exit(1)
93
+
94
+def maildir_make(dir):
95
+	if options.justtry:
96
+		logging.info('Maildir make %s' % dir)
97
+		return
98
+	os.mkdir(dir)
99
+	for s in ['cur','new','tmp']:
100
+		os.mkdir('%s/%s' % (dir,s))
101
+
102
+def isMboxFile(file):
103
+	return open(file,'r').readline().startswith('From ')
104
+
105
+maildir_make(options.mddir)
106
+options.mddir=os.path.abspath(options.mddir)
107
+
108
+def listMbox(dir,mboxlist):
109
+	for fname in os.listdir(dir):
110
+		path="%s%s" % (dir,fname)
111
+		if os.path.isfile(path):
112
+			if not re.search('\.(msf|dat|html|wdseml)$',fname) and isMboxFile(path):
113
+				md=re.sub('\.sbd/','/',path)
114
+				md=re.sub('^\.\/','.',md)
115
+				md=re.sub('\/+','.',md)
116
+				md=re.sub('^\.Inbox(\.|$)','INBOX.',md)
117
+				if options.replaceaccents:
118
+					md=replace_accents(md)
119
+				md=md.decode('utf-8').encode('utf-7')
120
+				md=re.sub('\+','&',md)
121
+				mboxlist[path]=md
122
+			elif options.debug:
123
+				logging.debug('File %s is not mbox' % path)
124
+		elif os.path.isdir(path):
125
+			path="%s/" % path
126
+			listMbox(path,mboxlist)
127
+		else:
128
+			print "unknown path '%s'" % path
129
+
130
+mboxlist={}
131
+os.chdir(options.mbdir)
132
+listMbox('./',mboxlist)
133
+
134
+def runPerfectMaildir(maildir,mbox):
135
+	if options.justtry:
136
+		logging.info("Run perfect_maildir.pl on maildir '%s' with mbox file '%s'" % (maildir, mbox))
137
+		return
138
+	logging.info("Read mbox file %s" % mbox)
139
+	f=open(mbox,'r')
140
+	data=f.read()
141
+	f.close()
142
+	logging.info("Running perfect_maildir.pl on maildir '%s' with mbox file '%s'" % (maildir,mbox))
143
+	p = subprocess.Popen(['perfect_maildir.pl',maildir],stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE)
144
+	output, err = p.communicate(data)
145
+	logging.info("End of perfect_maildir.pl : %s" % (output))
146
+	
147
+
148
+if './Inbox' in mboxlist:
149
+	runPerfectMaildir(options.mddir,'%s/Inbox' %options.mbdir)
150
+	del mboxlist['./Inbox']
151
+
152
+subs=[]
153
+for mbox in sorted(mboxlist.keys()):
154
+	maildir_make("%s/%s" % (options.mddir,mboxlist[mbox]))
155
+	runPerfectMaildir('%s/%s' % (options.mddir,mboxlist[mbox]),'%s/%s' % (options.mbdir,mbox))
156
+	subs.append(re.sub('^\.','',mboxlist[mbox]))
157
+
158
+
159
+if not options.justtry:
160
+	f=open('%s/subscriptions' % options.mddir,'w')
161
+logging.info('Write in subscriptions file :')
162
+for s in subs:
163
+	logging.info(s)
164
+	if not options.justtry:
165
+		f.write("%s\n" % s)
166
+
167
+if not options.justtry:
168
+	f.close()
... ...
@@ -0,0 +1,124 @@
1
+#!/usr/bin/python
2
+
3
+# This library is inspired by tbprocmailconv.py script
4
+# writed by Michael Scheper :
5
+# http://tbprocmailconv.sourceforge.net/
6
+# Some part of this script is simply copy from original
7
+# script with some corrections and adjustments.
8
+#
9
+# It's part of thunderbird2sogo scripts.
10
+#
11
+# Author : Benjamin Renard <brenard@zionetrix.net>
12
+# Date : Wed, 25 Dec 2013 20:41:39 +0100
13
+# Source : http://git.zionetrix.net/thunderbird2sogo
14
+
15
+import os
16
+import re
17
+import sys
18
+import urllib
19
+import logging
20
+from replace_accents import replace_accents
21
+
22
+def read_from_file(file):
23
+	"Read the Thunderbird filters file into a list of maps."
24
+
25
+	filters = []
26
+	current_filter = None
27
+	current_actions = []
28
+	warnings = []
29
+
30
+	# Each value gets run through each of these regex replacements.
31
+	value_replacements = (
32
+			(re.compile(r'\\\"'), '"'),
33
+			(re.compile(r'^ *\"(.*)\"\r*\n?$'), r'\1'),
34
+	)
35
+
36
+	for line in open(file):
37
+		(key, value) = line.split('=',1)
38
+		for (regex, repl) in value_replacements:
39
+			value = regex.sub(repl, value)
40
+
41
+		logging.debug('Key %s => %s' % (key,value))
42
+		# Each filter starts with a name.
43
+		if key == 'name':
44
+			if current_filter is not None:
45
+				if any(current_actions):
46
+					current_filter['actions'] = current_actions
47
+				logging.debug("Add filter : %s" % current_filter)
48
+				filters.append(current_filter)
49
+			logging.debug("Initialize new filter")
50
+			current_filter = {}
51
+			current_actions = []
52
+
53
+		# If we're still not up to the first filter, ignore this line.
54
+		if current_filter is None:
55
+			continue
56
+
57
+		# Each filter can have multiple actions. Each action has an optional
58
+		# actionValue.
59
+		if key == 'action':
60
+			logging.debug('New action : %s' % value)
61
+			# We'll add the value later if there is one.
62
+			current_actions.append((value, None))
63
+		elif key == 'actionValue':
64
+			if not any(current_actions):
65
+				warnings.append('Ignored unexpected action value "%s" in '
66
+						'"%s"' % (current_actions[-1][0],
67
+						current_filter.get('name', '(unnamed filter)')))
68
+			elif current_actions[-1][1] is not None:
69
+				warnings.append('Ignored extra value "%s" for action "%s" '
70
+						'in "%s"' % (value, current_actions[-1][0],
71
+						current_filter.get('name', '(unnamed filter)')))
72
+			else:
73
+				current_action = current_actions.pop()
74
+				current_actions.append((current_action[0], value))
75
+		else:
76
+			if key in current_filter:
77
+				warnings.append('Ignored extra %s ("%s") in %s' % (key, value,
78
+						current_filter.get('name', '(unnamed filter)')))
79
+			else:
80
+				current_filter[key] = value
81
+	if any(current_actions):
82
+		current_filter['actions'] = current_actions
83
+	logging.debug("Add filter : %s" % current_filter)
84
+	filters.append(current_filter)
85
+	return (filters, warnings)
86
+
87
+condition_regex = re.compile('(AND|OR) \(([^,]+),([^,]+),([^)]+)\) *')
88
+def convert_conditions(tb_condition):
89
+    "Converts a Thunderbird condition string into procmail condition strings."
90
+    conditions = []
91
+
92
+    for match in condition_regex.finditer(tb_condition):
93
+
94
+        (bool_operator, cri_operand, cri_operator, value) = match.groups()
95
+
96
+	conditions.append({
97
+		'bool_operator': bool_operator,
98
+		'cri_operand': cri_operand,
99
+		'cri_operator': cri_operator,
100
+		'value': value
101
+	})
102
+
103
+    return conditions
104
+
105
+_convert_uri_path_to_sogo=re.compile('^[a-z]*\:\/\/[^\/]*\/(.*)$')
106
+def convert_uri_path_to_maildir(path,separator='.',replaceaccents=False):
107
+	# URL decode
108
+	path=urllib.unquote(path)
109
+	# Remove URI prefix
110
+	path=_convert_uri_path_to_sogo.sub(r'\1',path)
111
+	# Replace accents
112
+	if replaceaccents:
113
+		path=replace_accents(path)
114
+	# UTF7 encode
115
+	path=path.decode('UTF-8').encode('UTF-7')
116
+	# Replace '+' by '&'
117
+	path=re.sub('\+','&',path)
118
+	# Replace ^Inbox by INBOX
119
+	path=re.sub('^Inbox\/','INBOX/',path)
120
+	# Replace '/' by separator
121
+	if separator!='/':
122
+		path=re.sub('\/',separator,path)
123
+	return path
124
+
0 125