2 # -*- coding: latin-1 -*-
5 Copyright © 2003 Bogdan Sumanariu <zarrok@yahoo.com>
7 This file is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 script name : evolutionvcard2claws.py
23 script purpose : convert an evolution addressbook VCARD file
24 into a Claws Mail addressbook
26 tested with evolution 1.2.x, and 1.4.x
34 from io
import StringIO
36 keywds
= ('x-evolution-file-as','fn', 'n','email;internet','nickname', 'url', 'org')
38 def normalizeLongLines(file):
40 Skip line breaks after 72 chars
44 line
= file.readline()
47 buf
= buf
.rstrip('\n')
52 line
= file.readline()
56 def getEmailAddress(vcard
):
61 - email;type=something
62 something := (internet,work,home, other)
66 items
= key
.split(';')
68 if items
[0].lower() == 'email':
72 if key
.lower() == 'email':
80 Find a version 3.0 name
83 items
= key
.split(';')
85 if items
[0].lower() == 'n':
88 if key
.lower() == 'n':
93 ################################################################################
94 ## reads a vcard and stores as hash pairs key/value where value is a list ##
95 ################################################################################
97 def readVCARD (buffer) :
101 skips fom <file> until a 'begin' tag from VCARD is encountered.
102 from this point starts constructing a map (key, [values] )
103 VCARD entry format -> tag:value
106 [values] <- list with the values of <tag> if there are more tags with the same name
112 while r
and bgn
< 0 :
113 r
= buffer.readline()
114 if len (r
) == 0 : return dict()
115 if r
.strip().lower().find('begin') :
117 while r
and end
< 0 :
118 r
= buffer.readline()
119 s
= r
.strip().lower().split(':')
127 if s
[0] == 'end' : end
= 1
130 ##################################################################################
132 ###############################################################################################
133 ## writes on a given file an xml representation for claws-mail addressbook received as a hash ##
134 ###############################################################################################
136 def writeXMLREPR (vcard
,file,uid
) :
139 based on <vcard> and <uid> writes only recognized tags (the ones defined in <keywds> list)
140 NOTE: <url> and <org> tag will be written as attributes (there are such tags in claws-mail's
143 if len (vcard
.keys()) == 0 : return
144 item
= vcard
.get(keywds
[2]);
146 name
= item
[0].split(';')
148 """ version 3.0 n ?"""
149 name
= findName(vcard
)
153 fn
, ln
, nick
, cn
, a
= '', '', '', '', ''
161 if keywds
[4] in vcard
:
162 nick
= vcard
.get(keywds
[4])[0]
163 if len(vcard
.get(keywds
[1])[0]) :
164 cn
= vcard
.get(keywds
[1])[0]
166 cn
= vcard
.get(keywds
[0])[0];
168 a
+= str('\n<person uid=\"' + str(uid
[0]) + '\" first-name=\"' + fn
+ '\" last-name=\"' + ln
169 + '\" nick-name=\"' + nick
+ '\" cn=\"' + cn
+ '\" >\n')
170 a
+= '\t<address-list>\n'
171 if vcard
.get(keywds
[3]) :
172 for c
in vcard
.get(keywds
[3]) :
174 a
+= '\t\t<address uid=\"' + str(uid
[0]) + '\" alias=\"' + nick
+ '\" email=\"' + c
+ '\" remarks=\"\" />\n'
176 email
= getEmailAddress(vcard
)
178 a
+= '\t\t<address uid=\"' + str(uid
[0]) + '\" alias=\"' + nick
+ '\" email=\"' + email
+ '\" remarks=\"\" />\n'
179 a
+= '\t</address-list>\n'
180 a
+= '\t<attribute-list>\n'
181 for key
in keywds
[5:] :
183 for c
in vcard
.get(key
) :
185 a
+= '\t\t<attribute uid=\"' + str(uid
[0]) + '\" name=\"' + key
+'\">'+c
+'</attribute>\n'
186 a
+= '\t</attribute-list>\n'
191 ###################################################################################################
193 def convert (in_f
, o_f
, name
='INBOX') :
195 uid
= [int(time
.time())]
198 print('proccessing...\n')
199 o_f
.write('<?xml version="1.0" encoding="ISO-8859-1" ?>\n<address-book name="'+name
+'" >\n');
201 buf
= normalizeLongLines(in_f
)
202 buffer = StringIO(buf
)
203 while len(d
.keys()) > 0 :
204 d
= readVCARD(buffer)
205 writeXMLREPR (d
, o_f
, uid
)
208 o_f
.write('\n</address-book>')
209 print('finished processing...\n')
210 except IOError as err
:
211 print('Caught an IOError : ',err
,'\t ABORTING!!!')
214 #################################################################################################
217 if len(sys
.argv
) != 3 and len(sys
.argv
) != 2 :
218 print(str("\nUsage: vcard2xml.py source_file [destination_file]\n\n" +
219 '\tWhen only <source_file> is specified will overwrite the existing addressbook.\n'+
220 '\tWhen both arguments are suplied will create a new additional addressbook named \n\tas the destination file.'+'\n\tNOTE: in both cases the Claws Mail must be closed and ran at least once.\n\n'))
225 path_to_out
= os
.environ
['HOME']+'/.claws-mail/addrbook/'
226 adr_idx
= 'addrbook--index.xml'
228 tmp_adr_idx_file
= None
232 in_file
= open(sys
.argv
[1])
234 print('Could not open input file <',sys
.argv
[1],'> ABORTING')
237 if len(sys
.argv
) == 2 :
239 dlist
= os
.listdir(path_to_out
);
242 if l
.find('addrbook') == 0 and l
.find("addrbook--index.xml") < 0 and l
.find('bak') < 0 :
245 out_file
= flist
.pop()
246 os
.rename(path_to_out
+out_file
, path_to_out
+out_file
+'.tmp')
247 out_file
= open(path_to_out
+out_file
,'w')
248 convert(in_file
, out_file
)
249 except Exception as e
:
251 print('got exception: ', e
)
254 os
.rename(path_to_out
+adr_idx
, path_to_out
+adr_idx
+'.tmp')
255 tmp_adr_idx_file
= open(path_to_out
+adr_idx
+'.tmp')
256 adr_idx_file
= open(path_to_out
+adr_idx
,'w')
257 except Exception as e
:
258 print('Could not open <', path_to_out
+adr_idx
,'> file. Make sure you started Claws Mail at least once.')
261 out_file
= open(path_to_out
+sys
.argv
[2],'w')
262 convert(in_file
, out_file
, sys
.argv
[2].split('.xml')[0])
263 l
= tmp_adr_idx_file
.readline()
265 if l
.strip() == '</book_list>' :
266 adr_idx_file
.write('\t<book name="'+sys
.argv
[2].split('.xml')[0] +'" file="'+sys
.argv
[2]+'" />\n')
267 adr_idx_file
.write(l
)
269 adr_idx_file
.write(l
)
270 l
= tmp_adr_idx_file
.readline()
271 except Exception as e
:
273 print('got exception: ', e
)
278 print('got exception, cleaning up the mess... changed files will be restored...\n')
283 if len(sys
.argv
) == 2 :
284 os
.rename(out_file
.name
+'.tmp', out_file
.name
)
286 os
.remove(out_file
.name
)
287 os
.rename(path_to_out
+adr_idx
+'.tmp', path_to_out
+adr_idx
)
288 if tmp_adr_idx_file
:
289 tmp_adr_idx_file
.close()
292 #closing all and moving temporary data into place
293 print('closing open files...\n')
296 if len(sys
.argv
) == 3 :
297 os
.rename(path_to_out
+adr_idx
+'.tmp',path_to_out
+adr_idx
+'.bak' )
298 if len(sys
.argv
) == 2 :
299 os
.rename(out_file
.name
+'.tmp', out_file
.name
+'.bak')
302 if tmp_adr_idx_file
:
303 tmp_adr_idx_file
.close()
307 if __name__
== '__main__':