]> www.wagner.pp.ru Git - oss/phonebook.git/commitdiff
Initial commit with data master
authorVictor Wagner <vitus@wagner.pp.ru>
Sun, 8 Jul 2018 11:04:01 +0000 (14:04 +0300)
committerVictor Wagner <vitus@wagner.pp.ru>
Sun, 8 Jul 2018 11:04:01 +0000 (14:04 +0300)
manpage.md [new file with mode: 0644]
phone [new file with mode: 0755]

diff --git a/manpage.md b/manpage.md
new file mode 100644 (file)
index 0000000..0175a06
--- /dev/null
@@ -0,0 +1,105 @@
+% phone(1)
+% Victor Wagner <vitus@wagner.pp.ru>
+% 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 (executable)
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)
+