Advertisement
agunq

ch.py

Feb 14th, 2021 (edited)
1,100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 48.39 KB | None | 0 0
  1. ################################################################
  2. # Original By : Lumirayz/Lumz lumirayz@gmail.com
  3. # Edited By : Agunq
  4. # Use python3.7+
  5. # Require websocket-client module
  6. #   pip install websocket-client
  7. ################################################################
  8.  
  9. import websocket
  10. import random
  11. import re
  12. import time
  13. import urllib.request
  14. import urllib.parse
  15. import threading
  16. import traceback
  17.  
  18. BigMessage_Multiple = 0
  19. BigMessage_Cut      = 1
  20. ReconnectingDelay   = 10
  21.  
  22. MessageFlags = {
  23.     "PREMIUM" : 1 << 2 ,
  24.     "BG_ON" : 1 << 3 ,
  25.     "MEDIA_ON" : 1 << 4 ,
  26.     "CENSORED" : 1 << 5 ,
  27.     "SHOW_MOD_ICON" : 1 << 6 ,
  28.     "SHOW_STAFF_ICON" : 1 << 7 ,
  29.     "CHANNEL_RED" : 1 << 8 ,
  30.     "CHANNEL_ORANGE" : 1 << 9 ,
  31.     "CHANNEL_GREEN" : 1 << 10 ,
  32.     "CHANNEL_CYAN" : 1 << 11 ,
  33.     "CHANNEL_BLUE" : 1 << 12 ,
  34.     "CHANNEL_PURPLE" : 1 << 13 ,
  35.     "CHANNEL_PINK" : 1 << 14 ,
  36.     "CHANNEL_MOD" : 1 << 15
  37.     }
  38.  
  39. RoomFlags = {
  40.     "LIST_TAXONOMY" : 1 << 0 ,
  41.     "NO_ANONS" : 1 << 2 ,
  42.     "NO_FLAGGING" : 1 << 3 ,
  43.     "NO_COUNTER" : 1 << 4 ,
  44.     "NO_IMAGES" : 1 << 5 ,
  45.     "NO_LINKS" : 1 << 6 ,
  46.     "NO_VIDEOS" : 1 << 7 ,
  47.     "NO_STYLED_TEXT" : 1 << 8 ,
  48.     "NO_LINKS_CHATANGO" : 1 << 9 ,
  49.     "NO_BROADCAST_MSG_WITH_BW" : 1 << 10 ,
  50.     "RATE_LIMIT_REGIMEON" : 1 << 11 ,
  51.     "CHANNELS_DISABLED" : 1 << 13 ,
  52.     "NLP_SINGLEMSG" : 1 << 14 ,
  53.     "NLP_MSGQUEUE" : 1 << 15 ,
  54.     "BROADCAST_MODE" : 1 << 16 ,
  55.     "CLOSED_IF_NO_MODS" : 1 << 17 ,
  56.     "IS_CLOSED" : 1 << 18 ,
  57.     "SHOW_MOD_ICONS" : 1 << 19 ,
  58.     "MODS_CHOOSE_VISIBILITY" : 1 << 20 ,
  59.     "NLP_NGRAM" : 1 << 21 ,
  60.     "NO_PROXIES" : 1 << 22 ,
  61.     "HAS_XML" : 1 << 28 ,
  62.     "UNSAFE" : 1 << 29
  63.     }
  64.  
  65. ModeratorFlags = {
  66.     "DELETED" : 1 << 0 ,
  67.     "EDIT_MODS" :  1 << 1 ,
  68.     "EDIT_MOD_VISIBILITY" : 1 << 2 ,
  69.     "EDIT_BW" : 1 << 3 ,
  70.     "EDIT_RESTRICTIONS" : 1 << 4 ,
  71.     "EDIT_GROUP" : 1 << 5 ,
  72.     "SEE_COUNTER" : 1 << 6 ,
  73.     "SEE_MOD_CHANNEL" : 1 << 7 ,
  74.     "SEE_MOD_ACTIONS" : 1 << 8 ,
  75.     "EDIT_NLP" : 1 << 9 ,
  76.     "EDIT_GP_ANNC" : 1 << 10 ,
  77.     "EDIT_ADMINS" : 1 << 11 ,
  78.     "EDIT_SUPERMODS" : 1 << 12 ,
  79.     "NO_SENDING_LIMITATIONS" : 1 << 13 ,
  80.     "SEE_IPS" : 1 << 14 ,
  81.     "CLOSE_GROUP" : 1 << 15 ,
  82.     "CAN_BROADCAST" : 1 << 16 ,
  83.     "MOD_ICON_VISIBLE" : 1 << 17 ,
  84.     "IS_STAFF" : 1 << 18 ,
  85.     "STAFF_ICON_VISIBLE" : 1 << 19 ,
  86.     "UNBAN_ALL" : 1 << 20
  87.     }
  88.  
  89. def getFlag(n, FlagSet):
  90.     if n <= 0: return {}
  91.     newflag = FlagSet
  92.     f = FlagSet.values()
  93.     c = 0
  94.     bit = n
  95.     newset = {}
  96.     while bit != 0:
  97.         bit >>= 1
  98.         c += 1
  99.         tv = 1 << c
  100.         if tv not in f:
  101.             newflag[str(tv)] = tv
  102.    
  103.     for flag, number in newflag.items():
  104.         if n & number :
  105.             newset[flag] = number
  106.          
  107.     return newset
  108.  
  109. specials = {'tango-hyoo': 60,
  110.             'monosekai': 76,
  111.             'nico-nico': 29
  112.             }
  113.  
  114. tsweights = [['5', 75], ['6', 75], ['7', 75], ['8', 75], ['16', 75], ['17', 75], ['18', 75], ['9', 95], ['11', 95], ['12', 95], ['13', 95], ['14', 95], ['15', 95], ['19', 110], ['23', 110], ['24', 110], ['25', 110], ['26', 110], ['28', 104], ['29', 104], ['30', 104], ['31', 104], ['32', 104], ['33', 104], ['35', 101], ['36', 101], ['37', 101], ['38', 101], ['39', 101], ['40', 101], ['41', 101], ['42', 101], ['43', 101], ['44', 101], ['45', 101], ['46', 101], ['47', 101], ['48', 101], ['49', 101], ['50', 101], ['52', 110], ['53', 110], ['55', 110], ['57', 110], ['58', 110], ['59', 110], ['60', 110], ['61', 110], ['62', 110], ['63', 110], ['64', 110], ['65', 110], ['66', 110], ['68', 95], ['71', 116], ['72', 116], ['73', 116], ['74', 116], ['75', 116], ['76', 116], ['77', 116], ['78', 116], ['79', 116], ['80', 116], ['81', 116], ['82', 116], ['83', 116], ['84', 116]]
  115.  
  116. def getServer(group):
  117.   try:
  118.     sn = specials[group]
  119.   except KeyError:
  120.     group = group.replace("_", "q")
  121.     group = group.replace("-", "q")
  122.     fnv = float(int(group[0:min(5, len(group))], 36))
  123.     lnv = group[6: (6 + min(3, len(group) - 5))]
  124.     if(lnv):
  125.       lnv = float(int(lnv, 36))
  126.       lnv = max(lnv,1000)
  127.     else:
  128.       lnv = 1000
  129.     num = (fnv % lnv) / lnv
  130.     maxnum = sum(map(lambda x: x[1], tsweights))
  131.     cumfreq = 0
  132.     sn = 0
  133.     for wgt in tsweights:
  134.       cumfreq += float(wgt[1]) / maxnum
  135.       if(num <= cumfreq):
  136.         sn = int(wgt[0])
  137.         break
  138.   return "s" + str(sn) + ".chatango.com"
  139.  
  140. def genUid():
  141.   return str(random.randrange(10 ** 15, 10 ** 16))
  142.  
  143. def clean_message(msg):
  144.   n = re.search("<n(.*?)/>", msg)
  145.   if n: n = n.group(1)
  146.   f = re.search("<f(.*?)>", msg)
  147.   if f: f = f.group(1)
  148.   msg = re.sub("<n.*?/>", "", msg)
  149.   msg = re.sub("<f.*?>", "", msg)
  150.   msg = strip_html(msg)
  151.   msg = msg.replace("&lt;", "<")
  152.   msg = msg.replace("&gt;", ">")
  153.   msg = msg.replace("&quot;", "\"")
  154.   msg = msg.replace("&apos;", "'")
  155.   msg = msg.replace("&amp;", "&")
  156.   return msg, n, f
  157.  
  158. def strip_html(msg):
  159.     msg = re.sub("<\/?[^>]*>", "", msg)
  160.     return msg
  161.  
  162. def parseNameColor(n):
  163.   return n
  164.  
  165. def parseFont(f):
  166.   try:
  167.     sizecolor, fontface = f.split("=", 1)
  168.     sizecolor = sizecolor.strip()
  169.     size = int(sizecolor[1:3])
  170.     col = sizecolor[3:6]
  171.     if col == "": col = None
  172.     face = f.split("\"", 2)[1]
  173.     return col, face, size
  174.   except:
  175.     return None, None, None
  176.  
  177. def getAnonId(n, ssid):
  178.   if n == None: n = "5504"
  179.   try:
  180.     return "".join(list(
  181.       map(lambda x: str(x[0] + x[1])[-1], list(zip(
  182.         list(map(lambda x: int(x), n)),
  183.         list(map(lambda x: int(x), ssid[4:]))
  184.       )))
  185.     ))
  186.   except ValueError:
  187.     return "NNNN"
  188.  
  189. class PM:
  190.   def __init__(self, mgr):
  191.     self._auth_re = re.compile(r"auth\.chatango\.com ?= ?([^;]*)", re.IGNORECASE)
  192.     self._connected = False
  193.     self._reconnecting = False
  194.  
  195.     self._mgr = mgr
  196.     self._auid = None
  197.     self._premium = False
  198.     self._wbuff = ""
  199.     self._blocklist = set()
  200.     self._contacts = set()
  201.     self._status = dict()
  202.     self._firstCommand = True
  203.     self._pingTask = None
  204.  
  205.     if self._mgr:
  206.       self._connect()
  207.  
  208.  
  209.   def on_message(self, ws, message):
  210.     self._feed(message)
  211.  
  212.   def on_error(self, ws, error):
  213.     print("pm", error)
  214.     print(traceback.format_exc())
  215.  
  216.   def on_close(self, ws, close_status_code, close_msg):
  217.     print("pm close", close_status_code, close_msg)
  218.     self._callEvent("onPMDisconnect")
  219.  
  220.   def on_open(self, ws):
  221.     self._firstCommand = True
  222.     self._auth()
  223.     self._pingTask = self.mgr.setInterval(self.mgr._pingDelay, self.ping)
  224.  
  225.   def _getAuth(self, name, password):
  226.     data = urllib.parse.urlencode({
  227.       "user_id": name,
  228.       "password": password,
  229.       "storecookie": "on",
  230.       "checkerrors": "yes"
  231.     }).encode()
  232.     try:
  233.       resp = urllib.request.urlopen("https://chatango.com/login", data)
  234.       headers = resp.headers
  235.     except Exception:
  236.       return None
  237.     for header, value in headers.items():
  238.       if header.lower() == "set-cookie":
  239.         m = self._auth_re.search(value)
  240.         if m:
  241.           auth = m.group(1)
  242.           if auth == "":
  243.             return None
  244.           return auth
  245.     return None
  246.  
  247.   def _auth(self):
  248.     self._auid = self._getAuth(self._mgr.name, self._mgr.password)
  249.     if self._auid == None:
  250.       self._websock.close()
  251.       self._callEvent("onLoginFail")
  252.       return False
  253.     self._sendCommand("tlogin", self._auid, "2")
  254.     return True
  255.  
  256.   def connect(self):
  257.     self._connect()
  258.  
  259.   def _connect(self):
  260.     self._websock = websocket.WebSocketApp('ws://%s:%s/' % (self._mgr._PMHost, self._mgr._PMPort),
  261.                                            header = { "Pragma" : "no-cache", "Cache-Control" : "no-cache" },
  262.                                            on_open= self.on_open,
  263.                                            on_message=self.on_message,
  264.                                            on_error=self.on_error,
  265.                                            on_close=self.on_close)
  266.    
  267.     kwargs = {"origin": "https://st.chatango.com", "reconnect": ReconnectingDelay}
  268.     thread = threading.Thread(target=self._websock.run_forever, kwargs=kwargs)
  269.     thread.daemon = True
  270.     thread.start()
  271.    
  272.   def disconnect(self):
  273.     self._disconnect()
  274.  
  275.   def _disconnect(self):
  276.     self._connected = False
  277.     self._pingTask.cancel()
  278.     self._websock.close()
  279.  
  280.   def _feed(self, data):
  281.     data = data.split("\x00")
  282.     for food in data:
  283.       self._process(food.rstrip("\r\n").replace("&#39;", "'"))
  284.  
  285.   def _process(self, data):
  286.     self._callEvent("onRaw", data)
  287.     data = data.split(":")
  288.     cmd, args = data[0], data[1:]
  289.     func = "rcmd_" + cmd
  290.     if hasattr(self, func):
  291.       getattr(self, func)(args)
  292.  
  293.   def getManager(self): return self._mgr
  294.   def getContacts(self): return self._contacts
  295.   def getBlocklist(self): return self._blocklist
  296.  
  297.   mgr = property(getManager)
  298.   contacts = property(getContacts)
  299.   blocklist = property(getBlocklist)
  300.  
  301.   def rcmd_OK(self, args):
  302.     self._connected = True
  303.     self._sendCommand("wl")
  304.     self._sendCommand("getblock")
  305.     self._sendCommand("getpremium", "1")
  306.     self._callEvent("onPMConnect")
  307.  
  308.   def rcmd_wl(self, args):
  309.     self._contacts = set()
  310.     for i in range(len(args) // 4):
  311.       name, last_on, is_on, idle = args[i * 4: i * 4 + 4]
  312.       user = User(name)
  313.       if last_on=="None":pass
  314.       elif is_on == "off": self._status[user] = [int(last_on), "offline", 0]
  315.       elif is_on == "app": self._status[user] = [int(last_on), "app", 0]
  316.       elif idle == '0' and is_on == "on": self._status[user] = [int(last_on), "online", 0]
  317.       else: self._status[user] = [int(last_on), "online", time.time() - int(idle) * 60]
  318.       self._contacts.add(user)
  319.     self._callEvent("onPMContactlistReceive")
  320.  
  321.   def rcmd_wladd(self, args):
  322.     name, is_on, last_on = args
  323.     user = User(name)
  324.     if is_on == "on":
  325.       if last_on == '0':
  326.         idle = 0
  327.       else:
  328.         idle = time.time() - int(last_on) * 60
  329.       last_on = 0
  330.       is_on = "online"
  331.     elif is_on == "app":
  332.       if last_on == '0':
  333.         idle = 0
  334.       else:
  335.         idle = time.time() - int(last_on) * 60
  336.       last_on = 0
  337.       is_on = "app"
  338.     else:
  339.       idle = 0
  340.       if last_on == "None":
  341.         last_on = 0
  342.       else:
  343.         last_on = int(last_on)
  344.       is_on = "offline"
  345.     self._status[user] = [last_on, is_on, idle]
  346.     if user not in self._contacts:
  347.       self._contacts.add(user)
  348.     self._callEvent("onPMContactAdd", user)
  349.  
  350.   def rcmd_wldelete(self, args):
  351.     user = User(args[0])
  352.     if user in self._contacts:
  353.       self._contacts.remove(user)
  354.     self._callEvent("onPMContactRemove", user)
  355.  
  356.   def rcmd_block_list(self, args):
  357.     self._blocklist = set()
  358.     for name in args:
  359.       if name == "": continue
  360.       self._blocklist.add(User(name))
  361.  
  362.   def rcmd_idleupdate(self, args):
  363.     user = User(args[0])
  364.     if user in self._status:
  365.       last_on, is_on, idle = self._status[user]  
  366.     if args[1] == '1':
  367.       self._status[user] = [last_on, is_on, 0]
  368.     else:
  369.       self._status[user] = [last_on, is_on, time.time()]
  370.  
  371.   def rcmd_track(self, args):
  372.     user = User(args[0])
  373.     is_on = args[2]
  374.     if is_on == "online":
  375.       if args[1] == '0':
  376.         idle = 0
  377.       else:
  378.         idle = time.time() - float(args[1]) * 60
  379.       last_on = idle
  380.     else:
  381.       last_on = float(args[1])
  382.       idle = 0
  383.     self._status[user] = [last_on, is_on, idle]
  384.  
  385.   def rcmd_status(self, args):
  386.     user = User(args[0])
  387.     is_on = args[2]
  388.     if is_on == "online":
  389.       if args[1] == '0':
  390.         idle = 0
  391.       else:
  392.         idle = time.time() - float(args[1]) * 60
  393.       last_on = idle
  394.     else:
  395.       last_on = float(args[1])
  396.       idle = 0
  397.     self._status[user] = [last_on, is_on, idle]
  398.  
  399.   def rcmd_connect(self, args):
  400.     user = User(args[0])
  401.     is_on = args[2]
  402.     if is_on == "online":
  403.       if args[1] == '0':
  404.         idle = 0
  405.       else:
  406.         idle = time.time() - float(args[1]) * 60
  407.       last_on = idle
  408.     else:
  409.       last_on = float(args[1])
  410.       idle = 0
  411.     self._status[user] = [last_on, is_on, idle]
  412.  
  413.   def rcmd_DENIED(self, args):
  414.     self._disconnect()
  415.     self._callEvent("onLoginFail")
  416.  
  417.   def rcmd_msg(self, args):
  418.     user = User(args[0])
  419.     body = strip_html(":".join(args[5:]))
  420.     self._callEvent("onPMMessage", user, body)
  421.  
  422.   def rcmd_msgoff(self, args):
  423.     user = User(args[0])
  424.     body = strip_html(":".join(args[5:]))
  425.     self._callEvent("onPMOfflineMessage", user, body)
  426.  
  427.   def rcmd_wlonline(self, args):
  428.     user = User(args[0])
  429.     last_on = float(args[1])
  430.     self._status[user] = [last_on,"online",last_on]
  431.     self._callEvent("onPMContactOnline", user)
  432.  
  433.   def rcmd_wlapp(self, args):
  434.     user = User(args[0])
  435.     last_on = float(args[1])
  436.     self._status[user] = [last_on,"app",last_on]
  437.     self._callEvent("onPMContactApp", user)
  438.  
  439.   def rcmd_wloffline(self, args):
  440.     user = User(args[0])
  441.     last_on = float(args[1])
  442.     self._status[user] = [last_on,"offline",0]
  443.     self._callEvent("onPMContactOffline", user)
  444.  
  445.   def rcmd_premium(self, args):
  446.     if float(args[1]) > time.time():
  447.       self._premium = True
  448.       self.setBgMode(1)
  449.       self.setRecordingMode(1)
  450.     else:
  451.       self._premium = False
  452.  
  453.   def rcmd_kickingoff(self, args):
  454.     self.disconnect()
  455.  
  456.   def rcmd_toofast(self, args):
  457.     self.disconnect()
  458.  
  459.   def rcmd_unblocked(self, user):
  460.     if user in self._blocklist:
  461.       self._blocklist.remove(user)
  462.       self._callEvent("onPMUnblock", user)
  463.  
  464.   def ping(self):
  465.     self._sendCommand("")
  466.     self._callEvent("onPMPing")
  467.  
  468.   def message(self, user, msg):
  469.     if msg!=None:
  470.       msg = "<n%s/><m v=\"1\"><g x%ss%s=\"%s\">%s</g></m>" % (self._mgr.user.nameColor.lower(), self._mgr.user.fontSize, self._mgr.user.fontColor.lower(), self._mgr.user.fontFace, msg)
  471.       self._sendCommand("msg", user.name, msg)
  472.  
  473.   def addContact(self, user):
  474.     if user not in self._contacts:
  475.       self._sendCommand("wladd", user.name)
  476.  
  477.   def removeContact(self, user):
  478.     if user in self._contacts:
  479.       self._sendCommand("wldelete", user.name)
  480.  
  481.   def block(self, user):
  482.     if user not in self._blocklist:
  483.       self._sendCommand("block", user.name, user.name, "S")
  484.       self._blocklist.add(user)
  485.       self._callEvent("onPMBlock", user)
  486.  
  487.   def unblock(self, user):
  488.     if user in self._blocklist:
  489.       self._sendCommand("unblock", user.name)
  490.  
  491.   def setBgMode(self, mode):
  492.     self._sendCommand("msgbg", str(mode))
  493.  
  494.   def setRecordingMode(self, mode):
  495.     self._sendCommand("msgmedia", str(mode))
  496.  
  497.   def setIdle(self):
  498.     self._sendCommand("idle:0")
  499.  
  500.   def setActive(self):
  501.     self._sendCommand("idle:1")
  502.  
  503.   def rawTrack(self, user):
  504.     self._sendCommand("track", user.name)
  505.     data = self._websock.sock.recv()
  506.     self.ping()
  507.     self._feed(data)
  508.    
  509.   def track(self, user):
  510.     self.rawTrack(user)
  511.     data = self._status.get(user)
  512.     return data
  513.  
  514.   def checkOnline(self, user):
  515.     if user in self._status:
  516.       return self._status[user][1]
  517.     else:
  518.       return None
  519.  
  520.   def getIdle(self, user):
  521.     if not user in self._status: return None
  522.     if not self._status[user][1]: return 0
  523.     if not self._status[user][2]: return time.time()
  524.     else: return self._status[user][2]
  525.  
  526.   def _callEvent(self, evt, *args, **kw):
  527.     getattr(self.mgr, evt)(self, *args, **kw)
  528.     self.mgr.onEventCalled(self, evt, *args, **kw)
  529.      
  530.   def _sendCommand(self, *args):
  531.     try:
  532.         if self._firstCommand:
  533.           terminator = "\x00"
  534.           self._firstCommand = False
  535.         else:
  536.           terminator = "\r\n\x00"
  537.        
  538.         if self._wbuff != "" and self._connected:
  539.           self._websock.send(self._wbuff + "\r\n\x00")
  540.           self._wbuff = ""
  541.         self._websock.send(":".join(args) + terminator)
  542.     except:
  543.         self._wbuff += (":".join(args) + "\r\n\x00")
  544.    
  545.  
  546. class Room:
  547.   def __init__(self, room, uid = None, server = None, port = None, mgr = None):
  548.     self._name = room
  549.     self._server = server or getServer(room)
  550.     self._port = port or 8081 #1800/8080
  551.     self._mgr = mgr
  552.     self._firstCommand = True
  553.     self._connected = False
  554.     self._reconnecting = False
  555.     self._uid = uid or genUid()
  556.     self._channel = "0"
  557.     self._owner = None
  558.     self._mods = dict()
  559.     self._wbuff = ""
  560.     self._mqueue = dict()
  561.     self._mbqueue = dict()
  562.     self._history = list()
  563.     self._status = dict()
  564.     self._connectAmmount = 0
  565.     self._premium = False
  566.     self._userCount = 0
  567.     self._pingTask = None
  568.     self._users = dict()
  569.     self._msgs = dict()
  570.     self._silent = False
  571.     self._banlist = dict()
  572.     self._unbanlist = dict()
  573.     self._bannedwords = list()
  574.    
  575.     if self._mgr:
  576.       self._mgr._rooms[self.name] = self
  577.       self._connect()
  578.  
  579.   def on_message(self, ws, message):
  580.     #print(message)
  581.     self._feed(message)
  582.  
  583.   def on_error(self, ws, error):
  584.     print("room", self._name, error)
  585.     print(traceback.format_exc())
  586.  
  587.   def on_close(self, ws, close_status_code, close_msg):
  588.     print("room close", self._name, close_status_code, close_msg)
  589.     if close_status_code == 1006:
  590.       self.connect()
  591.      
  592.     self._callEvent("onDisconnect")
  593.  
  594.   def on_open(self, ws):
  595.     self._firstCommand = True
  596.     self._auth()
  597.     self._pingTask = self.mgr.setInterval(self.mgr._pingDelay, self.ping)
  598.  
  599.   def getMessage(self, mid):
  600.     return self._msgs.get(mid)
  601.  
  602.   def createMessage(self, msgid, **kw):
  603.     if msgid not in self._msgs:
  604.       msg = Message(msgid = msgid, **kw)
  605.       self._msgs[msgid] = msg
  606.     else:
  607.       msg = self._msgs[msgid]
  608.     return msg
  609.  
  610.   def connect(self):
  611.     self._connect()
  612.  
  613.   def _connect(self):
  614.     #websocket.enableTrace(True)
  615.     self._websock = websocket.WebSocketApp('wss://%s:%s/' % (self._server, self._port),
  616.                                            header = { "Pragma" : "no-cache", "Cache-Control" : "no-cache" },
  617.                                            on_open= self.on_open,
  618.                                            on_message=self.on_message,
  619.                                            on_error=self.on_error,
  620.                                            on_close=self.on_close)
  621.     kwargs = {"origin": "https://st.chatango.com", "reconnect": ReconnectingDelay}
  622.     #self._websock.run_forever(origin = "https://st.chatango.com", reconnect = ReconnectingDelay)
  623.     thread = threading.Thread(target=self._websock.run_forever, kwargs=kwargs)
  624.     thread.daemon = True
  625.     thread.start()
  626.      
  627.   def disconnect(self):
  628.     self._disconnect()
  629.  
  630.   def _disconnect(self):
  631.     self._connected = False
  632.     self._pingTask.cancel()
  633.     self._websock.close()
  634.     if not self._reconnecting:
  635.       if self.name in self.mgr._rooms:
  636.         del self.mgr._rooms[self.name]
  637.    
  638.   def _auth(self):
  639.     if self._mgr._name and self._mgr._password:
  640.       self._sendCommand("bauth", self._name, self._uid, self._mgr._name, self._mgr._password)
  641.     else:
  642.       self._sendCommand("bauth", self._name, self._uid)
  643.  
  644.      
  645.   def login(self, name, password=None):
  646.     if password != None:
  647.       self._sendCommand("blogin", name, password)
  648.     else:
  649.       self._sendCommand("blogin", name)
  650.  
  651.   def logout(self):
  652.     self._sendCommand("blogout")
  653.  
  654.   def getName(self): return self._name
  655.   def getManager(self): return self._mgr
  656.   def getUserlist(self):
  657.     ul = []
  658.     for data in self._status.values():
  659.       user = data[0]
  660.       if user not in ul:
  661.           ul.append(user)
  662.     return ul
  663.  
  664.   def _getUserlist(self):
  665.     ul = []
  666.     for data in self._status.values():
  667.       user = data[0]
  668.       if user.name[0] not in ["!", "#"]:
  669.         ul.append(user)
  670.     return ul
  671.    
  672.   def getUserNames(self):
  673.     ul = self.getUserlist()
  674.     return list(map(lambda x: x.name, ul))
  675.  
  676.   def getOwner(self): return self._owner
  677.   def getOwnerName(self): return self._owner.name
  678.   def getMods(self):
  679.     newset = set()
  680.     for mod in self._mods.keys():
  681.       newset.add(mod)
  682.     return newset
  683.   def getModNames(self):
  684.     mods = self._mods.keys()
  685.     newset = list()
  686.     for x in mods:
  687.       newset.append(x.name)
  688.     return newset
  689.   def getUserCount(self):
  690.     if self._userCount == 0:
  691.       return len(self.getUserlist())
  692.     else:
  693.       return self._userCount
  694.   def getSilent(self): return self._silent
  695.   def setSilent(self, val): self._silent = val
  696.   def getBanlist(self): return list(self._banlist.keys())
  697.   def getUnBanlist(self): return [(record["target"], record["src"]) for record in self._unbanlist.values()]
  698.   def getBannedWords(self): return self._bannedwords
  699.   def getFlags(self): return self._flags
  700.    
  701.   name = property(getName)
  702.   mgr = property(getManager)
  703.   userlist = property(getUserlist)
  704.   _userlist = property(_getUserlist)
  705.   usernames = property(getUserNames)
  706.   owner = property(getOwner)
  707.   ownername = property(getOwnerName)
  708.   mods = property(getMods)
  709.   modnames = property(getModNames)
  710.   usercount = property(getUserCount)
  711.   silent = property(getSilent, setSilent)
  712.   banlist = property(getBanlist)
  713.   unbanlist = property(getUnBanlist)
  714.   bannedwords = property(getBannedWords)
  715.   flags = property(getFlags)
  716.  
  717.   def _feed(self, data):
  718.     data = data.split("\x00")
  719.     for food in data:
  720.       self._process(food.rstrip("\r\n").replace("&#39;", "'"))
  721.      
  722.   def _process(self, data):
  723.     self._callEvent("onRaw", data)
  724.     data = data.split(":")
  725.     cmd, args = data[0], data[1:]
  726.     func = "rcmd_" + cmd
  727.     if hasattr(self, func):
  728.       getattr(self, func)(args)
  729.  
  730.   def rcmd_ok(self, args):
  731.     self._connected = True
  732.     self._attempt = 0
  733.     if args[2] == "C" and self._mgr._password == None and self._mgr._name == None:
  734.       n = args[4].rsplit('.', 1)[0]
  735.       n = n[-4:]
  736.       pid = args[1][0:8]
  737.       name = "!anon" + getAnonId(n, pid)
  738.       self._mgr.user._nameColor = n
  739.     elif args[2] == "C" and self._mgr._password == None:
  740.       self.login(self._mgr._name)
  741.     elif args[2] != "M":
  742.       self._callEvent("onLoginFail")
  743.       self.disconnect()
  744.     self._owner = User(args[0])
  745.     self._uid = args[1]
  746.     self._aid = args[1][4:8]
  747.     if len(args[6]) > 0:
  748.       self._mods = dict((x,y) for x, y in list(map(lambda x: (User(x.split(",")[0]), getFlag(int(x.split(",")[1]), ModeratorFlags)), args[6].split(";"))))
  749.     self._flags = getFlag(int(args[7]), RoomFlags)
  750.     self._i_log = list()
  751.  
  752.   def rcmd_groupflagsupdate(self, args):
  753.     old_flags = set(self._flags.items())
  754.     self._flags = getFlag(int(args[0]), RoomFlags)
  755.     new_flags = set(self._flags.items())
  756.     add_flags = new_flags - old_flags
  757.     if len(add_flags) > 0:
  758.       self._callEvent("onGroupFlagsAdded", dict(add_flags))
  759.      
  760.     remove_flags = old_flags - new_flags
  761.     if len(remove_flags) > 0:
  762.       self._callEvent("onGroupFlagsRemoved", dict(remove_flags))
  763.      
  764.     self._callEvent("onGroupFlagsUpdate")
  765.  
  766.   def rcmd_denied(self, args):
  767.     self._disconnect()
  768.     self._callEvent("onConnectFail")
  769.  
  770.   def rcmd_inited(self, args):
  771.     self._sendCommand("g_participants", "start")
  772.     self._sendCommand("getpremium", "1")
  773.     self._sendCommand("getbannedwords")
  774.     self._sendCommand("getratelimit")
  775.     self.requestBanlist()
  776.     self.requestUnBanlist()
  777.     if self._connectAmmount == 0:
  778.       self._callEvent("onConnect")
  779.       for msg in reversed(self._i_log):
  780.         user = msg.user
  781.         self._callEvent("onHistoryMessage", user, msg)
  782.         self._addHistory(msg)
  783.       del self._i_log
  784.     else:
  785.       self._callEvent("onReconnect")
  786.     self._connectAmmount += 1
  787.    
  788.  
  789.   def rcmd_getratelimit(self, args):
  790.     pass
  791.  
  792.   def rcmd_bw(self, args):
  793.     for word in args:
  794.       words = urllib.parse.unquote(word).split(",")
  795.       for word in words:
  796.         if word not in self._bannedwords and len(word) > 0:  
  797.             self._bannedwords.append(word)
  798.     bannedwords = self._bannedwords
  799.     self._callEvent("onBannedWordsUpdated", bannedwords)
  800.  
  801.   def rcmd_premium(self, args):
  802.     if float(args[1]) > time.time():
  803.       self._premium = True
  804.       if self._mgr.user._mbg: self.setBgMode(1)
  805.       if self._mgr.user._mrec: self.setRecordingMode(1)
  806.     else:
  807.       self._premium = False
  808.  
  809.   def rcmd_mods(self, args):
  810.     modnames = args
  811.     mods = dict((x, y) for x, y in list(map(lambda x: (User(x.split(",")[0]), getFlag(int(x.split(",")[1]), ModeratorFlags)), modnames)))
  812.     curmods = mods.keys()
  813.     premods = self._mods.keys()
  814.     for user in curmods - premods: #modded
  815.       self._callEvent("onModAdd", user)
  816.     for user in premods - curmods: #demodded
  817.       self._callEvent("onModRemove", user)
  818.     self._callEvent("onModChange")
  819.     self._mods = mods
  820.  
  821.   def rcmd_b(self, args):
  822.     mtime = float(args[0])
  823.     channel = args[7]
  824.     puid = args[3]
  825.     ip = args[6]
  826.     name = args[1]
  827.     rawmsg = ":".join(args[8:])
  828.     msg, n, f = clean_message(rawmsg)
  829.     if name == "":
  830.       nameColor = None
  831.       name = "#" + args[2]
  832.       if name == "#":
  833.         name = "!anon" + getAnonId(n, puid)
  834.     else:
  835.       if n: nameColor = parseNameColor(n)
  836.       else: nameColor = None
  837.     i = args[5]
  838.     unid = args[4]
  839.     user = User(name)
  840.     if puid:
  841.       user.updatePuid(puid)
  842.     if f: fontColor, fontFace, fontSize = parseFont(f)
  843.     else: fontColor, fontFace, fontSize = None, None, None
  844.     msg = Message(
  845.       time = mtime,
  846.       channel = channel,
  847.       user = user,
  848.       body = msg[1:],
  849.       raw = rawmsg[1:],
  850.       uid = puid,
  851.       ip = ip,
  852.       nameColor = nameColor,
  853.       fontColor = fontColor,
  854.       fontFace = fontFace,
  855.       fontSize = fontSize,
  856.       unid = unid,
  857.       room = self
  858.     )
  859.  
  860.     umsgid = self._mbqueue.get(i)
  861.     if umsgid:
  862.         if msg.user != self.mgr.user:
  863.           msg.user._fontColor = msg.fontColor
  864.           msg.user._fontFace = msg.fontFace
  865.           msg.user._fontSize = msg.fontSize
  866.           msg.user._nameColor = msg.nameColor
  867.  
  868.         del self._mbqueue[i]
  869.         self._channel = msg.channel  
  870.         self._callEvent("onMessage", msg.user, msg)
  871.         self._addHistory(msg)
  872.     else:
  873.         self._mqueue[i] = msg
  874.      
  875.   def rcmd_u(self, args):
  876.     msg = self._mqueue.get(args[0])
  877.     if msg:
  878.         if msg.user != self.mgr.user:
  879.           msg.user._fontColor = msg.fontColor
  880.           msg.user._fontFace = msg.fontFace
  881.           msg.user._fontSize = msg.fontSize
  882.           msg.user._nameColor = msg.nameColor
  883.          
  884.         del self._mqueue[args[0]]
  885.         msg.attach(self, args[1])
  886.         self._channel = msg.channel  
  887.         self._callEvent("onMessage", msg.user, msg)
  888.         self._addHistory(msg)
  889.     else:
  890.         self._mbqueue[args[0]] = args[1]
  891.  
  892.   def rcmd_i(self, args):
  893.     mtime = float(args[0])
  894.     channel = args[7]
  895.     puid = args[3]
  896.     ip = args[6]
  897.     if ip == "": ip = None
  898.     name = args[1]
  899.     rawmsg = ":".join(args[8:])
  900.     msg, n, f = clean_message(rawmsg)
  901.     msgid = args[5]
  902.     if name == "":
  903.       nameColor = None
  904.       name = "#" + args[2]
  905.       if name == "#":
  906.         name = "!anon" + getAnonId(n, puid)
  907.     else:
  908.       if n: nameColor = parseNameColor(n)
  909.       else: nameColor = None
  910.     if f: fontColor, fontFace, fontSize = parseFont(f)
  911.     else: fontColor, fontFace, fontSize = None, None, None
  912.     user = User(name)
  913.     if puid:
  914.       user.updatePuid(puid)
  915.     msg = self.createMessage(
  916.       msgid = msgid,
  917.       time = mtime,
  918.       channel = channel,
  919.       user = user,
  920.       body = msg,
  921.       raw = rawmsg,
  922.       ip = args[6],
  923.       unid = args[4],
  924.       nameColor = nameColor,
  925.       fontColor = fontColor,
  926.       fontFace = fontFace,
  927.       fontSize = fontSize,
  928.       room = self
  929.     )
  930.     self._i_log.append(msg)
  931.  
  932.   def rcmd_g_participants(self, args):
  933.     args = ":".join(args)
  934.     args = args.split(";")
  935.     for data in args:
  936.       data = data.split(":")
  937.       sid = data[0]
  938.       usertime = float(data[1])
  939.       name = data[3]
  940.       puid = data[2]
  941.       if name.lower() == "none":
  942.           n = str(int(usertime))[-4:]
  943.           if data[4].lower() == "none":
  944.             name = "!anon" + getAnonId(n, puid)
  945.           else:
  946.             name = "#" + data[4]
  947.       user = User(name)
  948.       if puid:
  949.         user.updatePuid(puid)
  950.       user.addSessionId(self, sid)
  951.  
  952.       if sid not in self._status:
  953.         self._status[sid] = [user, usertime, data[2], data[3], data[4]]
  954.  
  955.   def rcmd_participant(self, args):
  956.     name = args[3]
  957.     sid = args[1]
  958.     usertime = float(args[6])
  959.     puid = args[2]
  960.     if name.lower() == "none":
  961.       n = str(int(usertime))[-4:]
  962.       if args[4].lower() == "none":
  963.         name = "!anon" + getAnonId(n, puid)
  964.       else:
  965.         name = "#" + args[4]
  966.     user = User(name)
  967.     if puid:
  968.       user.updatePuid(puid)
  969.     if args[0] == "0": #leave
  970.       user.removeSessionId(self, sid)
  971.       if sid in self._status:
  972.         del self._status[sid]
  973.         self._callEvent("onLeave", user, puid)
  974.        
  975.     if args[0] == "1" or args[0] == "2": #join
  976.       user.addSessionId(self, sid)
  977.       self._status[sid] = [user, usertime, args[2], args[3], args[4]]
  978.       self._callEvent("onJoin", user, puid)
  979.  
  980.        
  981.   def rcmd_show_fw(self, args):
  982.     self._callEvent("onFloodWarning")
  983.  
  984.   def rcmd_show_tb(self, args):
  985.     self._callEvent("onFloodBan")
  986.  
  987.   def rcmd_tb(self, args):
  988.     self._callEvent("onFloodBanRepeat")
  989.  
  990.   def rcmd_delete(self, args):
  991.     msg = self.getMessage(args[0])
  992.     if msg:
  993.       if msg in self._history:
  994.         self._history.remove(msg)
  995.         self._callEvent("onMessageDelete", msg.user, msg)
  996.         msg.detach()
  997.  
  998.   def rcmd_deleteall(self, args):
  999.     for msgid in args:
  1000.       self.rcmd_delete([msgid])
  1001.  
  1002.   def rcmd_n(self, args):
  1003.     self._userCount = int(args[0], 16)
  1004.     self._callEvent("onUserCountChange")
  1005.  
  1006.   def rcmd_blocklist(self, args):
  1007.     self._banlist = dict()
  1008.     sections = ":".join(args).split(";")
  1009.     for section in sections:
  1010.       params = section.split(":")
  1011.       if len(params) != 5: continue
  1012.       if params[2] == "": continue
  1013.       user = User(params[2])
  1014.       self._banlist[user] = {
  1015.         "unid":params[0],
  1016.         "ip":params[1],
  1017.         "target":user,
  1018.         "time":float(params[3]),
  1019.         "src":User(params[4])
  1020.       }
  1021.     self._callEvent("onBanlistUpdate")
  1022.  
  1023.   def rcmd_unblocklist(self, args):
  1024.     self._unbanlist = dict()
  1025.     sections = ":".join(args).split(";")
  1026.     for section in sections:
  1027.       params = section.split(":")
  1028.       if len(params) != 5: continue
  1029.       if params[2] == "": continue
  1030.       user = User(params[2])
  1031.       self._unbanlist[user] = {
  1032.         "unid":params[0],
  1033.         "ip":params[1],
  1034.         "target":user,
  1035.         "time":float(params[3]),
  1036.         "src":User(params[4])
  1037.       }
  1038.     self._callEvent("onUnBanlistUpdate")
  1039.  
  1040.   def rcmd_blocked(self, args):
  1041.     try:
  1042.       msg = self.getLastMessageByIp(args[1])
  1043.       if args[2] == "":
  1044.         target = msg.user
  1045.       else:
  1046.         target = User(args[2])
  1047.       user = User(args[3])
  1048.       self._banlist[target] = {"unid":args[0], "ip":args[1], "target":target, "time":float(args[4]), "src":user}
  1049.       self._callEvent("onBan", user, target)
  1050.       self.requestBanlist()
  1051.     except Exception as e:
  1052.       print(e)
  1053.    
  1054.   def rcmd_unblocked(self, args):
  1055.     if args[2] == "": return
  1056.     target = User(args[2])
  1057.     user = User(args[3])
  1058.     try:
  1059.        del self._banlist[target]
  1060.     except:
  1061.       return
  1062.     self._unbanlist[user] = {"unid":args[0], "ip":args[1], "target":target, "time":float(args[4]), "src":user}
  1063.     self._callEvent("onUnban", user, target)
  1064.     self.requestUnBanlist()
  1065.  
  1066.   def ping(self):
  1067.     self._sendCommand("")
  1068.     self._callEvent("onPing")
  1069.  
  1070.   def rawMessage(self, channel, msg):
  1071.     msg = "<n" + self._mgr.user.nameColor + "/>" + msg
  1072.     msg = "<f x%0.2i%s=\"%s\">" %(self._mgr.user.fontSize, self._mgr.user.fontColor, self._mgr.user.fontFace) + msg
  1073.     if not self._silent:
  1074.       self._sendCommand("bm", "tl2r", channel, msg)
  1075.  
  1076.   def message(self, msg, html = False, channel = None):
  1077.     if msg == None:
  1078.       return
  1079.     if not html:
  1080.       msg = msg.replace("<", "&lt;").replace(">", "&gt;")
  1081.     if len(msg) > self.mgr._maxLength:
  1082.       if self.mgr._tooBigMessage == BigMessage_Cut:
  1083.         self.message(msg[:self.mgr._maxLength], html = html)
  1084.       elif self.mgr._tooBigMessage == BigMessage_Multiple:
  1085.         while len(msg) > 0:
  1086.           sect = msg[:self.mgr._maxLength]
  1087.           msg = msg[self.mgr._maxLength:]
  1088.           self.message(sect, html = html)
  1089.       return
  1090.     if channel == None:
  1091.         channel = self._channel
  1092.     self.rawMessage(channel, msg)
  1093.  
  1094.   def setBgMode(self, mode):
  1095.     self._sendCommand("msgbg", str(mode))
  1096.  
  1097.   def setRecordingMode(self, mode):
  1098.     self._sendCommand("msgmedia", str(mode))
  1099.  
  1100.   def addBadWord(self, word):
  1101.     if self.getLevel(self._mgr.user) == 2:
  1102.       self._bannedwords.append(word)
  1103.       self._sendCommand("setbannedwords", "403", ", ".join(self._bannedwords))
  1104.        
  1105.   def removeBadWord(self, word):
  1106.     if self.getLevel(self._mgr.user) == 2:
  1107.       self._bannedwords.remove(word)
  1108.       self._sendCommand("setbannedwords", "403", ", ".join(self._bannedwords))
  1109.  
  1110.   def addMod(self, user):
  1111.     if self.getLevel(self._mgr.user) == 2:
  1112.       self._sendCommand("addmod", user.name)
  1113.    
  1114.   def removeMod(self, user):
  1115.     if self.getLevel(self._mgr.user) == 2:
  1116.       self._sendCommand("removemod", user.name)
  1117.  
  1118.   def flag(self, message):
  1119.     self._sendCommand("g_flag", message.msgid)
  1120.  
  1121.   def flagUser(self, user):
  1122.     msg = self.getLastMessage(user)
  1123.     if msg:
  1124.       self.flag(msg)
  1125.       return True
  1126.     return False
  1127.  
  1128.   def delete(self, message):
  1129.     if self.getLevel(self._mgr.user) > 0:
  1130.       self._sendCommand("delmsg", message.msgid)
  1131.  
  1132.   def rawClearUser(self, unid, ip, user):
  1133.     self._sendCommand("delallmsg", unid, ip, user)
  1134.  
  1135.   def clearUser(self, user):
  1136.     if self.getLevel(self._mgr.user) > 0:
  1137.       msg = self.getLastMessage(user)
  1138.       if msg:
  1139.         if user.name[0] in ["!","#"]:
  1140.           username = ""
  1141.         else:
  1142.           username = user.name
  1143.         self.rawClearUser(msg.unid, msg.ip, username)
  1144.       return True
  1145.     return False
  1146.  
  1147.   def clearall(self):
  1148.     self._sendCommand("clearall")
  1149.     if self.getLevel(self._mgr.user) == 1:
  1150.       for msg in self._history:
  1151.         self.clearUser(msg.user)
  1152.     self._callEvent("onClearAll")
  1153.    
  1154.  
  1155.   def rawBan(self, name, ip, unid):
  1156.     self._sendCommand("block", unid, ip, name)
  1157.  
  1158.   def ban(self, msg):
  1159.     if self.getLevel(self._mgr.user) > 0:
  1160.       if msg.user.name[0] in ["!","#"]:
  1161.         username = ""
  1162.       else:
  1163.         username = msg.user.name
  1164.       self.rawBan(username, msg.ip, msg.unid)
  1165.  
  1166.   def banUser(self, user):
  1167.     msg = self.getLastMessage(user)
  1168.     if msg:
  1169.       self.ban(msg)
  1170.       return True
  1171.     return False
  1172.  
  1173.   def requestBanlist(self):
  1174.     self._sendCommand("blocklist", "block", "", "next", "500")
  1175.    
  1176.   def requestUnBanlist(self):
  1177.     self._sendCommand("blocklist", "unblock", "", "next", "500")
  1178.  
  1179.   def rawUnban(self, name, ip, unid):
  1180.     self._sendCommand("removeblock", unid, ip, name)
  1181.  
  1182.   def unban(self, user):
  1183.     rec = self._getBanRecord(user)
  1184.     if rec:
  1185.       self.rawUnban(rec["target"].name, rec["ip"], rec["unid"])
  1186.       return True
  1187.     else:
  1188.       return False
  1189.  
  1190.   def _getBanRecord(self, user):
  1191.     if user in self._banlist:
  1192.       return self._banlist[user]
  1193.     return None
  1194.  
  1195.   def _callEvent(self, evt, *args, **kw):
  1196.     getattr(self.mgr, evt)(self, *args, **kw)
  1197.     self.mgr.onEventCalled(self, evt, *args, **kw)
  1198.    
  1199.   def _sendCommand(self, *args):
  1200.     try:
  1201.         if self._firstCommand:
  1202.           terminator = "\x00"
  1203.           self._firstCommand = False
  1204.         else:
  1205.           terminator = "\r\n\x00"
  1206.        
  1207.         if self._wbuff != "" and self._connected:
  1208.           self._websock.send(self._wbuff + "\r\n\x00")
  1209.           self._wbuff = ""
  1210.         self._websock.send(":".join(args) + terminator)
  1211.     except:
  1212.         self._wbuff += (":".join(args) + "\r\n\x00")
  1213.      
  1214.    
  1215.   def getLevel(self, user):
  1216.     if user == self._owner: return 2
  1217.     if user in self._mods: return 1
  1218.     return 0
  1219.  
  1220.   def getBadge(self, msg):
  1221.     channel = int(msg.channel)
  1222.     badge = getFlag(channel, MessageFlags)
  1223.     if "SHOW_MOD_ICON" in badge.keys() or "SHOW_STAFF_ICON" in badge.keys():
  1224.       return 1
  1225.     else:
  1226.       return 0
  1227.  
  1228.   def getLastMessage(self, user = None):
  1229.     if user:
  1230.       try:
  1231.         i = 0
  1232.         while True:
  1233.           msg = self._history[-i]
  1234.           if msg.user == user:
  1235.             return msg
  1236.           i += 1
  1237.       except IndexError:
  1238.         return None
  1239.     else:
  1240.       try:
  1241.         return self._history[-1]
  1242.       except IndexError:
  1243.         return None
  1244.     return None
  1245.  
  1246.   def getLastMessageByIp(self, ip = None):
  1247.     if ip:
  1248.       try:
  1249.         i = 0
  1250.         while True:
  1251.           msg = self._history[-i]
  1252.           if msg.ip == ip:
  1253.             return msg
  1254.           i += 1
  1255.       except IndexError:
  1256.         return None
  1257.     else:
  1258.       try:
  1259.         return self._history[-1]
  1260.       except IndexError:
  1261.         return None
  1262.     return None
  1263.  
  1264.   def getLastMessageByMsgId(self, msgid = None):
  1265.     if msgid:
  1266.       try:
  1267.         i = 0
  1268.         while True:
  1269.           msg = self._history[-i]
  1270.           if msg.msgid == msgid:
  1271.             return msg
  1272.           i += 1
  1273.       except IndexError:
  1274.         return None
  1275.     else:
  1276.       try:
  1277.         return self._history[-1]
  1278.       except IndexError:
  1279.         return None
  1280.     return None
  1281.  
  1282.   def findUser(self, name):
  1283.     name = name.lower()
  1284.     ul = self.getUserlist()
  1285.     udi = dict(zip([u.name for u in ul], ul))
  1286.     cname = None
  1287.     for n in udi.keys():
  1288.       if n.find(name) != -1:
  1289.         if cname: return None
  1290.         cname = n
  1291.     if cname: return udi[cname]
  1292.     else: return None
  1293.  
  1294.   def _addHistory(self, msg):
  1295.     self._history.append(msg)
  1296.     if self.getBadge(msg) > 0:
  1297.       if msg.user not in self._mods.keys() and msg.user != self._owner:
  1298.         self._mods[msg.user] = {}
  1299.     if len(self._history) > self.mgr._maxHistoryLength:
  1300.       rest, self._history = self._history[:-self.mgr._maxHistoryLength], self._history[-self.mgr._maxHistoryLength:]
  1301.       for msg in rest:
  1302.         msg.detach()
  1303.  
  1304. class RoomManager:
  1305.   _Room = Room
  1306.   _PM = PM
  1307.   _PMHost = "c1.chatango.com"
  1308.   _PMPort = 8080 #1800/8080
  1309.   _pingDelay = 20
  1310.   _tooBigMessage = BigMessage_Multiple
  1311.   _maxLength = 2800
  1312.   _maxHistoryLength = 150
  1313.  
  1314.   def __init__(self, name = None, password = None, pm = True):
  1315.     self._name = name
  1316.     self._password = password
  1317.     self._tasks = set()
  1318.     self._rooms = dict()
  1319.     self._running = False
  1320.     if pm:
  1321.       conn = self._PM(mgr = self)
  1322.       self._pm = conn
  1323.     else:
  1324.       self._pm = None
  1325.  
  1326.   def joinThread(self, room):
  1327.     self._Room(room, mgr = self)
  1328.    
  1329.   def joinRoom(self, room):
  1330.     room = room.lower()
  1331.     if room not in self._rooms:
  1332.       self.joinThread(room)
  1333.  
  1334.   def leaveRoom(self, room):
  1335.     room = room.lower()
  1336.     if room in self._rooms:
  1337.       con = self._rooms[room]
  1338.       con.disconnect()
  1339.  
  1340.   def getRoom(self, room):
  1341.     room = room.lower()
  1342.     if room in self._rooms:
  1343.       return self._rooms[room]
  1344.     else:
  1345.       return None
  1346.  
  1347.   def getUser(self): return User(self._name)
  1348.   def getName(self): return self._name
  1349.   def getPassword(self): return self._password
  1350.   def getRooms(self): return set(self._rooms.values())
  1351.   def getRoomNames(self): return set(self._rooms.keys())
  1352.   def getPM(self): return self._pm
  1353.  
  1354.   user = property(getUser)
  1355.   name = property(getName)
  1356.   password = property(getPassword)
  1357.   rooms = property(getRooms)
  1358.   roomnames = property(getRoomNames)
  1359.   pm = property(getPM)
  1360.  
  1361.   def onInit(self):
  1362.     pass
  1363.  
  1364.   def onConnect(self, room):
  1365.     pass
  1366.  
  1367.   def onReconnect(self, room):
  1368.     pass
  1369.  
  1370.   def onConnectFail(self, room):
  1371.     pass
  1372.  
  1373.   def onDisconnect(self, room):
  1374.     pass
  1375.  
  1376.   def onLoginFail(self, room):
  1377.     pass
  1378.  
  1379.   def onGroupFlagsUpdate(self, room):
  1380.     pass
  1381.  
  1382.   def onGroupFlagsAdded(self, room, flags):
  1383.     pass
  1384.  
  1385.   def onGroupFlagsRemoved(self, room, flags):
  1386.     pass
  1387.  
  1388.   def onFloodBan(self, room):
  1389.     pass
  1390.  
  1391.   def onFloodBanRepeat(self, room):
  1392.     pass
  1393.  
  1394.   def onFloodWarning(self, room):
  1395.     pass
  1396.  
  1397.   def onMessageDelete(self, room, user, message):
  1398.     pass
  1399.  
  1400.   def onModChange(self, room):
  1401.     pass
  1402.  
  1403.   def onModAdd(self, room, user):
  1404.     pass
  1405.    
  1406.   def onClearAll(self, room):
  1407.     pass
  1408.  
  1409.   def onModRemove(self, room, user):
  1410.     pass
  1411.  
  1412.   def onMessage(self, room, user, message):
  1413.     pass
  1414.  
  1415.   def onBannedWordsUpdated(self, room, words):
  1416.     pass
  1417.  
  1418.   def onHistoryMessage(self, room, user, message):
  1419.     pass
  1420.  
  1421.   def onJoin(self, room, user, puid):
  1422.     pass
  1423.  
  1424.   def onLeave(self, room, user, puid):
  1425.     pass
  1426.  
  1427.   def onRaw(self, room, raw):
  1428.     pass
  1429.  
  1430.   def onPing(self, room):
  1431.     pass
  1432.  
  1433.   def onUserCountChange(self, room):
  1434.     pass
  1435.  
  1436.   def onBan(self, room, user, target):
  1437.     pass
  1438.  
  1439.   def onUnban(self, room, user, target):
  1440.     pass
  1441.  
  1442.   def onBanlistUpdate(self, room):
  1443.     pass
  1444.  
  1445.   def onUnBanlistUpdate(self, room):
  1446.     pass
  1447.  
  1448.   def onPMConnect(self, pm):
  1449.     pass
  1450.  
  1451.   def onPMReconnect(self, pm):
  1452.     pass
  1453.  
  1454.   def onPMDisconnect(self, pm):
  1455.     pass
  1456.  
  1457.   def onPMPing(self, pm):
  1458.     pass
  1459.  
  1460.   def onPMMessage(self, pm, user, body):
  1461.     pass
  1462.  
  1463.   def onPMOfflineMessage(self, pm, user, body):
  1464.     pass
  1465.  
  1466.   def onPMContactlistReceive(self, pm):
  1467.     pass
  1468.  
  1469.   def onPMBlocklistReceive(self, pm):
  1470.     pass
  1471.  
  1472.   def onPMContactAdd(self, pm, user):
  1473.     pass
  1474.  
  1475.   def onPMContactRemove(self, pm, user):
  1476.     pass
  1477.  
  1478.   def onPMBlock(self, pm, user):
  1479.     pass
  1480.  
  1481.   def onPMUnblock(self, pm, user):
  1482.     pass
  1483.  
  1484.   def onPMContactOnline(self, pm, user):
  1485.     pass
  1486.  
  1487.   def onPMContactApp(self, pm, user):
  1488.     pass
  1489.  
  1490.   def onPMContactOffline(self, pm, user):
  1491.     pass
  1492.  
  1493.   def onEventCalled(self, room, evt, *args, **kw):
  1494.     pass
  1495.    
  1496.   class _Task:
  1497.     def cancel(self):
  1498.       self.mgr.removeTask(self)
  1499.  
  1500.   def _tick(self):
  1501.     now = time.time()
  1502.     for task in set(self._tasks):
  1503.       if task.target <= now:
  1504.         task.func(*task.args, **task.kw)
  1505.         if task.isInterval:
  1506.           task.target = now + task.timeout
  1507.         else:
  1508.           self._tasks.remove(task)
  1509.  
  1510.   def setTimeout(self, timeout, func, *args, **kw):
  1511.     task = self._Task()
  1512.     task.mgr = self
  1513.     task.target = time.time() + timeout
  1514.     task.timeout = timeout
  1515.     task.func = func
  1516.     task.isInterval = False
  1517.     task.args = args
  1518.     task.kw = kw
  1519.     self._tasks.add(task)
  1520.     return task
  1521.  
  1522.   def setInterval(self, timeout, func, *args, **kw):
  1523.     task = self._Task()
  1524.     task.mgr = self
  1525.     task.target = time.time() + timeout
  1526.     task.timeout = timeout
  1527.     task.func = func
  1528.     task.isInterval = True
  1529.     task.args = args
  1530.     task.kw = kw
  1531.     self._tasks.add(task)
  1532.     return task
  1533.  
  1534.   def removeTask(self, task):
  1535.     self._tasks.remove(task)
  1536.  
  1537.   @classmethod
  1538.   def easy_start(cl, rooms = None, name = None, password = None, pm = True):
  1539.     if not rooms: rooms = str(input("Room names separated by semicolons: ")).split(";")
  1540.     if len(rooms) == 1 and rooms[0] == "": rooms = []
  1541.     if name == None: name = str(input("User name: "))
  1542.     if name == "" or " " in name: name = None
  1543.     if password == None: password = str(input("User password: "))
  1544.     if password == "": password = None
  1545.     if name == None or password == None: pm = False
  1546.     self = cl(name, password, pm = pm)
  1547.     self.rooms_copy = rooms
  1548.     if len(self.rooms_copy)>0:
  1549.       for room in self.rooms_copy:
  1550.         self.joinRoom(room)
  1551.  
  1552.     if len(rooms) > 0 or (name != None and password != None):
  1553.       self.main()
  1554.  
  1555.   def main(self):
  1556.     self.onInit()
  1557.     self._running = True
  1558.     while self._running:
  1559.       self._tick()
  1560.       time.sleep(1)
  1561.      
  1562.      
  1563.   def stop(self):
  1564.     self._running = False
  1565.     conns = list(self._rooms.values())
  1566.     if self.pm:
  1567.       conns.append(self.pm)
  1568.     for conn in conns:
  1569.       conn.disconnect()
  1570.  
  1571.   def enableBg(self):
  1572.     self.user._mbg = True
  1573.     for room in self.rooms:
  1574.       room.setBgMode(1)
  1575.  
  1576.   def disableBg(self):
  1577.     self.user._mbg = False
  1578.     for room in self.rooms:
  1579.       room.setBgMode(0)
  1580.  
  1581.   def enableRecording(self):
  1582.     self.user._mrec = True
  1583.     for room in self.rooms:
  1584.       room.setRecordingMode(1)
  1585.  
  1586.   def disableRecording(self):
  1587.     self.user._mrec = False
  1588.     for room in self.rooms:
  1589.       room.setRecordingMode(0)
  1590.  
  1591.   def setNameColor(self, color3x):
  1592.     self.user._nameColor = color3x
  1593.  
  1594.   def setFontColor(self, color3x):
  1595.     self.user._fontColor = color3x
  1596.  
  1597.   def setFontFace(self, face):
  1598.     self.user._fontFace = face
  1599.  
  1600.   def setFontSize(self, size):
  1601.     if size < 9: size = 9
  1602.     if size > 22: size = 22
  1603.     self.user._fontSize = size
  1604.  
  1605.  
  1606. _users = dict()
  1607. def User(name):
  1608.   if name == None: name = ""
  1609.   user = _users.get(name.lower())
  1610.   if not user:
  1611.     user = _User(name)
  1612.     _users[name.lower()] = user
  1613.   return user
  1614.  
  1615. class _User:
  1616.   def __init__(self, name):
  1617.     self._name = name.lower()
  1618.     self._raw = name
  1619.     self._puid = ""
  1620.     self._sids = dict()
  1621.     self._msgs = list()
  1622.     self._nameColor = "000"
  1623.     self._fontSize = 12
  1624.     self._fontFace = "0"
  1625.     self._fontColor = "000"
  1626.     self._mbg = False
  1627.     self._mrec = False
  1628.  
  1629.   def getName(self): return self._name
  1630.   def getRaw(self): return self._raw
  1631.   def getPuid(self): return self._puid
  1632.   def getSessionIds(self, room = None):
  1633.     if room:
  1634.       return self._sids.get(room, set())
  1635.     else:
  1636.       return set.union(*self._sids.values())
  1637.   def getRooms(self): return self._sids.keys()
  1638.   def getRoomNames(self): return [room.name for room in self.getRooms()]
  1639.   def getFontColor(self): return self._fontColor
  1640.   def getFontFace(self): return self._fontFace
  1641.   def getFontSize(self): return self._fontSize
  1642.   def getNameColor(self): return self._nameColor
  1643.  
  1644.   name = property(getName)
  1645.   raw = property(getRaw)
  1646.   puid = property(getPuid)
  1647.   sids = property(getSessionIds)
  1648.   rooms = property(getRooms)
  1649.   roomnames = property(getRoomNames)
  1650.   fontColor = property(getFontColor)
  1651.   fontFace = property(getFontFace)
  1652.   fontSize = property(getFontSize)
  1653.   nameColor = property(getNameColor)
  1654.  
  1655.   def addSessionId(self, room, sid):
  1656.     if room not in self._sids:
  1657.       self._sids[room] = set()
  1658.     self._sids[room].add(sid)
  1659.  
  1660.   def removeSessionId(self, room, sid):
  1661.     try:
  1662.       self._sids[room].remove(sid)
  1663.       if len(self._sids[room]) == 0:
  1664.         del self._sids[room]
  1665.     except KeyError:
  1666.       pass
  1667.  
  1668.   def clearSessionIds(self, room):
  1669.     try:
  1670.       del self._sids[room]
  1671.     except KeyError:
  1672.       pass
  1673.  
  1674.   def hasSessionId(self, room, sid):
  1675.     try:
  1676.       if sid in self._sids[room]:
  1677.         return True
  1678.       else:
  1679.         return False
  1680.     except KeyError:
  1681.       return False
  1682.  
  1683.   def updatePuid(self, puid):
  1684.     self._puid = puid
  1685.  
  1686.   def __repr__(self):
  1687.     return "<User: %s>" %(self.name)
  1688.  
  1689. class Message:
  1690.   def attach(self, room, msgid):
  1691.     if self._msgid == None:
  1692.       self._room = room
  1693.       self._msgid = msgid
  1694.       self._room._msgs[msgid] = self
  1695.  
  1696.   def detach(self):
  1697.     if self._msgid != None and self._msgid in self._room._msgs:
  1698.       del self._room._msgs[self._msgid]
  1699.       self._msgid = None
  1700.  
  1701.   def __init__(self, **kw):
  1702.     self._msgid = None
  1703.     self._time = None
  1704.     self._channel = None
  1705.     self._user = None
  1706.     self._body = None
  1707.     self._room = None
  1708.     self._raw = ""
  1709.     self._ip = None
  1710.     self._unid = ""
  1711.     self._nameColor = "000"
  1712.     self._fontSize = 12
  1713.     self._fontFace = "0"
  1714.     self._fontColor = "000"
  1715.     for attr, val in kw.items():
  1716.       if val == None: continue
  1717.       setattr(self, "_" + attr, val)
  1718.  
  1719.   def getId(self): return self._msgid
  1720.   def getTime(self): return self._time
  1721.   def getChannel(self): return self._channel
  1722.   def getUser(self): return self._user
  1723.   def getBody(self): return self._body
  1724.   def getUid(self): return self._uid
  1725.   def getIP(self): return self._ip
  1726.   def getFontColor(self): return self._fontColor
  1727.   def getFontFace(self): return self._fontFace
  1728.   def getFontSize(self): return self._fontSize
  1729.   def getNameColor(self): return self._nameColor
  1730.   def getRoom(self): return self._room
  1731.   def getRaw(self): return self._raw
  1732.   def getUnid(self): return self._unid
  1733.  
  1734.   msgid = property(getId)
  1735.   time = property(getTime)
  1736.   channel = property(getChannel)
  1737.   user = property(getUser)
  1738.   body = property(getBody)
  1739.   uid = property(getUid)
  1740.   room = property(getRoom)
  1741.   ip = property(getIP)
  1742.   fontColor = property(getFontColor)
  1743.   fontFace = property(getFontFace)
  1744.   fontSize = property(getFontSize)
  1745.   raw = property(getRaw)
  1746.   nameColor = property(getNameColor)
  1747.   unid = property(getUnid)
  1748.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement