Skip to content

Instantly share code, notes, and snippets.

@andermoran
Created March 16, 2019 17:32
Show Gist options
  • Save andermoran/7551e17bccd334b2f304848520b41aaf to your computer and use it in GitHub Desktop.
Save andermoran/7551e17bccd334b2f304848520b41aaf to your computer and use it in GitHub Desktop.
A small program that grabs the information of every contact on a user's mac
import plistlib
import os
import sys
import getpass
# usage: python contact_reaper.py or python3 contact_reaper.py
# tested on macOS Mojave (10.14)
def get_main_dir_path():
return "/Users/" + getpass.getuser() + "/Library/Application Support/AddressBook/Sources/"
def get_source_subdirs():
main_dir_path = get_main_dir_path()
main_dir = os.fsencode(main_dir_path)
sub_dirs = []
for file in os.listdir(main_dir):
filename = os.fsdecode(file)
if not filename.endswith(".DS_Store"):
sub_dirs.append(os.path.join(main_dir_path, filename))
return sub_dirs
def get_contact_plist(path):
try:
contact_file = open(path, "rb")
pl = plistlib.load(contact_file)
return pl
except PermissionError:
print("[PermissionError] Unable to open file")
return None
except:
print("[Unknown Error] Unable to generate plist object")
return None
def get_contact_plist_for_name(name):
first_name = name.split(" ")[0]
last_name = name.split(" ")[1]
dirs = get_source_subdirs()
for dir in dirs:
dir_path = dir + "/Metadata/"
if os.path.isdir(dir_path): # because some folders may not contain the Metadata folder
directory = os.fsencode(dir_path)
print(dir_path, "is a dir")
for file in os.listdir(directory):
filename = os.fsdecode(file)
if filename.endswith(".abcdp"):
contact_filepath = os.path.join(dir_path, filename)
contact_pl = get_contact_plist(contact_filepath)
if contact_pl is None:
print("[Err] Unable to get contact plist for", name)
return None
try:
if contact_pl['First'] == first_name and contact_pl['Last'] == last_name:
return contact_pl
except:
""
#print("[debug]No first or last name found for contact at path", contact_filepath)
return None
def get_number_for_name(name):
pl = get_contact_plist_for_name(name)
if pl is not None:
try:
return pl['Phone']['values']
except:
print("[Oof] Contact does not contain phone number information")
else:
print("[Err] Unable to get phone number for", name)
return None
def get_address_for_name(name):
pl = get_contact_plist_for_name(name)
if pl is not None:
try:
return pl['Address']['values'][0]['Street']
except:
print("[Oof] Contact does not contain address information")
else:
print("[Err] Unable to get address for", name)
return None
def get_all_contacts():
dirs = get_source_subdirs()
contacts = []
for dir in dirs:
dir += "/Metadata/"
if os.path.isdir(dir): # because some folders may not contain the Metadata folder
for file in os.listdir(dir):
filename = os.fsdecode(file)
if not filename.endswith(".DS_Store"):
contact = get_contact_plist(os.path.join(dir, filename))
if contact is not None:
contacts.append(contact)
return contacts
contacts = get_all_contacts()
for contact in contacts:
try:
print("First name:", contact['First'])
except:
print("First name: (null)")
try:
print("Last name:", contact['Last'])
except:
print("Last name: (null)")
try:
number = ''.join(filter(lambda x: x.isdigit(), contact['Phone']['values'][0]))
print("Phone number:", number)
except:
print("Phone number: (null)")
try:
if len(contact['Email']['values']) > 0:
print("Email: ", end="")
for i in range(0, len(contact['Email']['values'])):
if i == 0 :
print(contact['Email']['values'][i], end="")
else:
print(",", contact['Email']['values'][i], end="")
print()
except:
print("Email: (null)")
try:
print("Street:", contact['Address']['values'][0]['Street'])
except:
""
try:
print("State:", contact['Address']['values'][0]['State'])
except:
""
try:
print("City:", contact['Address']['values'][0]['City'])
except:
""
try:
print("Zip:", contact['Address']['values'][0]['Zip'])
except:
""
print()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment