mirror of
https://github.com/barronwaffles/dwc_network_server_emulator.git
synced 2026-10-01 14:26:50 -05:00
Cleaned: gamespy_profile_server.py
This commit is contained in:
@@ -41,41 +41,57 @@ logger_output_to_console = True
|
||||
logger_output_to_file = True
|
||||
logger_name = "GameSpyProfileServer"
|
||||
logger_filename = "gamespy_profile_server.log"
|
||||
logger = utils.create_logger(logger_name, logger_filename, -1, logger_output_to_console, logger_output_to_file)
|
||||
logger = utils.create_logger(logger_name, logger_filename, -1,
|
||||
logger_output_to_console, logger_output_to_file)
|
||||
|
||||
address = ("0.0.0.0", 29900)
|
||||
|
||||
|
||||
class GameSpyProfileServer(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
endpoint = serverFromString(reactor, "tcp:%d:interface=%s" % (address[1], address[0]))
|
||||
endpoint = serverFromString(
|
||||
reactor,
|
||||
"tcp:%d:interface=%s" % (address[1], address[0])
|
||||
)
|
||||
conn = endpoint.listen(PlayerFactory())
|
||||
|
||||
try:
|
||||
if reactor.running is False:
|
||||
if not reactor.running:
|
||||
reactor.run(installSignalHandlers=0)
|
||||
except ReactorAlreadyRunning:
|
||||
pass
|
||||
|
||||
|
||||
class PlayerFactory(Factory):
|
||||
def __init__(self):
|
||||
# Instead of storing the sessions in the database, it might make more sense to store them in the PlayerFactory.
|
||||
logger.log(logging.INFO, "Now listening for connections on %s:%d...", address[0], address[1])
|
||||
"""Player Factory.
|
||||
|
||||
Instead of storing the sessions in the database, it might make more
|
||||
sense to store them in the PlayerFactory.
|
||||
"""
|
||||
logger.log(logging.INFO,
|
||||
"Now listening for connections on %s:%d...",
|
||||
address[0], address[1])
|
||||
self.sessions = {}
|
||||
|
||||
def buildProtocol(self, address):
|
||||
return PlayerSession(self.sessions, address)
|
||||
|
||||
|
||||
class PlayerSession(LineReceiver):
|
||||
def __init__(self, sessions, address):
|
||||
self.setRawMode() # We're dealing with binary data so set to raw mode
|
||||
self.setRawMode() # We're dealing with binary data so set to raw mode
|
||||
|
||||
self.db = gs_database.GamespyDatabase()
|
||||
|
||||
self.sessions = sessions
|
||||
self.address = address
|
||||
self.remaining_message = "" # Stores any unparsable/incomplete commands until the next rawDataReceived
|
||||
# Stores any unparsable/incomplete commands until the next
|
||||
# rawDataReceived
|
||||
self.remaining_message = ""
|
||||
|
||||
self.profileid = 0
|
||||
self.gameid = ""
|
||||
@@ -92,17 +108,25 @@ class PlayerSession(LineReceiver):
|
||||
|
||||
self.sdkrevision = "0"
|
||||
|
||||
def log(self, level, message):
|
||||
if self.profileid == 0:
|
||||
if self.gameid == "":
|
||||
logger.log(level, "[%s:%d] %s", self.address.host, self.address.port,message)
|
||||
def log(self, level, msg, *args, **kwargs):
|
||||
if not self.profileid:
|
||||
if not self.gameid:
|
||||
logger.log(level, "[%s:%d] " + msg,
|
||||
self.address.host, self.address.port,
|
||||
*args, **kwargs)
|
||||
else:
|
||||
logger.log(level, "[%s:%d | %s] %s", self.address.host, self.address.port, self.gameid, message)
|
||||
logger.log(level, "[%s:%d | %s] " + msg,
|
||||
self.address.host, self.address.port, self.gameid,
|
||||
*args, **kwargs)
|
||||
else:
|
||||
if self.gameid == "":
|
||||
logger.log(level, "[%s:%d | %d] %s", self.address.host, self.address.port, self.profileid, message)
|
||||
if not self.gameid:
|
||||
logger.log(level, "[%s:%d | %d] " + msg,
|
||||
self.address.host, self.address.port,
|
||||
self.profileid, *args, **kwargs)
|
||||
else:
|
||||
logger.log(level, "[%s:%d | %d | %s] %s", self.address.host, self.address.port, self.profileid, self.gameid, message)
|
||||
logger.log(level, "[%s:%d | %d | %s] " + msg,
|
||||
self.address.host, self.address.port,
|
||||
self.profileid, self.gameid, *args, **kwargs)
|
||||
|
||||
def get_ip_as_int(self, address):
|
||||
ipaddress = 0
|
||||
@@ -117,15 +141,20 @@ class PlayerSession(LineReceiver):
|
||||
try:
|
||||
self.transport.setTcpKeepAlive(1)
|
||||
|
||||
self.log(logging.INFO, "Received connection from %s:%d" % (self.address.host, self.address.port))
|
||||
self.log(logging.INFO,
|
||||
"Received connection from %s:%d",
|
||||
self.address.host, self.address.port)
|
||||
|
||||
# Create new session id
|
||||
self.session = ""
|
||||
|
||||
# Generate a random challenge string
|
||||
self.challenge = utils.generate_random_str(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
self.challenge = utils.generate_random_str(
|
||||
10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
)
|
||||
|
||||
# The first command sent to the client is always a login challenge containing the server challenge key.
|
||||
# The first command sent to the client is always a login challenge
|
||||
# containing the server challenge key.
|
||||
msg = gs_query.create_gamespy_message([
|
||||
('__cmd__', "lc"),
|
||||
('__cmd_val__', "1"),
|
||||
@@ -133,14 +162,16 @@ class PlayerSession(LineReceiver):
|
||||
('id', "1"),
|
||||
])
|
||||
|
||||
self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
|
||||
self.log(logging.DEBUG, "SENDING: '%s'...", msg)
|
||||
self.transport.write(bytes(msg))
|
||||
except:
|
||||
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||
self.log(logging.ERROR,
|
||||
"Unknown exception: %s",
|
||||
traceback.format_exc())
|
||||
|
||||
def connectionLost(self, reason):
|
||||
try:
|
||||
self.log(logging.INFO, "Client disconnected")
|
||||
self.log(logging.INFO, "%s", "Client disconnected")
|
||||
|
||||
self.status = "0"
|
||||
self.statstring = "Offline"
|
||||
@@ -151,28 +182,35 @@ class PlayerSession(LineReceiver):
|
||||
del self.sessions[self.profileid]
|
||||
|
||||
self.db.delete_session(self.sesskey)
|
||||
self.log(logging.INFO, "Deleted session " + self.session)
|
||||
self.log(logging.INFO, "Deleted session %s", self.session)
|
||||
except:
|
||||
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||
self.log(logging.ERROR,
|
||||
"Unknown exception: %s",
|
||||
traceback.format_exc())
|
||||
|
||||
def rawDataReceived(self, data):
|
||||
try:
|
||||
self.log(logging.DEBUG, "RESPONSE: '%s'..." % data)
|
||||
self.log(logging.DEBUG, "RESPONSE: '%s'...", data)
|
||||
|
||||
# In the case where command string is too big to fit into one read, any parts that could not be successfully
|
||||
# parsed are stored in the variable remaining_message. On the next rawDataReceived command, the remaining
|
||||
# message and the data are combined to create a full command.
|
||||
# In the case where command string is too big to fit into one
|
||||
# read, any parts that could not be successfully parsed are
|
||||
# stored in the variable remaining_message. On the next
|
||||
# rawDataReceived command, the remaining message and the data
|
||||
# are combined to create a full command.
|
||||
data = self.remaining_message + data
|
||||
|
||||
# Check to make sure the data buffer starts with a valid command.
|
||||
if len(data) > 0 and data[0] != '\\':
|
||||
# There is data in the buffer but it doesn't start with a \ so there's no chance of it being valid.
|
||||
# Look for the first instance of \final\ and remove everything before it.
|
||||
# If \final\ is not in the command string then ignore it.
|
||||
# There is data in the buffer but it doesn't start with a \ so
|
||||
# there's no chance of it being valid. Look for the first
|
||||
# instance of \final\ and remove everything before it. If
|
||||
# \final\ is not in the command string then ignore it.
|
||||
final = "\\final\\"
|
||||
data = data[data.index(final) + len(final):] if final in data else ""
|
||||
data = data[data.index(final) + len(final):] \
|
||||
if final in data else ""
|
||||
|
||||
commands, self.remaining_message = gs_query.parse_gamespy_message(data)
|
||||
commands, self.remaining_message = \
|
||||
gs_query.parse_gamespy_message(data)
|
||||
|
||||
cmds = {
|
||||
"login": self.perform_login,
|
||||
@@ -186,28 +224,36 @@ class PlayerSession(LineReceiver):
|
||||
"delbuddy": self.perform_delbuddy,
|
||||
"authadd": self.perform_authadd,
|
||||
}
|
||||
|
||||
def cmd_err(data_parsed):
|
||||
# Maybe write unknown commands to a separate file later so new data can be collected more easily?
|
||||
self.log(logging.ERROR, "Found unknown command, don't know how to handle '%s'." % data_parsed['__cmd__'])
|
||||
# Maybe write unknown commands to a separate file later so
|
||||
# new data can be collected more easily?
|
||||
self.log(logging.ERROR,
|
||||
"Found unknown command, don't know how to handle"
|
||||
" '%s'.", data_parsed['__cmd__'])
|
||||
|
||||
for data_parsed in commands:
|
||||
#self.log(-1, data_parsed)
|
||||
self.log(logging.DEBUG, data_parsed)
|
||||
# self.log(-1, data_parsed)
|
||||
self.log(logging.DEBUG, "%s", data_parsed)
|
||||
cmds.get(data_parsed['__cmd__'], cmd_err)(data_parsed)
|
||||
except:
|
||||
self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
|
||||
self.log(logging.ERROR,
|
||||
"Unknown exception: %s",
|
||||
traceback.format_exc())
|
||||
|
||||
def perform_login(self, data_parsed):
|
||||
authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db)
|
||||
authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'],
|
||||
self.db)
|
||||
|
||||
if authtoken_parsed is None:
|
||||
self.log(logging.WARNING, "Invalid Authtoken.")
|
||||
self.log(logging.WARNING, "%s", "Invalid Authtoken.")
|
||||
msg = gs_query.create_gamespy_message([
|
||||
('__cmd__', "error"),
|
||||
('__cmd_val__', ""),
|
||||
('err', '266'),
|
||||
('fatal', ''),
|
||||
('errmsg', 'There was an error validating the pre-authentication.'),
|
||||
('errmsg', 'There was an error validating the'
|
||||
' pre-authentication.'),
|
||||
('id', data_parsed['id']),
|
||||
])
|
||||
self.transport.write(bytes(msg))
|
||||
@@ -217,17 +263,35 @@ class PlayerSession(LineReceiver):
|
||||
self.sdkrevision = data_parsed['sdkrevision']
|
||||
|
||||
# Verify the client's response
|
||||
valid_response = gs_utils.generate_response(self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken'])
|
||||
valid_response = gs_utils.generate_response(
|
||||
self.challenge,
|
||||
authtoken_parsed['challenge'],
|
||||
data_parsed['challenge'],
|
||||
data_parsed['authtoken']
|
||||
)
|
||||
if data_parsed['response'] != valid_response:
|
||||
self.log(logging.ERROR, "ERROR: Got invalid response. Got %s, expected %s" % (data_parsed['response'], valid_response))
|
||||
self.log(logging.ERROR,
|
||||
"ERROR: Got invalid response."
|
||||
" Got %s, expected %s",
|
||||
data_parsed['response'], valid_response)
|
||||
|
||||
proof = gs_utils.generate_proof(self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken'])
|
||||
proof = gs_utils.generate_proof(
|
||||
self.challenge,
|
||||
authtoken_parsed['challenge'],
|
||||
data_parsed['challenge'],
|
||||
data_parsed['authtoken']
|
||||
)
|
||||
|
||||
userid, profileid, gsbrcd, uniquenick = gs_utils.login_profile_via_parsed_authtoken(authtoken_parsed, self.db)
|
||||
userid, profileid, gsbrcd, uniquenick = \
|
||||
gs_utils.login_profile_via_parsed_authtoken(authtoken_parsed,
|
||||
self.db)
|
||||
|
||||
if profileid is not None:
|
||||
# Successfully logged in or created account, continue creating session.
|
||||
loginticket = gs_utils.base64_encode(utils.generate_random_str(16))
|
||||
# Successfully logged in or created account, continue
|
||||
# creating session.
|
||||
loginticket = gs_utils.base64_encode(
|
||||
utils.generate_random_str(16)
|
||||
)
|
||||
self.sesskey = self.db.create_session(profileid, loginticket)
|
||||
|
||||
self.sessions[profileid] = self
|
||||
@@ -235,13 +299,11 @@ class PlayerSession(LineReceiver):
|
||||
self.buddies = self.db.get_buddy_list(self.profileid)
|
||||
self.blocked = self.db.get_blocked_list(self.profileid)
|
||||
|
||||
if self.sdkrevision == "11": # Used in Tatsunoko vs Capcom
|
||||
if self.sdkrevision == "11": # Used in Tatsunoko vs Capcom
|
||||
def make_list(data):
|
||||
list = []
|
||||
for d in data:
|
||||
if d['status'] == 1:
|
||||
list.append(str(d['buddyProfileId']))
|
||||
return list
|
||||
return [str(d['buddyProfileId'])
|
||||
for d in data
|
||||
if d['status'] == 1]
|
||||
|
||||
block_list = make_list(self.blocked)
|
||||
msg = gs_query.create_gamespy_message([
|
||||
@@ -250,7 +312,7 @@ class PlayerSession(LineReceiver):
|
||||
('list', ','.join(block_list)),
|
||||
])
|
||||
|
||||
self.log(logging.DEBUG, "SENDING: %s" % msg)
|
||||
self.log(logging.DEBUG, "SENDING: %s", msg)
|
||||
self.transport.write(bytes(msg))
|
||||
|
||||
buddy_list = make_list(self.buddies)
|
||||
@@ -260,10 +322,9 @@ class PlayerSession(LineReceiver):
|
||||
('list', ','.join(buddy_list)),
|
||||
])
|
||||
|
||||
self.log(logging.DEBUG, "SENDING: %s" % msg)
|
||||
self.log(logging.DEBUG, "SENDING: %s", msg)
|
||||
self.transport.write(bytes(msg))
|
||||
|
||||
|
||||
msg = gs_query.create_gamespy_message([
|
||||
('__cmd__', "lc"),
|
||||
('__cmd_val__', "2"),
|
||||
@@ -272,29 +333,35 @@ class PlayerSession(LineReceiver):
|
||||
('userid', userid),
|
||||
('profileid', profileid),
|
||||
('uniquenick', uniquenick),
|
||||
# Some kind of token... don't know it gets used or generated, but it doesn't seem to have any negative effects if it's not properly generated.
|
||||
# Some kind of token... don't know it gets used or generated,
|
||||
# but it doesn't seem to have any negative effects if it's
|
||||
# not properly generated.
|
||||
('lt', loginticket),
|
||||
('id', data_parsed['id']),
|
||||
])
|
||||
|
||||
# Take the first 4 letters of gsbrcd instead of gamecd because they should be consistent across game
|
||||
# regions. For example, the US version of Metroid Prime Hunters has the gamecd "AMHE" and the first 4 letters
|
||||
# of gsbrcd are "AMHE". However, the Japanese version of Metroid Prime Hunters has the gamecd "AMHJ" with
|
||||
# the first 4 letters of bsbrcd as "AMHE". Tetris DS is the other way, with the first 4 letters as the
|
||||
# Japanese version (ATRJ) while the gamecd is region specific (ATRE for US and ATRJ for JP).
|
||||
# gameid is used to send all people on the player's friends list a status updates, so don't make it region
|
||||
# specific.
|
||||
# Take the first 4 letters of gsbrcd instead of gamecd because
|
||||
# they should be consistent across game regions. For example, the
|
||||
# US version of Metroid Prime Hunters has the gamecd "AMHE" and
|
||||
# the first 4 letters of gsbrcd are "AMHE". However, the Japanese
|
||||
# version of Metroid Prime Hunters has the gamecd "AMHJ" with the
|
||||
# first 4 letters of bsbrcd as "AMHE". Tetris DS is the other way,
|
||||
# with the first 4 letters as the Japanese version (ATRJ) while
|
||||
# the gamecd is region specific (ATRE for US and ATRJ for JP).
|
||||
# gameid is used to send all people on the player's friends list a
|
||||
# status updates, so don't make it region specific.
|
||||
self.gameid = gsbrcd[:4]
|
||||
self.profileid = int(profileid)
|
||||
|
||||
self.log(logging.DEBUG, "SENDING: %s" % msg)
|
||||
self.log(logging.DEBUG, "SENDING: %s", msg)
|
||||
self.transport.write(bytes(msg))
|
||||
|
||||
# Get pending messages.
|
||||
self.get_pending_messages()
|
||||
|
||||
# Send any friend statuses when the user logs in.
|
||||
# This will allow the user to see if their friends are hosting a game as soon as they log in.
|
||||
# This will allow the user to see if their friends are hosting a
|
||||
# game as soon as they log in.
|
||||
self.get_status_from_friends()
|
||||
self.send_status_to_friends()
|
||||
|
||||
@@ -303,7 +370,7 @@ class PlayerSession(LineReceiver):
|
||||
# self.statstring = profile['stat']
|
||||
# self.locstring = profile['loc']
|
||||
else:
|
||||
self.log(logging.INFO, "Invalid password or banned user")
|
||||
self.log(logging.INFO, "%s", "Invalid password or banned user")
|
||||
msg = gs_query.create_gamespy_message([
|
||||
('__cmd__', "error"),
|
||||
('__cmd_val__', ""),
|
||||
@@ -312,11 +379,13 @@ class PlayerSession(LineReceiver):
|
||||
('errmsg', 'Login failed.'),
|
||||
('id', data_parsed['id']),
|
||||
])
|
||||
self.log(logging.DEBUG, "SENDING: %s" % msg)
|
||||
self.log(logging.DEBUG, "SENDING: %s", msg)
|
||||
self.transport.write(bytes(msg))
|
||||
|
||||
def perform_logout(self, data_parsed):
|
||||
self.log(logging.INFO, "Session %s has logged off" % (data_parsed['sesskey']))
|
||||
self.log(logging.INFO,
|
||||
"Session %s has logged off",
|
||||
data_parsed['sesskey'])
|
||||
self.db.delete_session(data_parsed['sesskey'])
|
||||
|
||||
if self.profileid in self.sessions:
|
||||
@@ -325,10 +394,16 @@ class PlayerSession(LineReceiver):
|
||||
self.transport.loseConnection()
|
||||
|
||||
def perform_getprofile(self, data_parsed):
|
||||
#profile = self.db.get_profile_from_session_key(data_parsed['sesskey'])
|
||||
# profile = self.db.get_profile_from_session_key(
|
||||
# data_parsed['sesskey']
|
||||
# )
|
||||
profile = self.db.get_profile_from_profileid(data_parsed['profileid'])
|
||||
|
||||
# Wii example: \pi\\profileid\474888031\nick\5pde5vhn1WR9E2g1t533\userid\442778352\email\5pde5vhn1WR9E2g1t533@nds\sig\b126556e5ee62d4da9629dfad0f6b2a8\uniquenick\5pde5vhn1WR9E2g1t533\pid\11\lon\0.000000\lat\0.000000\loc\\id\2\final\
|
||||
# Wii example:
|
||||
# \pi\\profileid\474888031\nick\5pde5vhn1WR9E2g1t533\userid\442778352
|
||||
# \email\5pde5vhn1WR9E2g1t533@nds\sig\b126556e5ee62d4da9629dfad0f6b2a8
|
||||
# \uniquenick\5pde5vhn1WR9E2g1t533\pid\11\lon\0.000000\lat\0.000000
|
||||
# \loc\\id\2\final\
|
||||
sig = utils.generate_random_hex_str(32)
|
||||
|
||||
msg_d = [
|
||||
@@ -343,10 +418,11 @@ class PlayerSession(LineReceiver):
|
||||
('pid', profile['pid']),
|
||||
]
|
||||
|
||||
if profile['firstname'] != "":
|
||||
msg_d.append(('firstname', profile['firstname'])) # Wii gets a firstname
|
||||
if profile['firstname']:
|
||||
# Wii gets a firstname
|
||||
msg_d.append(('firstname', profile['firstname']))
|
||||
|
||||
if profile['lastname'] != "":
|
||||
if profile['lastname']:
|
||||
msg_d.append(('lastname', profile['lastname']))
|
||||
|
||||
msg_d.extend([
|
||||
@@ -357,14 +433,18 @@ class PlayerSession(LineReceiver):
|
||||
])
|
||||
msg = gs_query.create_gamespy_message(msg_d)
|
||||
|
||||
self.log(logging.DEBUG, "SENDING: %s" % msg)
|
||||
self.log(logging.DEBUG, "SENDING: %s", msg)
|
||||
self.transport.write(bytes(msg))
|
||||
|
||||
def perform_updatepro(self, data_parsed):
|
||||
# Wii example: \updatepro\\sesskey\199714190\firstname\Wii:2555151656076614@WR9E\partnerid\11\final\
|
||||
"""Wii example:
|
||||
\updatepro\\sesskey\199714190\firstname\Wii:2555151656076614@WR9E
|
||||
\partnerid\11\final\
|
||||
|
||||
# Remove any fields not related to what we should be updating.
|
||||
# To avoid any crashes, make sure the key is actually in the dictionary before removing it.
|
||||
Remove any fields not related to what we should be updating.
|
||||
To avoid any crashes, make sure the key is actually in the dictionary
|
||||
before removing it.
|
||||
"""
|
||||
if "__cmd__" in data_parsed:
|
||||
data_parsed.pop('__cmd__')
|
||||
if "__cmd_val__" in data_parsed:
|
||||
@@ -380,7 +460,6 @@ class PlayerSession(LineReceiver):
|
||||
for f in data_parsed:
|
||||
self.db.update_profile(self.profileid, (f, data_parsed[f]))
|
||||
|
||||
|
||||
def perform_ka(self, data_parsed):
|
||||
self.keepalive = int(time.time())
|
||||
|
||||
@@ -390,7 +469,6 @@ class PlayerSession(LineReceiver):
|
||||
])
|
||||
self.transport.write(msg)
|
||||
|
||||
|
||||
def perform_status(self, data_parsed):
|
||||
self.sesskey = data_parsed['sesskey']
|
||||
self.status = data_parsed['__cmd_val__']
|
||||
@@ -405,9 +483,9 @@ class PlayerSession(LineReceiver):
|
||||
|
||||
self.send_status_to_friends()
|
||||
|
||||
|
||||
def perform_bm(self, data_parsed):
|
||||
if data_parsed['__cmd_val__'] in ("1", "5", "102", "103"): # Message to/from clients?
|
||||
# Message to/from clients?
|
||||
if data_parsed['__cmd_val__'] in ("1", "5", "102", "103"):
|
||||
if "t" in data_parsed:
|
||||
# Send message to the profile id in "t"
|
||||
dest_profileid = int(data_parsed['t'])
|
||||
@@ -416,7 +494,8 @@ class PlayerSession(LineReceiver):
|
||||
|
||||
not_buddies = False
|
||||
|
||||
# Check if the user is buddies with the target user before sending message.
|
||||
# Check if the user is buddies with the target user before
|
||||
# sending message.
|
||||
if not_buddies:
|
||||
for buddy in self.buddies:
|
||||
if buddy['userProfileId'] == dest_profileid:
|
||||
@@ -429,16 +508,21 @@ class PlayerSession(LineReceiver):
|
||||
not_buddies = True
|
||||
break
|
||||
|
||||
# Send error to user if they tried to send a message to someone who isn't a buddy.
|
||||
# Send error to user if they tried to send a message to
|
||||
# someone who isn't a buddy.
|
||||
if not_buddies:
|
||||
msg = gs_query.create_gamespy_message([
|
||||
('__cmd__', "error"),
|
||||
('__cmd_val__', ""),
|
||||
('err', 2305),
|
||||
('errmsg', "The profile the message was to be sent to is not a buddy."),
|
||||
('errmsg',
|
||||
"The profile the message was to be sent to is not"
|
||||
" a buddy."),
|
||||
('id', 1),
|
||||
])
|
||||
logger.log(logging.DEBUG, "Trying to send message to someone who isn't a buddy: %s" % msg)
|
||||
logger.log(logging.DEBUG,
|
||||
"Trying to send message to someone who isn't"
|
||||
" a buddy: %s", msg)
|
||||
self.transport.write(msg)
|
||||
return
|
||||
|
||||
@@ -450,33 +534,44 @@ class PlayerSession(LineReceiver):
|
||||
])
|
||||
|
||||
if dest_profileid in self.sessions:
|
||||
self.log(logging.DEBUG, "SENDING TO %s:%s: %s" % (self.sessions[dest_profileid].address.host, self.sessions[dest_profileid].address.port, msg))
|
||||
self.log(logging.DEBUG,
|
||||
"SENDING TO %s:%s: %s",
|
||||
self.sessions[dest_profileid].address.host,
|
||||
self.sessions[dest_profileid].address.port, msg)
|
||||
self.sessions[dest_profileid].transport.write(bytes(msg))
|
||||
self.send_status_to_friends(dest_profileid)
|
||||
self.get_status_from_friends(dest_profileid)
|
||||
else:
|
||||
if data_parsed['__cmd_val__'] == "1":
|
||||
self.log(logging.DEBUG, "Saving message to %d: %s" % (dest_profileid, msg))
|
||||
self.db.save_pending_message(self.profileid, dest_profileid, msg)
|
||||
self.log(logging.DEBUG,
|
||||
"Saving message to %d: %s",
|
||||
dest_profileid, msg)
|
||||
self.db.save_pending_message(self.profileid,
|
||||
dest_profileid, msg)
|
||||
else:
|
||||
msg = gs_query.create_gamespy_message([
|
||||
('__cmd__', "error"),
|
||||
('__cmd_val__', ""),
|
||||
('err', 2307),
|
||||
('errmsg', "The buddy to send a message to is offline."),
|
||||
('errmsg', "The buddy to send a message to"
|
||||
" is offline."),
|
||||
('id', 1),
|
||||
])
|
||||
logger.log(logging.DEBUG, "Trying to send message to someone who isn't online: %s" % msg)
|
||||
logger.log(logging.DEBUG,
|
||||
"Trying to send message to someone who"
|
||||
" isn't online: %s", msg)
|
||||
self.transport.write(msg)
|
||||
|
||||
|
||||
def perform_addbuddy(self, data_parsed):
|
||||
newprofileid = int(data_parsed['newprofileid'])
|
||||
if newprofileid == self.profileid:
|
||||
logger.log(logging.DEBUG, "Can't add self as friend: %d == %d", newprofileid, self.profileid)
|
||||
logger.log(logging.DEBUG,
|
||||
"Can't add self as friend: %d == %d",
|
||||
newprofileid, self.profileid)
|
||||
return
|
||||
|
||||
# Sample: \addbuddy\\sesskey\231601763\newprofileid\476756820\reason\\final\
|
||||
# Sample:
|
||||
# \addbuddy\\sesskey\231601763\newprofileid\476756820\reason\\final\
|
||||
self.buddies = self.db.get_buddy_list(self.profileid)
|
||||
|
||||
buddy_exists = False
|
||||
@@ -485,27 +580,37 @@ class PlayerSession(LineReceiver):
|
||||
buddy_exists = True
|
||||
break
|
||||
|
||||
if buddy_exists is False:
|
||||
if not buddy_exists:
|
||||
self.db.add_buddy(self.profileid, newprofileid)
|
||||
|
||||
if newprofileid in self.sessions:
|
||||
logger.log(logging.DEBUG, "User is online, sending direct request from profile id %d to profile id %d..." % (self.profileid, newprofileid))
|
||||
logger.log(logging.DEBUG,
|
||||
"User is online, sending direct request from"
|
||||
" profile id %d to profile id %d...",
|
||||
self.profileid, newprofileid)
|
||||
|
||||
# TODO: Add a way to check if a profile id is already a buddy using SQL
|
||||
# TODO: Add a way to check if a profile id is already a buddy
|
||||
# using SQL
|
||||
other_player_authorized = False
|
||||
target_buddy_list = self.db.get_buddy_list(newprofileid)
|
||||
logger.log(logging.DEBUG, target_buddy_list)
|
||||
logger.log(logging.DEBUG, "%s", target_buddy_list)
|
||||
for buddy in target_buddy_list:
|
||||
if buddy['buddyProfileId'] == self.profileid and buddy['blocked'] == 0:
|
||||
if buddy['buddyProfileId'] == self.profileid and \
|
||||
not buddy['blocked']:
|
||||
other_player_authorized = True
|
||||
break
|
||||
|
||||
if other_player_authorized == True:
|
||||
logger.log(logging.DEBUG, "Automatic authorization: %d (target) already has %d (source) as a friend." % (newprofileid, self.profileid))
|
||||
if other_player_authorized:
|
||||
logger.log(logging.DEBUG,
|
||||
"Automatic authorization: %d (target) already"
|
||||
" has %d (source) as a friend.",
|
||||
newprofileid, self.profileid)
|
||||
|
||||
# Force them both to add each other
|
||||
self.send_buddy_request(self.sessions[newprofileid], self.profileid)
|
||||
self.send_buddy_request(self.sessions[self.profileid], newprofileid)
|
||||
self.send_buddy_request(self.sessions[newprofileid],
|
||||
self.profileid)
|
||||
self.send_buddy_request(self.sessions[self.profileid],
|
||||
newprofileid)
|
||||
|
||||
self.send_bm4(newprofileid)
|
||||
|
||||
@@ -516,9 +621,11 @@ class PlayerSession(LineReceiver):
|
||||
self.get_status_from_friends(newprofileid)
|
||||
|
||||
else:
|
||||
self.send_buddy_request(self.sessions[newprofileid], self.profileid)
|
||||
self.send_buddy_request(self.sessions[newprofileid],
|
||||
self.profileid)
|
||||
else:
|
||||
# Trying to add someone who is already a friend. Just send status updates
|
||||
# Trying to add someone who is already a friend.
|
||||
# Just send status updates.
|
||||
self.send_status_to_friends(newprofileid)
|
||||
self.get_status_from_friends(newprofileid)
|
||||
|
||||
@@ -537,32 +644,42 @@ class PlayerSession(LineReceiver):
|
||||
self.transport.write(bytes(msg))
|
||||
|
||||
def perform_delbuddy(self, data_parsed):
|
||||
# Sample: \delbuddy\\sesskey\61913621\delprofileid\1\final\
|
||||
"""Sample:
|
||||
\delbuddy\\sesskey\61913621\delprofileid\1\final\
|
||||
"""
|
||||
self.db.delete_buddy(self.profileid, int(data_parsed['delprofileid']))
|
||||
self.buddies = self.db.get_buddy_list(self.profileid)
|
||||
|
||||
def perform_authadd(self, data_parsed):
|
||||
# Sample: \authadd\\sesskey\231587549\fromprofileid\217936895\sig\f259f26d3273f8bda23c7c5e4bd8c5aa\final\
|
||||
# Authorize the other person's friend request.
|
||||
"""Authorize the other person's friend request.
|
||||
|
||||
Sample:
|
||||
\authadd\\sesskey\231587549\fromprofileid\217936895
|
||||
\sig\f259f26d3273f8bda23c7c5e4bd8c5aa\final\
|
||||
"""
|
||||
target_profile = int(data_parsed['fromprofileid'])
|
||||
self.db.auth_buddy(target_profile, self.profileid)
|
||||
self.get_buddy_authorized()
|
||||
self.buddies = self.db.get_buddy_list(self.profileid)
|
||||
|
||||
|
||||
self.send_bm4(target_profile)
|
||||
|
||||
self.send_status_to_friends(target_profile)
|
||||
self.get_status_from_friends(target_profile)
|
||||
|
||||
def send_status_to_friends(self, buddy_profileid = None):
|
||||
# TODO: Cache buddy list so we don't have to query the database every time
|
||||
def send_status_to_friends(self, buddy_profileid=None):
|
||||
"""TODO: Cache buddy list so we don't have to query the
|
||||
database every time."""
|
||||
self.buddies = self.db.get_buddy_list(self.profileid)
|
||||
|
||||
if self.status == "0" and self.statstring == "Offline":
|
||||
# Going offline, don't need to send the other information.
|
||||
status_msg = "|s|%s|ss|%s" % (self.status, self.statstring)
|
||||
else:
|
||||
status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % (self.status, self.statstring, self.locstring, self.get_ip_as_int(self.address.host))
|
||||
status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % (
|
||||
self.status, self.statstring, self.locstring,
|
||||
self.get_ip_as_int(self.address.host)
|
||||
)
|
||||
|
||||
msg = gs_query.create_gamespy_message([
|
||||
('__cmd__', "bm"),
|
||||
@@ -573,28 +690,48 @@ class PlayerSession(LineReceiver):
|
||||
|
||||
buddy_list = self.buddies
|
||||
if buddy_profileid is not None:
|
||||
buddy_list = [{"buddyProfileId":buddy_profileid}]
|
||||
buddy_list = [{"buddyProfileId": buddy_profileid}]
|
||||
|
||||
for buddy in buddy_list:
|
||||
if buddy['buddyProfileId'] in self.sessions:
|
||||
#self.log(logging.DEBUG, "Sending status to buddy id %s (%s:%d): %s" % (str(buddy['buddyProfileId']), self.sessions[buddy['buddyProfileId']].address.host, self.sessions[buddy['buddyProfileId']].address.port, msg))
|
||||
self.sessions[buddy['buddyProfileId']].transport.write(bytes(msg))
|
||||
# self.log(logging.DEBUG,
|
||||
# "Sending status to buddy id %s (%s:%d): %s",
|
||||
# str(buddy['buddyProfileId']),
|
||||
# self.sessions[
|
||||
# buddy['buddyProfileId']
|
||||
# ].address.host,
|
||||
# self.sessions[
|
||||
# buddy['buddyProfileId']
|
||||
# ].address.port, msg)
|
||||
self.sessions[buddy['buddyProfileId']].transport \
|
||||
.write(bytes(msg))
|
||||
|
||||
def get_status_from_friends(self, buddy_profileid = None):
|
||||
# This will be called when the player logs in. Grab the player's buddy list and check the current sessions to
|
||||
# see if anyone is online. If they are online, make them send an update to the calling client.
|
||||
def get_status_from_friends(self, buddy_profileid=None):
|
||||
"""This will be called when the player logs in.
|
||||
|
||||
Grab the player's buddy list and check the current sessions to
|
||||
see if anyone is online. If they are online, make them send an update
|
||||
to the calling client.
|
||||
"""
|
||||
self.buddies = self.db.get_buddy_list(self.profileid)
|
||||
|
||||
buddy_list = self.buddies
|
||||
if buddy_profileid is not None:
|
||||
buddy_list = [{"buddyProfileId":buddy_profileid}]
|
||||
buddy_list = [{"buddyProfileId": buddy_profileid}]
|
||||
|
||||
for buddy in self.buddies:
|
||||
if buddy['status'] != 1:
|
||||
continue
|
||||
|
||||
if buddy['buddyProfileId'] in self.sessions and self.sessions[buddy['buddyProfileId']].gameid == self.gameid:
|
||||
status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % (self.sessions[buddy['buddyProfileId']].status, self.sessions[buddy['buddyProfileId']].statstring, self.sessions[buddy['buddyProfileId']].locstring, self.get_ip_as_int(self.sessions[buddy['buddyProfileId']].address.host))
|
||||
if buddy['buddyProfileId'] in self.sessions and \
|
||||
self.sessions[buddy['buddyProfileId']].gameid == self.gameid:
|
||||
status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % (
|
||||
self.sessions[buddy['buddyProfileId']].status,
|
||||
self.sessions[buddy['buddyProfileId']].statstring,
|
||||
self.sessions[buddy['buddyProfileId']].locstring,
|
||||
self.get_ip_as_int(self.sessions[
|
||||
buddy['buddyProfileId']
|
||||
].address.host))
|
||||
else:
|
||||
status_msg = "|s|0|ss|Offline"
|
||||
|
||||
@@ -615,20 +752,25 @@ class PlayerSession(LineReceiver):
|
||||
('__cmd__', "bm"),
|
||||
('__cmd_val__', "1"),
|
||||
('f', buddy['userProfileId']),
|
||||
('msg', "I have authorized your request to add me to your list"),
|
||||
('msg', "I have authorized your request to add me to"
|
||||
" your list"),
|
||||
])
|
||||
|
||||
self.transport.write(bytes(msg))
|
||||
self.db.buddy_sent_auth_message(buddy['userProfileId'], buddy['buddyProfileId'])
|
||||
self.db.buddy_sent_auth_message(buddy['userProfileId'],
|
||||
buddy['buddyProfileId'])
|
||||
|
||||
def get_buddy_requests(self):
|
||||
# Get list people who have added the user but haven't been accepted yet.
|
||||
"""Get list people who have added the user but haven't been accepted
|
||||
yet."""
|
||||
buddies = self.db.get_pending_buddy_requests(self.profileid)
|
||||
|
||||
for buddy in buddies:
|
||||
self.send_buddy_request(self, buddy['userProfileId'], buddy['time'])
|
||||
self.send_buddy_request(self,
|
||||
buddy['userProfileId'],
|
||||
buddy['time'])
|
||||
|
||||
def send_buddy_request(self, session, profileid, senttime = None):
|
||||
def send_buddy_request(self, session, profileid, senttime=None):
|
||||
sig = utils.generate_random_hex_str(32)
|
||||
msg = "\r\n\r\n"
|
||||
msg += "|signed|" + sig
|
||||
@@ -656,6 +798,7 @@ class PlayerSession(LineReceiver):
|
||||
except:
|
||||
self.transport.write(bytearray(message['msg'], "utf-8"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
gsps = GameSpyProfileServer()
|
||||
gsps.start()
|
||||
|
||||
Reference in New Issue
Block a user