Init
This commit is contained in:
commit
f17739dc92
|
@ -0,0 +1,51 @@
|
||||||
|
VCARD2PERSON (and PERSON2VCARD)
|
||||||
|
===============================================================================
|
||||||
|
Some bash scripts that can convert in-between vcard and Haiku person files.
|
||||||
|
Sorta in the spirit of mbox2mail and mail2mbox.
|
||||||
|
|
||||||
|
It supports vcards of version 2.1, 3.0, and 4.0.— and supports all attributes
|
||||||
|
applicable to a person file (including photo [through URL or embeded image],
|
||||||
|
address, name, phone numbers, email, etc).
|
||||||
|
|
||||||
|
My use-case is converting contacts between my Android phone and Haiku, which
|
||||||
|
uses version 2.1 vcards, so that version's been tested fairly well.
|
||||||
|
3.0 and 4.0 have only been tested on the example files in ./ex/
|
||||||
|
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
USAGE
|
||||||
|
--------------------
|
||||||
|
usage: vcard2person vcard [-h] [-d directory] [-o path] file
|
||||||
|
|
||||||
|
People files will be created using the data from a vcard. Each vcard defined
|
||||||
|
by a given vcf/vcard file have its person file be named after the vcard's
|
||||||
|
full-name.
|
||||||
|
-o changes the output person filename
|
||||||
|
-d outputs all people files to a given directory-- useful if a file
|
||||||
|
defines multiple vcards.
|
||||||
|
-h prints this message.
|
||||||
|
|
||||||
|
|
||||||
|
usage: person2vcard [-h] [-v version] [-o path] person
|
||||||
|
|
||||||
|
Creates a vcard from the given person file's attributes. By default will
|
||||||
|
output to a file of the same name with a .vcf file-extension.
|
||||||
|
-o changes output vcard filename
|
||||||
|
-v specify vcard version: 2.1, 3.0, or 4.0. Defaults to 4.0.
|
||||||
|
a random URL, and use it as the vcard's photo URL.
|
||||||
|
-h print this message.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
CUSTOMIZATION
|
||||||
|
--------------------
|
||||||
|
It should be pretty easy to work with your own custom attributes-- a couple
|
||||||
|
examples are in './patches/', for a META:birthday attribute (BDAY) and for
|
||||||
|
a META:group (X-ANDROID-CUSTOM:vnd.android.cursor.item).
|
||||||
|
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
BORING STUFF
|
||||||
|
--------------------
|
||||||
|
Author: Jaidyn Ann <jadedctrl@teknik.io>
|
||||||
|
License: CC0
|
|
@ -0,0 +1,10 @@
|
||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:2.1
|
||||||
|
N:Klemenski;Mandy;;Ms.;
|
||||||
|
FN:Mandy Klemenski
|
||||||
|
TEL;CELL:+1-404-888-9999
|
||||||
|
EMAIL;HOME:mommy@emailingtime.co.uk
|
||||||
|
ADR;HOME:;;1999 Duck Land Road, Candy, IN 88888, USA;;;;
|
||||||
|
ADR;WORK:;;1889 Sparrow Lane, Candy, IN 88888, USA;;;;
|
||||||
|
BDAY:1990-04-05
|
||||||
|
END:VCARD
|
|
@ -0,0 +1,86 @@
|
||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:2.1
|
||||||
|
N:Klemanto;Mandy;;Ms.;
|
||||||
|
FN:Mandy Klemanto
|
||||||
|
TEL;HOME:1-404-123-4535
|
||||||
|
ADR;HOME:;;1903 Madoka Avenue;Charleton;Utah;98989;USA
|
||||||
|
PHOTO;ENCODING=BASE64;JPEG:/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEU
|
||||||
|
AAQEAAAIYAAAAAAIQAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAAHRyWFlaAAABZAAAABRnWFlaAA
|
||||||
|
ABeAAAABRiWFlaAAABjAAAABRyVFJDAAABoAAAAChnVFJDAAABoAAAAChiVFJDAAABoAAAACh
|
||||||
|
3dHB0AAAByAAAABRjcHJ0AAAB3AAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFgAAAAcAHMA
|
||||||
|
UgBHAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIA
|
||||||
|
AAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z3BhcmEAAAAAAAQAAAACZmYAAPK
|
||||||
|
nAAANWQAAE9AAAApbAAAAAAAAAABYWVogAAAAAAAA9tYAAQAAAADTLW1sdWMAAAAAAAAAAQAA
|
||||||
|
AAxlblVTAAAAIAAAABwARwBvAG8AZwBsAGUAIABJAG4AYwAuACAAMgAwADEANv/bAEMAAwICA
|
||||||
|
wICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFh
|
||||||
|
QYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ
|
||||||
|
UFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAF4AYAMBIgACEQEDEQH/xAAbAAACAwEBAQAAAAAA
|
||||||
|
AAAAAAAGBwQFCAMCAP/EAD0QAAIBAgUCBAMGAwUJAAAAAAECAwQRAAUGEiExQQcTIlFhcYEIF
|
||||||
|
DKRocEVI0IWM4Kx4QkkNENSctHw8f/EABsBAAMBAQEBAQAAAAAAAAAAAAUGBwQDAgAB/8QANB
|
||||||
|
EAAQMCBAQEBAQHAAAAAAAAAQACAwQRBSExQRITUYFhcbHBBiKRoRRS0fAVJDJCouHx/9oADAM
|
||||||
|
BAAIRAxEAPwDSgaK/BF8eiUI6j88QMtkZMrWfM6Q0c5ALQxuHsfa464n0k+W1MYfbKAexIBxB
|
||||||
|
XODTZyoLmkXtnbosZaryuGt1vqnUWfbppYKllihuLKi8L2+WB7JdM0meEZ/r3MKjL8iU/wAml
|
||||||
|
gG55BzYADphs+O/hjmuW5rmed5K0mYZPWnzailjsJIWsL/9y8X+GF/4d6ro811dp9c8y8V0VE
|
||||||
|
zeXQqLh5Nvp3A9gbflhyglc+n5sTrgDO2rQBoOlzv3TnwwTwgR6WJt1Pj1tsCfa2hvCDTetK6
|
||||||
|
gjqNB6SyLw50uQpbPtTC888QNi6oCGuBc+sgG/UYtdR+K/h74U5GU1n9pfNc+zUrNLFSaMp6V
|
||||||
|
g20X8sBIZgjNcBTJIik9wASMD/aR+0Bq7WWq8wy3NMxb7vQztFHlsUoNPSbTYKFU7d4FwT1Bu
|
||||||
|
OLWGfaiskrJTJI7OW5JYk84OUOD85okmtnta5+pv+n2UrxHES2VzW6g/vM3J+3ktyeIX+0By6
|
||||||
|
ANT6Fz7xFnvtvVakq6Ajr6h5UcJPyPmd+gxaaX+17p7xayyfINcU0FZJKpWkrGphGZGtyHVS2
|
||||||
|
xhf8AEODjBcERJ5F7+4GLKgZ6OrWaBJkeJtyywGxBHf8A1wYl+H6WWOzRwnqMih9PjksEge5o
|
||||||
|
cAfI/UWK2Tknhy+ZaibTVHCathUlVCyb1iiuLkkG3HTGh/G7UNH4c+GtYqbVlWBaWlReLtYLc
|
||||||
|
fIc4Q32IfHfT9NmE+mc2fZnda4eCvlBJk9JJR2JPYA36D1XPOKb7WHiV/anXE+W0sm6hywmIW
|
||||||
|
vZpP6z9On0wlVNJM+uFPNo3O/UZZ99FQDirK2NlRG3hYwf5dO3p5pH59m3noQGJP42PucE1F6
|
||||||
|
6KA+6Dp8sAVaxNNKe9sMHIV83KqdybkoMNTTZqwYZI+pqnl+pHun79l3TdVqfJ82zOq1FVCoj
|
||||||
|
dYV+8VTtccm9icOmHTVJG4gq9QBJCbqm8jdjO3gZntLpHT2ZRwyN5T1EagqdxHpY/tgt1DrEZ
|
||||||
|
h92mpRK00Ml726jvid18EslY+39O2XgmyGkqC1reKwsNLHbqfFOOXI8jhFqjORJ8ycZ3+1dW6
|
||||||
|
X0ToCeoymaifNqp/KRQipI4JClhcXbbu3EDrYA+ksMGFVqsTxktBOT15TGJ/tLV9XmniG9bVL
|
||||||
|
sR4lSFOgCKSBwT8bm3cnvfGzBaF8tU0vdYDPz8ENxV82HUbpQ4knLawuDn29UsHdpnPe5v8T8
|
||||||
|
8e6KkkrJxHEu9j7dBjjASwXj8R2qB1Y4Yem8kTLaVGlB+8yHlUFyfYWHP055xZ4I+M+ChtVPy
|
||||||
|
gTuu2mPDsVciNVSEoObLwD74cOR6Ko6OkMccMaoVtaw5xQadcROjVFJWRLewIpzYfPuMM6jgi
|
||||||
|
ly5aiOX+Vs8wm3IUd/fthljgYxuQSLPWTPfmUhdf6ROiM6gzajY0wMqyRTRelopV9QII5BuAb
|
||||||
|
/AAx8+ZSZlGtRI5kllG5mJvcnqcHHjHV5dX6KrFp5jUGOWMBvJcAHeo4YrY8E9DhbZFC6ZRTq
|
||||||
|
/BVe/tfj9MJONMaxwIGaouAzSSRkEm3Ty/6u1Uu+FwBc7Txhh6ZYNp+kbvt/fADIvHx+GDLSU
|
||||||
|
t9O049hbC435mkKl4I4Mqjf8p9QpdBmRyvRQGWu8EJrAAYGsDZW5/XFbPrDMtpBra5to6eccW
|
||||||
|
lU9M/h8s9KVanFeFV06H0N0wIud6u17Ai17Y5tsS423WisqJYAyON/9o000Vx/a/MpEBNbWG3
|
||||||
|
Yzk/pgD1nDLqXUFKtS8jCOIXeX1EAm3f5jDd05lWWRUCSR1UFKUi8ySpm/mSM3ZET3+JNh3tx
|
||||||
|
hC641h9/1Q1RAzeXCxVd5F7dOoA7dPa/0wQoC0z5tyGqE48yoiomiSa7naDXvf8A13UGkyhqL
|
||||||
|
UaoXEyeZtViu2wB6W7dMMGupKpsuZKKdqapI/vEHNva/b6YGNP1GX1SwJHUB5mcNsYepG2+od
|
||||||
|
Onx6frhlZMFU2kTdfpcYe6dgvbYqNVszxZxGYQrkNZmOUUs9OIa6WVvLPnySKsai93AG0k34A
|
||||||
|
5HxB6YP8AT+qs1qqGqoYZCtXIg8skgkWYe/wvbHCrow0Mk3BWMXVb9/a2J2gsgjmzKasd55Fi
|
||||||
|
H/EKAikm1gByR369bYKlhbk05IGJ2zkve0AhBGfPqKaat+8eauTl/LZaiMox9QZCeSCRt5tYc
|
||||||
|
jr25QEPC42geojjp17YavidGiaYEKuvnVEwsCedoBN/zt+eFVQBmpo3b+pQ2ETG3gvt4qjYAC
|
||||||
|
WcVrZFcnAAv7dsE2iZL5JbsHYW9ucULQ3xcaKc/wAPnQ9Flbp88L0Qu0p+w13BVt8QVdRS0tR
|
||||||
|
4PB6NU8gZsApQWFvLbp+uBRxaBubC2CvLmgm8GHlgA8k5yoFhYf3TYEa6ojp6OWSRgiKvJOOE
|
||||||
|
Ys54HUr3Vu4msefyBDer89koKNIIZCjup3EHovT/AMjCyqAdxYg8m18Xud5icwriexsApbgDs
|
||||||
|
P3P1xVFDIHe2+MW/EebHn9j+eGWmi4GZpJqJjI7M6L3kFU9FmsEi3Nvbvh/ZRPHWwQzRuGNhf
|
||||||
|
CGy+jaRlmT0BCG5HTngn37e3XDbyN3Slp6iE+lgNyg3+owy0JNiEn4rYlrkXagZ6PJmNNBLVV
|
||||||
|
DEeiEXIWxubdz0FvniiyTUGoKaop1pspmaFiRIz3FjcAWQL+K1x15+HTBHldbuljWc+Wb8M34
|
||||||
|
Tg6zPUuU6N05NmuaV0flxpZEQAvK/ZEFxdj/AKmwuQckF2cd7Dslujm5b+Tyw4k65pe+JuYSV
|
||||||
|
uc0MLMFakprSR2sVd13Pc9CLLH8ucDMXpiQDgBQBx8MU2W6nm1U89ZWH/eJpWaQAkgXN7C5J2
|
||||||
|
9ABfoAMXO8W4OJZXPdLM4u3P22Vhw2NsMLWt2Fu+68ym4288+2LHRcm2KtTssp/wA8VErlWBG
|
||||||
|
JGQytHHmW0+otx+Qxmh3CNUkvLqWyHa/or8aiynKPAtUEgHnZuzwRRi7SBI1DWHa29epA5OFF
|
||||||
|
qDU8+dRvFTAQ0yc82LPzxfnj5c491GWSmEu+1GX8Q5Cq9+R7cH24tjzlWQVcjyEpsl8ssVkW1
|
||||||
|
wBu5uPhh8ofh5jDd9yXElJdZjr52gNs0NAb52QuYm27im42J4PWxx0lmilb0xkAjav6DBjJkb
|
||||||
|
vDTkwxvJJKYQWutrqWubfL/wB4wO1GTJTF4qifypIZGV4URma3QMOgIv2LD5HBCbDDCfl0QmO
|
||||||
|
sbLqV7yxBJPEDtUfgZQeSO35/thraXgWkpoIB6/TYC/bt+2FZQVlGUNLNSrCrNeGU23ix5vJb
|
||||||
|
k/Ai3wGDvIWqctttnjqNt2uvRgTzY/Pg/EdxYnrDEIXB4zHp5oTiIdK0t3TIz7OMt03k8s3lC
|
||||||
|
SVV4Um4B/PGaM8rZM1rpquVi89Q+9uenYD6DB1rfUEk9G6Mltx/q56YWkkxLFr3bucC8SlD3h
|
||||||
|
rdAtmCUxhiL3alXGU5m+XwwzwKN8TukhHdTYrf9fywa5Zqb747gpuCqWsgNz8vlhf5HVmkllJ
|
||||||
|
RZI5ABIjKCCnN+3X2PYgYn6fzOKgzunmmsIwwDFluB8P2+uMEVPTSubzxkculu6OPmniDuUdM
|
||||||
|
0xY6yCrRnhkD2APcdfgecd9OAyT5jEDzYEfliFS+WldNTxs7FowyqR6ebMCLmwNyw59xiZpiQ
|
||||||
|
HNa3aeWQWP0wOxHDf4dOAw3a4XH1zCM4PW/jXN4hmDY9xqhqpeqpqctIf5zm21DcL04N+5PXp
|
||||||
|
3xIo80EFbE7h/KBLItO42Ne9lP1uLWFhY8hr4qxI8kYLtvd2LndyLm5/fEaKtNVTBkXyo4pNj
|
||||||
|
IvU83vfv0P6YqTSGWsVPwziBuES5jmdZS5qyPtbyZrhVI4423t2B9ses0dJJG3U8MM0rGaQub
|
||||||
|
Nawtf5k3xW5vM8VZG67SDHC3I54I6+/THeszCaPdENjmoaMXdfwi5sL47SH5iL7rMyMDhIG36
|
||||||
|
IeqoqWsSdtsS+WLgKzbjxzYcfP6YK8jeH+HRxrsQr61EcvzBsh5Fz8bdcCrz1EE6OFiJQ/Hnn
|
||||||
|
Ftk6fcojWRu/lQgrKrEkutz8QDzz/8xgDeIutnf9hbJ2kxgHsoWrZBNHtPoIv0PBPvgFJ5sOm
|
||||||
|
DLU2Zw1lPBLGjqCxNmtz6SP3wIxxiSXb/ANRHPthMq85SjOH3EQyVnkNO89QSpIdF3pYX6H2x
|
||||||
|
YTRpR1kFQsQqKWQ3MVxtsbjaTzyCGH+EHuDiRpKBBWFXJKkOpI6j082xHjkaamdf+Wrn57gL8
|
||||||
|
fMD/L2xrpI2yRDi3Jt5iy+meRKQPBHuSZxJSSNDJOUhWnanSRYtxmRVslybkWVwP8Ix0yLdHq
|
||||||
|
SrUgKCvRT8TiDRVn3OnyyfaGlSNo7kA+k+nn3NiOcd8qdk1Eqsdzmki3HtfYt7DsPbHvGG/wA
|
||||||
|
o2+rXW7EX9gv3BH8Fdlv7G3uv/9k=
|
||||||
|
|
||||||
|
END:VCARD
|
|
@ -0,0 +1,10 @@
|
||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:2.1
|
||||||
|
N:Klemenski;Mandy;;Ms.;
|
||||||
|
FN:Mandy Klemenski
|
||||||
|
TEL;CELL:+1-404-888-9999
|
||||||
|
EMAIL;HOME:mommy@emailingtime.co.uk
|
||||||
|
ADR;HOME:;;1999 Duck Road;Candy;IN;888888;USA
|
||||||
|
ADR;WORK:;;1889 Sparrow Lane;Candy;IN;88888;USA
|
||||||
|
BDAY:1990-04-05
|
||||||
|
END:VCARD
|
|
@ -0,0 +1,20 @@
|
||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:4.0
|
||||||
|
NOTE:A super-valid v4.0 vcard.
|
||||||
|
N:Alderson;Darlene;;Ms.;
|
||||||
|
FN:Darlene
|
||||||
|
Alderson
|
||||||
|
ORG:Fun Society, Inc.
|
||||||
|
PHOTO;MEDIATYPE=image/jpeg:http://coinsh.red/u/darlene.jpg
|
||||||
|
TEL;TYPE=work,voice;VALUE=uri:tel:+1-111-555-1212
|
||||||
|
TEL;TYPE=home,voice;VALUE=uri:tel:+1-404-555-1212
|
||||||
|
ADR;TYPE=WORK;PREF=1;LABEL="3027 West 12th Street, Coney Island\nNew York City\, NY\nUnited States of America":;;
|
||||||
|
3027 West 12th Street, Coney Island;
|
||||||
|
New York City;NY;
|
||||||
|
1234;
|
||||||
|
United States of America
|
||||||
|
ADR;TYPE=HOME;LABEL="217 E. Broadway\nNew York City\, NY\nUnited States of America":;;217 E. Broadway;New York City;NY;1234;United States of America
|
||||||
|
EMAIL:d0loreshaze@protonmail.com
|
||||||
|
REV:20160428T195243Z
|
||||||
|
x-qq:21588891
|
||||||
|
END:VCARD
|
|
@ -0,0 +1,12 @@
|
||||||
|
69a70,71
|
||||||
|
> ## CUSTOM
|
||||||
|
> set_vcard_group "$vc" "$(catattr -d META:group "$person" 2>/dev/null)"
|
||||||
|
98a101,108
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> ## CUSTOM
|
||||||
|
> function set_vcard_group {
|
||||||
|
> local vcard="$1"
|
||||||
|
> local group="$2"
|
||||||
|
> simple_set_vcard "$vcard" "X-ANDROID-CUSTOM" \
|
||||||
|
> "vnd.android.cursor.item/relation;${group};1;;;;;;;;;;;;;"
|
|
@ -0,0 +1,14 @@
|
||||||
|
191a192,201
|
||||||
|
> ## CUSTOM
|
||||||
|
> function vcard_group {
|
||||||
|
> local vcard="$1"
|
||||||
|
> grep "X-ANDROID-CUSTOM:vnd.android.cursor.item/relation;" "$vcard" \
|
||||||
|
> | sed 's%X-ANDROID-CUSTOM:vnd.android.cursor.item/relation;%%' \
|
||||||
|
> | sed 's%;.*%%' \
|
||||||
|
> | clean
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
>
|
||||||
|
203a214,215
|
||||||
|
> ## CUSTOM
|
||||||
|
> addattr -t string META:group "$(vcard_group "$vcard")" "$person"
|
|
@ -0,0 +1,11 @@
|
||||||
|
69a70,71
|
||||||
|
> ## CUSTOM
|
||||||
|
> set_vcard_bday "$vc" "$(catattr -d META:birthday "$person" 2>/dev/null)"
|
||||||
|
98a101,107
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> ## CUSTOM
|
||||||
|
> function set_vcard_bday {
|
||||||
|
> local vcard="$1"
|
||||||
|
> local bday="$2"
|
||||||
|
> simple_set_vcard "$vcard" "BDAY" "$bday"
|
|
@ -0,0 +1,6 @@
|
||||||
|
190a191,192
|
||||||
|
> ## CUSTOM
|
||||||
|
> function vcard_bday { local vc="$1"; get_vcard_value "$vc" "BDAY" | clean; }
|
||||||
|
203a206,207
|
||||||
|
> ## CUSTOM
|
||||||
|
> addattr -t string META:birthday "$(vcard_bday "$vcard")" "$person"
|
|
@ -0,0 +1,289 @@
|
||||||
|
#!/boot/system/bin/bash
|
||||||
|
# --------------------------------------
|
||||||
|
# PERSON2VCARD
|
||||||
|
# simple script for convertining a person
|
||||||
|
# into a vcard.
|
||||||
|
# CC0, jadedctrl@teknik.io
|
||||||
|
# --------------------------------------
|
||||||
|
|
||||||
|
# PERSON INPUT
|
||||||
|
# --------------------------------------
|
||||||
|
# convert a given vcard file into a person file
|
||||||
|
function person_to_vcard {
|
||||||
|
local person="$1"
|
||||||
|
|
||||||
|
if test -n "$OUTPUT_PATH"; then vcard="$OUTPUT_PATH"
|
||||||
|
else vcard="${person}.vcf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
make_vcard "$vcard"
|
||||||
|
populate_vcard_person "$vcard" "$person"
|
||||||
|
finish_vcard "$vcard"
|
||||||
|
}
|
||||||
|
|
||||||
|
# return a properly-formatted colon-delimited address, and a pretty address for
|
||||||
|
# labels. the former on first line, latter on the second.
|
||||||
|
function person_address {
|
||||||
|
local person="$person"
|
||||||
|
|
||||||
|
local address="$(catattr -d META:address "$person" 2>/dev/null)"
|
||||||
|
local city="$(catattr -d META:city "$person" 2>/dev/null)"
|
||||||
|
local state="$(catattr -d META:state "$person" 2>/dev/null)"
|
||||||
|
local zip="$(catattr -d META:zip "$person" 2>/dev/null)"
|
||||||
|
local country="$(catattr -d META:country "$person" 2>/dev/null)"
|
||||||
|
|
||||||
|
if test -z "$city" -a -z "$address"; then return 2; fi
|
||||||
|
echo ";;${address};${city};${state};${zip};${country}"
|
||||||
|
echo "${address}, ${city}, ${state} ${zip}, ${country}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# VCARD OUTPUT
|
||||||
|
# --------------------------------------
|
||||||
|
# create a fresh, blank vcard
|
||||||
|
function make_vcard {
|
||||||
|
local vcard="$1"
|
||||||
|
printf 'BEGIN:VCARD\nVERSION:%s\n' "$VERSION" >> "$vcard"
|
||||||
|
addattr -t mime BEOS:TYPE text/x-vcard "$vcard"
|
||||||
|
}
|
||||||
|
|
||||||
|
# wrap up the current vcard
|
||||||
|
function finish_vcard {
|
||||||
|
local vcard="$1"
|
||||||
|
date +"REV:%Y%m%d" >> "$vcard"
|
||||||
|
echo "END:VCARD" >> "$vcard"
|
||||||
|
}
|
||||||
|
|
||||||
|
# populate a vcard with a person's attributes
|
||||||
|
function populate_vcard_person {
|
||||||
|
local vc="$1"
|
||||||
|
local person="$2"
|
||||||
|
set_vcard_name "$vc" "$(catattr -d META:name "$person" 2>/dev/null)"
|
||||||
|
set_vcard_org "$vc" "$(catattr -d META:company "$person" 2>/dev/null)"
|
||||||
|
set_vcard_url "$vc" "$(catattr -d META:url "$person" 2>/dev/null)"
|
||||||
|
set_vcard_email "$vc" "$(catattr -d META:email "$person" 2>/dev/null)"
|
||||||
|
set_vcard_phone "$vc" "$(catattr -d META:wphone "$person" 2>/dev/null)" "WORK"
|
||||||
|
set_vcard_phone "$vc" "$(catattr -d META:hphone "$person" 2>/dev/null)" "HOME"
|
||||||
|
set_vcard_nick "$vc" "$(catattr -d META:nickname "$person" 2>/dev/null)"
|
||||||
|
set_vcard_address "$vc" "$(person_address "$person")" "HOME"
|
||||||
|
set_vcard_photo "$vc" "$person"
|
||||||
|
}
|
||||||
|
|
||||||
|
# set the name and full-name of a vcard.
|
||||||
|
function set_vcard_name {
|
||||||
|
local vcard="$1"
|
||||||
|
local name="$2"
|
||||||
|
simple_set_vcard "$vcard" "N" "$(infer_name "$name")"
|
||||||
|
simple_set_vcard "$vcard" "FN" "$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# set the email of a vcard.
|
||||||
|
function set_vcard_email {
|
||||||
|
local vcard="$1"
|
||||||
|
local email="$2"
|
||||||
|
simple_set_vcard "$vcard" "EMAIL" "$email"
|
||||||
|
}
|
||||||
|
|
||||||
|
# set a vcard's url attribute.
|
||||||
|
function set_vcard_url {
|
||||||
|
local vcard="$1"
|
||||||
|
local url="$2"
|
||||||
|
simple_set_vcard "$vcard" "URL" "$url"
|
||||||
|
}
|
||||||
|
|
||||||
|
# set a vcard's organization attribute.
|
||||||
|
function set_vcard_org {
|
||||||
|
local vcard="$1"
|
||||||
|
local org="$2"
|
||||||
|
simple_set_vcard "$vcard" "ORG" "$org"
|
||||||
|
}
|
||||||
|
|
||||||
|
# set a vcard's nick. only for 3.0 and 4.0; 2.1 doesn't support NICKNAME.
|
||||||
|
function set_vcard_nick {
|
||||||
|
local vcard="$1"
|
||||||
|
local nick="$2"
|
||||||
|
if test -z "$nick"; then return 2; fi
|
||||||
|
|
||||||
|
if test "$VERSION" = "3.0" -o "$VERSION" = "4.0"; then
|
||||||
|
echo "NICKNAME:${nick}" >> "$vcard"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# set a vcard's phone-number of the given type.
|
||||||
|
function set_vcard_phone {
|
||||||
|
local vcard="$1"
|
||||||
|
local number="$2"
|
||||||
|
local type="$3"
|
||||||
|
if test -z "$number"; then return 2; fi
|
||||||
|
if test -z "$type"; then type="HOME"; fi
|
||||||
|
|
||||||
|
local prefix=""
|
||||||
|
if test "$VERSION" = "2.1"; then prefix="TEL;${type};VOICE:"
|
||||||
|
elif test "$VERSION" = "3.0"; then prefix="TEL;TYPE=${type},VOICE:"
|
||||||
|
elif test "$VERSION" = "4.0"
|
||||||
|
then prefix="TEL;TYPE=${type},voice;VALUE=uri:tel:"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${prefix}${number}" >> "$vcard"
|
||||||
|
}
|
||||||
|
|
||||||
|
# sets a vcard's address and address label
|
||||||
|
# ($addresses is a two-lined string, with the colon-delimited address on top
|
||||||
|
# and the user-friendly comma-delimited on bottom.)
|
||||||
|
function set_vcard_address {
|
||||||
|
local vcard="$1"
|
||||||
|
local addresses="$2"
|
||||||
|
local type="$3"
|
||||||
|
|
||||||
|
local address="$(echo "$addresses" | head -1)"
|
||||||
|
local label="$(echo "$addresses" | tail -1)"
|
||||||
|
local addrstr=""
|
||||||
|
local labelstr=""
|
||||||
|
|
||||||
|
if test "$VERSION" = "2.1" -o "$VERSION" = "3.0"; then
|
||||||
|
labelstr="LABEL;TYPE=${type}:${label}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$VERSION" = "2.1"; then
|
||||||
|
addrstr="ADR;${type}:${address}"
|
||||||
|
elif test "$VERSION" = "3.0"; then
|
||||||
|
addrstr="ADR;TYPE=${type}:${address}"
|
||||||
|
elif test "$VERSION" = "4.0"; then
|
||||||
|
addrstr="ADR;TYPE=${type};LABEL=\"${label}\":${address}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$address" -o -z "$label"; then return 2; fi
|
||||||
|
|
||||||
|
echo "$addrstr" >> "$vcard"
|
||||||
|
if test -n "$labelstr"; then
|
||||||
|
echo "$labelstr" >> "$vcard"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# embeds the given photo into the vcard file (base64), if possible
|
||||||
|
function set_vcard_photo {
|
||||||
|
local vcard="$1"
|
||||||
|
local photo="$2"
|
||||||
|
if is_image "$photo"; then ls>/dev/null; else return 2; fi
|
||||||
|
|
||||||
|
local mime="$(file --mime-type "$photo")"
|
||||||
|
local type="$(file "$photo" | awk -F : '{print $1}' | awk '{print $1}')"
|
||||||
|
echo >> "$vcard"
|
||||||
|
if test "$VERSION" = "2.1"; then
|
||||||
|
echo "PHOTO;${type};ENCODING=BASE64:$(base64 -w 79 "$photo")" \
|
||||||
|
>>"$vcard"
|
||||||
|
elif test "$VERSION" = "3.0"; then
|
||||||
|
echo "PHOTO;TYPE=${type};ENCODING=b:$(base64 -w 79 "$photo")" \
|
||||||
|
>> "$vcard"
|
||||||
|
elif test "$VERSION" = "4.0"; then
|
||||||
|
echo "PHOTO:data:${mime};base64,$(base64 -w 79 "$photo")" \
|
||||||
|
>> "$vcard"
|
||||||
|
fi
|
||||||
|
echo >> "$vcard"
|
||||||
|
}
|
||||||
|
|
||||||
|
# generic function for setting simple attrs of vcards.
|
||||||
|
function simple_set_vcard {
|
||||||
|
local vcard="$1"; local key="$2"; local val="$3"
|
||||||
|
if test -z "$val"; then return 2; fi
|
||||||
|
echo "${key}:${val}" >> "$vcard"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# MISC
|
||||||
|
# --------------------------------------
|
||||||
|
# takes a trad. comma-delimited address and converts to vcard format
|
||||||
|
function infer_name {
|
||||||
|
local names="$1"
|
||||||
|
|
||||||
|
local inferred_name=""
|
||||||
|
local honorific=""
|
||||||
|
local slot_count=5
|
||||||
|
local name_count="$(echo "$names" | wc -w)"
|
||||||
|
for name in $names; do
|
||||||
|
if is_honorific "$name"; then
|
||||||
|
honorific="$name"
|
||||||
|
else
|
||||||
|
inferred_name="${name};${inferred_name}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
local i=""
|
||||||
|
if test "$name_count" -ne "$slot_count"; then
|
||||||
|
i="$((slot_count - $name_count - 1))"
|
||||||
|
|
||||||
|
while test "$i" -ne 0; do
|
||||||
|
inferred_name="${inferred_name};"
|
||||||
|
i="$((i - 1))"
|
||||||
|
done
|
||||||
|
|
||||||
|
if test -n "$honorific" -a "$name_count" -lt "$slot_count"; then
|
||||||
|
inferred_name="${inferred_name}${honorific};"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$inferred_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ok so this is super language-dependant and is omega cringe
|
||||||
|
# you'll probably have to modify this for your locale
|
||||||
|
function is_honorific {
|
||||||
|
local name="$1"
|
||||||
|
|
||||||
|
local honorifics="ms. mrs. mr. s-ro s-ano s-ino"
|
||||||
|
if echo "$honorifics" | grep -i "$name" > /dev/null; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# check whether or not a file is an image
|
||||||
|
function is_image {
|
||||||
|
local file="$1"
|
||||||
|
file "$file" | grep "image" > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# INVOCATION
|
||||||
|
# --------------------------------------
|
||||||
|
function help {
|
||||||
|
echo "usage: $(basename $0) [-h] [-v version] [-o path] person"
|
||||||
|
echo
|
||||||
|
echo \
|
||||||
|
"Creates a vcard from the given person file's attributes. By default will
|
||||||
|
output to a file of the same name with a .vcf file-extension.
|
||||||
|
-o changes output vcard filename
|
||||||
|
-v specify vcard version: 2.1, 3.0, or 4.0. Defaults to 4.0.
|
||||||
|
a random URL, and use it as the vcard's photo URL.
|
||||||
|
-h print this message."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VERSION="4.0"
|
||||||
|
OUTPUT_PATH=""
|
||||||
|
while getopts ":hUo:v:" arg; do
|
||||||
|
case $arg in
|
||||||
|
o) OUTPUT_PATH="$OPTARG";;
|
||||||
|
v) if test "$OPTARG" = "4.0" -o "$OPTARG" = "3.0" \
|
||||||
|
-o "$OPTARG" = "2.1"; then
|
||||||
|
VERSION="$OPTARG"
|
||||||
|
else
|
||||||
|
echo "Invalid version number." >&2
|
||||||
|
exit 3
|
||||||
|
fi;;
|
||||||
|
h) help;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
shift $(($OPTIND - 1))
|
||||||
|
remaining_args="$@"
|
||||||
|
|
||||||
|
if test -z "$1"; then help
|
||||||
|
else PERSON="$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
person_to_vcard "$PERSON"
|
|
@ -0,0 +1,429 @@
|
||||||
|
#!/boot/system/bin/bash
|
||||||
|
# --------------------------------------
|
||||||
|
# VCARD2PERSON
|
||||||
|
# simple script for convertining a vcard
|
||||||
|
# into a haiku person file.
|
||||||
|
# CC0, jadedctrl@teknik.io
|
||||||
|
# --------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# VCARD INPUT
|
||||||
|
# --------------------------------------
|
||||||
|
# convert a given vcard file into a person file
|
||||||
|
function vcard_to_person {
|
||||||
|
local vcard="$1"
|
||||||
|
local person="$2"
|
||||||
|
if test -n "$OUTPUT_PATH"; then person="$OUTPUT_PATH"; fi
|
||||||
|
if test -n "$OUTPUT_DIR"; then person="${OUTPUT_DIR}/${person}"; fi
|
||||||
|
|
||||||
|
make_person "$person"
|
||||||
|
populate_person_vcard "$person" "$vcard"
|
||||||
|
}
|
||||||
|
|
||||||
|
# sometimes vcf files contain multiple vcard definitions.
|
||||||
|
# if so, then process each vcard individually.
|
||||||
|
function vcf_to_persons {
|
||||||
|
orig_vcf="$1"
|
||||||
|
|
||||||
|
vcf="$(mktemp -t 'v2p-XXXX')"
|
||||||
|
vcard="$(mktemp -t 'v2p-XXXX')"
|
||||||
|
cp "$orig_vcf" "$vcf"
|
||||||
|
|
||||||
|
while grep "END:VCARD" "$vcf" > /dev/null; do
|
||||||
|
sed '/END:VCARD/q' "$vcf" \
|
||||||
|
> "$vcard"
|
||||||
|
|
||||||
|
vcard_to_person "$vcard" "$(vcard_name "$vcard"| remove_cr)"
|
||||||
|
|
||||||
|
tail -n +2 "$vcf" \
|
||||||
|
| sed '/BEGIN:VCARD/,$!d' \
|
||||||
|
> "$vcf.tmp"
|
||||||
|
mv "$vcf.tmp" "$vcf"
|
||||||
|
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
rm "$vcf" "$vcard"
|
||||||
|
}
|
||||||
|
|
||||||
|
# get a given value from a vcard
|
||||||
|
function get_vcard_value {
|
||||||
|
local file="$1"
|
||||||
|
local key="$2"
|
||||||
|
|
||||||
|
# local matching="$(grep "^${key}" "$file")"
|
||||||
|
local matching="$(grep -n "^${key}" "$file" | awk -F : '{print $1}')"
|
||||||
|
echo "===${matching}">>/tmp/dad
|
||||||
|
|
||||||
|
if test "$(line_length "$matching")" -gt 1; then
|
||||||
|
matching="$(select_match "$file" "$key" "$matching")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local end_line="$(next_match "$file" "$matching" '^.*[A-Z a-z "]:')"
|
||||||
|
|
||||||
|
cat "$file" \
|
||||||
|
| get_line "$matching" \
|
||||||
|
| cut --complement -d ':' -f 1
|
||||||
|
|
||||||
|
cat "$file" \
|
||||||
|
| line_range "$((matching + 1))" "$((end_line - 1))"
|
||||||
|
}
|
||||||
|
|
||||||
|
# print how many matches a given key has
|
||||||
|
function vcard_match_count {
|
||||||
|
local file="$1"
|
||||||
|
local key="$2"
|
||||||
|
line_length "$(grep "^${key}" "$file")"
|
||||||
|
}
|
||||||
|
|
||||||
|
# select a given match; for when there are mulitple possible slots
|
||||||
|
function select_match {
|
||||||
|
local file="$1"
|
||||||
|
local key="$2"
|
||||||
|
local matches="$3"
|
||||||
|
local match_count="$(line_length "$matches")"
|
||||||
|
|
||||||
|
echo "There are a few matching slots for ${key}." 1>&2
|
||||||
|
echo "Which one do you want to use?" 1>&2
|
||||||
|
echo "(0 for skip)" 1>&2
|
||||||
|
|
||||||
|
local prompt="[0-${match_count}] >> "
|
||||||
|
select_line "$file" "$prompt" "$matches"
|
||||||
|
}
|
||||||
|
|
||||||
|
# return a given field-number of vcard's adr
|
||||||
|
function vcard_adr_value {
|
||||||
|
local adr="$1"
|
||||||
|
local index="$2"
|
||||||
|
|
||||||
|
echo "$adr" \
|
||||||
|
| awk -v ind="$index" -F ';' '{print $ind}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# get a vcard's telephone number
|
||||||
|
function vcard_tel {
|
||||||
|
local file="$1"
|
||||||
|
get_vcard_value "$file" "TEL" \
|
||||||
|
| sed 's%tel:%%' \
|
||||||
|
| clean
|
||||||
|
}
|
||||||
|
|
||||||
|
# puts a vcard's photo to a given output, if it exists
|
||||||
|
function vcard_photo {
|
||||||
|
local vcard="$1"
|
||||||
|
local output="$2"
|
||||||
|
|
||||||
|
local photo_value="$(get_vcard_value "$vcard" "PHOTO")"
|
||||||
|
if test -z "$photo_value"; then return 2; fi
|
||||||
|
|
||||||
|
if echo "$photo_value" | grep "http://">/dev/null; then
|
||||||
|
vcard_photo_url "$photo_value" "$output"
|
||||||
|
else
|
||||||
|
vcard_photo_base64 "$photo_value" "$output";
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# if vcard has a url to a photo (and it's an image), save to output file
|
||||||
|
function vcard_photo_url {
|
||||||
|
local photo="$1"
|
||||||
|
local output="$2"
|
||||||
|
|
||||||
|
local uri="$(echo "$photo" | sed 's%.*http%http%')"
|
||||||
|
if echo "$uri" | grep http > /dev/null; then
|
||||||
|
wget --quiet -O "${output}.tmp" "$uri"
|
||||||
|
if file "${output}.tmp" | grep "image" > /dev/null; then
|
||||||
|
cat "${output}.tmp" > "$output"
|
||||||
|
fi
|
||||||
|
rm "$output.tmp"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# tries to decode base64 photo from a vcard, save to an output file
|
||||||
|
# if the GNU base64 decoder fails, tries the openssl decoder.
|
||||||
|
# ... if *that* fails, tries the python one.
|
||||||
|
# (can you tell I really want contact photos? lmao)
|
||||||
|
function vcard_photo_base64 {
|
||||||
|
local photo="$1"
|
||||||
|
local output="$2"
|
||||||
|
|
||||||
|
echo "$photo" \
|
||||||
|
| clean \
|
||||||
|
| base64 -d \
|
||||||
|
2> /dev/null \
|
||||||
|
> "${output}.tmp"
|
||||||
|
local result="$?"
|
||||||
|
|
||||||
|
if test "$result" -ne 0; then
|
||||||
|
echo "$photo" \
|
||||||
|
| openssl enc -base64 -d \
|
||||||
|
2> /dev/null \
|
||||||
|
> "${output}.tmp"
|
||||||
|
result="$?"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$result" -ne 0; then
|
||||||
|
echo "$photo" \
|
||||||
|
| clean \
|
||||||
|
| python -m base64 -d \
|
||||||
|
2> /dev/null \
|
||||||
|
> "${output}.tmp"
|
||||||
|
result="$?"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$result" -eq 0; then
|
||||||
|
cat "${output}.tmp" > "${output}"
|
||||||
|
fi
|
||||||
|
rm "${output}.tmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
# pretty self-explanatory
|
||||||
|
function vcard_version { local v="$1"; get_vcard_value "$v" "VERSION" | clean; }
|
||||||
|
function vcard_name { local vc="$1"; get_vcard_value "$vc" "FN" | clean; }
|
||||||
|
function vcard_org { local vc="$1"; get_vcard_value "$vc" "ORG" | clean; }
|
||||||
|
function vcard_url { local vc="$1"; get_vcard_value "$vc" "URL" | clean; }
|
||||||
|
function vcard_email { local vc="$1"; get_vcard_value "$vc" "EMAIL" | clean; }
|
||||||
|
function vcard_adr { local vc="$1"; get_vcard_value "$vc" "ADR" | clean; }
|
||||||
|
function adr_address { local adr="$1";vcard_adr_value "$adr" 3 | clean; }
|
||||||
|
function adr_city { local adr="$1";vcard_adr_value "$adr" 4 | clean; }
|
||||||
|
function adr_state { local adr="$1";vcard_adr_value "$adr" 5 | clean; }
|
||||||
|
function adr_zip { local adr="$1";vcard_adr_value "$adr" 6 | clean; }
|
||||||
|
function adr_country { local adr="$1";vcard_adr_value "$adr" 7 | clean; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# PERSON OUTPUT
|
||||||
|
# --------------------------------------
|
||||||
|
# populate the given person with the data of the given vcard
|
||||||
|
function populate_person_vcard {
|
||||||
|
local person="$1"
|
||||||
|
local vcard="$2"
|
||||||
|
|
||||||
|
addattr -t string META:name "$(vcard_name "$vcard")" "$person"
|
||||||
|
addattr -t string META:company "$(vcard_org "$vcard")" "$person"
|
||||||
|
addattr -t string META:email "$(vcard_email "$vcard")" "$person"
|
||||||
|
|
||||||
|
populate_person_telephone "$person" "$vcard"
|
||||||
|
populate_person_address "$person" "$vcard"
|
||||||
|
vcard_photo "$vcard" "$person"
|
||||||
|
}
|
||||||
|
|
||||||
|
# populate a person with a vcard's address data
|
||||||
|
function populate_person_address {
|
||||||
|
local person="$1"
|
||||||
|
local vcard="$2"
|
||||||
|
|
||||||
|
local adr="$(vcard_adr "$vcard")"
|
||||||
|
|
||||||
|
# some implementations (wrongly) put all address info in the address
|
||||||
|
# slot, delimiting with commas and leaving other slots blank.
|
||||||
|
# we can try and work around that.
|
||||||
|
if test -n "$(adr_address "$adr")" -a -z "$(adr_city "$adr")"; then
|
||||||
|
if echo "$adr" | grep "," > /dev/null; then
|
||||||
|
adr="$(infer_comma_address "$adr")"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
addattr -t string META:address "$(adr_address "$adr")" "$person"
|
||||||
|
addattr -t string META:city "$(adr_city "$adr")" "$person"
|
||||||
|
addattr -t string META:state "$(adr_state "$adr")" "$person"
|
||||||
|
addattr -t string META:zip "$(adr_zip "$adr")" "$person"
|
||||||
|
addattr -t string META:country "$(adr_country "$adr")" "$person"
|
||||||
|
}
|
||||||
|
|
||||||
|
# populate a person with a vcard's phone data
|
||||||
|
function populate_person_telephone {
|
||||||
|
local person="$1"
|
||||||
|
local vcard="$2"
|
||||||
|
|
||||||
|
if test "$(vcard_match_count "$vcard" "TEL")" -eq 1; then
|
||||||
|
addattr -t string META:hphone "$(vcard_tel "$vcard")" "$person"
|
||||||
|
elif test "$(vcard_match_count "$vcard" "TEL")" -gt 1; then
|
||||||
|
echo "Home number:"
|
||||||
|
addattr -t string META:hphone "$(vcard_tel "$vcard")" "$person"
|
||||||
|
echo "Work number:"
|
||||||
|
addattr -t string META:wphone "$(vcard_tel "$vcard")" "$person"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# make a new person file
|
||||||
|
function make_person {
|
||||||
|
local file="$1"
|
||||||
|
|
||||||
|
touch "$file"
|
||||||
|
addattr -t mime BEOS:TYPE application/x-person "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# MISC
|
||||||
|
# --------------------------------------
|
||||||
|
# takes a trad. comma-delimited address and converts to vcard format
|
||||||
|
function infer_comma_address {
|
||||||
|
local addr="$1"
|
||||||
|
|
||||||
|
local addr_split="$(echo "$addr"| tr -d ';'| tr ',' '\n'| sed 's%^ %%')"
|
||||||
|
local city_zip_line="$(echo "$addr_split" | grep '[0-9]$')"
|
||||||
|
local zip="$(echo "$city_zip_line" | awk -F ' ' '{print $NF}')"
|
||||||
|
|
||||||
|
echo ";;${addr_split}" \
|
||||||
|
| sed 's% '"$zip"'%\n'"$zip"'%' \
|
||||||
|
| tr '\n' ';' \
|
||||||
|
| sed 's%\;$%%'
|
||||||
|
}
|
||||||
|
|
||||||
|
# have the user select a given line (enumerates output, captive)
|
||||||
|
# also outputs everything to stderr
|
||||||
|
function select_line {
|
||||||
|
local file="$1"
|
||||||
|
local prompt="$2"
|
||||||
|
local line_nums="$3"
|
||||||
|
|
||||||
|
local index=1
|
||||||
|
for line in $line_nums; do
|
||||||
|
printf '%s ' "$index" >&2
|
||||||
|
cat "$file" \
|
||||||
|
| get_line "$line" \
|
||||||
|
>&2
|
||||||
|
index="$((index + 1))"
|
||||||
|
done
|
||||||
|
|
||||||
|
index="$(select_number 0 $(line_length "$line_nums") "$prompt")"
|
||||||
|
echo "$line_nums" \
|
||||||
|
| get_line "$index"
|
||||||
|
}
|
||||||
|
|
||||||
|
# have the user choose a number within the given range
|
||||||
|
# ouputs everything to stderr except the number
|
||||||
|
function select_number {
|
||||||
|
local min=$1
|
||||||
|
local max=$2
|
||||||
|
local prompt="$3"
|
||||||
|
|
||||||
|
printf "$prompt" >&2
|
||||||
|
read response
|
||||||
|
|
||||||
|
if test "$response" -le "$max" -a "$response" -ge "$min"; then
|
||||||
|
echo $response
|
||||||
|
else
|
||||||
|
select_number $min $max "$prompt"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# echoes everything piped into it.
|
||||||
|
# useful for taking piped info in a shell function.
|
||||||
|
function reade {
|
||||||
|
local stack=""
|
||||||
|
while read input; do
|
||||||
|
stack="$(printf '%s\n%s' "$stack" "$input")"
|
||||||
|
done
|
||||||
|
echo "$stack"
|
||||||
|
}
|
||||||
|
|
||||||
|
# self-explanatory, no?
|
||||||
|
function escape_spaces { sed 's% %\\ %g'; }
|
||||||
|
function remove_cr { tr -d '\r'; }
|
||||||
|
function replace_nl { tr '\n' ' '; }
|
||||||
|
function trim { awk '{$1=$1};1'; }
|
||||||
|
|
||||||
|
# does some handy sanitization-work
|
||||||
|
function clean {
|
||||||
|
remove_cr \
|
||||||
|
| replace_nl \
|
||||||
|
| trim
|
||||||
|
}
|
||||||
|
|
||||||
|
# check whether or not a file is an image
|
||||||
|
function is_image {
|
||||||
|
local file="$1"
|
||||||
|
file "$file" | grep "image" > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# prints the amount of lines a string has
|
||||||
|
function line_length {
|
||||||
|
local lines="$1"
|
||||||
|
echo "$lines" \
|
||||||
|
| wc -l
|
||||||
|
}
|
||||||
|
|
||||||
|
# prints the line at given index
|
||||||
|
function get_line {
|
||||||
|
local line_index="$1"
|
||||||
|
awk -v ind="$line_index" 'NR==ind'
|
||||||
|
}
|
||||||
|
|
||||||
|
# prints lines after given index (inclusive)
|
||||||
|
function after_line {
|
||||||
|
local line_index="$1"
|
||||||
|
awk -v ind="$line_index" 'NR>=ind'
|
||||||
|
}
|
||||||
|
|
||||||
|
# prints lines before given index (inclusive)
|
||||||
|
function before_line {
|
||||||
|
local line_index="$1"
|
||||||
|
awk -v ind="$line_index" 'NR<=ind'
|
||||||
|
}
|
||||||
|
|
||||||
|
# prints a range of lines (inclusive)
|
||||||
|
function line_range {
|
||||||
|
local min="$1"
|
||||||
|
local max="$2"
|
||||||
|
awk -v min="$min" -v max="$max" 'min <= NR && NR <= max'
|
||||||
|
}
|
||||||
|
|
||||||
|
# prints the line index of the next match following a given line index
|
||||||
|
function next_match {
|
||||||
|
local file="$1"
|
||||||
|
local after_index="$2"
|
||||||
|
local regex="$3"
|
||||||
|
|
||||||
|
cat "$file" \
|
||||||
|
| after_line "$((after_index+1))" \
|
||||||
|
| grep -n "${regex}" \
|
||||||
|
| head -1 \
|
||||||
|
| awk -v last="$after_index" -F : '{print last + $1}' \
|
||||||
|
| bc
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# INVOCATION
|
||||||
|
# --------------------------------------
|
||||||
|
function help {
|
||||||
|
echo "usage: $(basename $0) vcard [-h] [-d directory] [-o path] file"
|
||||||
|
echo
|
||||||
|
echo \
|
||||||
|
"People files will be created using the data from a vcard. Each vcard defined
|
||||||
|
by a given vcf/vcard file have its person file be named after the vcard's
|
||||||
|
full-name.
|
||||||
|
-o changes the output person filename
|
||||||
|
-d outputs all people files to a given directory-- useful if a file
|
||||||
|
defines multiple vcards.
|
||||||
|
-h prints this message."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OUTPUT_DIR=""
|
||||||
|
OUTPUT_PATH=""
|
||||||
|
while getopts ":hd:o:" arg; do
|
||||||
|
case $arg in
|
||||||
|
o) OUTPUT_PATH="$OPTARG";;
|
||||||
|
d) if test -d "$OPTARG"; then
|
||||||
|
OUTPUT_DIR="$OPTARG"
|
||||||
|
else
|
||||||
|
echo "Directory does not exist." >&2
|
||||||
|
exit 3
|
||||||
|
fi;;
|
||||||
|
h) help;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
shift $(($OPTIND - 1))
|
||||||
|
remaining_args="$@"
|
||||||
|
|
||||||
|
if test -z "$1"; then help
|
||||||
|
else VCARD="$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
vcf_to_persons "$VCARD"
|
Ŝarĝante…
Reference in New Issue