1#!/usr/bin/env python3
2
3# Script name : tbird2claws.py
4# Script purpose : Integrate a Thunderbird folder tree to Claws Mail
5# Author : Aleksandar Urosevic aka Urke MMI <urke@gmx.net>
6# Licence : GPL
7# Author: Rodrigo Dias Arruda Senra
8
9#The script receives two parameters from command-line:
10#<Thunderbird folder path> <Claws Mail folder path>
11
12#Best way to use it is to go to inside yout Thunderbird
13#root mailfolder directory and invoke it as:
14
15#<path>\python3 <path>\tbird2claws.py . <path to claws-mail>\Mail
16
17import os
18import sys
19import importlib
20
21__author__ = 'Rodrigo Senra <rsenra@acm.org>'
22__date__ =  '2005-03-23'
23__version__ =  '0.3'
24
25__doc__ = r"""
26This module integrates your Mozilla Thunderbird 1.0 tree to
27your Claws Mail MH mailbox tree.
28
29The script receives two parameters from command-line:
30 <Thunderbird folder path> <Claws Mail folder path>
31
32Best way to use it is to go to inside your Thunderbird
33root mailfolder directory and invoke it as:
34
35  <path>\python3 <path>\tbird2claws.py . <path to claws mail>\Mail
36
37This idiom will avoid the creation of the folder Thunderbird inside
38your Claws Mail folder tree.
39
40If the names of your directories match in both trees, files should
41be placed in the correct folder.
42
43This is an alpha release, so it may be a little rough around the edges.
44Nevertheless, I used it with great success to convert a very large and
45deep folder tree.
46
47Please, do backup your claws-mail (destination) folder tree before trying
48this out. Live safe and die old!
49
50This code is released in the public domain.
51"""
52
53def harvest_offsets(filepath):
54    """Given the filepath, this runs through the file finding
55    the number of the line where a message begins.
56
57    The function returns a list of integers corresponding to
58    the beginning of messages.
59    """
60    offsets = []
61    i = 0
62    state = 'begin'
63    for i,line in enumerate(open(filepath)):
64        if line.startswith('From - ') and state!='found_head':
65           offsets.append(i)
66           continue
67#        elif line.startswith('Return-Path') and state=='found_head':
68#	    state = 'found_offset'
69#	    offsets.append(i)
70#	    continue
71    offsets.append(i)
72    return offsets
73
74def make_messages(outputdir, filepath, offsets, start):
75    """Given a filepath holding several messages in Thunderbird format,
76    extract the messages and create individual files for them, inside
77    outputdir with appropriate the appropriate naming scheme.
78    """
79    if not os.path.exists(outputdir):
80        os.makedirs(outputdir)
81    if not os.path.exists(filepath):
82        raise Exception('Cannot find message file  %s'%(filepath))
83    lines = open(filepath).readlines()
84    aux = offsets[:]
85    msgoffs = zip(offsets[:-1], aux[1:])
86    for i,j in msgoffs:
87       fd  = open(os.path.join(outputdir,"%d"%start),"w")
88       fd.write(''.join(lines[i:j-1])) #-1 to remove first from line
89       fd.close()
90       start +=1
91
92def process_file(filepath, outputdir):
93    """Integrates a Thunderbird message file into a claws-mail message directory.
94    """
95    offs = harvest_offsets(filepath)
96    make_messages(outputdir, filepath, offs, 1)
97
98def clean_path(path):
99    """Rename all directories and subdirectories <X>.sbd to <X>
100    """
101    l = []
102    f = os.path.basename(path)
103    while f and f != "":
104        if f.endswith('.sbd'):
105            f = f[:-4]
106        l.append(f)
107        path = os.path.dirname(path)
108        f = os.path.basename(path)
109    l.reverse()
110    r = os.path.join(*l)
111    return r
112
113
114
115def convert_tree(in_treepath, out_treepath):
116    """Traverse your thunderbird tree, converting each message file found into
117    a claws-mail message directory.
118    """
119    for path,subs,files in os.walk(in_treepath):
120        outpath = clean_path(path)
121        if files:
122            for f in [x for x in files if not x.endswith('.msf')]:
123                process_file(os.path.join(path,f),
124                             os.path.join(out_treepath,outpath,f))
125
126if __name__=='__main__':
127    if len(sys.argv)<3:
128        print (__doc__)
129    else:
130        if sys.version[0] == '2':
131            importlib.reload(sys)
132            sys.setdefaultencoding('utf8')
133        convert_tree(sys.argv[1], sys.argv[2])
134