Skip to content

Commit

Permalink
First commit. Very much broken.
Browse files Browse the repository at this point in the history
  • Loading branch information
krishnangovindraj committed Jun 16, 2014
0 parents commit 52f089d
Show file tree
Hide file tree
Showing 14 changed files with 668 additions and 0 deletions.
42 changes: 42 additions & 0 deletions Config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#Config and plenty of constants
class Config:
keepAlive = True
sendReceipts = False

session_opts = {'session.type': 'file', 'session.cookie_expires': True,}
'''
def __init__():
#Nothing
'''
class Constants:
#DBI
DBI_FETCHALL = 1
DBI_FETCHONE = 2
DBI_ROWCOUT = 3

#INBOX
INBOX_UNSEEN = 1
INBOX_SEEN = 2

#OUTBOX
OUTBOX_PENDING = 1
OUTBOX_SENDING = 2
OUTBOX_SENT = 3

OUTBOX_TIMEOUT = 90 #1.5 minutes

#AUTH
AUTHSTATUS_IDLE = 1
AUTHSTATUS_TRYING = 2
AUTHSTATUS_LOGGEDIN = 3


#INSTANCESTATUS (Notes the status of the process in the databases. Mostly to keep track of instances
INSTANCESTATUS_RUNNING = 0
INSTANCESTATUS_WRAPPEDUP = 2


'''
def __init():
#Nothing
'''
95 changes: 95 additions & 0 deletions Core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
'''
Core
'''
from Yowsup.connectionmanager import YowsupConnectionManager
from Config import Config,Constants
from WWMException import WWMException

import MySQLdb,time, os, hashlib
class WWMCore:
def __init__(self):

connectionManager = YowsupConnectionManager()
connectionManager.setAutoPong(Config.keepAlive)

self.signalsInterface = connectionManager.getSignalsInterface()
self.methodsInterface = connectionManager.getMethodsInterface()

self.cm = connectionManager

self.listener = None
self.sender = None
self.session = None
self.httpRequestHandler = None
self.instanceId = None


self.dbi = None #Do not connect yet
self.dbiCursor = None

self.yowsupRunning = 0

#Just to keep track of the instances created
def registerInstance(self, procId):
timeNow = time.time()
procId = os.getpid()
status = Constants.INSTANCESTATUS_STARTED
authStatus = Constants.AUTHSTATUS_IDLE
self.dbiCursor.execute("INSERT INTO pythoninstances (userId, procId, lastUpdated,status, authStatus) VALUES(%s, %s, %s, %s)", (self.session.userId, procId, timeNow, status,authStatus))
#self.instanceId =

def genAESKey(self, str):
#md5 hash of reverse of str
return hashlib.md5(str[::-1]).hexdigest()


def initSender(self):
self.yowsupRunning = 1
self.listener = Listener(self)

def initListener(self):
self.yowsupRunning = 1
self.sender = Sender(self)

def initDBI(self):
try:
self.dbi = MySQLdb.connect('localhost','root','','webwhatsapp')
self.dbiCursor = self.dbi.cursor(MySQLdb.cursors.DictCursor)
except MySQLdb.Error e:
raise WWMException("MySQL could not connect: %s", %e)

def getDBICursor(self):
if self.dbi == None or self.dbi.open==0:
self.initDBI()

return self.dbiCursor

#This method is called from session
def initSession(self, userId, AESKey):
self.yowsupRunning = 1
self.session = Session(self, userId, AESKey)
self.session.login()

def checkStatus():
self.dbiCursor.execute("SELECT status FROM pythoninstances WHERE instanceId=%s",(self.instanceId,))
row = self.dbiCursor.fetchone()
status = row["status"]

def wrapUp(self):
#Write some code to wrap up
status = Constants.INSTANCESTATUS_WRAPPEDUP
self.dbiCursor.execute("UPDATE pythonInstances set status=%s WHERE instanceId=%s ", (status, self.instanceId))

self.yowsupRunning = 0

def addUser(self, phone,email,name,password,whatsapp_pass):
AESKey = self.genAESKey(password)
hash = hashlib.md5(password).hexdigest()
try:
db = self.getDBICursor()
db.execute( "INSERT INTO users (phone,email,name,password,whatsapp_pass) VALUES(%s,%s,%s,%s,AES_ENCRYPT(%s,%s))", (phone, email,name,hash,whatsapp_pass,AESKey) )
except MySQLdb.Error, e:
print "Exception: %s"%e
#if self.dbi.error: raise WWMException("DB Error:%s" db.error)
print "Executed but nothing doing"

37 changes: 37 additions & 0 deletions Listener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'''
Copyright (c) <2012> Tarek Galal <[email protected]>
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.
'''
import datetime, sys

from Yowsup.connectionmanager import YowsupConnectionManager

class Listener:

def __init__(self, coreRef):
self.core = coreRef
self.core.signalsInterface.registerListener("message_received", self.onMessageReceived)

def onMessageReceived(self, messageId, jid, messageContent, timestamp, wantsReceipt, pushName, isBroadCast):
sender = jid
self.core.dbiCursor.execute("INSERT INTO inbox (messageId, recipient, sender, message, tstamp, seen ) VALUES( %s, %s, %s, %s, %s )",
( messageId, self.session.phone, sender, messageContent, timestamp, 0))

if wantsReceipt and Config.SEND_RECEIPTS:
self.methodsInterface.call("message_ack", (jid, messageId))
4 changes: 4 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
README:
Aim: Make a web client for whatsapp. Do whatever you want as long as that's achieved. And rewrite this readme when you're done

NOTE: You need Yowsup copied to the same directory. ie .\Yowsup has to contain all the Yowsup library files
168 changes: 168 additions & 0 deletions RequestHandler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#RequestHandler.py

from Core import WWMCore
from Skin import Skin
import urlparse,hashlib

class RequestHandler:

validPaths = ["","inbox","send","logout"]
def __init__(self):
self.core = WWMCore()
self.error = ""
self.headers = []
self.environ = None
self.HTTPsession = None
self.get = None
self.post = None
self.path = ""
self.responseCode = "500 Internal Server Error"
#No clue what this does

def requestHandler(self, environ, start_response):
self.environ = environ

self.HTTPSession = environ['beaker.session']



self.path = environ["PATH_INFO"][1:]
self.requestMethod = environ["REQUEST_METHOD"]
self.queryString = environ["QUERY_STRING"]

self.get = urlparse.parse_qs(self.queryString)
self.parsePost()


if self.HTTPSession.get("phone",False) == False:
print "Session not set"
if self.path == "index" or self.path == "":
self.index()
else:
if self.path == "login":
self.login()
else:
self.redirect302("index")

start_response(self.responseCode, self.headers)
return self.response

handler = self.resolveRequest()
print "\n>Resolved to handler %s\n"% handler.__name__
handler()

self.session.save()
start_response(self.responseCode, self.headers)

return self.response

def resolveRequest(self):
#Stackoverflow's equivalent to switch
return {
"inbox": self.inbox,
"chat": self.chat,
"send": self.send,
"logout": self.logout,
"startYowsup:": self.startYowsup
}.get(self.path, self.notFound)

def parsePost(self):
# the environment variable CONTENT_LENGTH may be empty or missing
try:
request_body_size = int(self.environ.get('CONTENT_LENGTH', 0))
except (ValueError):
request_body_size = 0


request_body = self.environ['wsgi.input'].read(request_body_size)
self.post = urlparse.parse_qs(request_body)

def redirect302(self, location):
self.responseCode = "302 Moved Temporarily"
self.response = ""
self.headers.append(("Location",location))


def inbox(self):
self.headers.append(('Content-type','text/html'))
self.responseCode = "200 OK"
recipient = self.core.session.phone
self.core.dbiCursor.execute("SELECT DISTINCT sender,tstamp, 1 AS isunread FROM inbox WHERE recipient=%s AND seen=0 UNION SELECT DISTINCT sender, tstamp,0 AS isunread FROM inbox WHERE recipient=%s AND seen=1 ORDER BY isunread DESC, tstamp DESC",(recipient,recipient))
convos = self.core.dbiCursor.fetchAll()
self.response = Skin.inbox(convos)

def chat(self):
self.headers.append(('Content-type','text/html'))
self.responseCode = "200 OK"
otherperson = self.get.get("with")
me = self.core.session.phone

if sender==False:
self.response = "No messages from that person found"
else:
self.core.dbiCursor.execute("SELECT * FROM inbox WHERE sender=%s AND recipient=%s AND seen=0 ORDER BY tstamp DESC LIMIT 20", (otherperson,me))
received = self.core.dbiCursor.fetchall()
getafter = received[0].tstamp
self.core.dbiCursor.execute("SELECT *,1 as seen FROM outbox WHERE sender=%s AND recipient=%s AND tstamp>%s ORDER BY tstamp DESC ", (me, otherperson,getafter))
sent = self.core.dbiCursor.fetchall()
#convo = Merge(received, sent)
self.response = Skin.chat(convo)

def send(self):
self.headers.append(('Content-type','text/html'))
self.responseCode = "200 OK"
self.response = "SEND MY REGARDS TO YO MOMMA!"

def logout(self):
self.core.wrapUp()
self.redirect302("/")
'''
self.responseCode = "302 Moved Temporarily"
self.headers.append(("Location","/"))
#self.response="WISE CHOICE. QUIT WHILE YOU STILL CAN"
'''
def notFound(self):
self.responseCode = "404 Not Found"
self.response = "Invalid path"

def siteLogin(self):

if self.requestMethod!="POST":
self.response="This page can only be accessed by POST. Please go back to the index"
else:
self.responseCode = "200 OK"
db = self.core.getDBICursor()
phone, password = self.post.get("phone"), self.post.get("password")
hash = hashlib.md5(password).hexdigest()
db.execute( "SELECT phone FROM users WHERE phone=%s AND password=%s", (phone,hash) )
if db.rowcount>0:
row = db.fetchone()
self.HTTPSession["phone"] = row.get("phone")
self.HTTPSession["AESKey"] = core.genAESKey(password)
self.response= "SUCCESS!"
else
self.response ="Login failed"

def startYowsup(self):
if self.core.yowsupRunning==1:
self.headers.append(("Location","/inbox"))
self.responseCode ="302 Moved Temporarily"
return

s= self.HTTPSession
if s.get("userId")==None or s.get("AESKey")==None:
self.badRequest()
return
else:
self.core.session = Session(self.HTTPSession.userId, self.HTTPSession.AESKey)

def index(self):
self.responseCode="200 OK"
if self.HTTPSession.get("phone",False)!=False:
self.response = Skin.index()
else:
self.response = Skin.loginForm()

def badRequest(self):
self.responseCode = "400 Bad Request"
self.response = "Bad request"
Loading

0 comments on commit 52f089d

Please sign in to comment.