def handle(self):
        Debug("Realmlist thread started")
        
        while True:
            self.db.QueryOne("""DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()""")
            self.db.QueryOne("""UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()""")
            res = self.db.QueryAll("""select id, name, address, port, icon, color, timezone, allowedsecuritylevel, population, gamebuild from realmlist""")
            
            if res == None:
                Debug("No realms")
                continue

            tmp = []            
            for r in res:
                tmp.append({
                            'id': int(r[0]),
                            'name': r[1],
                            'address': r[2] + ':' + str(r[3]),
                            'icon': int(r[4]),
                            'color': int(r[5]),
                            'timezone': int(r[6]),
                            'security': int(r[7]),
                            'population': r[8],
                            'build': int(r[9])
                           })
            self.server.realms = tmp

            time.sleep(TCAuthSettings.REALMLIST_UPDATE_DELAY)

        Debug("Realmlist thread quit")
 def handleRealmList(self):
     Debug("->handleRealmList")
     if not self.authed: return False
     if len(self.sock.recv(4)) != 4: return False
     
     data = ''
     cnt = 0
     
     realms = deepcopy(self.server.realms)        
     
     for r in realms:
         if r['build'] != self.gamebuild: continue
         if r['security'] > self.security: continue
         
         data += pack('<BBB', r['icon'], 0, r['color'])
         data += r['name'] + chr(0) + r['address'] + chr(0)
         data += pack('<fBBB', r['population'], 0, r['timezone'], 0x2C)
         
         cnt = cnt + 1
     
     data += pack('<BB', 0x10, 0)
     
     res = pack('<BHIH', 16, 6 + len(data), 0, cnt)
     res += data
     self.sock.sendall(res)
     return True
    def handleReconnectProof(self):
        Debug("->handleReconnectProof")

        t1 = TCBigNumber()
        R2 = TCBigNumber()

        tmp = self.sock.recv(16)
        if len(tmp) != 16: return False
        t1.SetBytes(tmp)
        
        tmp = self.sock.recv(20)
        if len(tmp) != 20: return False
        R2.SetBytes(tmp)
        
        if len(self.sock.recv(21)) != 21: return False
        
        sha = hashlib.sha1()
        sha.update(self.login)
        sha.update(t1.GetBytes())
        sha.update(self.crypt_reconnectProof.GetBytes())
        sha.update(self.crypt_K.GetBytes())
        
        res = TCBigNumber()
        res.SetBytes(sha.digest())
        
        if res.GetInt() == R2.GetInt():
            self.authed = True
            self.sock.sendall(pack('<BBH', 3, 0, 0))
            return True        

        return False
 def RecalculateVS(self, pwhash):
     Debug("->RecalculateVS")
     
     self.crypt_s.SetRand(32)
     I = TCBigNumber()
     I.SetHex(pwhash)        
     sha = hashlib.sha1()
     sha.update(self.crypt_s.GetBytes())
     sha.update(I.GetBytes(20, True))        
     x = TCBigNumber()
     x.SetBytes(sha.digest())        
     self.crypt_v = self.crypt_g.ModExp(x.GetInt(), self.crypt_N.GetInt())
     self.db.QueryOne("""UPDATE account SET v=%s, s=%s WHERE username=%s""", (self.crypt_v.GetHex(),
                                                                       self.crypt_s.GetHex(),
                                                                       self.login))
    def handleReconnectChallenge(self):
        Debug("->handleReconnectChallenge")

        header = self.sock.recv(3)
        if len(header) != 3:
            return False

        error, length = unpack('<BH', header)
        data = self.sock.recv(30)
        if len(data) != 30:
            return False

        gamename, version1, version2, version3, self.gamebuild, platform, self.os, self.country, timezone, ip, login_len = unpack('<IBBBHIIIIIB', data)
        
        self.login = self.sock.recv(login_len)
        if len(self.login) != login_len:
            return False

        accinfo = self.db.QueryOne("""select acc.id, acc.sessionkey, max(aca.gmlevel) from account acc left join account_access aca on acc.id=aca.id and aca.RealmID=-1
                     where acc.username=%s""", (self.login,))
        if accinfo == None or accinfo[0] == None:
            return False
        
        self.security = accinfo[2]
        if self.security == None:
            self.security = 0
        
        self.crypt_K.SetHex(accinfo[1])
        self.crypt_reconnectProof.SetRand(16)
        
        response = pack('<BB', 2, 0)
        response += self.crypt_reconnectProof.GetBytes(16)
        response += pack('<IIII', 0, 0, 0, 0)

        self.sock.sendall(response)
        return True
    def handleAuthLogonChallenge(self):
        Debug("->handleAuthLogonChallenge")
        
        result = 0
        
        header = self.sock.recv(3)
        if len(header) != 3:
            return False

        error, length = unpack('<BH', header)
        data = self.sock.recv(30)
        if len(data) != 30:
            return False

        gamename, version1, version2, version3, self.gamebuild, platform, self.os, self.country, timezone, ip, login_len = unpack('<IBBBHIIIIIB', data)
        
        self.login = self.sock.recv(login_len)
        if len(self.login) != login_len:
            return False
        
        Log("Account trying to log in [AccName: {}] [IP: {}]".format(self.login, self.address[0]))

        if TCAuthSettings.ALLOWED_BUILDS.count(self.gamebuild) == 0:
            result = 0x08
        else:            
            ban = self.db.QueryOne("""select bandate, unbandate from ip_banned where ip=%s union all select bandate, unbandate from account_banned b
                         join account a on a.id=b.id and a.username=%s and b.active=1 limit 1""", (self.address[0], self.login))
            if ban != None:
                if ban[0] == ban[1]:
                    result = 0x03 # Permanent ban
                else:
                    result = 0x0C # Temporary ban
            else:
                accinfo = self.db.QueryOne("""select acc.id, acc.sha_pass_hash, acc.v, acc.s, acc.locked, acc.last_ip, max(aca.gmlevel), aau.authentificator
                    from account acc left join account_access aca on acc.id=aca.id and aca.RealmID=-1 left join account_authentificator aau on acc.id=aau.account
                    where acc.username=%s""", (self.login,))    
                if accinfo == None or accinfo[0] == None:
                    result = 0x04 # Wrong username
                elif accinfo[4] != 0 and accinfo[5] != self.address[0]:
                    result = 0x0C # Account locked to different IP
                else:
                    db_v = accinfo[2]
                    db_s = accinfo[3]
                    
                    if db_v == None or db_s == None:
                        db_v = ''
                        db_s = ''

                    self.authenticator = accinfo[7]

                    self.security = accinfo[6]
                    if self.security == None:
                        self.security = 0
    
                    if len(db_v) != 64 or len(db_s) != 64:
                        self.RecalculateVS(accinfo[1])
                    else:
                        self.crypt_s.SetHex(db_s)
                        self.crypt_v.SetHex(db_v)
    
                    self.crypt_b.SetInt(random.randrange(0, 19 * 8))
                    gmod = self.crypt_g.ModExp(self.crypt_b.GetInt(), self.crypt_N.GetInt())
                    self.crypt_B.SetInt(((self.crypt_v.GetInt() * 3) + gmod.GetInt()) % self.crypt_N.GetInt())
                    
                    unk3 = TCBigNumber()
                    unk3.SetInt(random.randrange(0, 16 * 8))
    
                    response = pack('<BH', 0, 0)
                    response += self.crypt_B.GetBytes(32)
                    response += pack('<B', 1)
                    response += self.crypt_g.GetBytes(1)
                    response += pack('<B', 32)
                    response += self.crypt_N.GetBytes(32)
                    response += self.crypt_s.GetBytes(32)
                    response += unk3.GetBytes(16)
                    if self.authenticator:
                        response += pack('<BB', 4, 1)
                    else:
                        response += pack('<B', 0)
    
                    Log("Account passed LogonChallenge [AccName: {}] [IP: {}]".format(self.login, self.address[0]))
                    self.sock.sendall(response)
                    return True

        Log("Account failed LogonChallenge [AccName: {}] [IP: {}] [Error: {}]".format(self.login, self.address[0], result))
        self.sock.sendall(pack('<HB', 0, result))
        return False
    def handleAuthLogonProof(self):
        Debug("->handleAuthLogonProof")   

        tmp = self.sock.recv(32)
        if len(tmp) != 32: return False
        A = TCBigNumber()
        A.SetBytes(tmp)
        if A.GetInt() == 0: return False
        
        tmp = self.sock.recv(20)
        if len(tmp) != 20: return False
        m1 = TCBigNumber()
        m1.SetBytes(tmp)
        
        tmp = self.sock.recv(20)
        if len(tmp) != 20: return False
        crc = TCBigNumber()
        crc.SetBytes(tmp)
        
        if len(self.sock.recv(2)) != 2: return False

        sha = hashlib.sha1()
        sha.update(A.GetBytes())
        sha.update(self.crypt_B.GetBytes())
        
        u = TCBigNumber()
        u.SetBytes(sha.digest())

        S = TCBigNumber()
        S.SetInt(A.GetInt() * self.crypt_v.ModExp(u.GetInt(), self.crypt_N.GetInt()).GetInt())
        S = S.ModExp(self.crypt_b.GetInt(), self.crypt_N.GetInt())
        
        t = S.GetBytes(32)
        t1 = ''
        
        for i in range(16):
            t1 += t[i * 2]
        
        bytefix = TCBigNumber()    
        
        sha = hashlib.sha1()
        sha.update(t1)
        bytefix.SetBytes(sha.digest())
        t1 = bytefix.GetBytes(20)
        
        t2 = ''
        for i in range(16):
            t2 += t[i * 2 + 1]
            
        sha = hashlib.sha1()
        sha.update(t2)
        bytefix.SetBytes(sha.digest())
        t2 = bytefix.GetBytes(20)
        
        vK = ''
        for i in range(20):
            vK += t1[i]
            vK += t2[i]
        
        self.crypt_K.SetBytes(vK)
        
        sha = hashlib.sha1()
        sha.update(self.crypt_N.GetBytes())
        bytefix.SetBytes(sha.digest())
        tmp = bytefix.GetBytes(20)
        
        sha = hashlib.sha1()
        sha.update(self.crypt_g.GetBytes())
        bytefix.SetBytes(sha.digest())
        
        hsh = ''
        for i in range(20):
            h1 = int(tmp[i].encode('hex'), 16)
            h2 = int(bytefix.GetBytes(20)[i].encode('hex'), 16)
            hsh += chr(h1 ^ h2)
        
        t3 = TCBigNumber()
        t3.SetBytes(hsh)
                
        sha = hashlib.sha1()
        sha.update(self.login)
        
        t4 = TCBigNumber()
        t4.SetBytes(sha.digest())
        
        sha = hashlib.sha1()
        sha.update(t3.GetBytes(20))
        sha.update(t4.GetBytes(20))
        sha.update(self.crypt_s.GetBytes())
        sha.update(A.GetBytes())
        sha.update(self.crypt_B.GetBytes())
        sha.update(self.crypt_K.GetBytes())
        
        M = TCBigNumber()
        M.SetBytes(sha.digest())

        if M.GetInt() == m1.GetInt():
            if self.authenticator:
                passed = False
                tmp = self.sock.recv(1)
                if len(tmp) == 1:
                    tmp = unpack('<B', tmp)[0]
                    key = self.sock.recv(tmp)
                    if len(key) == tmp:
                        try:
                            key = int(key)
                            print key
                            if ATGoogleAuth(self.authenticator, key):
                                passed = True
                        except ValueError:
                            passed = False
                if not passed:
                    Log('Account failed LogonProof (otc) [AccName: {}] [IP: {}]'.format(self.login, self.address[0]))
                    self.sock.sendall(pack('<BBBB', 1, 4, 3, 0))
                    return False
                

            Log('Account passed LogonProof [AccName: {}] [IP: {}]'.format(self.login, self.address[0]))
            self.db.QueryOne("""UPDATE account SET sessionkey=%s, last_ip=%s, last_login=NOW(),
                         locale=%s, operatingSystem=%s WHERE username=%s""", (self.crypt_K.GetHex(),
                                                                              self.address[0],
                                                                              self.locale,
                                                                              self.os,
                                                                              self.login))
            sha = hashlib.sha1()
            sha.update(A.GetBytes())                      
            sha.update(M.GetBytes())
            sha.update(self.crypt_K.GetBytes())
            m2 = TCBigNumber()
            m2.SetBytes(sha.digest())
        
            response = pack('<BB', 1, 0)
            response += m2.GetBytes(20)
            response += pack('<IIH', 0x00800000, 0, 0)
            self.sock.sendall(response)
            
            self.authed = True
            return True
    
        Log('Account failed LogonProof [AccName: {}] [IP: {}]'.format(self.login, self.address[0]))
        self.sock.sendall(pack('<BBBB', 1, 4, 3, 0))
        return False