8bd4ef31b665861e60f57c83a865ac6a3c2bb7d0
Benjamin Renard Initial commit

Benjamin Renard authored 10 years ago

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) 
Benjamin Renard Add support to 'ALL' Thunde...

Benjamin Renard authored 10 years ago

110) 		if f["condition"]=='ALL':
111) 			sf['match']='allmessages'
112) 		else:
113) 			fc=thunderbirdFilters.convert_conditions(f["condition"])
114) 			bool_ops=[]
115) 			sfr=[]
116) 			for c in fc:
117) 				r={}
118) 				if c['bool_operator'] not in bool_ops:
119) 					bool_ops.append(c['bool_operator'])
120) 		
121) 				if c['cri_operator']=='contains' or c['cri_operator']=='is':
122) 					r['operator']=c['cri_operator']
123) 				elif c['cri_operator']=="isn't":
124) 					r['operator']='is_not'
125) 				else:
126) 					raise Exception('Condition operator "%s" not recognized. Pass' % c['cri_operator'])
127) 				if c['cri_operand'] in ['subject','to','from']:
128) 					r['field']=c['cri_operand']
Benjamin Renard Add support to 'to or cc' T...

Benjamin Renard authored 10 years ago

129) 				elif c['cri_operand']=='to or cc':
130) 					r['field']='to_or_cc'
Benjamin Renard Add support to 'ALL' Thunde...

Benjamin Renard authored 10 years ago

131) 				elif c['cri_operand']=='cc':
132) 					r['field']='to_or_cc'
133) 					if not options.dontwarncc:
134) 						logging.warning('Filter %s : Condition operator cc convert to to_or_cc' % f['name'])
135) 				elif c['cri_operand'].startswith('"') and c['cri_operand'].endswith('"'):
136) 					r['field']='header'
137) 					r['custom_header']=re.sub('^"(.*)"$',r'\1',c['cri_operand'],count=1)
138) 				else:
139) 					raise Exception('Condition operand "%s" not recognized. Pass' % c['cri_operand'])
140) 				r['value']=c['value']
141) 				sfr.append(r)
142) 			if len(sfr)==0:
143) 				logging.error('Filter %s : No condition found ! Pass this filter' % f['name'])
144) 				continue
145) 			sf['rules']=sfr
146) 		
147) 			if len(bool_ops)==1:
148) 				if bool_ops[0]=='AND':
149) 					sf['match']='all'
150) 				elif bool_ops[0]=='OR':
151) 					sf['match']='any'
152) 				else:
153) 					logging.error("Filter %s : Boolean operator not recognized %s, pass this filter." % (f['name'],bool_ops[0]))
154) 					continue
Benjamin Renard Initial commit

Benjamin Renard authored 10 years ago

155) 			else:
Benjamin Renard Add support to 'ALL' Thunde...

Benjamin Renard authored 10 years ago

156) 				logging.error('Filter %s : Multiple boolean operator not supported (%s). Pass this filter.' % (f['name'],','.join(bool_ops)))