· 10 years ago · Jul 08, 2016, 07:18 PM
1import math
2import json
3import time
4import socks
5import socket
6import struct
7import random
8import hashlib
9import sqlite3
10import requests
11import datetime
12import threading
13from xml.dom import minidom
14
15# http://api.xgenstudios.com/?method=xgen.stickarena.stats.get&username={}
16# http://api.xgenstudios.com/?method=xgen.users.changeName&username={}&password={}&new_username={}
17# http://api.xgenstudios.com/?method=xgen.users.add&username={}&password={}&email_address={}&v=2
18# http://api.xgenstudios.com/?method=xgen.users.addEmail&username={}&password={}&email={}
19# http://api.xgenstudios.com/?method=xgen.users.changePassword&username={}&password={}&new_password={}
20
21class SABot:
22 def __init__(self, Username, Password, IP, Port, Commands):
23 self.DatabaseFile = 'SABot.db'
24 self.DatabaseConn = sqlite3.connect(self.DatabaseFile, check_same_thread=False)
25 self.Database = self.DatabaseConn.cursor()
26
27 self.Database.execute("""CREATE TABLE IF NOT EXISTS users
28 (username VARCHAR(20) UNIQUE COLLATE NOCASE NOT NULL,
29 rgb VARCHAR(9) NOT NULL,
30 hex VARCHAR(6) NOT NULL,
31 kills VARCHAR(30) NOT NULL,
32 deaths VARCHAR(30) NOT NULL,
33 wins VARCHAR(30) NOT NULL,
34 losses VARCHAR(30) NOT NULL,
35 rounds VARCHAR(30) NOT NULL,
36 ballistick BOOLEAN NOT NULL,
37 access BOOLEAN NOT NULL,
38 lastseen VARCHAR(30) NULL,
39 status BOOLEAN NOT NULL DEFAULT 0)
40 """)
41
42 self.Database.execute("""CREATE TABLE IF NOT EXISTS blacklist
43 (username VARCHAR(20) UNIQUE COLLATE NOCASE NOT NULL,
44 color BOOLEAN NOT NULL,
45 location BOOLEAN NOT NULL)
46 """)
47
48 self.DatabaseConn.commit()
49
50 self.NullByte = struct.pack('B', 0)
51 self.BufSize = 4096
52 self.CommandChar = '.'
53 self.InLobby = False
54 self.AutoRespond = True
55 self.OnlineUsers = {}
56 self.OnlineUserMap = {}
57 self.BotAdmin = '' # set
58 self.Dead = []
59 self.Blacklist = [] # will ignore from specified users
60
61 self.BadStatusCodes = [400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413,
62 414, 415, 416, 417, 500, 501, 502, 503, 504, 505]
63
64 self.BotResponses = ['It is certain', 'It is decidedly so', 'Without a doubt', 'Yes, definitely', 'You may rely on it',
65 'As I see it, yes', 'Most likely', 'Outlook good', 'Yes', 'Signs point to yes', 'No, but at least I still love you',
66 'My sources say no', 'Outlook not so good', 'Very doubtful', 'Ask someone who cares', 'Not in a million years',
67 'As if', 'Dumb question, ask another', 'Yeah and I\'m the pope', 'Ask me if I care', 'All signs point to you sucking actually',
68 'Please for the love of god leave me alone, you must be lonely', 'All signs point to yes, or maybe no']
69
70 self.NameToIP = {'2D Central': '74.86.43.9:1138', 'Paper Thin City': '74.86.43.8:1138', 'Fine Line Island': '198.58.106.101:1138', 'U of SA': '69.164.207.72:1138',
71 'Amsterdam': '139.162.151.57:1138', 'Mobius Metro': '45.56.72.83:1138', 'Cartesian': '198.58.106.101:1139'}
72
73 self.IPToName = {'74.86.43.9:1138': '2D Central', '74.86.43.8:1138': 'Paper Thin City', '198.58.106.101:1138': 'Fine Line Island', '69.164.207.72:1138': 'U of SA',
74 '139.162.151.57:1138': 'Amsterdam', '45.56.72.83:1138': 'Mobius Metro', '198.58.106.101:1139': 'Cartesian'}
75
76 self.ServerIP = IP
77 self.ServerPort = Port
78 self.Commands = Commands
79 self.BotServer = self.IPToName[ '{}:{}'.format(self.ServerIP, self.ServerPort)]
80
81 socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, 'localhost', 9150)
82 socket.create_connection = socks.create_connection
83 socket.socket = socks.socksocket
84
85 self.connectToServer(Username, Password, self.ServerIP, self.ServerPort)
86
87 def executeDatabaseQuery(self, Query, Parameters = None, ExecuteMany = False, ReturnResults = False):
88 QueryFinished = False
89
90 while not QueryFinished:
91 try:
92 if ExecuteMany and Parameters:
93 self.Database.executemany(Query, Parameters)
94 else:
95 if Parameters:
96 self.Database.execute(Query, Parameters)
97 else:
98 self.Database.execute(Query)
99
100 if ReturnResults:
101 QueryFinished = True
102 Results = self.Database.fetchall()
103
104 self.DatabaseConn.commit()
105
106 if 'Results' in locals():
107 return Results
108 else:
109 return
110 except sqlite3.OperationalError:
111 pass
112 except Exception as Error:
113 QueryFinished = True
114
115 print('[could not save query]: ' + Error)
116
117 def changeUsername(self, Username, Password, NewUsername): # not implemented with bot commands
118 APIData = {'username': Username, 'password': Password, 'new_username': NewUsername}
119 RequestData = minidom.parseString(requests.get('http://api.xgenstudios.com/?method=xgen.users.changeName', params=APIData).text)
120 Response = RequestData.getElementsByTagName('rsp')[0].attributes['stat'].value
121
122 if Response == 'fail':
123 return RequestData.getElementsByTagName('err')[0].attributes['msg'].value
124 else:
125 return 'Username successfully changed'
126
127 def createAccount(self, Username, Password, UseAPI = False): # also not implemented with commands
128 if UseAPI:
129 APIData = {'username': Username, 'password': Password, 'v': '2'}
130 URLData = requests.get('http://api.xgenstudios.com/?method=xgen.users.add', params=APIData).text
131 Response = minidom.parseString(URLData).getElementsByTagName('rsp')[0].attributes['stat'].value
132
133 if Response == 'fail':
134 Returned = 'Could not create ' + Username
135 else:
136 Returned = 'Successfully created ' + Username
137 else:
138 PostData = {'username': Username, 'userpass': Password, 'usercol': '090090190', 'action': 'create'}
139 URLData = requests.post('http://www.xgenstudios.com/stickarena/stick_arena.php', data=PostData).text
140
141 if 'success' in URLData:
142 Returned = 'Successfully created ' + Username
143 else:
144 Returned = 'Could not create ' + Username
145
146 return Returned
147
148 def sendPacket(self, Socket, PacketData, Receive = False):
149 Packet = bytes(PacketData, 'utf-8')
150
151 if Socket:
152 Socket.send(Packet + self.NullByte)
153
154 if Receive:
155 return Socket.recv(self.BufSize).decode('utf-8')
156
157 def startKeepAlive(self, TimerSeconds = 20):
158 if hasattr(self, 'SocketConn'):
159 KeepAliveTimer = threading.Timer(TimerSeconds, self.startKeepAlive)
160 KeepAliveTimer.daemon = True
161 KeepAliveTimer.start()
162
163 self.sendPacket(self.SocketConn, '0')
164
165 def sendPrivateMessage(self, UserID, Message):
166 if UserID != self.BotID:
167 if UserID in self.OnlineUsers:
168 self.sendPacket(self.SocketConn, '00' + UserID + 'P' + Message)
169
170 def sendPublicMessage(self, Message):
171 self.sendPacket(self.SocketConn, '9' + Message)
172
173 def connectionHandler(self):
174 Buffer = b''
175
176 while hasattr(self, 'SocketConn'):
177 try:
178 Buffer += self.SocketConn.recv(self.BufSize)
179 except OSError:
180 if hasattr(self, 'SocketConn'):
181 self.SocketConn.shutdown(socket.SHUT_RD)
182 self.SocketConn.close()
183
184 if len(Buffer) == 0:
185 print('Disconnected')
186 self.executeDatabaseQuery("UPDATE users SET status = 0")
187 self.DatabaseConn.close()
188 break
189 elif Buffer.endswith(self.NullByte):
190 Receive = Buffer.split(self.NullByte)
191 Buffer = b''
192
193 for Data in Receive:
194 Data = Data.decode('utf-8')
195
196 if Data.startswith('U'):
197 UserID = Data[1:][:3]
198 Username = Data[4:][:20].replace('#', '')
199
200 self.parseUserData(Data)
201 elif Data.startswith('D'):
202 UserID = Data[1:][:3]
203 Username = self.OnlineUsers[UserID]
204
205 self.executeDatabaseQuery("UPDATE users SET status = 0 WHERE username = ?", [(Username)])
206
207 CurrentInfo = '{}:{};{}'.format(self.ServerIP, self.ServerPort, time.strftime('%m/%d/%Y at %H:%M (EST)'))
208 self.executeDatabaseQuery("UPDATE users SET lastseen = ? WHERE username = ?", [(CurrentInfo, Username)], True)
209
210 del self.OnlineUserMap[Username]
211 del self.OnlineUsers[UserID]
212 elif Data.startswith('M'):
213 UserID = Data[1:][:3]
214
215 self.parseUserMessage(UserID, Data)
216 elif Data.startswith('0g') or Data.startswith('0j'):
217 print('{{Server}}: {}'.format(Data[2:]))
218 elif Data.startswith('093'):
219 print('Secondary login')
220 break
221 elif Data.startswith('0f') or Data.startswith('0e'):
222 Time, Reason = Data[2:].split(';')
223 print('This account has just been banned [Time: {} / Reason: {}]'.format(Time, Reason))
224 elif Data.startswith('0c'):
225 print(Data[2:])
226
227 def connectToServer(self, Username, Password, ServerIP, ServerPort):
228 if Username.lower() == '': # if running multiple bots, set to first one to ensure it doesn't reset the db users status
229 self.executeDatabaseQuery("UPDATE users SET status = 0")
230
231 try:
232 self.SocketConn = socket.create_connection((ServerIP, ServerPort), socks.PROXY_TYPE_SOCKS5, 'localhost', 9150)
233 except Exception as Error:
234 print(Error)
235 return
236
237 Handshake = self.sendPacket(self.SocketConn, '08HxO9TdCC62Nwln1P', True).strip(self.NullByte.decode('utf-8'))
238
239 if Handshake == '08':
240 Credentials = '09{};{}'.format(Username, Password)
241 RawData = self.sendPacket(self.SocketConn, Credentials, True).split(self.NullByte.decode('utf-8'))
242
243 for Data in RawData:
244 if Data.startswith('A'):
245 self.InLobby = True
246 self.BotID = Data[1:][:3]
247 self.BotUsername = Data[4:][:20].replace('#', '')
248
249 print('Bot Username: {} / Bot ID: {} / Located in {}'.format(self.BotUsername, self.BotID, self.BotServer))
250
251 EntryPackets = ['02Z900_', '03_', '0a', '01']
252
253 for Packet in EntryPackets:
254 self.sendPacket(self.SocketConn, Packet)
255
256 self.startKeepAlive()
257 ConnectionThread = threading.Thread(target=self.connectionHandler)
258 ConnectionThread.start()
259 break
260 elif Data == '09':
261 print('Incorrect password')
262 break
263 elif Data == '091':
264 print('Currently banned')
265 break
266 else:
267 print('Server capacity check failed')
268
269 def parseUserData(self, Packet, Password = None):
270 StatsString = Packet.replace('\x00', '')
271 UserID = StatsString[1:][:3]
272 Type = StatsString[:1]
273
274 if Type == 'U':
275 if self.InLobby == True:
276 Username = StatsString[4:][:20].replace('#', '')
277 StatsString = StatsString[24:]
278
279 self.OnlineUsers[UserID] = Username
280 self.OnlineUserMap[Username] = UserID
281
282 RGBString = StatsString[:9]
283 R = int(RGBString[:3])
284 G = int(RGBString[3:][:3])
285 B = int(RGBString[6:][:3])
286 HexString = '#%02x%02x%02x' % (R, G, B)
287
288 Stats = StatsString[9:].split(';')
289 CurrentInfo = '{}:{};{}'.format(self.ServerIP, self.ServerPort, time.strftime('%m/%d/%Y at %H:%M (EST)'))
290 Data = [(Username, RGBString, HexString, Stats[0], Stats[1], Stats[2], Stats[3], Stats[4], Stats[5], Stats[6], CurrentInfo, '1')]
291
292 self.executeDatabaseQuery("INSERT OR REPLACE INTO users VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Data, True)
293 self.executeDatabaseQuery("INSERT OR IGNORE INTO blacklist VALUES (?, ?, ?)", [(Username, '0', '0')], True)
294 else:
295 Username = StatsString[9:][:20].replace('#', '')
296
297 self.OnlineUsers[UserID] = Username
298 self.OnlineUserMap[Username] = UserID
299
300 def parseUserMessage(self, SenderID, Packet):
301 if SenderID in self.OnlineUsers:
302 Sender = self.OnlineUsers[SenderID]
303
304 if Sender in self.Blacklist:
305 return
306
307 NoUseTypes = ['1', '2', '4', '5', '6', '7', '8', '~']
308 MessageType = Packet[4:][:1]
309 SenderMessage = Packet[5:]
310 RawMessage = Packet[1:].replace(SenderID, '')
311
312 if MessageType in NoUseTypes:
313 return
314 elif MessageType == '9':
315 if self.Commands:
316 self.handleCommand(SenderID, Sender, SenderMessage, False)
317 elif MessageType == 'P':
318 if self.Commands:
319 self.handleCommand(SenderID, Sender, SenderMessage, True)
320 elif MessageType == 'K':
321 Kicker = Sender
322 KickerID = SenderID
323
324 if SenderMessage == self.BotID:
325 self.sendPublicMessage('{} is trying to kick me'.format(Kicker))
326 return
327
328 ToKick = self.OnlineUsers[SenderMessage]
329 ToKickID = SenderMessage
330
331 if ToKick == self.BotAdmin:
332 self.sendPublicMessage('Do not kick {}, {}.'.format(self.BotAdmin, Kicker))
333 else:
334 if Kicker == self.BotAdmin:
335 self.sendPublicMessage('Autokicking {}'.format(ToKick))
336 self.sendPacket(self.SocketConn, 'K{}'.format(ToKickID))
337 else:
338 self.sendPublicMessage('{} is trying to kick {}'.format(Kicker, ToKick))
339 else:
340 self.handleCommand(SenderID, Sender, RawMessage, True)
341
342 try:
343 print('[' + Sender + ']: ' + RawMessage)
344 except:
345 pass
346
347 def handleCommand(self, SenderID, Sender, SenderMessage, Private):
348 RespondByPM = (False if Private == False else True)
349 Message = SenderMessage.strip()
350 MessageCheck = Message.split()
351
352 if Message.startswith(self.CommandChar):
353 Command = MessageCheck[0][1:].lower()
354 HasArguments = (True if len(MessageCheck) > 1 else False)
355 Arguments = (' '.join(MessageCheck[1:]) if HasArguments else None)
356
357 if Sender == self.BotAdmin:
358 if Command == 'exec':
359 if HasArguments:
360 try:
361 exec(Arguments)
362 except Exception as Error:
363 print('{}'.format(Error))
364 elif Command == 'reset':
365 RespondByPM = True
366
367 if HasArguments:
368 ResetTarget = MessageCheck[1].lower()
369
370 if ResetTarget == 'rr':
371 self.Dead = []
372
373 Response = 'Reset the list of the dead.'
374 elif ResetTarget == 'owner':
375 self.BotAdmin = None
376
377 Response = 'Reset bot owner.'
378 else:
379 Response = 'Invalid reset target.'
380 else:
381 self.Dead = []
382 self.BotAdmin = None
383
384 Response = 'Reset all items. You are no longer the current bot owner.'
385 elif Command == 'users':
386 RespondByPM = True
387 UserList = []
388
389 for User in self.OnlineUserMap:
390 UserList .append(User)
391
392 Response = 'There are {} people in the lobby. Users: {}'.format(len(UserList), ', '.join(UserList))
393
394 if Command == 'blacklist':
395 RespondByPM = True
396
397 if HasArguments:
398 Target = Arguments.replace(' ', '').lower()
399 Username = Sender
400
401 Results = self.executeDatabaseQuery("SELECT * FROM blacklist WHERE username = ?", [(Username)], False, True)
402
403 if Results:
404 if Target == 'color':
405 Blacklisted = Results[0][1]
406
407 if Blacklisted:
408 self.executeDatabaseQuery("UPDATE blacklist SET color = 0 WHERE username = ?", [(Username)])
409 Response = 'Your color codes can now be publicly requested.'
410 else:
411 self.executeDatabaseQuery("UPDATE blacklist SET color = 1 WHERE username = ?", [(Username)])
412 Response = 'Your color codes can no longer be publicly requested.'
413 elif Target == 'location':
414 Blacklisted = Results[0][2]
415
416 if Blacklisted:
417 self.executeDatabaseQuery("UPDATE blacklist SET location = 0 WHERE username = ?", [(Username)])
418 Response = 'Your location can now be publicly requested.'
419 else:
420 self.executeDatabaseQuery("UPDATE blacklist SET location = 1 WHERE username = ?", [(Username)])
421 Response = 'Your location can no longer be publicly requested.'
422 else:
423 Username = Sender
424
425 Results = self.executeDatabaseQuery("SELECT * FROM blacklist WHERE username = ?", [(Username)], False, True)
426
427 if Results:
428 ColorBlacklisted = Results[0][1]
429 LocationBlacklisted = Results[0][2]
430
431 if ColorBlacklisted:
432 ColorBlacklisted = 0
433 self.executeDatabaseQuery("UPDATE blacklist SET color = 0 WHERE username = ?", [(Username)])
434 else:
435 ColorBlacklisted = 1
436 self.executeDatabaseQuery("UPDATE blacklist SET color = 1 WHERE username = ?", [(Username)])
437
438 if LocationBlacklisted:
439 LocationBlacklisted = 0
440 self.executeDatabaseQuery("UPDATE blacklist SET location = 0 WHERE username = ?", [(Username)])
441 else:
442 LocationBlacklisted = 1
443 self.executeDatabaseQuery("UPDATE blacklist SET location = 1 WHERE username = ?", [(Username)])
444
445 ColorBlacklisted = ('Your color codes can no longer be publicly requested' if ColorBlacklisted else 'Your color codes can be publicly requested')
446 LocationBlacklisted = ('Your location can no longer be publicly requested' if LocationBlacklisted else 'Your location can be publicly requested')
447
448 Response = '{}; {}'.format(ColorBlacklisted, LocationBlacklisted)
449 elif Command == 'hex' or Command == 'rgb':
450 RespondByPM = True
451
452 if HasArguments:
453 Arguments = Arguments.replace(' ', '')
454 Target = Arguments
455 else:
456 Target = Sender
457
458 Results = self.executeDatabaseQuery("SELECT * FROM blacklist WHERE lower(username) = ?", [(Target.lower())], False, True)
459
460 if Results:
461 Username = Results[0][0]
462 Blacklisted = Results[0][1]
463 else:
464 Username = Target
465 Blacklisted = 0
466
467 Results = self.executeDatabaseQuery("SELECT * FROM users WHERE lower(username) = ?", [(Username.lower())], False, True)
468
469 if Results:
470 RGB = Results[0][1]
471 Hex = Results[0][2]
472
473 if Sender.lower() == Username.lower():
474 BlacklistCheck = ('blacklisted.' if Blacklisted else 'not blacklisted.')
475 Response = 'Your color codes: [RGB]: {} | [Hex]: {} / You are {}'.format(RGB, Hex, BlacklistCheck)
476 else:
477 if Blacklisted:
478 if Sender == self.BotAdmin:
479 Response = '[Blacklisted] {}\'s color codes: [RGB]: {} | [Hex]: {}'.format(Username, RGB, Hex)
480 else:
481 Response = '{} isn\'t allowing requests for their color.'.format(Username)
482 else:
483 Response = '{}\'s color codes: [RGB]: {} | [Hex]: {}'.format(Username, RGB, Hex)
484 else:
485 Response = 'There are currently no color codes stored for "{}"'.format(Target)
486 elif Command == 'addcol' or Command == 'getcol':
487 RespondByPM = True
488
489 if Private:
490 if HasArguments:
491 try:
492 SpinnerType = Arguments.split()[0]
493 RGB = Arguments.split()[1]
494 Password = Arguments.replace(' ', '')[12:]
495 Response = 'Attempting to add the requested RGB to your account...'
496
497 ColorRequest = threading.Thread(target=self.handleColorRequest, args=(SenderID, Sender, SpinnerType, RGB, Password))
498 ColorRequest.daemon = True
499 ColorRequest.start()
500 except Exception as Error:
501 print(Error)
502 Response = 'Incorrect usage of this command. Example: .getcol 100 255000000 Password'
503 else:
504 Response = 'This command can not be used in the public chat.'
505 elif Command == 'stats':
506 RespondByPM = True
507
508 if HasArguments:
509 Arguments = Arguments.replace(' ', '')
510
511 if len(Arguments) <= 20:
512 Target = Arguments
513 Valid = True
514 else:
515 Response = 'Invalid username.'
516 Valid = False
517 else:
518 Target = Sender
519 Valid = True
520
521 if Valid:
522 APIURL = 'http://api.xgenstudios.com/?method=xgen.stickarena.stats.get&username={}'.format(Target)
523 APIData = minidom.parseString(requests.get(APIURL).text)
524 URLResp = APIData.getElementsByTagName('rsp')[0].attributes['stat'].value
525 Username = APIData.getElementsByTagName('user')[0].attributes['username'].value
526
527 if URLResp == 'ok':
528 if Username != '':
529 StatTag = APIData.getElementsByTagName('stat')
530
531 Wins = StatTag[0].firstChild.nodeValue
532 Losses = StatTag[1].firstChild.nodeValue
533 Kills = StatTag[2].firstChild.nodeValue
534 Deaths = StatTag[3].firstChild.nodeValue
535 Rounds = StatTag[4].firstChild.nodeValue
536 Ballistick = StatTag[5].firstChild.nodeValue
537
538 UserStatus = int(APIData.getElementsByTagName('user')[0].attributes['perms'].value)
539
540 BanCheck = ('Yes' if UserStatus < 0 else 'No')
541 ModCheck = ('Yes' if UserStatus > 0 else 'No')
542 LabpassCheck = ('Yes' if Ballistick == '1' else 'No')
543 StatsString = 'Wins: {} / Losses: {} / Kills: {} / Deaths: {} / Rounds: {}/ Labpass: {} / Banned: {} / Mod: {}'.format(Wins, Losses, Kills, Deaths, Rounds, LabpassCheck, BanCheck, ModCheck)
544
545 if len(StatsString) <= 135:
546 Response = StatsString
547 else:
548 print('Stats string was too long to send') # should never happen but Justin Case hahaha... no..? ok.
549 else:
550 Response = '{} does not exist.'.format(Target)
551 elif Command == 'rr':
552 if Sender not in self.Dead:
553 GoodNumber = random.randint(0, 2)
554 BadNumber = random.randint(0, 2)
555
556 if GoodNumber == BadNumber:
557 self.Dead.append(Sender)
558 Response = 'You\'re dead, {}'.format(Sender)
559 else:
560 Response = 'You live, {}'.format(Sender)
561 elif Command == 'find':
562 RespondByPM = True
563
564 if HasArguments:
565 Target = Arguments.replace(' ', '').lower()
566
567 if Target.startswith('*mod'): # will search for any user listed in db as status online and access level > 0
568 Results = self.executeDatabaseQuery("SELECT * FROM users WHERE access != 0", None, False, True)
569
570 if Results:
571 OnlineMods = []
572
573 for Mod in Results:
574 if Mod[11] == 1:
575 OnlineMods.append(Mod[0])
576
577 if len(OnlineMods) == 0:
578 Response = 'There are currently no mods online in any lobby I am located in.'
579 else:
580 Response = 'Online Mods: {}'.format(', '.join(OnlineMods))
581 else:
582 Results = self.executeDatabaseQuery("SELECT * FROM blacklist WHERE lower(username) = ?", [(Target.lower())], False, True)
583
584 if Results:
585 Username = Results[0][0]
586 Blacklisted = Results[0][2]
587
588 if Blacklisted and Sender != self.BotAdmin:
589 Response = '{} is not allowing requests for their location.'.format(Username)
590 Retrieve = False
591 else:
592 Retrieve = True
593 else:
594 Retrieve = True
595
596 if Retrieve:
597 Results = self.executeDatabaseQuery("SELECT * FROM users WHERE lower(username) = ?", [(Target)], False, True)
598
599 if Results:
600 Username = Results[0][0]
601 LastSeen = Results[0][10]
602 Status = Results[0][11]
603
604 if LastSeen != None:
605 Server, Time = LastSeen.split(';')
606 ServerName = self.IPToName[Server]
607
608 if Status == 1:
609 Response = '{} is currently online in {}'.format(Username, ServerName)
610 else:
611 Response = '{} was last seen in {} on {}'.format(Username, ServerName, Time)
612 else:
613 Response = '{} has no last seen record.'.format(Username)
614 else:
615 Response = 'No record is stored for "{}"'.format(Target)
616 elif '8ball' in SenderMessage:
617 if len(MessageCheck) >= 2 and len(MessageCheck[1]) >= 2:
618 Response = '{}, {}'.format(random.choice(self.BotResponses), Sender)
619 else:
620 if self.AutoRespond and Private:
621 Response = 'Hello, {}!'.format(Sender)
622
623 if 'Response' in locals():
624 if Private:
625 print('[PM from {} in {}] Response: {}'.format(Sender, self.BotServer, Response))
626 else:
627 print('[{} in {}] Response: {}'.format(Sender, self.BotServer, Response))
628
629 if RespondByPM:
630 self.sendPrivateMessage(SenderID, Response)
631 else:
632 self.sendPublicMessage(Response)
633
634 def handleColorRequest(self, SenderID, Sender, SpinnerType, RGB, Password):
635 SocketConn = socket.create_connection((self.ServerIP, self.ServerPort), socks.PROXY_TYPE_SOCKS5, 'localhost', 9150)
636 Handshake = self.sendPacket(SocketConn, '08HxO9TdCC62Nwln1P', True).strip(self.NullByte.decode('utf-8'))
637
638 if Handshake == '08':
639 Credentials = '09{};{}'.format(Sender, Password)
640 RawData = self.sendPacket(SocketConn, Credentials, True)
641
642 for Data in RawData:
643 if Data.startswith('A'):
644 self.sendPacket(SocketConn, '02Z900_')
645 self.sendPacket(SocketConn, '03_')
646
647 self.sendPacket(SocketConn, '0b' + SpinnerType + RGB + RGB)
648 break
649 elif Data == '09':
650 self.sendPrivateMessage(SenderID, 'Incorrect password')
651 break
652
653 SocketConn.shutdown(socket.SHUT_RD)
654 SocketConn.close()
655 del SocketConn
656
657if __name__ == '__main__': # rest in pieces
658 SABot('machiev', 'cat', '74.86.43.8', 1138, True)