diff --git a/gamespy/gs_database.py b/gamespy/gs_database.py index 4d451b9..57b65cb 100644 --- a/gamespy/gs_database.py +++ b/gamespy/gs_database.py @@ -2,6 +2,7 @@ import sqlite3 import hashlib import itertools import other.utils as utils +import time class GamespyDatabase(object): def __init__(self, filename='gpcm.db'): @@ -21,7 +22,7 @@ class GamespyDatabase(object): # evidence yet to say otherwise as far as Nintendo DS games go. c.execute('''CREATE TABLE users (profileid INT, userid TEXT, password TEXT, gsbrcd TEXT, email TEXT, uniquenick TEXT, pid TEXT, lon TEXT, lat TEXT, loc TEXT, firstname TEXT, lastname TEXT, stat TEXT, partnerid TEXT, console INT, csnum TEXT, cfc TEXT, bssid TEXT, devname TEXT, birth TEXT, sig TEXT)''') c.execute('''CREATE TABLE sessions (session TEXT, profileid INT)''') - c.execute('''CREATE TABLE buddies (userProfileid INT, buddyProfileId INT, status INT)''') + c.execute('''CREATE TABLE buddies (userProfileId INT, buddyProfileId INT, time INT, status INT, notified INT)''') self.conn.commit() def get_dict(self, row): @@ -32,6 +33,7 @@ class GamespyDatabase(object): # User functions def get_next_free_profileid(self): + # TODO: Make profile ids start at 1 for each game? c = self.conn.cursor() c.execute("SELECT max(profileid) FROM users") @@ -152,9 +154,7 @@ class GamespyDatabase(object): for field in fields: print "UPDATE users SET %s = %s WHERE profileid = %s" % (field[0], field[1], profileid) c.execute("UPDATE users SET %s = ? WHERE profileid = ?" % (field[0]), [field[1], profileid]) - - self.conn.commit() - + self.conn.commit() # Session functions # TODO: Cache session keys so we don't have to query the database every time we get a profile id. @@ -231,7 +231,8 @@ class GamespyDatabase(object): # Buddy functions def add_buddy(self, userProfileId, buddyProfileId): c = self.conn.cursor() - c.execute("INSERT INTO buddies VALUES (?, ?, ?)", [userProfileId, buddyProfileId, 0]) # 0 will mean not authorized + now = int(time.time()) + c.execute("INSERT INTO buddies VALUES (?, ?, ?, ?, ?)", [userProfileId, buddyProfileId, now, 0, 0]) # 0 will mean not authorized self.conn.commit() def auth_buddy(self, userProfileId, buddyProfileId): @@ -239,6 +240,16 @@ class GamespyDatabase(object): c.execute("UPDATE buddies SET status = ? WHERE userProfileId = ? AND buddyProfileId = ?", [1, userProfileId, buddyProfileId]) # 1 will mean authorized self.conn.commit() + def get_buddy(self, userProfileId, buddyProfileId): + profile = {} + if userProfileId != None and buddyProfileId != None: + c = self.conn.cursor() + c.execute("SELECT * FROM buddies WHERE userProfileId = ? AND buddyProfileId = ?", [userProfileId, buddyProfileId]) + profile = self.get_dict(c.fetchone()) + + c.close() + return profile + def delete_buddy(self, userProfileId, buddyProfileId): c = self.conn.cursor() c.execute("DELETE FROM buddies WHERE userProfileId = ? AND buddyProfileId = ?", [userProfileId, buddyProfileId]) @@ -252,3 +263,26 @@ class GamespyDatabase(object): users.append(self.get_dict(row)) return users + + def get_pending_buddy_requests(self, userProfileId): + c = self.conn.cursor() + + users = [] + for row in c.execute("SELECT * FROM buddies WHERE buddyProfileId = ? AND status = 0", [userProfileId]): + users.append(self.get_dict(row)) + + return users + + def buddy_need_auth_message(self, userProfileId): + c = self.conn.cursor() + + users = [] + for row in c.execute("SELECT * FROM buddies WHERE buddyProfileId = ? AND status = 1 AND notified = 0", [userProfileId]): + users.append(self.get_dict(row)) + + return users + + def buddy_sent_auth_message(self, userProfileId, buddyProfileId): + c = self.conn.cursor() + c.execute("UPDATE buddies SET notified = ? WHERE userProfileId = ? AND buddyProfileId = ?", [1, userProfileId, buddyProfileId]) # 1 will mean that the player has been sent the " + self.conn.commit() diff --git a/gamespy_server.py b/gamespy_server.py index 7dcdb35..74854be 100644 --- a/gamespy_server.py +++ b/gamespy_server.py @@ -71,6 +71,8 @@ class PlayerSession(LineReceiver): self.perform_bm(data_parsed) elif data_parsed['__cmd__'] == "addbuddy": self.perform_addbuddy(data_parsed) + elif data_parsed['__cmd__'] == "delbuddy": + self.perform_delbuddy(data_parsed) elif data_parsed['__cmd__'] == "authadd": self.perform_authadd(data_parsed) else: @@ -260,8 +262,14 @@ class PlayerSession(LineReceiver): self.statstring = data_parsed['statstring'] self.locstring = data_parsed['locstring'] + # Send authorization requests to client + self.get_buddy_requests() + # Send authorizationed message to client + self.get_buddy_authorized() + self.send_status_to_friends() + def perform_bm(self, data_parsed): if data_parsed['__cmd_val__'] == "1": # Message to/from clients? if "t" in data_parsed: @@ -281,29 +289,33 @@ class PlayerSession(LineReceiver): def perform_addbuddy(self, data_parsed): + if int(data_parsed['newprofileid']) == self.profileid: + print "Can't add self as friend" + return + # Sample: \addbuddy\\sesskey\231601763\newprofileid\476756820\reason\\final\ buddies = self.db.get_buddy_list(self.profileid) buddy_exists = False for buddy in buddies: - if buddy['buddyProfileId'] == data_parsed['newprofileid']: + if buddy['buddyProfileId'] == int(data_parsed['newprofileid']): buddy_exists = True break - if not buddy_exists: - self.db.add_buddy(self.profileid, data_parsed['newprofileid']) + if buddy_exists == False: + self.db.add_buddy(self.profileid, int(data_parsed['newprofileid'])) - # In the case that the user is already a buddy: - # \bm\2\f\217936895\msg\|signed|f259f26d3273f8bda23c7c5e4bd8c5aa\final\ - # \error\\err\1539\errmsg\The profile requested is already a buddy.\final\ - # Handle later? + + def perform_delbuddy(self, data_parsed): + # Sample: \delbuddy\\sesskey\61913621\delprofileid\1\final\ + self.db.delete_buddy(self.profileid, int(data_parsed['delprofileid'])) def perform_authadd(self, data_parsed): # Sample: \authadd\\sesskey\231587549\fromprofileid\217936895\sig\f259f26d3273f8bda23c7c5e4bd8c5aa\final\ - self.db.auth_buddy(self.profileid, data_parsed['newprofileid']) + # Authorize the other person's friend request. + self.db.auth_buddy(int(data_parsed['fromprofileid']), self.profileid) - # After authorization, send the person who was authorized a message like so: - # \bm\1\f\476756820\msg\I have authorized your request to add me to your list\final\ + self.get_buddy_authorized() def send_status_to_friends(self): # TODO: Cache buddy list so we don't have to query the database every time @@ -328,17 +340,58 @@ class PlayerSession(LineReceiver): buddies = self.db.get_buddy_list(self.profileid) for buddy in buddies: + print buddy + + 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)) + else: + status_msg = "|s|0|ss|Offline" - msg_d = [] - msg_d.append(('__cmd__', "bm")) - msg_d.append(('__cmd_val__', "100")) - msg_d.append(('f', buddy['buddyProfileId'])) - msg_d.append(('msg', status_msg)) - msg = gs_query.create_gamespy_message(msg_d) + msg_d = [] + msg_d.append(('__cmd__', "bm")) + msg_d.append(('__cmd_val__', "100")) + msg_d.append(('f', buddy['buddyProfileId'])) + msg_d.append(('msg', status_msg)) + msg = gs_query.create_gamespy_message(msg_d) - self.transport.write(bytes(msg)) + self.transport.write(bytes(msg)) + + def get_buddy_authorized(self): + buddies = self.db.buddy_need_auth_message(self.profileid) + + for buddy in buddies: + msg_d = [] + msg_d.append(('__cmd__', "bm")) + msg_d.append(('__cmd_val__', "1")) + msg_d.append(('f', buddy['userProfileId'])) + msg_d.append(('msg', "I have authorized your request to add me to your list")) + msg = gs_query.create_gamespy_message(msg_d) + + self.transport.write(bytes(msg)) + 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. + buddies = self.db.get_pending_buddy_requests(self.profileid) + + profile = self.db.get_profile_from_profileid(self.profileid) + msg = "\r\n\r\n" + if "sig" in profile: + msg += "|signed|" + profile['sig'] + + for buddy in buddies: + msg_d = [] + msg_d.append(('__cmd__', "bm")) + msg_d.append(('__cmd_val__', "2")) + msg_d.append(('f', buddy['userProfileId'])) + msg_d.append(('date', buddy['time'])) + msg_d.append(('msg', msg)) + msg = gs_query.create_gamespy_message(msg_d) + + self.transport.write(bytes(msg)) class PlayerSearch(LineReceiver): diff --git a/gs_server_database.py b/gs_server_database.py index 48e59b7..64aa322 100644 --- a/gs_server_database.py +++ b/gs_server_database.py @@ -317,8 +317,10 @@ def update_server_list(gameid, session, value): # Add new server value['__session__'] = session + utils.print_log("Added %s to the server list for %s" % (value, gameid)) server_list[gameid].append(value) + print "%s servers: %d" % (gameid, len(server_list[gameid])) def delete_server(gameid, session): if not gameid in server_list: @@ -326,8 +328,10 @@ def delete_server(gameid, session): return # Remove all servers hosted by the given session id. - print "Deleting all %s servers where session = %d" % (gameid, session) + count = len(server_list[gameid]) server_list[gameid] = [x for x in server_list[gameid] if x['__session__'] != session] + count -= len(server_list[gameid]) + print "Deleted %d %s servers where session = %d" % (count, gameid, session) def find_server_by_address(ip, port, gameid = None): if gameid == None: