-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.py
139 lines (119 loc) · 3.77 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import re
import quopri
from aliases import ALIASES
import array
FIELD_RE = r"[a-zA-Z0-9;=\-]+:"
IGNORED_FIELDS = ["VERSION", "N"]
XC = "X-ANDROID-CUSTOM"
REMOVE_PH_DASH = True
def decode_strs(field, value):
"""Decodes strings
Args:
field (str): field name
value (str): value
Returns:
[str, str]: decoded string along with modified field name
"""
separate = field.split(";ENCODING=")
if len(separate) > 1:
txt = value
if separate[1] == "QUOTED-PRINTABLE":
value = quopri.decodestring(value.replace("==", "=")).decode("utf-8")
field = separate[0]
return [field, value]
def extract_field_data(value):
field_data = "Custom Attribute"
field_name = value
# X-ANDROID-FIELDs
if "vnd.android.cursor.item/" in value:
value = value[24:]
[field_name, field_data, field_attr] = value.split(";")[:3]
if field_name in ALIASES[XC]:
alias_data = ALIASES[XC][field_name]
if isinstance(alias_data, str):
field_name = alias_data
else:
field_data = f"{field_data} ({alias_data[field_attr]})"
return [field_name, field_data]
def fmt_number(num):
return num.replace("-", "") if REMOVE_PH_DASH else num
def format_tel(contact):
tel_nums = {}
tels = [f for f in dict.keys(contact) if "TEL;" in f]
for t in tels:
prefix = t[4:].capitalize()
fname = f"Phone{f': {prefix}' if prefix != 'Cell' else ''}"
if isinstance(contact[t], list):
c = 0
for num in contact[t]:
num_name = f"{fname}{f' {c}' if c > 0 else ''}"
contact[num_name] = fmt_number(num)
c += 1
else:
contact[fname] = fmt_number(contact[t])
del contact[t]
# preprocess fields (ie replace by aliases)
def preprocess_fields(contact):
c2 = {}
for field in contact.copy():
if field in IGNORED_FIELDS:
continue
[f, d] = decode_strs(field, contact[field])
c2[f] = d
subfields = field.split(";")
f0 = subfields[0]
fp = f
if f0 in ALIASES:
alias = ALIASES[f0]
val = c2[f]
if isinstance(alias, str):
c2[alias] = val
fp = alias
else:
[ex_field, data] = extract_field_data(val)
c2[ex_field] = data
fp = ex_field
del c2[f]
# format phone numbers
format_tel(c2)
return c2
# convert vcf to array of contacts object
def toObj(f):
field = ""
contact = {}
contacts = []
for i, ln in enumerate(f):
line = ln.strip()
f = re.search(FIELD_RE, line)
# remove last column
if f:
f = f.group()[:-1]
else:
f = ""
# start from : remove that colon if it exists
value = line[len(f) :].replace(":", "")
if f == "BEGIN":
field = ""
elif f == "END":
field = ""
contact = preprocess_fields(contact)
contacts += [contact]
contact = {}
elif f == "" and field != "":
# no field names are present appears to
# be continuation of previous field, like note/photo
if isinstance(contact[field], array.array):
contact[field] += [value]
else:
contact[field] += value
else:
# new field
field = f
if field in contact:
if isinstance(contact[field], list):
contact[field] += [value]
else:
contact[field] = [value, contact[field]]
else:
contact[field] = value
return contacts