Skip to content

Instantly share code, notes, and snippets.

@thusoy
Last active November 26, 2022 19:32
Show Gist options
  • Save thusoy/e6706ab24574868f7b17 to your computer and use it in GitHub Desktop.
Save thusoy/e6706ab24574868f7b17 to your computer and use it in GitHub Desktop.
Convert your Google contacts to mutt format
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This script is designed to sync mutt aliases with Google contacts
from __future__ import unicode_literals
import sys
import datetime
import atom
import argparse
from oauth2client import tools
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.file import Storage
import gdata.contacts
import gdata.contacts.data
from collections import namedtuple
import gdata.contacts.client
import gdata.gauth
import gdata.contacts.service
import httplib2
client_id = '<ADD_CLIENT_ID_HERE>'
client_secret = '<ADD_CLIENT_SECRET_HERE>'
class OAuthToken(object):
def __init__(self, access_token):
self.access_token = access_token
def modify_request(self, http_request):
print 'modify_request'
http_request.headers['Authorization'] = 'Bearer %s' % (self.access_token)
return http_request
def main(client_id, client_secret):
def remove_aliases(email):
lookup_key = name.replace(' ', '-').lower()
emails_without_known_alias = []
# Extract the emails with a known relation, such as work and home,
# and add separate aliases for them
for i, email in enumerate(emails[:]):
rel_name = rel_map.get(email.rel)
if rel_name:
lookup_key += '-%s' % rel_name
aliases.append(Alias(lookup_key, name, email.address))
else:
emails_without_known_alias.append(email)
if len(emails_without_known_alias) == 1:
email = emails_without_known_alias[0]
aliases.append(Alias(lookup_key, name, email.address))
return []
return emails_without_known_alias
scope = 'https://www.google.com/m8/feeds/'
flow = OAuth2WebServerFlow(client_id=client_id,
client_secret=client_secret,
scope=scope,
redirect_uri='urn:ietf:wg:oauth:2.0:oob')
query = gdata.contacts.client.ContactsQuery()
query.max_results = 4000
storage = Storage('a_credentials_file')
parser = argparse.ArgumentParser(parents=[tools.argparser])
flags = parser.parse_args()
credentials = storage.get()
# Google returns 'invalid_grant' when trying to refresh the token, but fails
# to properly describe why this happens. Thus we create a new set of credentials
# from scratch if they have expired
if not credentials or datetime.datetime.utcnow() > credentials.token_expiry:
credentials = tools.run_flow(flow, storage, flags)
contacts = []
access_token = credentials.get_access_token()
auth_token = OAuthToken(access_token.access_token)
gd_client = gdata.contacts.client.ContactsClient()
try:
with open('contact_feed.atom') as fh:
feed_body = fh.read()
desired_class = gdata.contacts.data.ContactsFeed
feed = atom.core.parse(feed_body, desired_class)
except IOError:
try:
feed = gd_client.GetContacts(q=query, auth_token=auth_token)
with open('contact_feed.atom', 'w') as fh:
fh.write(feed.to_string())
except Exception as e:
print e.status
sys.exit(1)
wtf_contacts = []
for contact in feed.entry:
if contact.name:
contacts.append(contact)
else:
wtf_contacts.append(contact)
rel_map = {
'http://schemas.google.com/g/2005#home': 'privat',
'http://schemas.google.com/g/2005#work': 'work',
}
Alias = namedtuple('Alias', ['identifier', 'name', 'email'])
aliases = []
for contact in contacts:
name = contact.name.full_name.text
lookup_key = name.replace(' ', '-').lower()
emails = contact.email
if len(emails) == 0:
print 'No email for %s' % name
elif len(emails) > 1:
emails = remove_aliases(emails)
if emails:
handle_multiple_emails(name, emails)
else:
email = emails[0]
aliases.append(Alias(lookup_key, name, email.address))
with open('mutt_aliases.txt', 'w') as fh:
for alias in aliases:
fh.write(('%s %s <%s>\n' % (alias.identifier, alias.name, alias.email)).encode('utf-8'))
def handle_multiple_emails(name, emails):
for i, email in enumerate(emails):
print '%d: %s' % (i, email.address)
chosen_email_num = -1
while not 0 <= chosen_email_num < len(emails):
try:
chosen_email_num = int(raw_input(('Select email to use for %s:' % name).encode('utf-8')))
except ValueError as e:
print 'Enter a number between 0 and %d to indicate which email to use for %s' % (
len(emails) -1, name)
except Exception as e:
import pdb; pdb.set_trace()
print e
email = emails[chosen_email_num]
if __name__ == '__main__':
main(client_id, client_secret)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment