示例#1
0
    def perform_getpd(self, data_parsed):
        profile = self.db.pd_get(self.profileid, data_parsed['dindex'], data_parsed['ptype'])

        data = ""
        keys = data_parsed['keys'].split('\x01')

        profile_data = None

        if profile != None and 'data' in profile:
            profile_data = gs_query.parse_gamespy_message("\\prof\\" + profile['data'] + "\\final\\")

        if profile_data != None:
            profile_data = profile_data[0][0]

        for key in keys:
            if key != "__cmd__" and key != "__cmd_val__" and key != "":
                data += "\\"
                data += key
                data += "\\"
                if key in profile_data:
                    data += profile_data[key]

        modified = int(time.time())

        msg_d = []
        msg_d.append(('__cmd__', "getpdr"))
        msg_d.append(('__cmd_val__', 1))
        msg_d.append(('lid', self.lid))
        msg_d.append(('pid', self.profileid))
        msg_d.append(('mod', modified))
        msg_d.append(('length', len(data)))
        msg_d.append(('data', data))
        msg = gs_query.create_gamespy_message(msg_d)

        self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
    def rawDataReceived(self, data):
        try:
            # Decrypt packet
            self.remaining_message += data

            if "\\final\\" not in data:
                return

            msg = str(self.crypt(self.remaining_message))
            self.data = msg
            self.remaining_message = ""

            commands, self.remaining_message = gs_query.parse_gamespy_message(msg)
            logger.log(logging.DEBUG, "STATS RESPONSE: %s" % msg)

            cmds = {
                    "auth":    self.perform_auth,
                    "authp":   self.perform_authp,
                    "ka":      self.perform_ka,
                    "setpd":   self.perform_setpd,
                    "getpd":   self.perform_getpd,
                    "newgame": self.perform_newgame,
                    "updgame": self.perform_updgame,
            }

            def cmd_err(data_parsed):
                logger.log(logging.DEBUG, "Found unknown command, don't know how to handle '%s'.", data_parsed['__cmd__'])

            for data_parsed in commands:
                print(data_parsed)

                cmds.get(data_parsed['__cmd__'], cmd_err)(data_parsed)
        except:
            self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
示例#3
0
    def rawDataReceived(self, data):
        # Decrypt packet
        msg = str(self.crypt(data))

        logger.log(logging.DEBUG, "STATS RESPONSE: %s" % msg)

        #data = self.leftover + data
        commands, self.leftover = gs_query.parse_gamespy_message(msg)
        print commands

        for data_parsed in commands:
            print data_parsed

            if data_parsed['__cmd__'] == "auth":
                self.perform_auth(data_parsed)
            elif data_parsed['__cmd__'] == "authp":
                self.perform_authp(data_parsed)
            elif data_parsed['__cmd__'] == "ka":
                self.perform_ka(data_parsed)
            elif data_parsed['__cmd__'] == "setpd":
                self.perform_setpd(data_parsed, msg)
            elif data_parsed['__cmd__'] == "getpd":
                self.perform_getpd(data_parsed)
            elif data_parsed['__cmd__'] == "newgame":
                self.perform_newgame(data_parsed)
            elif data_parsed['__cmd__'] == "updgame":
                self.perform_updgame(data_parsed)
            else:
                logger.log(
                    logging.DEBUG,
                    "Found unknown command, don't know how to handle '%s'." %
                    data_parsed['__cmd__'])
    def rawDataReceived(self, data):
        # Decrypt packet
        msg = str(self.crypt(data))

        logger.log(logging.DEBUG, "STATS RESPONSE: %s" % msg)

        #data = self.leftover + data
        commands, self.leftover = gs_query.parse_gamespy_message(msg)
        print commands

        for data_parsed in commands:
            print data_parsed

            if data_parsed['__cmd__'] == "auth":
                self.perform_auth(data_parsed)
            elif data_parsed['__cmd__'] == "authp":
                self.perform_authp(data_parsed)
            elif data_parsed['__cmd__'] == "ka":
                self.perform_ka(data_parsed)
            elif data_parsed['__cmd__'] == "setpd":
                self.perform_setpd(data_parsed, msg)
            elif data_parsed['__cmd__'] == "getpd":
                self.perform_getpd(data_parsed)
            elif data_parsed['__cmd__'] == "newgame":
                self.perform_newgame(data_parsed)
            elif data_parsed['__cmd__'] == "updgame":
                self.perform_updgame(data_parsed)
            else:
                logger.log(logging.DEBUG, "Found unknown command, don't know how to handle '%s'." % data_parsed['__cmd__'])
    def rawDataReceived(self, 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.
        data = self.remaining_message + data
        commands, self.remaining_message = gs_query.parse_gamespy_message(data)

        for data_parsed in commands:
            self.log(-1, data_parsed)

            if data_parsed['__cmd__'] == "login":
                self.perform_login(data_parsed)
            elif data_parsed['__cmd__'] == "logout":
                self.perform_logout(data_parsed)
            elif data_parsed['__cmd__'] == "getprofile":
                self.perform_getprofile(data_parsed)
            elif data_parsed['__cmd__'] == "updatepro":
                self.perform_updatepro(data_parsed)
            elif data_parsed['__cmd__'] == "ka":
                self.perform_ka(data_parsed)
            elif data_parsed['__cmd__'] == "status":
                self.perform_status(data_parsed)
            elif data_parsed['__cmd__'] == "bm":
                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:
                # 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__'])
示例#6
0
	def rawDataReceived(self, data):
		try:
			# Decrypt packet
			self.remaining_message += data

			if "\\final\\" not in data:
				return

			msg = str(self.crypt(self.remaining_message))
			self.data = msg
			self.remaining_message = ""

			commands, self.remaining_message = gs_query.parse_gamespy_message(msg)
			logger.log(logging.DEBUG, "STATS RESPONSE: %s" % msg)

			cmds = {
					"auth":    self.perform_auth,
					"authp":   self.perform_authp,
					"ka":      self.perform_ka,
					"setpd":   self.perform_setpd,
					"getpd":   self.perform_getpd,
					"newgame": self.perform_newgame,
					"updgame": self.perform_updgame,
			}

			def cmd_err(data_parsed):
				logger.log(logging.DEBUG, "Found unknown command, don't know how to handle '%s'.", data_parsed['__cmd__'])

			for data_parsed in commands:
				print(data_parsed)

				cmds.get(data_parsed['__cmd__'], cmd_err)(data_parsed)
		except:
			self.log(logging.ERROR, "Unknown exception: %s" % traceback.format_exc())
    def perform_getpd(self, data_parsed):
        profile = self.db.pd_get(self.profileid, data_parsed['dindex'], data_parsed['ptype'])

        keys = data_parsed['keys'].split('\x01')

        profile_data = None

        if profile != None and 'data' in profile:
            profile_data = gs_query.parse_gamespy_message("\\prof\\" + profile['data'] + "\\final\\")

        data = ""
        if profile_data != None:
            profile_data = profile_data[0][0]

            for key in (key for key in keys if key not in ("__cmd__", "__cmd_val__", "")):
                data += "\\" + key + "\\"
                # this WILL error if profile_data isn't properly set above
                if key in profile_data:
                    data += profile_data[key]

        modified = int(time.time())

        msg = gs_query.create_gamespy_message([
            ('__cmd__', "getpdr"),
            ('__cmd_val__', 1),
            ('lid', self.lid),
            ('pid', self.profileid),
            ('mod', modified),
            ('length', len(data)),
            ('data', data),
        ])

        self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
示例#8
0
    def rawDataReceived(self, data):
        try:
            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.
            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.
                final = "\\final\\"
                data = data[data.index(final) + len(final):] \
                    if final in data else ""

            commands, self.remaining_message = \
                gs_query.parse_gamespy_message(data)
            if self.db.is_ip_banned({'ipaddr': self.address.host}):
                self.log(logging.DEBUG,
                         "**** Banned user, closing network socket for %s...",
                         self.address.host)
                self.transport.abortConnection()
                return

            cmds = {
                "login": self.perform_login,
                "logout": self.perform_logout,
                "getprofile": self.perform_getprofile,
                "updatepro": self.perform_updatepro,
                "ka": self.perform_ka,
                "status": self.perform_status,
                "bm": self.perform_bm,
                "addbuddy": self.perform_addbuddy,
                "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__'])

            for data_parsed in commands:
                # 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())
    def rawDataReceived(self, data):
        try:
            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.
            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.
                final = "\\final\\"
                data = data[data.index(final) + len(final):] \
                    if final in data else ""

            commands, self.remaining_message = \
                gs_query.parse_gamespy_message(data)

            cmds = {
                "login": self.perform_login,
                "logout": self.perform_logout,
                "getprofile": self.perform_getprofile,
                "updatepro": self.perform_updatepro,
                "ka": self.perform_ka,
                "status": self.perform_status,
                "bm": self.perform_bm,
                "addbuddy": self.perform_addbuddy,
                "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__'])

            for data_parsed in commands:
                # 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())
    def rawDataReceived(self, data):
        self.log(logging.DEBUG, "SEARCH RESPONSE: %s" % data)

        data = self.leftover + data
        commands, self.leftover = gs_query.parse_gamespy_message(data)

        for data_parsed in commands:
            print data_parsed

            if data_parsed['__cmd__'] == "otherslist":
                self.perform_otherslist(data_parsed)
            else:
                self.log(logging.DEBUG, "Found unknown search command, don't know how to handle '%s'." % data_parsed['__cmd__'])
    def perform_getpd(self, data_parsed):
        pid = int(data_parsed['pid'])
        profile = self.db.pd_get(pid, data_parsed['dindex'], data_parsed['ptype'])

        if profile == None:
            self.log(logging.WARNING, "Could not find profile for %d %s %s" % (pid, data_parsed['dindex'], data_parsed['ptype']))

        keys = data_parsed['keys'].split('\x01')

        profile_data = None
        data = ""

        # Someone figure out if this is actually a good way to handle this when no profile is found
        if profile != None and 'data' in profile:
            profile_data = profile['data']
            if profile_data.endswith("\\"):
                profile_data = profile_data[:-1]
            profile_data = gs_query.parse_gamespy_message("\\prof\\" + profile_data + "\\final\\")

            if profile_data != None:
                profile_data = profile_data[0][0]
            else:
                self.log(logging.WARNING, "Could not get data section from profile for %d" % pid)

            if len(keys) > 0 and keys[0] != "":
                for key in (key for key in keys if key not in ("__cmd__", "__cmd_val__", "")):
                    data += "\\" + key + "\\"

                    if profile_data != None and key in profile_data:
                        data += profile_data[key]
            else:
                self.log(logging.WARNING, "No keys requested, defaulting to all keys: %s" % (profile['data']))
                data = profile['data']

        modified = int(time.time())

        msg = gs_query.create_gamespy_message([
            ('__cmd__', "getpdr"),
            ('__cmd_val__', 1),
            ('lid', self.lid),
            ('pid', pid),
            ('mod', modified),
            ('length', len(data)),
            ('data', data),
        ])

        self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
        msg = self.crypt(msg)
        self.transport.write(bytes(msg))
示例#12
0
    def rawDataReceived(self, data):
        logger.log(logging.DEBUG, "SEARCH RESPONSE: %s" % data)

        data = self.leftover + data
        commands, self.leftover = gs_query.parse_gamespy_message(data)

        for data_parsed in commands:
            print data_parsed

            if data_parsed['__cmd__'] == "otherslist":
                self.perform_otherslist(data_parsed)
            else:
                logger.log(
                    logging.DEBUG,
                    "Found unknown search command, don't know how to handle '%s'."
                    % data_parsed['__cmd__'])
    def rawDataReceived(self, data):
        try:
            logger.log(logging.DEBUG, "SEARCH RESPONSE: %s", data)

            data = self.leftover + data
            commands, self.leftover = gs_query.parse_gamespy_message(data)

            for data_parsed in commands:
                print data_parsed

                if data_parsed['__cmd__'] == "otherslist":
                    self.perform_otherslist(data_parsed)
                else:
                    logger.log(
                        logging.DEBUG,
                        "Found unknown search command, don't know"
                        " how to handle '%s'.", data_parsed['__cmd__'])
        except:
            logger.log(logging.ERROR, "Unknown exception: %s",
                       traceback.format_exc())
    def rawDataReceived(self, data):
        try:
            logger.log(logging.DEBUG, "SEARCH RESPONSE: %s", data)

            data = self.leftover + data
            commands, self.leftover = gs_query.parse_gamespy_message(data)

            for data_parsed in commands:
                print data_parsed

                if data_parsed['__cmd__'] == "otherslist":
                    self.perform_otherslist(data_parsed)
                else:
                    logger.log(logging.DEBUG,
                               "Found unknown search command, don't know"
                               " how to handle '%s'.",
                               data_parsed['__cmd__'])
        except:
            logger.log(logging.ERROR,
                       "Unknown exception: %s",
                       traceback.format_exc())
    def rawDataReceived(self, 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.
        data = self.remaining_message + data
        commands, self.remaining_message = gs_query.parse_gamespy_message(data)

        for data_parsed in commands:
            #self.log(-1, data_parsed)
            self.log(logging.DEBUG, data_parsed)

            if data_parsed['__cmd__'] == "login":
                self.perform_login(data_parsed)
            elif data_parsed['__cmd__'] == "logout":
                self.perform_logout(data_parsed)
            elif data_parsed['__cmd__'] == "getprofile":
                self.perform_getprofile(data_parsed)
            elif data_parsed['__cmd__'] == "updatepro":
                self.perform_updatepro(data_parsed)
            elif data_parsed['__cmd__'] == "ka":
                self.perform_ka(data_parsed)
            elif data_parsed['__cmd__'] == "status":
                self.perform_status(data_parsed)
            elif data_parsed['__cmd__'] == "bm":
                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:
                # 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__'])
    def perform_getpd(self, data_parsed):
        pid = int(data_parsed['pid'])
        profile = self.db.pd_get(pid,
                                 data_parsed['dindex'],
                                 data_parsed['ptype'])

        if profile is None:
            self.log(logging.WARNING,
                     "Could not find profile for %d %s %s",
                     pid, data_parsed['dindex'], data_parsed['ptype'])

        keys = data_parsed['keys'].split('\x01')

        profile_data = None
        data = ""

        # Someone figure out if this is actually a good way to handle this
        # when no profile is found
        if profile is not None and 'data' in profile:
            profile_data = profile['data']
            if profile_data.endswith("\\"):
                profile_data = profile_data[:-1]
            profile_data = \
                gs_query.parse_gamespy_message("\\prof\\" + profile_data +
                                               "\\final\\")

            if profile_data is not None:
                profile_data = profile_data[0][0]
            else:
                self.log(logging.WARNING,
                         "Could not get data section from profile for %d",
                         pid)

            if len(keys):
                # TODO: more clean/pythonic way to do (join?)
                for key in keys:
                    if key in ("__cmd__", "__cmd_val__", ""):
                        continue
                    data += "\\" + key + "\\"

                    if profile_data is not None and key in profile_data:
                        data += profile_data[key]
            else:
                self.log(logging.WARNING,
                         "No keys requested, defaulting to all keys: %s",
                         profile['data'])
                data = profile['data']

        modified = int(time.time())

        msg = gs_query.create_gamespy_message([
            ('__cmd__', "getpdr"),
            ('__cmd_val__', 1),
            ('lid', self.lid),
            ('pid', pid),
            ('mod', modified),
            ('length', len(data)),
            ('data', data),
        ])

        # data needs to be preceded by an extra slash
        msg = msg.replace("\\data\\", "\\data\\\\")

        datastring = ""
        try:
            datastring = re.findall('.*data\\\\(.*)', msg)[0] \
                           .replace("\\final\\", "")
        except:
            pass

        # This works because the data string is a key-value pair, splitting
        # the string by \ should yield a list with an even number of elements.
        # But, because of the extra \ prepended to the datastring, it'll be
        # odd. So ultimately I expect the list to have an odd number of
        # elements. If it's even, len(list)%2 will be zero... and that means
        # the last field in the datastring is empty and doesn't have a
        # closing \.
        if datastring and not len(datastring.split('\\')) % 2:
            # An empty field must be terminated by \ before \final\
            msg = msg.replace("\\final\\", "\\\\final\\")

        self.log(logging.DEBUG, "SENDING: '%s'...", msg)
        msg = self.crypt(msg)
        self.transport.write(bytes(msg))
示例#17
0
	def perform_getpd(self, data_parsed):
		pid = int(data_parsed['pid'])
		profile = self.db.pd_get(pid, data_parsed['dindex'], data_parsed['ptype'])

		if profile == None:
			self.log(logging.WARNING, "Could not find profile for %d %s %s" % (pid, data_parsed['dindex'], data_parsed['ptype']))

		keys = data_parsed['keys'].split('\x01')

		profile_data = None
		data = ""

		# Someone figure out if this is actually a good way to handle this when
		# no profile is found
		if profile != None and 'data' in profile:
			profile_data = profile['data']
			if profile_data.endswith("\\"):
				profile_data = profile_data[:-1]
			profile_data = gs_query.parse_gamespy_message("\\prof\\" + profile_data + "\\final\\")

			if profile_data != None:
				profile_data = profile_data[0][0]
			else:
				self.log(logging.WARNING, "Could not get data section from profile for %d" % pid)

			if len(keys):
				for key in (key for key in keys if key not in ("__cmd__", "__cmd_val__", "")):
					data += "\\" + key + "\\"

					if profile_data != None and key in profile_data:
						data += profile_data[key]
			else:
				self.log(logging.WARNING, "No keys requested, defaulting to all keys: %s" % (profile['data']))
				data = profile['data']

		modified = int(time.time())

		msg = gs_query.create_gamespy_message([('__cmd__', "getpdr"),
			('__cmd_val__', 1),
			('lid', self.lid),
			('pid', pid),
			('mod', modified),
			('length', len(data)),
			('data', data),])

		msg = msg.replace("\\data\\","\\data\\\\") # data needs to be preceded by an extra slash

		datastring = ""
		try:
			datastring = re.findall('.*data\\\\(.*)',msg)[0].replace("\\final\\","")
		except:
			pass

		# This works because the data string is a key-value pair, splitting the
		# string by \ should yield a list with an even number of elements.
		# But,
		# because of the extra \ prepended to the datastring, it'll be odd.
		# So ultimately I expect the list to have an odd number of elements.
		# If it's even, len(list)%2 will be zero...  and that means the last
		# field in the datastring is empty and doesn't have a closing \.
		if datastring and not len(datastring.split('\\')) % 2:
			msg = msg.replace("\\final\\","\\\\final\\") # An empty field must be terminated by \ before \final\

		self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
		msg = self.crypt(msg)
		self.transport.write(bytes(msg))
    def perform_getpd(self, data_parsed):
        pid = int(data_parsed['pid'])
        profile = self.db.pd_get(pid,
                                 data_parsed['dindex'],
                                 data_parsed['ptype'])

        if profile is None:
            self.log(logging.WARNING,
                     "Could not find profile for %d %s %s",
                     pid, data_parsed['dindex'], data_parsed['ptype'])

        keys = data_parsed['keys'].split('\x01')

        profile_data = None
        data = ""

        # Someone figure out if this is actually a good way to handle this
        # when no profile is found
        if profile is not None and 'data' in profile:
            profile_data = profile['data']
            if profile_data.endswith("\\"):
                profile_data = profile_data[:-1]
            profile_data = \
                gs_query.parse_gamespy_message("\\prof\\" + profile_data +
                                               "\\final\\")

            if profile_data is not None:
                profile_data = profile_data[0][0]
            else:
                self.log(logging.WARNING,
                         "Could not get data section from profile for %d",
                         pid)

            if len(keys):
                # TODO: more clean/pythonic way to do (join?)
                for key in keys:
                    if key in ("__cmd__", "__cmd_val__", ""):
                        continue
                    data += "\\" + key + "\\"

                    if profile_data is not None and key in profile_data:
                        data += profile_data[key]
            else:
                self.log(logging.WARNING,
                         "No keys requested, defaulting to all keys: %s",
                         profile['data'])
                data = profile['data']

        modified = int(time.time())

        # Check if there is a nul byte and data after it
        data_blocks = data.split('\x00')
        if len(data_blocks) > 1 and any(block for block in data_blocks[1:]):
            self.log(logging.WARNING, "Data after nul byte: %s", data)

        data = data_blocks[0]
        msg = gs_query.create_gamespy_message([
            ('__cmd__', "getpdr"),
            ('__cmd_val__', 1),
            ('lid', self.lid),
            ('pid', pid),
            ('mod', modified),
            ('length', len(data)),
            ('data', ''),
            (data,)
        ])

        if msg.count('\\') % 2:
            # An empty field must be terminated by \ before \final\
            msg = msg.replace("\\final\\", "\\\\final\\")

        self.log(logging.DEBUG, "SENDING: '%s'...", msg)
        msg = self.crypt(msg)
        self.transport.write(bytes(msg))
    def perform_getpd(self, data_parsed):
        pid = int(data_parsed['pid'])
        profile = self.db.pd_get(pid, data_parsed['dindex'],
                                 data_parsed['ptype'])

        if profile is None:
            self.log(logging.WARNING, "Could not find profile for %d %s %s",
                     pid, data_parsed['dindex'], data_parsed['ptype'])

        keys = data_parsed['keys'].split('\x01')

        profile_data = None
        data = ""

        # Someone figure out if this is actually a good way to handle this
        # when no profile is found
        if profile is not None and 'data' in profile:
            profile_data = profile['data']
            if profile_data.endswith("\\"):
                profile_data = profile_data[:-1]
            profile_data = \
                gs_query.parse_gamespy_message("\\prof\\" + profile_data +
                                               "\\final\\")

            if profile_data is not None:
                profile_data = profile_data[0][0]
            else:
                self.log(logging.WARNING,
                         "Could not get data section from profile for %d", pid)

            if len(keys):
                # TODO: more clean/pythonic way to do (join?)
                for key in keys:
                    if key in ("__cmd__", "__cmd_val__", ""):
                        continue
                    data += "\\" + key + "\\"

                    if profile_data is not None and key in profile_data:
                        data += profile_data[key]
            else:
                self.log(logging.WARNING,
                         "No keys requested, defaulting to all keys: %s",
                         profile['data'])
                data = profile['data']

        modified = int(time.time())

        # Check if there is a nul byte and data after it
        data_blocks = data.split('\x00')
        if len(data_blocks) > 1 and any(block for block in data_blocks[1:]):
            self.log(logging.WARNING, "Data after nul byte: %s", data)

        data = data_blocks[0]
        msg = gs_query.create_gamespy_message([('__cmd__', "getpdr"),
                                               ('__cmd_val__', 1),
                                               ('lid', self.lid), ('pid', pid),
                                               ('mod', modified),
                                               ('length', len(data)),
                                               ('data', ''), (data, )])

        if msg.count('\\') % 2:
            # An empty field must be terminated by \ before \final\
            msg = msg.replace("\\final\\", "\\\\final\\")

        self.log(logging.DEBUG, "SENDING: '%s'...", msg)
        msg = self.crypt(msg)
        self.transport.write(bytes(msg))