Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
#!/usr/bin/env python
# Copyright (C) 2011 by Jonathan Beluch
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
''' Dunkin Donus Amex Activator via SMS or IM
Automates the dd gift card activation found at:
http://www.dunkindonuts.com/card/Activation/
Send a 16 digit card number, an 8 digit pin and an optional email address,
and the script will activate the card for you by filling out the online form.
Uses Tropo for the IM/SMS interaction.
Setup:
1. Set up an account on tropo.com
2. Create a new application in the web ui and use this as the source
3. In your application settings, request a phone number and activate a
jabber IM account.
4. Text/IM away
Example SMS:
1111222233334444 77778888 larry@google.com
\ \ \
[16 digit card #] [8 digit PIN] [optional email address to include in the
activation form]
Text 'help' to get the usage via SMS.
'''
import urllib
import re
def parse_card_amount(src):
'''Parse the card amount from the success page. If there is an
error, attempt to parse the error and return it. Else, return a
generic error message
'''
amount_pattern = '<IMG class="amount" alt="(.+?)"'
amount_match = re.search(amount_pattern, src)
error_pattern = r'<div class="error">(.+?)<'
error_match = re.search(error_pattern, src)
if amount_match:
return amount_match.group(1)
elif error_match:
raise ActivationError(error_match.group(1))
raise ActivationError('Error activating your card.')
def activate_card(cardnumber, pin, email):
'''Submits the activation form for a given cardnumber, pin and
email
'''
#GET, load activation page
url = 'http://www.dunkindonuts.com/card/Activation/'
#POST, activate the card
url2 = 'https://www.dunkindonuts.com/card/Activation/Default.aspx'
#load activation page and get hidden __VIEWSTATE form parameter
src = urllib.urlopen(url).read()
#just use regex and get it over with
p = '<input type="hidden" name="__VIEWSTATE" value="(.*?)" />'
m = re.search(p, src)
if not m:
raise ActivationError('ERROR: Couldn\'t parse __VIEWSTATE from activation page. Script update needed.')
viewstate = m.group(1)
#create post params
params = {'txtCardNumber': cardnumber, #16 digits
'txtPIN': pin, #8digits
'txtFirstName': 'test',
'txtLastName': 'test',
'txtEmail': email,
'txtEmail2': email,
'txtZipcode': '90210',
'txtAgree': '1', #click the box 13 and older
'__EVENTTARGET': 'btnSubmit',
'__EVENTARG': '',
'__VIEWSTATE': viewstate,
}
log(params)
src = urllib.urlopen(url2, urllib.urlencode(params)).read()
#check for success message and txt user back
amount = parse_card_amount(src)
say('Your dunkin donuts card with a value of %s has been activated.' % amount)
def parse_sms_args(text):
'''Parse the card number, PIN and optional email from a users text
message.
'''
cardnumber_pattern = r'\b(\d{16})\b'
pin_pattern = r'\b(\d{8})\b'
email_pattern = r'\b(\S+?@\S+?)\b'
m = re.search(cardnumber_pattern, text)
if not m:
raise UsageError('No 16 digit card number found.')
cardnumber = m.group(1)
m = re.search(pin_pattern, text)
if not m:
raise UsageError('No 8 digit pin found.')
pin = m.group(1)
m = re.search(email_pattern, text)
email = 'larry@google.com'
if m:
email = m.group(1)
return cardnumber, pin, email
class DDException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class UsageError(DDException):
pass
class ActivationError(DDException):
pass
#start here
#verify we are using sms, twitter or IM
if currentCall.channel == 'TEXT' and currentCall.initialText.lower() == 'help':
say('I need a 16 digit card number and an 8 digit pin number. You can also include an optional email address to enter into the form.')
elif currentCall.channel == 'TEXT':
try:
cardnumber, pin, email = parse_sms_args(currentCall.initialText)
activate_card(cardnumber, pin, email)
except UsageError, e:
say('ERROR: %s Text \'help\' for usage.' % e)
except ActivationError, e:
say('ERROR: %s Text \'help\' for usage.' % e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment