123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- #!/usr/bin/env python3
- # -*- 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
- from io 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 r.strip().lower().find('begin') :
- bgn = 1
- while r and end < 0 :
- r = buffer.readline()
- s = r.strip().lower().split(':')
- if s[0] != '' :
- if s[0] in d :
- 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 = item[0].split(';')
- 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 keywds[4] in vcard :
- 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(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 as 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/addrbook/'
- 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 as 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 as 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 as 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 as 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 ()
|