2013-08-27 15:14:44 +04:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
|
|
|
|
|
|
u"""%(scriptname)s: afficher les contacts téléphoniques
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
USAGE
|
|
|
|
%(scriptname)s [patterns...]"""
|
|
|
|
|
|
|
|
import os, sys, re, string
|
|
|
|
from os import path
|
|
|
|
|
|
|
|
from ulib.all import *
|
|
|
|
|
|
|
|
class ContactsrcFile(ShConfigFile):
|
|
|
|
CONTACTSRC = "contactsrc"
|
|
|
|
DEFAULT_CONTACTSFILE = "Contacts.txt"
|
|
|
|
|
|
|
|
def __init__(self, file=None, raise_exception=True):
|
|
|
|
if file is None:
|
|
|
|
testdir = path.join(scriptdir, "../../test")
|
|
|
|
utoolsrcdir = path.join(path.expanduser("~"), ".utools")
|
|
|
|
if path.isdir(testdir): file = path.join(testdir, self.CONTACTSRC)
|
|
|
|
else: file = path.join(utoolsrcdir, self.CONTACTSRC)
|
|
|
|
raise_exception = False
|
|
|
|
ShConfigFile.__init__(self, file=file, raise_exception=raise_exception)
|
|
|
|
|
|
|
|
CONTACTSDIR = "contactsdir"
|
|
|
|
CONTACTSFILE = "contacts"
|
|
|
|
|
|
|
|
def __p(self, p, refdir=None):
|
|
|
|
if refdir is not None:
|
|
|
|
if path.isfile(refdir): refdir = path.split(refdir)[0]
|
|
|
|
return abspath2(path.expanduser(p), refdir)
|
|
|
|
def __pcd(self, p):
|
|
|
|
return self.__p(p, self.get_contactsdir())
|
|
|
|
|
|
|
|
def __get(self, name, default, list=False, strip=False, fix_path=True):
|
|
|
|
if fix_path is True: fix_path = self.__pcd
|
|
|
|
if self.has_key(name):
|
|
|
|
if list:
|
|
|
|
values = self.get_list(name, strip)
|
|
|
|
if fix_path: values = [fix_path(value) for value in values]
|
|
|
|
value = values
|
|
|
|
else:
|
|
|
|
value = self[name]
|
|
|
|
if fix_path: value = fix_path(value)
|
|
|
|
else:
|
|
|
|
value = default
|
|
|
|
return value
|
|
|
|
|
|
|
|
def __join(self, values):
|
|
|
|
if isseq(values): values = u"\n".join(map(lambda v: _u(v), values))
|
|
|
|
else: values = _u(values)
|
|
|
|
return values
|
|
|
|
|
|
|
|
def __set(self, name, value, list=False):
|
|
|
|
if value is None:
|
|
|
|
if self.has_key(name): del self[name]
|
|
|
|
else:
|
|
|
|
self[name] = self.__join(value)
|
|
|
|
|
|
|
|
def get_contactsdir(self):
|
|
|
|
"""Retourner le répertoire de base pour les fichiers de contact
|
|
|
|
Par défaut, il s'agit de ~/.utools
|
|
|
|
"""
|
|
|
|
return self.__get(self.CONTACTSDIR, self.absfiledir, list=True, strip=True, fix_path=self.__p)
|
|
|
|
def set_contactsdir(self, contactsdir=None):
|
|
|
|
self.__set(self.CONTACTSDIR, contactsdir, list=True)
|
|
|
|
|
|
|
|
def get_default_contactsfile(self):
|
|
|
|
return self.__pcd(self.DEFAULT_CONTACTSFILE)
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def get_contactsfile(self, default=True):
|
|
|
|
"""Retourner la valeur contactsfile si elle est définie, default sinon.
|
|
|
|
Il s'agit du fichier qui contient les tâches par défaut.
|
|
|
|
Si default==True, retourner la première valeur de get_stores(), sinon
|
|
|
|
la valeur par défaut ~/.utools/Contacts.txt
|
|
|
|
"""
|
|
|
|
if default is True:
|
|
|
|
default = self.get_default_contactsfile()
|
|
|
|
return self.__get(self.CONTACTSFILE, default)
|
|
|
|
def set_contactsfile(self, contactsfile):
|
|
|
|
self.__set(self.CONTACTSFILE, contactsfile)
|
2015-08-20 07:58:17 +04:00
|
|
|
|
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def compile_pattern(pattern):
|
|
|
|
if isstr(pattern): pattern = re.compile(pattern)
|
|
|
|
return pattern
|
|
|
|
|
|
|
|
TEL = u"Tél personnel"
|
|
|
|
FAX = u"Fax personnel"
|
|
|
|
GSM = u"GSM personnel"
|
|
|
|
EMAIL = u"E-mail"
|
|
|
|
ADRESSE = u"Adresse personnelle"
|
|
|
|
PROFTEL = u"Tél professionnel"
|
|
|
|
PROFFAX = u"Fax professionnel"
|
|
|
|
PROFGSM = u"GSM Professionnel"
|
|
|
|
PROFEMAIL = u"E-mail professionnel"
|
|
|
|
PROFADRESSE = u"Adresse professionnelle"
|
|
|
|
|
|
|
|
class Telephone(object):
|
|
|
|
_tel = None
|
|
|
|
_prefix = None
|
|
|
|
|
|
|
|
RE_SPACES = re.compile(r'\s+')
|
|
|
|
PREFIXES = {None: TEL, u"tel": TEL, u"fax": FAX, u"gsm": GSM,
|
|
|
|
u"ptel": PROFTEL, u"pfax": PROFFAX, u"pgsm": PROFGSM,
|
|
|
|
u"email": EMAIL, u"mail": EMAIL,
|
|
|
|
u"pemail": PROFEMAIL, u"pmail": PROFEMAIL,
|
|
|
|
u"adresse": ADRESSE, u"padresse": PROFADRESSE,
|
|
|
|
u"adr": ADRESSE, u"padr": PROFADRESSE,
|
|
|
|
}
|
|
|
|
LITERALS = [EMAIL, PROFEMAIL, ADRESSE, PROFADRESSE]
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def is_literal(cls, prefix):
|
|
|
|
prefix = cls.PREFIXES.get(prefix, prefix)
|
|
|
|
return prefix in cls.LITERALS
|
2015-08-20 07:58:17 +04:00
|
|
|
is_literal = classmethod(is_literal)
|
2013-08-27 15:14:44 +04:00
|
|
|
|
|
|
|
def __init__(self, tel, prefix=None):
|
|
|
|
tel = self.RE_SPACES.sub(u"", tel)
|
|
|
|
prefix = self.PREFIXES.get(prefix, prefix)
|
|
|
|
self._tel = _u(tel)
|
|
|
|
self._prefix = _u(prefix)
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
prefix = property(lambda self: self._prefix)
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def get_tel(self, cooked=True):
|
|
|
|
if not cooked or self._prefix in self.LITERALS:
|
|
|
|
return self._tel
|
|
|
|
else:
|
|
|
|
tel = self._tel
|
|
|
|
nums = []
|
|
|
|
while tel:
|
|
|
|
if len(tel) > 4:
|
|
|
|
num = tel[-2:]
|
|
|
|
tel = tel[:-2]
|
|
|
|
nums.insert(0, num)
|
|
|
|
else:
|
|
|
|
nums.insert(0, tel)
|
|
|
|
tel = None
|
|
|
|
return u" ".join(nums)
|
|
|
|
tel = property(get_tel)
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def __str__(self):
|
|
|
|
s = _s(self.tel)
|
|
|
|
if self._prefix is not None:
|
|
|
|
s = "%s (%s)" % (s, _s(self._prefix))
|
|
|
|
return s
|
|
|
|
def __repr__(self):
|
|
|
|
tel = self.tel
|
|
|
|
prefix = self._prefix
|
|
|
|
if prefix is None: prefix = "None"
|
|
|
|
else: prefix = "'%s'" % prefix
|
|
|
|
return "%s('%s', %s)" % (self.__class__.__name__, tel, prefix)
|
|
|
|
def __unicode__(self):
|
|
|
|
u = _u(self.tel)
|
|
|
|
if self._prefix is not None:
|
|
|
|
u = u"%s (%s)" % (u, _u(self._prefix))
|
|
|
|
return u
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def matches(self, pattern):
|
|
|
|
return compile_pattern(pattern).search(self._tel) is not None
|
|
|
|
|
|
|
|
class Contact(object):
|
|
|
|
_nom = None
|
|
|
|
_prenom = None
|
|
|
|
_tels = None
|
|
|
|
|
|
|
|
RE_COMMA = re.compile(r'\s*,\s*')
|
|
|
|
RE_PREF = re.compile(r'(\S+)=')
|
|
|
|
RE_PREF_TEL = re.compile(r'(?:(\S+)=)?((?:\d|\s)+)$')
|
|
|
|
RE_PREF_ANY = re.compile(r'(?:(\S+)=)?\s*(.+)\s*$')
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def __init__(self, line):
|
|
|
|
parts = self.RE_COMMA.split(line.strip())
|
|
|
|
self._nom = parts[0:1] and parts[0] or u""
|
|
|
|
self._prenom = parts[1:2] and parts[1] or u""
|
|
|
|
self._tels = []
|
|
|
|
for part in filter(None, parts[2:]):
|
|
|
|
if not part: continue
|
|
|
|
mo = self.RE_PREF.match(part)
|
|
|
|
if mo is not None:
|
|
|
|
prefix = mo.group(1)
|
|
|
|
if Telephone.is_literal(prefix):
|
|
|
|
mo = self.RE_PREF_ANY.match(part)
|
|
|
|
if mo is None: raise ValueError("inconsistent match: %s" % part)
|
|
|
|
prefix, tel = mo.group(1), mo.group(2)
|
|
|
|
self._tels.append(Telephone(tel, prefix))
|
|
|
|
continue
|
|
|
|
mo = self.RE_PREF_TEL.match(part)
|
|
|
|
if mo is None:
|
|
|
|
raise ValueError("Invalid telephone number: %s" % part)
|
|
|
|
prefix, tel = mo.group(1), mo.group(2)
|
|
|
|
self._tels.append(Telephone(tel, prefix))
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
nom = property(lambda self: self._nom)
|
|
|
|
prenom = property(lambda self: self._prenom)
|
|
|
|
tels = property(lambda self: self._tels)
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def get_np(self):
|
|
|
|
np = []
|
|
|
|
if self._nom: np.append(self._nom)
|
|
|
|
if self._prenom: np.append(self._prenom)
|
|
|
|
return u" ".join(np)
|
|
|
|
np = property(get_np)
|
|
|
|
|
|
|
|
def get_pn(self):
|
|
|
|
pn = []
|
|
|
|
if self._prenom: pn.append(self._prenom)
|
|
|
|
if self._nom: pn.append(self._nom)
|
|
|
|
return u" ".join(pn)
|
|
|
|
pn = property(get_pn)
|
|
|
|
|
|
|
|
def _tel(self, name, cooked=True):
|
|
|
|
name = Telephone.PREFIXES.get(name, name)
|
|
|
|
for tel in self.tels:
|
|
|
|
if tel.prefix == name:
|
|
|
|
return tel.get_tel(cooked)
|
|
|
|
return None
|
|
|
|
tel = property(lambda self: self._tel("tel"))
|
|
|
|
fax = property(lambda self: self._tel("fax"))
|
|
|
|
gsm = property(lambda self: self._tel("gsm"))
|
|
|
|
mail = property(lambda self: self._tel("mail"))
|
|
|
|
ptel = property(lambda self: self._tel("ptel"))
|
|
|
|
pfax = property(lambda self: self._tel("pfax"))
|
|
|
|
pgsm = property(lambda self: self._tel("pgsm"))
|
|
|
|
pmail = property(lambda self: self._tel("pmail"))
|
|
|
|
xtel = property(lambda self: self._tel("tel", False))
|
|
|
|
xfax = property(lambda self: self._tel("fax", False))
|
|
|
|
xgsm = property(lambda self: self._tel("gsm", False))
|
|
|
|
xmail = property(lambda self: self._tel("mail", False))
|
|
|
|
xptel = property(lambda self: self._tel("ptel", False))
|
|
|
|
xpfax = property(lambda self: self._tel("pfax", False))
|
|
|
|
xpgsm = property(lambda self: self._tel("pgsm", False))
|
|
|
|
xpmail = property(lambda self: self._tel("pmail", False))
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
def matches(self, patterns):
|
|
|
|
if not isseq(patterns): patterns = (patterns,)
|
|
|
|
patterns = map(compile_pattern, patterns)
|
|
|
|
nom = self._nom
|
|
|
|
prenom = self._prenom
|
|
|
|
tels = self._tels
|
|
|
|
for pattern in patterns:
|
|
|
|
if pattern.search(nom) is None:
|
|
|
|
if pattern.search(prenom) is None:
|
|
|
|
for tel in tels:
|
|
|
|
if tel.matches(pattern): return True
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
RE_COMMENT = re.compile(r'^#|^\s*$')
|
|
|
|
def load_contacts(infdn):
|
|
|
|
lines = Lines()
|
|
|
|
lines.readlines(infdn)
|
|
|
|
lines.filter(lambda line: RE_COMMENT.match(line) is None)
|
|
|
|
return [Contact(line) for line in lines]
|
|
|
|
|
|
|
|
def show_contacts(contacts):
|
|
|
|
for contact in contacts:
|
|
|
|
etitle(contact.np)
|
|
|
|
for tel in contact.tels:
|
|
|
|
uprint(tel)
|
|
|
|
|
|
|
|
def display_help():
|
|
|
|
uprint(__doc__ % globals())
|
|
|
|
|
|
|
|
def run_Contacts():
|
|
|
|
options, longoptions = build_options([
|
|
|
|
('h', 'help', "Afficher l'aide"),
|
|
|
|
('o:', 'output=', "Exporter au format csv pour Outlook"),
|
|
|
|
])
|
|
|
|
options, args = get_args(None, options, longoptions)
|
|
|
|
action = "search"
|
|
|
|
outf = None
|
|
|
|
for option, value in options:
|
|
|
|
if option in ('-h', '--help'):
|
|
|
|
display_help()
|
|
|
|
sys.exit(0)
|
|
|
|
elif option in ('-o', '--output'):
|
|
|
|
action = "export"
|
|
|
|
outf = value
|
|
|
|
|
|
|
|
cf = ContactsrcFile()
|
|
|
|
contacts = load_contacts(cf.get_contactsfile())
|
|
|
|
if action == "search":
|
|
|
|
if args:
|
|
|
|
patterns = map(compile_pattern, map(_u, args))
|
|
|
|
contacts = [contact for contact in contacts
|
|
|
|
if contact.matches(patterns)]
|
|
|
|
show_contacts(contacts)
|
|
|
|
elif action == "export":
|
|
|
|
lines = []
|
|
|
|
lines.append(u'"Nom","Téléphone (domicile)","Télécopie (domicile)","Tél. mobile","Adresse de messagerie","Téléphone (bureau)","Télécopie (bureau)","Téléphone 2 (bureau)","Adresse de messagerie 2"\r\n')
|
|
|
|
for contact in contacts:
|
|
|
|
values = [contact.pn or u"",
|
|
|
|
contact.xtel or u"",
|
|
|
|
contact.xfax or u"",
|
|
|
|
contact.xgsm or u"",
|
|
|
|
contact.xmail or u"",
|
|
|
|
contact.xptel or u"",
|
|
|
|
contact.xpfax or u"",
|
|
|
|
contact.xpgsm or u"",
|
|
|
|
contact.xpmail or u"",
|
|
|
|
]
|
|
|
|
if values[7]:
|
|
|
|
if not values[5]:
|
|
|
|
values[5] = values[7]
|
|
|
|
values[7] = u""
|
|
|
|
elif not values[3]:
|
|
|
|
values[3] = values[7]
|
|
|
|
values[7] = u""
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
lines.append(u",".join(values) + u"\r\n")
|
|
|
|
cp1252 = UnicodeIO("cp1252")
|
|
|
|
lines = map(cp1252.s, lines)
|
|
|
|
|
|
|
|
close = True
|
|
|
|
if outf != "-":
|
|
|
|
outf = open(outf, "wb")
|
|
|
|
else:
|
|
|
|
outf = sys.stdout
|
|
|
|
close = False
|
|
|
|
outf.writelines(lines)
|
|
|
|
if close: outf.close()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
run_Contacts()
|