add Charles to the man page
[claws.git] / tools / vcard2xml.py
blobecff3d5bb672857505b448fbcc889513a5ae9527
1 #!/usr/bin/env python
2 # -*- coding: latin-1 -*-
3 """
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
28 """
30 import string
31 import sys
32 import time
33 import os
34 import StringIO
36 keywds = ('x-evolution-file-as','fn', 'n','email;internet','nickname', 'url', 'org')
38 def normalizeLongLines(file):
39 """
40 Skip line breaks after 72 chars
41 """
42 buf = ''
44 line = file.readline()
45 while line:
46 if line[0] == ' ':
47 buf = buf.rstrip('\n')
48 line = line.lstrip();
49 buf += line
50 else:
51 buf += line
52 line = file.readline()
54 return buf
56 def getEmailAddress(vcard):
57 """
58 Get email address.
59 Supported formats:
60 - email;something
61 - email;type=something
62 something := (internet,work,home, other)
63 """
65 for key in vcard:
66 items = key.split(';')
67 if len(items) == 2:
68 if items[0].lower() == 'email':
69 list = vcard[key]
70 return list[0]
71 else:
72 if key.lower() == 'email':
73 list = vcard[key]
74 return list[0]
76 return ""
78 def findName(vcard):
79 """
80 Find a version 3.0 name
81 """
82 for key in vcard:
83 items = key.split(';')
84 if len(items) == 2:
85 if items[0].lower() == 'n':
86 return vcard[key]
87 else:
88 if key.lower() == 'n':
89 return vcard[key]
91 return None
93 ################################################################################
94 ## reads a vcard and stores as hash pairs key/value where value is a list ##
95 ################################################################################
97 def readVCARD (buffer) :
99 """
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
105 key <- tag
106 [values] <- list with the values of <tag> if there are more tags with the same name
109 r=' '
110 bgn,end = -1, -1;
111 d = dict()
112 while r and bgn < 0 :
113 r = buffer.readline()
114 if len (r) == 0 : return dict()
115 if string.find('begin',string.lower(string.strip(r))) :
116 bgn = 1
117 while r and end < 0 :
118 r = buffer.readline()
119 s = string.split(string.lower(string.strip(r)),':')
120 if s[0] <> '' :
121 if d.has_key(s[0]) :
122 d[s[0]].append(s[1])
123 elif len(s) > 1:
124 d[s[0]] = [s[1]]
125 else :
126 d[s[0]] = ['']
127 if s[0] == 'end' : end = 1
128 return d
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
141 XML schema)
143 if len (vcard.keys()) == 0 : return
144 item = vcard.get(keywds[2]);
145 if item:
146 name = string.split(item[0],';')
147 else:
148 """ version 3.0 n ?"""
149 name = findName(vcard)
150 if not name:
151 return
153 fn, ln, nick, cn, a = '', '', '', '', ''
155 if len(name) >= 2 :
156 fn = name[0]
157 ln = name[1]
158 elif len(name) ==1 :
159 fn = name[0]
161 if vcard.has_key(keywds[4]) :
162 nick = vcard.get(keywds[4])[0]
163 if len(vcard.get(keywds[1])[0]) :
164 cn = vcard.get(keywds[1])[0]
165 else :
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]) :
173 uid[0] = uid[0] + 1
174 a += '\t\t<address uid=\"' + str(uid[0]) + '\" alias=\"' + nick + '\" email=\"' + c + '\" remarks=\"\" />\n'
175 else :
176 email = getEmailAddress(vcard)
177 uid[0] = uid[0]+1
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:] :
182 if vcard.get(key) :
183 for c in vcard.get(key) :
184 uid[0] = uid[0] + 1
185 a += '\t\t<attribute uid=\"' + str(uid[0]) + '\" name=\"' + key +'\">'+c+'</attribute>\n'
186 a += '\t</attribute-list>\n'
187 a += '</person>\n'
188 file.write(a)
189 file.flush()
191 ###################################################################################################
193 def convert (in_f, o_f, name='INBOX') :
194 d = {'d':1}
195 uid = [int(time.time())]
197 try :
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.StringIO(buf)
203 while len(d.keys()) > 0 :
204 d = readVCARD(buffer)
205 writeXMLREPR (d, o_f, uid)
206 uid[0] = uid [0]+1
208 o_f.write('\n</address-book>')
209 print 'finished processing...\n'
210 except IOError, err :
211 print 'Caught an IOError : ',err,'\t ABORTING!!!'
212 raise err
214 #################################################################################################
216 def execute () :
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')
221 sys.exit(1)
223 in_file = None
224 out_file = None
225 path_to_out = os.environ['HOME']+'/.claws-mail/'
226 adr_idx = 'addrbook--index.xml'
227 adr_idx_file = None
228 tmp_adr_idx_file= None
229 got_ex = 0
231 try :
232 in_file = open(sys.argv[1])
233 except IOError, e:
234 print 'Could not open input file <',sys.argv[1],'> ABORTING'
235 sys.exit(1)
237 if len(sys.argv) == 2 :
238 try :
239 dlist = os.listdir(path_to_out);
240 flist=[]
241 for l in dlist :
242 if l.find('addrbook') == 0 and l.find("addrbook--index.xml") < 0 and l.find('bak') < 0 :
243 flist.append(l)
244 flist.sort()
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, e:
250 got_ex = 1
251 print 'got exception: ', e
252 else :
253 try :
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, e :
258 print 'Could not open <', path_to_out+adr_idx,'> file. Make sure you started Claws Mail at least once.'
259 sys.exit(1)
260 try :
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()
264 while l :
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)
268 else :
269 adr_idx_file.write(l)
270 l = tmp_adr_idx_file.readline()
271 except Exception, e:
272 got_ex = 1
273 print 'got exception: ', e
276 if got_ex :
277 #clean up the mess
278 print 'got exception, cleaning up the mess... changed files will be restored...\n'
279 if adr_idx_file :
280 adr_idx_file.close()
281 if out_file :
282 out_file.close()
283 if len(sys.argv) == 2 :
284 os.rename(out_file.name+'.tmp', out_file.name)
285 else :
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()
291 else :
292 #closing all and moving temporary data into place
293 print 'closing open files...\n'
294 in_file.close()
295 out_file.close()
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')
300 if adr_idx_file :
301 adr_idx_file.close()
302 if tmp_adr_idx_file :
303 tmp_adr_idx_file.close()
304 print 'done!'
307 if __name__ == '__main__':
308 execute ()