-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
155 lines (131 loc) · 3.99 KB
/
utils.py
File metadata and controls
155 lines (131 loc) · 3.99 KB
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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]
def preprocess_fields(contact):
"""Removes ignored fields, decodes strings and replaces field names
with aliases
Args:
contact (object):
Returns:
object
"""
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
def toObj(f):
"""convert vcf to array of contacts object
Args:
f : file
Returns:
array: array of contacts
"""
field = ""
print(type(f))
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