diff --git a/GUI.py b/GUI.py index 7a80676..f43ce82 100644 --- a/GUI.py +++ b/GUI.py @@ -9,26 +9,22 @@ def Enter(): - db, qq, key, msg, n1, n2 = e1.get(), e2.get(), e3.get(), e4.get(), e5.get( - ), e6.get() - group = 1 if e7.get() == '私聊' else 2 - if (db == "" or qq == "" or (key == "" and msg == "")): + dir, qq_self, qq = e1.get(), e2.get(), e3.get() + group = 1 if e4.get() == '私聊' else 2 + if (dir == "" or qq_self == "" or qq == ""): info.set("信息不完整!") return () info.set("开始导出") try: - realkey = QQ_History.main(db, qq, key, msg, n1, n2, group) + QQ_History.main(dir, qq_self, qq, group) except Exception as e: info.set(repr(e)) return () - if (key == ""): - keyGet.set(realkey) - info.set("完成") def SelectPath(): - pathTmp = filedialog.askopenfilename() - pathGet.set(pathTmp) + dir = filedialog.askdirectory() + pathGet.set(dir) def url(): @@ -46,41 +42,30 @@ def url(): root.title("QQ聊天记录导出") -ttk.Label(root, text="*db文件地址:").grid(row=0, column=0, sticky="e") +ttk.Label(root, text="*com.tencent.mobileqq:").grid(row=0, column=0, sticky="e") e1 = ttk.Entry(root, textvariable=pathGet) e1.grid(row=0, column=1) ttk.Button(root, text="选择", command=SelectPath, width=5).grid(row=0, column=3) -ttk.Label(root, text="*对方QQ号:").grid(row=1, column=0, sticky="e") +ttk.Label(root, text="*自己QQ号:").grid(row=1, column=0, sticky="e") e2 = ttk.Entry(root) e2.grid(row=1, column=1, columnspan=3, sticky="ew", pady=3) -ttk.Label(root, text="手机识别码:").grid(row=2, column=0, sticky="e") -e3 = ttk.Entry(root, textvariable=keyGet) +ttk.Label(root, text="*QQ号/群号:").grid(row=2, column=0, sticky="e") +e3 = ttk.Entry(root) e3.grid(row=2, column=1, columnspan=3, sticky="ew", pady=3) -ttk.Label(root, text="最后一次聊天记录\n(至少六个汉字)").grid(row=3, column=0, sticky="e") -e4 = ttk.Entry(root) +ttk.Label(root, text="私聊/群聊:").grid(row=3, column=0, sticky="e") +e4 = ttk.Combobox(root) +e4['values'] = ('私聊', '群聊') +e4.current(0) e4.grid(row=3, column=1, columnspan=3, sticky="ew", pady=3) -ttk.Label(root, text="我的名字:").grid(row=4, column=0, sticky="e") -e5 = ttk.Entry(root) -e5.grid(row=4, column=1, columnspan=3, sticky="ew", pady=3) -ttk.Label(root, text="对方名字:").grid(row=5, column=0, sticky="e") -e6 = ttk.Entry(root) -e6.grid(row=5, column=1, columnspan=3, sticky="ew", pady=3) - -ttk.Label(root, text="私聊/群聊:").grid(row=6, column=0, sticky="e") -e7 = ttk.Combobox(root) -e7['values'] = ('私聊', '群聊') -e7.current(0) -e7.grid(row=6, column=1, columnspan=3, sticky="ew", pady=3) - root.grid_columnconfigure(2, weight=1) -ttk.Button(root, text="确认", command=Enter).grid(row=7, column=1) +ttk.Button(root, text="确认", command=Enter).grid(row=4, column=1) l1 = ttk.Label(root, textvariable=info) -l1.grid(row=7, column=1) +l1.grid(row=4, column=1) tmp = open("tmp.png", "wb+") tmp.write(base64.b64decode(github_mark)) @@ -93,4 +78,4 @@ def url(): root.mainloop() -## pyinstaller -F -w -i icon.ico GUI.py +# pyinstaller -F -w -i icon.ico GUI.py diff --git a/QQ_History.py b/QQ_History.py index 3d20c3f..cb03014 100644 --- a/QQ_History.py +++ b/QQ_History.py @@ -2,70 +2,43 @@ import hashlib import sqlite3 import time +import os import traceback class QQoutput(): - def __init__(self, db, key, mode, s): - self.key = key # 解密用的密钥 - self.c = sqlite3.connect(db).cursor() + def __init__(self, dir, qq_self, qq, mode): + self.dir = dir + self.key = self.get_key() # 解密用的密钥 + db = os.path.join(dir, "databases", qq_self + ".db") + self.c1 = sqlite3.connect(db).cursor() + db = os.path.join(dir, "databases", "slowtable_" + qq_self + ".db") + self.c2 = sqlite3.connect(db).cursor() + self.qq_self = qq_self + self.qq = qq self.mode = mode - self.s = s - - def fix(self, data, mode): - # msgdata mode=0 - # other mode=1 - if (mode == 0): - rowbyte = [] - for i in range(0, len(data)): - rowbyte.append(data[i] ^ ord(self.key[i % len(self.key)])) - rowbyte = bytes(rowbyte) + self.num_to_name = {} + + def decrypt(self, data): + if type(data) == bytes: + msg = b'' try: - msg = rowbyte.decode(encoding="utf-8") + for i in range(0, len(data)): + msg += bytes([data[i] ^ ord(self.key[i % len(self.key)])]) + return msg.decode(encoding="utf-8") except: - msg = NULL - return msg - elif (mode == 1): - str = "" + return NULL + elif type(data) == str: + msg = "" try: for i in range(0, len(data)): - str += chr(ord(data[i]) ^ ord(self.key[i % len(self.key)])) + msg += chr(ord(data[i]) ^ ord(self.key[i % len(self.key)])) except: - str = NULL - return str - - def decode(self, cursor): - for row in cursor: - continue - data = row[0] - MsgEnc = self.s.encode(encoding="utf-8") - KeySet = "" - # for i in range(0,min(len(MsgEnc), len(data))): - for i in range(0, len(MsgEnc)): - KeySet += chr(data[i] ^ MsgEnc[i]) - # TO AVOID LOOP - RealKey, restKey = "", "" - for i in range(4, len(KeySet)): - ''' - bug WARNING!! - Assuming Key should be longer than 5 digits - To Prevent string loop in single key - Like "121212456" - ''' - RealKey, nextKey, restKey = KeySet[0:i], KeySet[i:2 * i], KeySet[ - 2 * i:len(KeySet)] - KeyLen = len(RealKey) - flagLoop = True - for j in range(KeyLen): - if ((j < len(nextKey) and RealKey[j] != nextKey[j]) - or (j < len(restKey) and RealKey[j] != restKey[j])): - flagLoop = False - break - if (flagLoop and j == KeyLen - 1): - break - return RealKey + msg = NULL + return msg + return NULL - def AddEmoji(self, msg): + def add_emoji(self, msg): pos = msg.find('\x14') while (pos != -1): lastpos = pos @@ -78,98 +51,134 @@ def AddEmoji(self, msg): break return msg - def message(self, num): + def message(self): # mode=1 friend # mode=2 troop - num = str(num).encode("utf-8") + num = self.qq.encode("utf-8") md5num = hashlib.md5(num).hexdigest().upper() if (self.mode == 1): - execute = "select msgData,senderuin,time from mr_friend_{md5num}_New".format( - md5num=md5num) - elif (self.mode == 2): - execute = "select msgData,senderuin,time from mr_troop_{md5num}_New".format( + cmd = "select msgData,senderuin,time from mr_friend_{md5num}_New".format( md5num=md5num) + self.get_friends() else: - print("error mode") - exit(1) + cmd = "select msgData,senderuin,time from mr_troop_{md5num}_New".format( + md5num=md5num) + self.get_troop_members() - cursor = self.c.execute(execute) - if (self.key == "" and len(self.s) >= 5): - self.key = self.decode(cursor) - cursor = self.c.execute(execute) + cursors = self.fill_cursors(cmd) allmsg = [] - for row in cursor: - msgdata = row[0] - if (not msgdata): - continue - uin = row[1] - ltime = time.localtime(row[2]) - - sendtime = time.strftime("%Y-%m-%d %H:%M:%S", ltime) - msg = self.fix(msgdata, 0) - senderuin = self.fix(uin, 1) - - amsg = [] - amsg.append(sendtime) - amsg.append(senderuin) - amsg.append(msg) - allmsg.append(amsg) + for cs in cursors: + for row in cs: + msgdata = row[0] + if (not msgdata): + continue + uin = row[1] + ltime = time.localtime(row[2]) + sendtime = time.strftime("%Y-%m-%d %H:%M:%S", ltime) + + amsg = [] + amsg.append(sendtime) + amsg.append(self.decrypt(uin)) + amsg.append(self.decrypt(msgdata)) + allmsg.append(amsg) return allmsg - def output(self, num, n1, n2): - name1 = n1 if n1 != "" else "我" - name2 = n2 if n2 != "" else str(num) - file = str(num) + ".html" + def get_friends(self): + cmd = "SELECT uin, remark FROM Friends" + cursors = self.fill_cursors(cmd) + for cs in cursors: + for row in cs: + num = self.decrypt(row[0]) + name = self.decrypt(row[1]) + self.num_to_name[num] = name + + def get_troop_members(self): + cmd = "SELECT troopuin, memberuin, friendnick, troopnick FROM TroopMemberInfo" + cursors = self.fill_cursors(cmd) + for cs in cursors: + for row in cs: + if(self.decrypt(row[0]) != self.qq): + continue + num = self.decrypt(row[1]) + name = self.decrypt(row[3]) or self.decrypt(row[2]) + self.num_to_name[num] = name + + def fill_cursors(self, cmd): + cursors = [] + try: + cursors.append(self.c2.execute(cmd)) + except: + pass + try: + cursors.append(self.c1.execute(cmd)) + except: + pass + return cursors + + def output(self): + name1 = "我" + file = str(self.qq) + ".html" f2 = open(file, "w", encoding="utf-8") f2.write( "
" ) - allmsg = self.message(num) + allmsg = self.message() f2.write("") - f2.write("") - f2.write(name2) - f2.write("-----") - f2.write(msg[0]) - f2.write("") - else: - f2.write("
") - f2.write("") - f2.write(msg[0]) - f2.write("-----") - f2.write(name1) - f2.write("") + if (msg[1] == str(self.qq_self)): + f2.write("
") + f2.write("") + f2.write(msg[0]) + f2.write("-----") + f2.write(name1) + f2.write("") else: f2.write("
") f2.write("") - f2.write(msg[1]) + f2.write(self.num_to_name.get(msg[1]) or msg[1]) f2.write("-----") f2.write(msg[0]) f2.write("") - f2.write(self.AddEmoji(msg[2])) + f2.write(self.add_emoji(msg[2])) f2.write("") f2.write("
") except: pass f2.write("