forked from PhilRW/gcontacts-asterisk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
googlecontacts.py
executable file
·212 lines (175 loc) · 8.11 KB
/
googlecontacts.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/usr/bin/env python
# Original By: John Baab
# Email: rhpot1991@ubuntu.com
# Updated By: Jay Schulman
# Email: info@jayschulman.com
# Updated Again By: Philip Rosenberg-Watt
# And a little again by: Vicente Monroig (vmonroig@digitaldisseny.com)
# Purpose: syncs contacts from google to asterisk server
# Updates: Updating for Google API v3 with support for Google Apps
# OAuth2 auth flow and tokens
# Requirements: python, gdata python client, asterisk
#
# License:
#
# This Package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this package; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# On Debian & Ubuntu systems, a complete copy of the GPL can be found under
# /usr/share/common-licenses/GPL-3, or (at your option) any later version
import atom,re,sys,os
import json
import gdata.data
import gdata.auth
import gdata.contacts
import gdata.contacts.client
import gdata.contacts.data
import argparse
import unicodedata
from oauth2client import client
from oauth2client import file
from oauth2client import tools
# Native application Client ID JSON from the Google Developers Console,
# store in the same directory as this script:
CLIENT_SECRETS_JSON = 'client_secret_XXXXXXXXXXX-yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.apps.googleusercontent.com.json'
parent_parsers = [tools.argparser]
parser = argparse.ArgumentParser(parents=parent_parsers)
parser.add_argument("--allgroups", help="only works in combination with --group to show members with multiple groups", action="store_true", default=False)
parser.add_argument("--anygroup", help="show members of any user-created group (not My Contacts), OVERRIDES other options", action="store_true", default=False)
parser.add_argument("--asterisk", help="send commands to Asterisk instead of printing to console", action="store_true", default=False)
parser.add_argument("--dbname", help="database tree to use")
parser.add_argument("--delete", help="delete the existing database first", action="store_true", default=False)
parser.add_argument("--group", action="append", help="group name, can use multiple times")
parser.add_argument("--non_interactive", help="abort script if credentials are missing or invalid", action="store_true", default=False)
parser.add_argument("--ascii", help="remove all non-ascii characters from names", action="store_true", default=False)
args = parser.parse_args()
if args.dbname is None:
args.dbname = "cidname"
phone_map = {2: ["A", "B", "C"],
3: ["D", "E", "F"],
4: ["G", "H", "I"],
5: ["J", "K", "L"],
6: ["M", "N", "O"],
7: ["P", "Q", "R", "S"],
8: ["T", "U", "V"],
9: ["W", "X", "Y", "Z"]}
phone_map_one2one = {}
for k, v in phone_map.items():
for l in v:
phone_map_one2one[l] = str(k)
def phone_translate(phone_number):
new_number = ""
for l in phone_number:
if l.upper() in phone_map_one2one.keys():
new_number += phone_map_one2one[l.upper()]
else:
l = re.sub('[^0-9]', '', l)
new_number += l
if len(new_number) == 11 and new_number[0] == "1":
new_number = new_number[1:]
return new_number
def get_auth_token():
scope = 'https://www.googleapis.com/auth/contacts.readonly'
user_agent = __name__
client_secrets = os.path.join(os.path.dirname(__file__), CLIENT_SECRETS_JSON)
filename = os.path.splitext(__file__)[0] + '.dat'
flow = client.flow_from_clientsecrets(client_secrets, scope=scope, message=tools.message_if_missing(client_secrets))
storage = file.Storage(filename)
credentials = storage.get()
if credentials is None or credentials.invalid:
if args.non_interactive:
sys.stderr.write('ERROR: Invalid or missing Oauth2 credentials. To reset auth flow manually, run without --non_interactive\n')
sys.exit(1)
else:
credentials = tools.run_flow(flow, storage, args)
j = json.loads(open(filename).read())
return gdata.gauth.OAuth2Token(j['client_id'], j['client_secret'], scope, user_agent, access_token = j['access_token'], refresh_token = j['refresh_token'])
def add_to_asterisk(dbname, cid, name):
command = "asterisk -rx \'database put " + dbname + " " + cid + " \"" + name + "\"\'"
if args.asterisk:
os.system(command.encode('utf8'))
else:
print command.encode('utf8')
def main():
# Change this if you aren't in the US. If you have more than one country code in your contacts,
# then use an empty string and make sure that each number has a country code.
country_code = ""
token = get_auth_token()
gd_client = gdata.contacts.client.ContactsClient()
gd_client = token.authorize(gd_client)
qry = gdata.contacts.client.ContactsQuery(max_results=2000)
feed = gd_client.GetContacts(query=qry)
groups = {}
gq = gd_client.GetGroups()
for e in gq.entry:
striptext = "System Group: "
groupname = e.title.text
if groupname.startswith(striptext):
groupname = groupname[len(striptext):]
groups[e.id.text] = groupname
# delete all of our contacts before we refetch them, this will allow deletions
if args.delete:
command = "asterisk -rx \'database deltree %s\'" % args.dbname
if args.asterisk:
os.system(command)
else:
print command
# for each phone number in the contacts
for i, entry in enumerate(feed.entry):
glist = []
for grp in entry.group_membership_info:
glist.append(groups[grp.href])
name = None
if entry.organization is not None and entry.organization.name is not None:
name = entry.organization.name.text
if entry.title.text is not None:
name = entry.title.text
if entry.nickname is not None:
name = entry.nickname.text
for r in entry.relation:
if r.label == "CID":
name = r.text
break
for phone in entry.phone_number:
# Strip out any non numeric characters and convert to UTF-8
# phone.text = re.sub('[^0-9]', '', phone.text)
phone.text = unicode(phone.text, 'utf8')
phone.text = phone_translate(phone.text)
# Remove leading digit if it exists, we will add this again later for all numbers
# Only if a country code is defined.
if country_code != "":
phone.text = re.compile('^\+?%s' % country_code, '', phone.text)
phone.text = country_code + phone.text
name = name.replace('\'','')
name = name.replace('"','')
if args.ascii:
if not isinstance(name, bytes):
name = unicodedata.normalize('NFKD', name).encode('ascii', 'ignore')
if args.anygroup:
if (("My Contacts" in glist and len(glist) > 1) or
("My Contacts" not in glist and len(glist) > 0)):
add_to_asterisk(args.dbname, phone.text, name)
else:
if args.group:
if args.allgroups:
if set(args.group).issubset(glist):
add_to_asterisk(args.dbname, phone.text, name)
else:
for g in args.group:
if g in glist:
add_to_asterisk(args.dbname, phone.text, name)
else:
add_to_asterisk(args.dbname, phone.text, name)
if __name__ == '__main__':
main()