310 lines
8.6 KiB
Python
Executable file
310 lines
8.6 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- coding: latin-1 -*-
|
|
"""
|
|
|
|
Copyright © 2003 Bogdan Sumanariu <zarrok@yahoo.com>
|
|
|
|
This file is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
script name : evolutionvcard2claws.py
|
|
|
|
script purpose : convert an evolution addressbook VCARD file
|
|
into a Claws Mail addressbook
|
|
|
|
tested with evolution 1.2.x, and 1.4.x
|
|
|
|
"""
|
|
|
|
import string
|
|
import sys
|
|
import time
|
|
import os
|
|
import StringIO
|
|
|
|
keywds = ('x-evolution-file-as','fn', 'n','email;internet','nickname', 'url', 'org')
|
|
|
|
def normalizeLongLines(file):
|
|
"""
|
|
Skip line breaks after 72 chars
|
|
"""
|
|
buf = ''
|
|
|
|
line = file.readline()
|
|
while line:
|
|
if line[0] == ' ':
|
|
buf = buf.rstrip('\n')
|
|
line = line.lstrip();
|
|
buf += line
|
|
else:
|
|
buf += line
|
|
line = file.readline()
|
|
|
|
return buf
|
|
|
|
def getEmailAddress(vcard):
|
|
"""
|
|
Get email address.
|
|
Supported formats:
|
|
- email;something
|
|
- email;type=something
|
|
something := (internet,work,home, other)
|
|
"""
|
|
|
|
for key in vcard:
|
|
items = key.split(';')
|
|
if len(items) == 2:
|
|
if items[0].lower() == 'email':
|
|
list = vcard[key]
|
|
return list[0]
|
|
else:
|
|
if key.lower() == 'email':
|
|
list = vcard[key]
|
|
return list[0]
|
|
|
|
return ""
|
|
|
|
def findName(vcard):
|
|
"""
|
|
Find a version 3.0 name
|
|
"""
|
|
for key in vcard:
|
|
items = key.split(';')
|
|
if len(items) == 2:
|
|
if items[0].lower() == 'n':
|
|
return vcard[key]
|
|
else:
|
|
if key.lower() == 'n':
|
|
return vcard[key]
|
|
|
|
return None
|
|
|
|
################################################################################
|
|
## reads a vcard and stores as hash pairs key/value where value is a list ##
|
|
################################################################################
|
|
|
|
def readVCARD (buffer) :
|
|
|
|
"""
|
|
|
|
skips fom <file> until a 'begin' tag from VCARD is encountered.
|
|
from this point starts constructing a map (key, [values] )
|
|
VCARD entry format -> tag:value
|
|
|
|
key <- tag
|
|
[values] <- list with the values of <tag> if there are more tags with the same name
|
|
|
|
"""
|
|
r=' '
|
|
bgn,end = -1, -1;
|
|
d = dict()
|
|
while r and bgn < 0 :
|
|
r = buffer.readline()
|
|
if len (r) == 0 : return dict()
|
|
if string.find('begin',string.lower(string.strip(r))) :
|
|
bgn = 1
|
|
while r and end < 0 :
|
|
r = buffer.readline()
|
|
s = string.split(string.lower(string.strip(r)),':')
|
|
if s[0] <> '' :
|
|
if d.has_key(s[0]) :
|
|
d[s[0]].append(s[1])
|
|
elif len(s) > 1:
|
|
d[s[0]] = [s[1]]
|
|
else :
|
|
d[s[0]] = ['']
|
|
if s[0] == 'end' : end = 1
|
|
return d
|
|
|
|
##################################################################################
|
|
|
|
###############################################################################################
|
|
## writes on a given file an xml representation for claws-mail addressbook received as a hash ##
|
|
###############################################################################################
|
|
|
|
def writeXMLREPR (vcard,file,uid) :
|
|
|
|
"""
|
|
based on <vcard> and <uid> writes only recognized tags (the ones defined in <keywds> list)
|
|
NOTE: <url> and <org> tag will be written as attributes (there are such tags in claws-mail's
|
|
XML schema)
|
|
"""
|
|
if len (vcard.keys()) == 0 : return
|
|
item = vcard.get(keywds[2]);
|
|
if item:
|
|
name = string.split(item[0],';')
|
|
else:
|
|
""" version 3.0 n ?"""
|
|
name = findName(vcard)
|
|
if not name:
|
|
return
|
|
|
|
fn, ln, nick, cn, a = '', '', '', '', ''
|
|
|
|
if len(name) >= 2 :
|
|
fn = name[0]
|
|
ln = name[1]
|
|
elif len(name) ==1 :
|
|
fn = name[0]
|
|
|
|
if vcard.has_key(keywds[4]) :
|
|
nick = vcard.get(keywds[4])[0]
|
|
if len(vcard.get(keywds[1])[0]) :
|
|
cn = vcard.get(keywds[1])[0]
|
|
else :
|
|
cn = vcard.get(keywds[0])[0];
|
|
|
|
a += str('\n<person uid=\"' + str(uid[0]) + '\" first-name=\"' + fn + '\" last-name=\"' + ln
|
|
+ '\" nick-name=\"' + nick + '\" cn=\"' + cn + '\" >\n')
|
|
a += '\t<address-list>\n'
|
|
if vcard.get(keywds[3]) :
|
|
for c in vcard.get(keywds[3]) :
|
|
uid[0] = uid[0] + 1
|
|
a += '\t\t<address uid=\"' + str(uid[0]) + '\" alias=\"' + nick + '\" email=\"' + c + '\" remarks=\"\" />\n'
|
|
else :
|
|
email = getEmailAddress(vcard)
|
|
uid[0] = uid[0]+1
|
|
a += '\t\t<address uid=\"' + str(uid[0]) + '\" alias=\"' + nick + '\" email=\"' + email + '\" remarks=\"\" />\n'
|
|
a += '\t</address-list>\n'
|
|
a += '\t<attribute-list>\n'
|
|
for key in keywds[5:] :
|
|
if vcard.get(key) :
|
|
for c in vcard.get(key) :
|
|
uid[0] = uid[0] + 1
|
|
a += '\t\t<attribute uid=\"' + str(uid[0]) + '\" name=\"' + key +'\">'+c+'</attribute>\n'
|
|
a += '\t</attribute-list>\n'
|
|
a += '</person>\n'
|
|
file.write(a)
|
|
file.flush()
|
|
|
|
###################################################################################################
|
|
|
|
def convert (in_f, o_f, name='INBOX') :
|
|
d = {'d':1}
|
|
uid = [int(time.time())]
|
|
|
|
try :
|
|
print 'proccessing...\n'
|
|
o_f.write('<?xml version="1.0" encoding="ISO-8859-1" ?>\n<address-book name="'+name+'" >\n');
|
|
|
|
buf = normalizeLongLines(in_f)
|
|
buffer = StringIO.StringIO(buf)
|
|
while len(d.keys()) > 0 :
|
|
d = readVCARD(buffer)
|
|
writeXMLREPR (d, o_f, uid)
|
|
uid[0] = uid [0]+1
|
|
|
|
o_f.write('\n</address-book>')
|
|
print 'finished processing...\n'
|
|
except IOError, err :
|
|
print 'Caught an IOError : ',err,'\t ABORTING!!!'
|
|
raise err
|
|
|
|
#################################################################################################
|
|
|
|
def execute () :
|
|
if len(sys.argv) <> 3 and len(sys.argv) <> 2 :
|
|
print str("\nUsage: vcard2xml.py source_file [destination_file]\n\n" +
|
|
'\tWhen only <source_file> is specified will overwrite the existing addressbook.\n'+
|
|
'\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')
|
|
sys.exit(1)
|
|
|
|
in_file = None
|
|
out_file = None
|
|
path_to_out = os.environ['HOME']+'/.claws-mail/'
|
|
adr_idx = 'addrbook--index.xml'
|
|
adr_idx_file = None
|
|
tmp_adr_idx_file= None
|
|
got_ex = 0
|
|
|
|
try :
|
|
in_file = open(sys.argv[1])
|
|
except IOError, e:
|
|
print 'Could not open input file <',sys.argv[1],'> ABORTING'
|
|
sys.exit(1)
|
|
|
|
if len(sys.argv) == 2 :
|
|
try :
|
|
dlist = os.listdir(path_to_out);
|
|
flist=[]
|
|
for l in dlist :
|
|
if l.find('addrbook') == 0 and l.find("addrbook--index.xml") < 0 and l.find('bak') < 0 :
|
|
flist.append(l)
|
|
flist.sort()
|
|
out_file = flist.pop()
|
|
os.rename(path_to_out+out_file, path_to_out+out_file+'.tmp')
|
|
out_file = open(path_to_out+out_file,'w')
|
|
convert(in_file, out_file)
|
|
except Exception, e:
|
|
got_ex = 1
|
|
print 'got exception: ', e
|
|
else :
|
|
try :
|
|
os.rename(path_to_out+adr_idx, path_to_out+adr_idx+'.tmp')
|
|
tmp_adr_idx_file = open(path_to_out+adr_idx+'.tmp')
|
|
adr_idx_file = open(path_to_out+adr_idx,'w')
|
|
except Exception, e :
|
|
print 'Could not open <', path_to_out+adr_idx,'> file. Make sure you started Claws Mail at least once.'
|
|
sys.exit(1)
|
|
try :
|
|
out_file = open(path_to_out+sys.argv[2],'w')
|
|
convert(in_file, out_file, sys.argv[2].split('.xml')[0])
|
|
l = tmp_adr_idx_file.readline()
|
|
while l :
|
|
if l.strip() == '</book_list>' :
|
|
adr_idx_file.write('\t<book name="'+sys.argv[2].split('.xml')[0] +'" file="'+sys.argv[2]+'" />\n')
|
|
adr_idx_file.write(l)
|
|
else :
|
|
adr_idx_file.write(l)
|
|
l = tmp_adr_idx_file.readline()
|
|
except Exception, e:
|
|
got_ex = 1
|
|
print 'got exception: ', e
|
|
|
|
|
|
if got_ex :
|
|
#clean up the mess
|
|
print 'got exception, cleaning up the mess... changed files will be restored...\n'
|
|
if adr_idx_file :
|
|
adr_idx_file.close()
|
|
if out_file :
|
|
out_file.close()
|
|
if len(sys.argv) == 2 :
|
|
os.rename(out_file.name+'.tmp', out_file.name)
|
|
else :
|
|
os.remove(out_file.name)
|
|
os.rename(path_to_out+adr_idx+'.tmp', path_to_out+adr_idx)
|
|
if tmp_adr_idx_file :
|
|
tmp_adr_idx_file.close()
|
|
|
|
else :
|
|
#closing all and moving temporary data into place
|
|
print 'closing open files...\n'
|
|
in_file.close()
|
|
out_file.close()
|
|
if len(sys.argv) == 3 :
|
|
os.rename(path_to_out+adr_idx+'.tmp',path_to_out+adr_idx+'.bak' )
|
|
if len(sys.argv) == 2 :
|
|
os.rename(out_file.name+'.tmp', out_file.name+'.bak')
|
|
if adr_idx_file :
|
|
adr_idx_file.close()
|
|
if tmp_adr_idx_file :
|
|
tmp_adr_idx_file.close()
|
|
print 'done!'
|
|
|
|
|
|
if __name__ == '__main__':
|
|
execute ()
|
|
|
|
|