Created
September 21, 2017 08:44
-
-
Save costastf/c5fc1dd0f73e566d312e7d6c5484b140 to your computer and use it in GitHub Desktop.
Legacy code to translate a thunderbird msgFilterRules.dat to gmail.xml format
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2.7 | |
# -*- coding: UTF-8 -*- | |
# File: moz_filter_to_gmail | |
# | |
__author__ = 'Costas Tyfoxylos <costas.tyf@gmail.com>' | |
__docformat__ = 'plaintext' | |
__date__ = '2015-04-14' | |
import sys | |
import logging | |
import argparse | |
import os | |
from string import Template | |
# This is the main prefix used for logging | |
logger_basename = 'thunderbird2gmail' | |
logger = logging.getLogger(logger_basename) | |
ch = logging.StreamHandler() | |
ch.setLevel(logging.INFO) | |
# create formatter | |
formatter = logging.Formatter( | |
'%(asctime)s - %(name)s - %(levelname)s - %(message)s') | |
# add formatter to ch | |
ch.setFormatter(formatter) | |
# add ch to logger | |
logger.addHandler(ch) | |
logger.setLevel(logging.INFO) | |
class Filter(object): | |
def __init__(self, filter_condition): | |
self.properties = [] | |
self.active = True | |
self.label = '' | |
self.name = '' | |
self.render_filter(filter_condition) | |
def render_filter(self, filter_condition): | |
if not all(text in filter_condition for text in | |
['name', 'actionValue', 'condition']): | |
self.active = False | |
return False | |
self.name = self.__get_name(filter_condition) | |
self.label = self.__get_label(filter_condition) | |
self.properties = self.__get_properties(filter_condition) | |
@staticmethod | |
def __get_name(filter_condition): | |
name = '' | |
for line in filter_condition.splitlines(): | |
if line.startswith('name'): | |
name = line.split('"')[1] | |
break | |
return name | |
@staticmethod | |
def __get_properties(filter_condition): | |
found = False | |
filter_type = '' | |
properties = [] | |
for line in filter_condition.splitlines(): | |
if line.startswith('condition'): | |
condition = line.split('"')[1] | |
break | |
if 'AND' in condition: | |
conditions = condition.split('AND ')[1:] | |
filter_type = '&&' | |
elif 'OR' in condition: | |
conditions = condition.split('OR ')[1:] | |
filter_type = '||' | |
for condition in conditions: | |
condition = condition.replace('(', '').replace(')', | |
'').strip().split( | |
',') | |
if not properties: | |
properties.append([condition[0], condition[2]]) | |
else: | |
for prop in properties: | |
if condition[0] == prop[0]: | |
prop[1] = '{property} {type} {condition}'.format( | |
property=prop[1], | |
type=filter_type, | |
condition=condition[2]) | |
found = True | |
if not found: | |
properties.append([condition[0], condition[2]]) | |
return properties | |
@staticmethod | |
def __get_label(filter_condition): | |
value = '' | |
for line in filter_condition.splitlines(): | |
if line.startswith('actionValue'): | |
value = line.split('//')[1].partition('/')[2].replace('"', '') | |
break | |
return value | |
class MozToGmail(object): | |
def __init__(self, filter_file): | |
self.filters = self.__read_file(filter_file) | |
self.records = [] | |
self.email = '' | |
self.name = '' | |
self.__populate() | |
self.root_template = '''<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:apps='http://schemas.google.com/apps/2006'> | |
<title>Mail Filters</title> | |
<id>tag:mail.google.com,2008:filters:$ids</id> | |
<updated>2015-04-14T13:17:46Z</updated> | |
<author> | |
<name>$name</name> | |
<email>$email</email> | |
</author> | |
$entries | |
</feed>''' | |
self.entry_template = '''<entry> | |
<category term='filter'></category> | |
<title>Mail Filter</title> | |
<id>tag:mail.google.com,2008:filter:$id</id> | |
<updated>2015-04-14T13:17:46Z</updated> | |
<content></content> | |
$properties | |
<apps:property name='label' value='$label'/> | |
<apps:property name='shouldArchive' value='true'/> | |
<apps:property name='sizeOperator' value='s_sl'/> | |
<apps:property name='sizeUnit' value='s_smb'/> | |
</entry> | |
''' | |
self.property_template = "<apps:property name='$name' value='$value'/>" | |
@staticmethod | |
def __read_file(filter_file): | |
try: | |
filters = open(filter_file).read() | |
except Exception: | |
logger.error('Unable to read file') | |
raise SystemExit(1) | |
return filters | |
def __populate(self): | |
for line in self.filters.splitlines(): | |
if line.startswith('actionValue="imap'): | |
self.email = line.split('//')[1].split('@')[0].replace('%40', | |
'@') | |
self.name = self.email.split('@')[0] | |
break | |
for filter in self.filters.split('\nname'): | |
record = Filter('\nname' + filter) | |
if record.active: | |
self.records.append(record) | |
def render(self, file_path): | |
ids = ','.join([str(num) for num in range(len(self.records))]) | |
entries = '' | |
properties = '' | |
for index, record in enumerate(self.records): | |
entry = Template(self.entry_template) | |
property = Template(self.property_template) | |
for item in record.properties: | |
properties += property.substitute(name=item[0], value=item[1]) | |
entries += entry.substitute(id=index, properties=properties, | |
label=record.label) | |
properties = '' | |
xml = Template(self.root_template) | |
text = xml.substitute(ids=ids, name=self.name, email=self.email, | |
entries=entries) | |
with open(os.path.join(file_path, 'mailFilters.xml'), 'w') as out_file: | |
out_file.write(text) | |
out_file.close() | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser( | |
description='thunderbird to gmail filter converter') | |
parser.add_argument('--input', '-i', | |
dest='input', | |
action='store', | |
help="thunderbird msgFilterRules.dat file", | |
required=True) | |
parser.add_argument('--output', '-o', | |
dest='output', | |
action='store', | |
help="path to save the google xml", | |
required=True) | |
args = parser.parse_args() | |
filters = MozToGmail(args.input) | |
filters.render(args.output) |
License is MIT so feel free.
Thx
Why is this "legacy"? Is there a newer version?
It's legacy because it's almost ten years old and there is no newer version
since I am not using thunderbird any more. It should be fairly easy to
tweak if this version does not work for you i would guess.
…On Thu, Feb 4, 2021, 09:28 Michele Locati ***@***.***> wrote:
***@***.**** commented on this gist.
------------------------------
Why is this "legacy"? Is there a newer version?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<https://gist.github.com/c5fc1dd0f73e566d312e7d6c5484b140#gistcomment-3619578>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABDMK25DEBJBYYGOD4DKKOLS5JLBJANCNFSM4JILFERQ>
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is there a license so I can reuse it?