From: Victor Wagner Date: Sun, 8 Jul 2018 11:04:01 +0000 (+0300) Subject: Initial commit with data X-Git-Url: http://wagner.pp.ru/gitweb/?a=commitdiff_plain;h=HEAD;p=oss%2Fphonebook.git Initial commit with data --- 130a4d6b63585a3f0dd7f1abacf0f9466b44345a diff --git a/manpage.md b/manpage.md new file mode 100644 index 0000000..0175a06 --- /dev/null +++ b/manpage.md @@ -0,0 +1,105 @@ +% phone(1) +% Victor Wagner +% June 2018 + +NAME +==== + +*phone* - manage phonebook in vcf file + +SYNOPSIS +======== + +**phone** [**-vtm**] *pattern* + +**phone** **-p** *pattern* > *filename.jpg* + +**phone** **-e** *pattern* + +**phone** **-n** + +**phone** **-d** *pattern* + +**phone** **-i** *filename.vcf* + +**phone** **-P** *pattern* *filename.jpg* + +DESCRIPTION +=========== + +This program allows you to query and modify addressbook stored in +single file of VCARDs. Such phone book can be exported from most mobile +phones or synchronized from CardDAV server using **vdirsyncer**(1). + +Phonebook can be also added as address source into **claws-mail**(1). + +Default mode of operation is to search phonebook for given pattern and +output results in the specified format. + +One of available output formats is VCARD, so it is possible to export +some contacts as vcf files. + +Other functions available are + +* Display/export contact's photo +* Edit entry in the text editor +* Create new contact by entering field by field from keyboard +* Add/replace photo +* Delete contact(s) + +This program doesn't understand GNU-style long options. It is +intentional. + +PATTERN SYNTAX +============== + +By default pattern is interpreted as regular expression and matched +against all meaningful fields. + +Also possible to use syntax *name*=*regular-expression* which allows +to match specific field. + +OPTIONS +======= + +Output Options +-------------- + +**-m** + + : *Mail* output just E-Mail address. Suitable to use as **mutt**(1) + `query_command` option + +**-v** + + : *VCARD* output output found contacts as vcards. + +**-t** + + : *tabular* output. + +**-p** + + : output contacts *photo*. If stdout is redirected, sends it there, + otherwise saves it to temporary file and invokes **xdg-open**(1) to + display. If more than one contact with photo matches the pattern, + lets user choose interactively. + +Common Options +-------------- + +**-f** *filename.vcf* + + : Use specified file instead of default one. + +Editing options +--------------- + +**-n** + + : Create new contact by asking for fields from STDIN + +**-e** + + : Edit contact + diff --git a/phone b/phone new file mode 100755 index 0000000..b351138 --- /dev/null +++ b/phone @@ -0,0 +1,161 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +import base64 +import quopri +import re +import sys +import os.path + + +printnames={ +"X-JABBER":"Jabber", +"EMAIL":"E-Mail", +"HOME":"домашний", +"ADR" : "Адрес", +"TEL":"Телефон", +"CELL":"Мобильный", +"BDAY" : "День рождения", +"X-INTERNET" : "", +"VOICE" : "", +"FAX" : "(факс)", +"WORK" : "рабочий", +"X-NICKNAME": "Прозвище", +"NOTE" : "Примечание", +"URL" : "URL", +"ORG" : "Организация", +"PHOTO" : "Фото", +"N" : "Имя", +"X-SKYPE-USERNAME" : "Skype", +"FN" : "Полное имя", +"PRESENT": "есть", +"UID": "UID" +} + +def printname(name): + s=[] + for part in name.split(";"): + if part in printnames: + s.append(printnames[part]) + return " ".join(s) + +def printcard_readable(card): + print ("---------------------") + for (name,value) in card : + if name.find("PHOTO")==0: + value=printnames["PRESENT"] + printable_name = printname(name) + if printable_name=="": + continue + print ("%s: %s"%(printable_name,value)) +def printcard_mail(card): + for (name,value) in card: + if name.find("EMAIL")==0: + print(value); + +def printcard_vcard(card): + print("BEGIN:VCARD") + print("VERSION:2.1") + for (name,value) in card: + if name.startswith('PHOTO'): + value = "\n ".join(value.split("\n")) + if name.find('ENCODING=')==-1: + u=value.encode("utf-8") + if len(value) != len(u): + name=name+";CHARSET=UTF-8;ENCODING=8BIT" + print (name+":"+value) + print ("END:VCARD") + +def printcard_tab(card): + d=dict(map(lambda x:(x,""),['N','TEL','EMAIL','PHOTO'])) + for (name,value) in card: + if name[0:2]=='FN': + d['N']=value + elif (name[0:2]=='N;' or name[0:2]=='N:') and d['N']=='': + d['N']=value + elif name[0:8]=='TEL;CELL': + d['TEL']=value + elif name[0:3]=='TEL' and d['TEL']=='' : + d['TEL']=value + elif name[0:5]=='EMAIL': + d['EMAIL']=value + elif name[0:5]=='PHOTO': + d['PHOTO']=u'фото' + print ( u"%-32s %12s %-28s %s"%(d['EMAIL'],d['N'],d['TEL'],d['PHOTO'])) + + +# This is a main program +print_card = printcard_readable + +if len(sys.argv)<2 or sys.argv[1]=='-h' or sys.argv[1]=='--help': + print ("Usage %s [-vta] search-pattern"%(sys.argv[0]),file=sys.stderr) + print ( "\t -v output vcards for found persons",file=sys.stderr) + print ("\t -a output just E-Mail addresses",file=sys.stderr) + print ("\t -t output name, phone and email in tabular format",file=sys.stderr) + sys.exit(1) +elif sys.argv[1] == "-v": + print_card = printcard_vcard + pattern=sys.argv[2] +elif sys.argv[1] == "-a": + print_card = printcard_mail + pattern=sys.argv[2] +elif sys.argv[1] == '-t': + print_card = printcard_tab + pattern=sys.argv[2] +else: + pattern=sys.argv[1] + +pattern=re.compile(pattern) + +card=[] +names={} +f=open(os.path.expanduser("~/.contacts/all_addressbook.vcf"),"r", encoding="utf-8") +for line in f: + line=line.rstrip("\r\n") + if line=="END:VCARD": + decoded=[] + toprint=False + for (name,value) in card: + if name.find("PHOTO")==0: + # do not decode photo + pass + elif name.find("ENCODING=BASE64")!=-1: + name=name.replace("ENCODING=BASE64","").replace(";;",";") + value=base64.b64decode(value).decode("utf-8") + elif name.find("ENCODING=QUOTED-PRINTABLE")!=-1: + name=name.replace("ENCODING=QUOTED-PRINTABLE","").replace(";;",";") + value=quopri.decodestring(value) + elif name.find("ENCODING=8BIT") !=-1: + name=name.replace("ENCODING=8BIT","").replace(";;",";") + name=name.replace("CHARSET=UTF-8","").replace(";;",";"); + name=name.rstrip(";") + if isinstance(value, bytes): + value=value.decode("utf-8") + try: + value=value.rstrip(";") + except TypeError as e: + print(str(e)+"\n"+repr(value)) + decoded.append((name,value)) + if name.find("PHOTO")==0: + continue + if pattern.search(value): + toprint=True + if toprint: + print_card(decoded) + elif line.find("BEGIN:VCARD")==0: + card = []; + else: + (name,sep,value)=line.partition(":") + if sep == "": + # Seems to be a continuation + card[-1]=(card[-1][0],card[-1][1]+"\n"+name.strip(" \t\r\n")) + else: + # Seems to be a field + if name=="VERSION": + #ignore the version + continue + card.append((name,value)) + +# For broken card +for (key,value) in names.items(): + print (key,":",value) +