Commits

johannes committed 4f51602

A console application for sending SMSes with the Norwegian telecom company OneCall

  • Participants

Comments (0)

Files changed (1)

+#!/usr/bin/python
+"""
+This code is licensed under public domain. Feel free to give it away to friends and foes.
+
+- Johannes Hoff, November 19th 2011
+"""
+
+import requests
+import json
+from sys import argv, exit
+import os
+import codecs
+from AddressBook import *
+import pprint
+
+home = os.environ['HOME']
+config_file = os.path.join(home, '.sms', 'config.json')
+
+if not os.path.exists(config_file):
+	print 'You need a config file called %s, with the following contents:' % config_file
+	print '{"username": <your phone number>, "password": "<your password>"}'
+	print 'Where the stuff within <> needs to be replaced.'
+	exit(-6)
+
+# Stole the following awesome function legally from http://www.programmish.com/?p=26 :
+def addressBookToList():
+	"""
+	Read the current user's AddressBook database, converting each person
+	in the address book into a Dictionary of values. Some values (addresses,
+	phone numbers, email, etc) can have multiple values, in which case a
+	list of all of those values is stored. The result of this method is
+	a List of Dictionaries, with each person represented by a single record
+	in the list.
+	"""
+	# get the shared addressbook and the list of
+	# people from the book.
+	ab = ABAddressBook.sharedAddressBook()
+	people = ab.people()
+
+	peopleList = []
+
+	# convert the ABPerson to a hash
+	for person in people:
+		thisPerson = {}
+		props = person.allProperties()
+		for prop in props:
+
+			# skip some properties
+			if prop == "com.apple.ABPersonMeProperty":
+			    continue
+			elif prop == "com.apple.ABImageData":
+			    continue
+
+			# How we convert the value depends on the ObjC
+			# class used to represent it
+			val = person.valueForProperty_(prop)
+			if type(val) == objc.pyobjc_unicode:
+				# Unicode String
+				thisPerson[prop.lower()] = val
+			elif issubclass(val.__class__, NSDate):
+				# NSDate
+				thisPerson[prop.lower()] = val.description()
+			elif type(val) == ABMultiValueCoreDataWrapper:
+				# List -- convert each item in the list
+				# into the proper format
+				thisPerson[prop.lower()] = []
+				for valIndex in range(0, val.count()):
+					indexedValue = val.valueAtIndex_(valIndex)
+					if type(indexedValue) == objc.pyobjc_unicode:
+						# Unicode string
+						thisPerson[prop.lower()].append(indexedValue)
+					elif issubclass(indexedValue.__class__, NSDate):
+						# Date
+						thisPerson[prop.lower()].append(indexedValue.description())
+					elif type(indexedValue) == NSCFDictionary:
+						# NSDictionary -- convert to a Python Dictionary
+						propDict = {}
+						for propKey in indexedValue.keys():
+							propValue = indexedValue[propKey]
+							propDict[propKey.lower()] = propValue
+						thisPerson[prop.lower()].append(propDict)
+		peopleList.append(thisPerson)
+	return peopleList
+
+
+if len(argv) != 3:
+	print 'Usage: %s <number> <message>' % argv[0]
+	exit(-1)
+
+def match_contacts(name):
+	address_book = addressBookToList()
+	for person in address_book:
+		if 'nickname' in person and person['nickname'].lower() == name:
+			yield (1, person)
+		elif 'first' in person and name in person['first'].lower():
+			yield (2, person)
+		elif 'last' in person and name in person['last'].lower():
+			yield (2, person)
+
+name_arg = codecs.decode(argv[1], 'utf-8')
+if name_arg.isdigit() or name_arg.startswith('+') and name_arg[1:].isdigit():
+	number = name_arg
+else:
+	matches = sorted(match_contacts(name_arg))
+
+	if len(matches) == 0:
+		print 'No matches for %s' % (name_arg)
+		exit(-2)
+	elif len(matches) > 1 and (matches[0][0] == matches[1][0]):
+		print 'Ambigous match for %s:' % (name_arg)
+		print '\n'.join('%s %s: %s (priority %d)' % (person['first'], person['last'], person['phone'][0], pri) for pri, person in matches)
+		exit(-3)
+	else:
+		number = matches[0][1]['phone'][0]
+
+pri, person = matches[0]
+message = unicode(codecs.decode(argv[2], 'utf-8'))
+print 'Message to %s %s: %s (priority %d)' % (person['first'], person['last'], person['phone'][0], pri)
+print 'Message length %d' % len(message)
+
+if len(message) > 160:
+	print 'Message to long. Edit the source to override ;)'
+	exit(-4)
+
+def login(credentials):
+	url = 'https://www.onecall.no/minesider/login.php'
+	data = {'Logg_Inn': 'Logg_Inn'}
+	data.update(credentials)
+
+	req = requests.post(url, data=data)
+
+	return req.cookies  #'minesider logged_in' in req.content
+
+def sendsms(cookies, number, message):
+	url = 'https://www.onecall.no/minesider/send_sms.php'
+	req = requests.post(url, cookies=cookies, data={'nummer': number, 'smsmsg': message, 'submit': 'Send SMS'})
+
+	return 'Melding er sendt' in req.content
+
+cookies = login(json.load(open(config_file)))
+
+if not cookies:
+	print 'Login failed'
+else:
+	ok = sendsms(cookies, number, message)
+	if ok:
+		print 'Message sent successfully'
+	else:
+		print 'Failed to send message'