Permalink
9943b58 Apr 1, 2016
@tgalal @girish946 @davidbecker @abloch
executable file 370 lines (299 sloc) 14.2 KB
#!/usr/bin/env python
__version__ = "2.0.15"
__author__ = "Tarek Galal"
import sys, argparse, yowsup, logging
from yowsup.env import YowsupEnv
HELP_CONFIG = """
############# Yowsup Configuration Sample ###########
#
# ====================
# The file contains info about your WhatsApp account. This is used during registration and login.
# You can define or override all fields in the command line args as well.
#
# Country code. See http://www.ipipi.com/help/telephone-country-codes.htm. This is now required.
cc=49
#
# Your full phone number including the country code you defined in 'cc', without preceding '+' or '00'
phone=491234567890
#
# You obtain this password when you register using Yowsup.
password=NDkxNTIyNTI1NjAyMkBzLndoYXRzYXBwLm5ldA==
#######################################################
"""
CR_TEXT = """yowsup-cli v{cliVersion}
yowsup v{yowsupVersion}
Copyright (c) 2012-2016 Tarek Galal
http://www.openwhatsapp.org
This software is provided free of charge. Copying and redistribution is
encouraged.
If you appreciate this software and you would like to support future
development please consider donating:
http://openwhatsapp.org/yowsup/donate
"""
logger = logging.getLogger("yowsup-cli")
class YowArgParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(YowArgParser, self).__init__(*args, **kwargs)
self.add_argument("-v", "--version",
action = "store_true",
help = "Print version info and exit"
)
self.add_argument("-d", "--debug",
action = "store_true",
help = "Show debug messages"
)
self.add_argument("--help-config", help = "Prints a config file sample", action = "store_true")
self.args = {}
def getArgs(self):
return self.parse_args()
def getConfig(self, config):
try:
f = open(config)
out = {}
for l in f:
line = l.strip()
if len(line) and line[0] not in ('#',';'):
prep = line.split('#', 1)[0].split(';', 1)[0].split('=', 1)
varname = prep[0].strip()
val = prep[1].strip()
out[varname.replace('-', '_')] = val
return out
except IOError:
print("Invalid config path: %s" % config)
sys.exit(1)
def process(self):
self.args = vars(self.parse_args())
if self.args["debug"]:
logging.basicConfig(level = logging.DEBUG)
else:
logging.basicConfig(level = logging.INFO)
if self.args["version"]:
print("yowsup-cli v%s\nUsing yowsup v%s" % (__version__, yowsup.__version__))
sys.exit(0)
if self.args["help_config"]:
print(HELP_CONFIG)
sys.exit(0)
def printInfoText(self):
print(CR_TEXT.format(cliVersion=__version__, yowsupVersion=yowsup.__version__))
class RegistrationArgParser(YowArgParser):
def __init__(self, *args, **kwargs):
super(RegistrationArgParser, self).__init__(*args, **kwargs)
self.description = "WhatsApp Registration options"
configGroup = self.add_argument_group("Configuration options",
description = "Config file is optional. Other configuration arguments have higher priority if given, and will override those specified in the config file")
configGroup.add_argument("-c", '--config',
action = "store",
help = 'Path to config file. If this is not set then you must set at least --phone and --cc arguments')
configGroup.add_argument('-E', '--env',
action = "store",
help = "Set the environment yowsup simulates",
choices = YowsupEnv.getRegisteredEnvs())
configGroup.add_argument("-m", '--mcc',
action = "store",
help = "Mobile Country Code. Check your mcc here: https://en.wikipedia.org/wiki/Mobile_country_code")
configGroup.add_argument("-n", '--mnc',
action = "store",
help = "Mobile Network Code. Check your mnc from https://en.wikipedia.org/wiki/Mobile_country_code")
# configGroup.add_argument("-M", '--sim-mcc',
# action = "store",
# help = "Mobile Country Code. Check your mcc here: https://en.wikipedia.org/wiki/Mobile_country_code"
# )
# configGroup.add_argument("-N", '--sim-mnc',
# action= "store",
# help = "SIM MNC"
# )
configGroup.add_argument("-p", '--phone',
action= "store",
help = " Your full phone number including the country code you defined in 'cc', without preceeding '+' or '00'")
configGroup.add_argument("-C", '--cc',
action = "store",
help = "Country code. See http://www.ipipi.com/networkList.do. This is now required")
# configGroup.add_argument("-i", '--id',
# action="store",
# help = "Identity"
# )
regSteps = self.add_argument_group("Modes")
regSteps = regSteps.add_mutually_exclusive_group()
regSteps.add_argument("-r", '--requestcode', help='Request the digit registration code from Whatsapp.', action="store", required=False, metavar="(sms|voice)")
regSteps.add_argument("-R", '--register', help='Register account on Whatsapp using the code you previously received', action="store", required=False, metavar="code")
def process(self):
super(RegistrationArgParser, self).process()
config = self.getConfig(self.args["config"]) if self.args["config"] else {}
if self.args["env"]:
YowsupEnv.setEnv(self.args["env"])
if self.args["mcc"] : config["mcc"] = self.args["mcc"]
if self.args["mnc"] : config["mnc"] = self.args["mnc"]
if self.args["phone"] : config["phone"] = self.args["phone"]
if self.args["cc" ] : config["cc"] = self.args["cc"]
#if self.args["sim_mnc"] : config["sim_mnc"] = self.args["sim_mnc"]
#if self.args["sim_mcc"] : config["sim_mcc"] = self.args["sim_mcc"]
if not "mcc" in config: config["mcc"] = "000"
if not "mnc" in config: config["mnc"] = "000"
if not "sim_mcc" in config: config["sim_mcc"] = "000"
if not "sim_mnc" in config: config["sim_mnc"] = "000"
try:
assert self.args["requestcode"] or self.args["register"], "Must specify one of the modes -r/-R"
assert "cc" in config, "Must specify cc (country code)"
assert "phone" in config, "Must specify phone number"
except AssertionError as e:
print(e)
print("\n")
return False
if not config["phone"].startswith(config["cc"]):
print("Error, phone number does not start with the specified country code\n")
return False
config["phone"] = config["phone"][len(config["cc"]):]
if self.args["requestcode"]:
self.handleRequestCode(self.args["requestcode"], config)
elif self.args["register"]:
self.handleRegister(self.args["register"], config)
else:
return False
return True
def handleRequestCode(self, method, config):
from yowsup.registration import WACodeRequest
self.printInfoText()
codeReq = WACodeRequest(config["cc"],
config["phone"],
config["mcc"],
config["mnc"],
config["mcc"],
config["mnc"],
method
)
result = codeReq.send()
print(self.resultToString(result))
def handleRegister(self, code, config):
from yowsup.registration import WARegRequest
self.printInfoText()
code = code.replace('-', '')
req = WARegRequest(config["cc"], config["phone"], code)
result = req.send()
print(self.resultToString(result))
def resultToString(self, result):
unistr = str if sys.version_info >= (3, 0) else unicode
out = []
for k, v in result.items():
if v is None:
continue
out.append("%s: %s" %(k, v.encode("utf-8") if type(v) is unistr else v))
return "\n".join(out)
class DemosArgParser(YowArgParser):
def __init__(self, *args, **kwargs):
super(DemosArgParser, self).__init__(*args, **kwargs)
self.description = "Run a yowsup demo"
configGroup = self.add_argument_group("Configuration options for demos")
credentialsOpts = configGroup.add_mutually_exclusive_group()
credentialsOpts.add_argument("-l", "--login", action="store", metavar="phone:b64password",
help = "WhatsApp login credentials, in the format phonenumber:password, where password is base64 encoded.")
credentialsOpts.add_argument("-c", "--config", action="store",
help = "Path to config file containing authentication info. For more info about config format use --help-config")
configGroup.add_argument('-E', '--env',
action = "store",
help = "Set the environment yowsup simulates",
choices = YowsupEnv.getRegisteredEnvs())
configGroup.add_argument("-M", "--unmoxie", action="store_true", help="Disable E2E Encryption")
cmdopts = self.add_argument_group("Command line interface demo")
cmdopts.add_argument('-y', '--yowsup', action = "store_true", help = "Start the Yowsup command line client")
echoOpts = self.add_argument_group("Echo client demo")
echoOpts.add_argument('-e', '--echo', action = "store_true", help = "Start the Yowsup Echo client")
sendOpts = self.add_argument_group("Send client demo")
sendOpts.add_argument('-s', '--send', action="store", help = "Send a message to specified phone number, "
"wait for server receipt and exit",
metavar=("phone", "message"), nargs = 2)
syncContacts = self.add_argument_group("Sync contacts")
syncContacts.add_argument('-S','--sync', action = "store" , help = "Sync ( check valid ) whatsapp contacts",metavar =("contacts"))
def process(self):
super(DemosArgParser, self).process()
if self.args["env"]:
YowsupEnv.setEnv(self.args["env"])
if self.args["yowsup"]:
self.startCmdline()
elif self.args["echo"]:
self.startEcho()
elif self.args["send"]:
self.startSendClient()
elif self.args["sync"]:
self.startSyncContacts()
else:
return False
return True
def _getCredentials(self):
if self.args["login"]:
return tuple(self.args["login"].split(":"))
elif self.args["config"]:
config = self.getConfig(self.args["config"])
assert "password" in config and "phone" in config, "Must specify at least phone number and password in config file"
return config["phone"], config["password"]
else:
return None
def startCmdline(self):
from yowsup.demos import cli
credentials = self._getCredentials()
if not credentials:
print("Error: You must specify a configuration method")
sys.exit(1)
self.printInfoText()
stack = cli.YowsupCliStack(credentials, not self.args["unmoxie"])
stack.start()
def startEcho(self):
from yowsup.demos import echoclient
credentials = self._getCredentials()
if not credentials:
print("Error: You must specify a configuration method")
sys.exit(1)
try:
self.printInfoText()
stack = echoclient.YowsupEchoStack(credentials, not self.args["unmoxie"])
stack.start()
except KeyboardInterrupt:
print("\nYowsdown")
sys.exit(0)
def startSendClient(self):
from yowsup.demos import sendclient
credentials = self._getCredentials()
if not credentials:
print("Error: You must specify a configuration method")
sys.exit(1)
try:
self.printInfoText()
stack = sendclient.YowsupSendStack(credentials, [([self.args["send"][0], self.args["send"][1]])],
not self.args["unmoxie"])
stack.start()
except KeyboardInterrupt:
print("\nYowsdown")
sys.exit(0)
def startSyncContacts(self):
from yowsup.demos import contacts
credentials = self._getCredentials()
if not credentials:
print("Error: You must specify a configuration method")
sys.exit(1)
try:
self.printInfoText()
stack = contacts.YowsupSyncStack(credentials,self.args["sync"].split(','), not self.args["unmoxie"])
stack.start()
except KeyboardInterrupt:
print("\nYowsdown")
sys.exit(0)
if __name__ == "__main__":
args = sys.argv
if(len(args) > 1):
del args[0]
modeDict = {
"demos": DemosArgParser,
"registration": RegistrationArgParser,
"version": None
}
if(len(args) == 0 or args[0] not in modeDict):
print("Available commands:\n===================")
print(", ".join(modeDict.keys()))
sys.exit(1)
mode = args[0]
if mode == "version":
print("yowsup-cli v%s\nUsing yowsup v%s" % (__version__, yowsup.__version__))
sys.exit(0)
else:
parser = modeDict[mode]()
if not parser.process():
parser.print_help()