Advertisement
Guest User

chatango.py

a guest
Dec 8th, 2010
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 29.46 KB | None | 0 0
  1. import re
  2. import sys
  3. import time
  4. import queue
  5. import random
  6. import socket
  7. import _thread
  8. import urllib.parse
  9. import html.entities
  10. import urllib.request
  11.  
  12. class InvalidCredentials(Exception): pass
  13. class KickedOff(Exception): pass
  14. class NotConnected(Exception): pass
  15.  
  16. # -----------------------------------------------------
  17. # User class for holding user data in PMs and chatrooms
  18. # -----------------------------------------------------
  19.  
  20. class chuser:
  21.     ANON = 0
  22.     TEMP = 1
  23.     REGD = 2
  24.    
  25.     def __init__(self, username="", uid=None, umid=None, session=None, logintime=None, type=None, ip=None, ts=None):
  26.         '''Holds user data information. displayname gives the person's
  27.         username with the same capitalization as they typed in when
  28.         they logged in. username returns their username in lowercase.
  29.         You really don't need to worry about the rest.'''
  30.         self._username = username
  31.         self._ts = ts
  32.         self.uid = int(uid) if uid != None else self._get_uid()
  33.         self.umid = umid
  34.         self.session = int(session) if session != None else session
  35.         self.logintime = float(logintime) if logintime != None else logintime
  36.         self.type = type
  37.         self.ip = ip
  38.     displayname = property(lambda x: x._username if (x.type == x.TEMP or x.type == x.REGD) else _anon_name(x.uid, x._ts))
  39.     username = property(lambda x: x.displayname.lower(), lambda x, y: setattr(x, "_username", y))
  40.        
  41.     @staticmethod
  42.     def _get_uid():
  43.         return random.randrange(1000000000000000, 10000000000000000)
  44.  
  45. # -----------------------------------
  46. # Empty shiz for holding message data
  47. # -----------------------------------
  48.  
  49. class chmessage:
  50.     HISTORY = 0
  51.     NEW = 1
  52.     def __init__(self, **kwargs):
  53.         # This should hold: posttime, user, content, formatted, mid, umid, index
  54.         for keyword in kwargs:
  55.             setattr(self, keyword, kwargs[keyword])
  56.  
  57. # ---------
  58. # PMS CLASS
  59. # ---------
  60.  
  61. class pms:
  62.     def __init__(self, username, password):
  63.         self._username = username
  64.         self._password = password
  65.         self._connected = False
  66.         self._reconnected = False
  67.         self._logintime = time.time()
  68.    
  69.     # ------------------
  70.      # Interface methods
  71.    
  72.     def login(self):
  73.         '''Login to PMs.'''
  74.         # Get the auth token
  75.         self._auth = _get_auth(self._username, self._password)
  76.         if not self._auth:
  77.             raise InvalidCredentials
  78.         else:
  79.             self._connected = True
  80.  
  81.         # Connect to chatango
  82.         self._sock = socket.socket()
  83.         self._sock.connect(("s2.chatango.com", 443))
  84.        
  85.         # Login
  86.         self._send("tlogin", self._auth, 2, chuser._get_uid())
  87.        
  88.         # Set some personal shiz up
  89.         self._q = queue.Queue()
  90.         self._buffer = b''
  91.        
  92.         # Start shit
  93.         _thread.start_new_thread(self._ping, ())
  94.         _thread.start_new_thread(self._main, ())
  95.        
  96.         # Yay, nothing bad happened
  97.         return True
  98.    
  99.     def disconnect(self):
  100.         '''Disconnect from PMs.'''
  101.         self._connected = False
  102.         self._sock.close()
  103.  
  104.     def send(self, username, msg):
  105.         '''Send msg to username.'''
  106.         if isinstance(username, chuser):
  107.             username = username.username
  108.         msg = _to_str(msg).split("\n")
  109.         msg = "<P>" + "</P><P>".join(msg) + "</P>"
  110.         msg = re.sub("\t", " \x01 \x01 \x01 \x01", msg)
  111.         self._send("msg", username, msg)
  112.    
  113.     def add_friend(self, username):
  114.         '''Add someone to your friends list.'''
  115.         self._send("connect", username.lower())
  116.    
  117.     def remove_friend(self, username):
  118.         '''Remove someone from your friends list.'''
  119.         self._send("delete", username.lower())
  120.    
  121.     def block(self, username):
  122.         '''Block a user.'''
  123.         self._send("block", username.lower())
  124.    
  125.     def unblock(self, username):
  126.         '''Unblock a blocked user.'''
  127.         self._send("unblock", username.lower())
  128.    
  129.     def get_event(self):
  130.         '''Wait for the next event from pms. Events are
  131.         dictionaries with an "event" key holding 1 of 3 values:
  132.         "message", "login" or "logout".
  133.        
  134.         They have the following format:
  135.        
  136.         {
  137.             "event": "message",
  138.             "message": <class 'ch.chmessage'>,
  139.             "pms": <class 'ch.pms'>,
  140.             "reply": <function <lambda>>
  141.         }
  142.         {
  143.             "event": "login",
  144.             "username": username,
  145.             "pms": <class 'ch.pms'>,
  146.             "reply": <function <lambda>>
  147.         }
  148.         {
  149.             "event": "logout",
  150.             "username": username,
  151.             "pms": <class 'ch.pms'>,
  152.             "reply": <function <lambda>>
  153.         }'''
  154.         if not self._connected:
  155.             raise NotConnected
  156.         return self._q.get(timeout=1000000)
  157.    
  158.     # ---------------
  159.      # Helper methods
  160.    
  161.     def _ping(self):
  162.         time.sleep(60)
  163.         while self._connected:
  164.             self._send("")
  165.             time.sleep(60)
  166.    
  167.     def _main(self):
  168.         while self._connected:
  169.             event, args = self._recv()
  170.             try:
  171.                 self._handle(event, args)
  172.             except Exception as details:
  173.                 print(_get_tb())
  174.    
  175.     def _recv(self):
  176.         if not self._connected:
  177.             raise NotConnected
  178.         while self._buffer.startswith(b'\x00'):
  179.             self._buffer = self._buffer[1:]
  180.         while not b'\x00' in self._buffer:
  181.             successful = False
  182.             while not successful:
  183.                 dc_count = 0
  184.                 next = self._sock.recv(8192)
  185.                 if next == b'':
  186.                     dc_count += 1
  187.                     if dc_count > 5:
  188.                         self._reconnect()
  189.                         continue
  190.                 self._buffer += next
  191.                 successful = True
  192.         buffer = self._buffer.split(b'\x00')
  193.         data = b'\r\n'
  194.         while data == b'\r\n':
  195.             data = buffer.pop(0)
  196.         data = data.strip(b'\r\n').decode()
  197.         self._buffer = b'\x00'.join(buffer)
  198.         event = data.split(":")[0]
  199.         args = data.split(":")[1:]
  200.         if _DEBUG: print("PMS <<", data.encode())
  201.         return [event, args]
  202.    
  203.     def _send(self, *args, terminator="\r\n\x00"):
  204.         if not self._connected:
  205.             raise NotConnected
  206.         args = ":".join([_to_str(x) for x in args])
  207.         args += terminator
  208.         args = args.encode()
  209.         sent = False
  210.         while not sent:
  211.             try:
  212.                 self._sock.send(args)
  213.             except:
  214.                 self._reconnect()
  215.             else:
  216.                 sent = True
  217.         if _DEBUG: print("PMS >>", args)
  218.    
  219.     def _reconnect(self):
  220.         # Get the auth token
  221.         self._auth = _get_auth(self._username, self._password)
  222.        
  223.         # If the password has changed, gracefully exit, mimicking a Kicked-Off
  224.         if not self._auth:
  225.             self.diconnect()
  226.             raise KickedOff
  227.        
  228.         # Connect to chatango
  229.         self._sock = socket.socket()
  230.         self._sock.connect(("s2.chatango.com", 443))
  231.        
  232.         # Login
  233.         self._send("tlogin", self._auth, 2, self._user.uid)
  234.        
  235.         # Handle incoming messages differently, now
  236.         self._reconnected = True
  237.         self._buffer = b''
  238.    
  239.     # ------------------
  240.      # PMS Event Handler
  241.    
  242.     def _handle(self, event, args):
  243.         if event == "time":
  244.             self._logintime = float(args[0])
  245.         elif event == "seller_name":
  246.             username, self._uid = args
  247.             self._uid = int(self._uid)
  248.         elif event == "kickingoff":
  249.             raise KickedOff
  250.         elif event == "wloffline":
  251.             username, logintime = args
  252.             logintime = float(logintime)
  253.             self._q.put({"event": "logout", "username": username, "pms": self, "reply": lambda x: self.send(username, x)})
  254.         elif event == "wlonline":
  255.             username, logintime = args
  256.             logintime = float(logintime)
  257.             self._q.put({"event": "login", "username": username, "pms": self, "reply": lambda x: self.send(username, x)})
  258.         elif event == "msg" or (event == "msgoff" and self._reconnected == True):
  259.             username, anon_uid, unknown, posttime, pro = args[:5]
  260.             if username.startswith("*"):
  261.                 user_type = chuser.ANON
  262.                 username = "anon" + anon_uid[-4:]
  263.             else:
  264.                 user_type = chuser.REGD
  265.             posttime = float(posttime)
  266.             raw = ":".join(args[5:])
  267.             content = re.sub("</P><P>", "\n", raw)
  268.             content = re.sub("<[^>]+>", "", content)
  269.             msg = chmessage(posttime=posttime, formatted=raw, content=content, user=chuser(username=username, type=user_type))
  270.             self._q.put({"event": "message", "message": msg, "pms": self, "reply": lambda x: self.send(username, x)})
  271.  
  272. class chatroom:
  273.     def __init__(self, name):
  274.         self.name = name.lower()
  275.         self._mods = ()
  276.         self._user = chuser()
  277.         self._premium = False
  278.         self._buffer = b''
  279.         self._online = []
  280.         self._history = []
  281.         self._noid_messages = {}
  282.         self._bw_regx = []
  283.         self._connected = False
  284.         self._reconnected = False
  285.         self._ignore_messages = {}
  286.         self.server = "s%i.chatango.com" % _get_server_num(self.name)
  287.         # Register some default settings
  288.         self.obey_badwords()
  289.         self.keep_history(100)
  290.         self.silent(False)
  291.         self._font = {}
  292.     font = property(lambda x: '<n%s/><f x%s%s="%s">' % (x._font.get("name") or "", x._font.get("size") or "", x._font.get("color") or "", _font_family.get(x._font.get("family")) or ""))
  293.    
  294.     # -------------------
  295.      # Connection methods
  296.    
  297.     def login(self, username=None, password=None):
  298.         '''Login to the chatroom with the given credentials.
  299.         If you provide:
  300.        
  301.         username, password - Login as a registered user
  302.         username - Login with a temporary anon name
  303.         zilch - Login as an anon'''
  304.         if self._connected:
  305.             self.logout()
  306.         self._user.username = username
  307.         self._user.password = password
  308.        
  309.         # Set the user type
  310.         if username and password:
  311.             self._user.type = chuser.REGD
  312.         elif username:
  313.             self._user.type = chuser.TEMP
  314.         else:
  315.             self._user.type = chuser.ANON
  316.  
  317.         if self._connected and self._user.username and self._user.password:
  318.             self._send("blogin", self._user.displayname, self._user.password)
  319.         elif self._connected and self._user.username:
  320.             self._send("blogin", self._user.displayname)
  321.         elif not self._connected:
  322.             # Login for the first time
  323.             self._sock = socket.socket()
  324.             self._sock.connect((self.server, 443))
  325.             self._connected = True
  326.            
  327.             # Send the login info
  328.             if self._user.username and self._user.password:
  329.                 self._send("bauth", self.name, self._user.uid, self._user.displayname, self._user.password, terminator="\x00")
  330.             else:
  331.                 self._send("bauth", self.name, terminator="\x00")
  332.            
  333.             # Set some personal shiz up
  334.             self._session = random.randrange(10000,100000)
  335.             self._q = queue.Queue()
  336.            
  337.             # Wait to get inited
  338.             event = None
  339.             while event != "inited":
  340.                 event, args = self._recv()
  341.                 self._handle(event, args)
  342.            
  343.             # Start shit
  344.             _thread.start_new_thread(self._ping, (self._session,))
  345.             _thread.start_new_thread(self._main, ())
  346.            
  347.         # Yay, nothing bad happened
  348.         return True
  349.    
  350.     def logout(self):
  351.         '''Logout. Go anon. Troll and shit.'''
  352.         self._send("blogout")
  353.    
  354.     def disconnect(self):
  355.         '''Disconnect from the chatroom.'''
  356.         self._connected = False
  357.         self._sock.close()
  358.    
  359.     def get_event(self):
  360.         '''Wait for the next event from the chatroom. Events
  361.         are dictionaries with an "event" key holding 1 of 4 values:
  362.         "message", "login", "logout" or "nickchange".
  363.        
  364.         They have the following format:
  365.        
  366.         {
  367.             "event": "message",
  368.             "message": <class 'ch.chmessage'>,
  369.             "room": <class 'ch.chatroom'>,
  370.             "reply": <function <lambda>>
  371.         }
  372.         {
  373.             "event": "login",
  374.             "username": username,
  375.             "user": <class 'ch.chuser'>,
  376.             "room": <class 'ch.chatroom'>,
  377.             "reply": <function <lambda>>
  378.         }
  379.         {
  380.             "event": "logout",
  381.             "username": username,
  382.             "user": <class 'ch.chuser'>,
  383.             "room": <class 'ch.chatroom'>,
  384.             "reply": <function <lambda>>
  385.         }
  386.         {
  387.             "event": "nickchange",
  388.             "old": <class 'ch.chuser'>,
  389.             "new": <class 'ch.chuser'>,
  390.             "room": <class 'ch.chatroom'>,
  391.             "reply": <function <lambda>>
  392.         }'''
  393.         if not self._connected:
  394.             raise NotConnected
  395.         return self._q.get(timeout=1000000)
  396.    
  397.     # ----------------------------
  398.      # Interface with the chatroom
  399.    
  400.     def say(self, msg, raw=True):
  401.         '''Say something in the chatroom. If the raw option is True,
  402.         html tags are embedded, else they are escaped.'''
  403.         if not self._silenced:
  404.             if not raw:
  405.                 msg = msg.replace("<", "&lt;")
  406.             if self._obey_badwords:
  407.                 for word in self._bw_regx:
  408.                     msg = re.sub(word, "*", msg, re.IGNORECASE)
  409.             if self._user.type == chuser.REGD:
  410.                 self._send("bmsg", self.font + _to_str(msg))
  411.             else:
  412.                 self._send("bmsg", _to_str(msg))
  413.    
  414.     def find_user(self, key, online=True, history=True):
  415.         '''Finds a user based on the lambda function key. Optionally
  416.         search the list of online users and/or the message history.'''
  417.         matches = []
  418.         if online:
  419.             for user in self._online:
  420.                 if key(user):
  421.                     matches.append(user)
  422.         if history:
  423.             for msg in self._history:
  424.                 if key(msg.user):
  425.                     matches.append(msg.user)
  426.         return matches
  427.    
  428.     def is_online(self, username):
  429.         '''Search the online list for a registered user.'''
  430.         username.lower()
  431.         if self.find_user(lambda x: x.username == username and x.type == chuser.REGD):
  432.             return True
  433.         else:
  434.             return False
  435.    
  436.     def is_mod(self, username=None):
  437.         '''See if a person is a mod in the chatroom. If no argument is
  438.         provided, return whether or not the logged in user is a mod.'''
  439.         if username == None and self._user.type == chuser.REGD:
  440.             username = self._user.username
  441.         elif not username:
  442.             return False
  443.         return bool(username.lower() in self._mods)
  444.  
  445.     def get_history(self, user):
  446.         '''Takes a chuser object and returns that person's history
  447.         in the chatroom.'''
  448.         matches = []
  449.         for msg in self._history:
  450.             if msg.user.type == chuser.REGD and msg.user.username == user.username:
  451.                 matches.append(msg)
  452.             elif msg.user.type == chuser.ANON and user.uid and msg.user.uid == user.uid:
  453.                 matches.append(msg)
  454.             elif msg.user.type == chuser.TEMP and user.uid and [msg.user.uid, msg.user.username, msg.user.type] == [user.uid, user.username, user.type]:
  455.                 matches.append(msg)
  456.         return matches
  457.    
  458.     # ------------------
  459.      # Moderator methods
  460.    
  461.     def ban(self, user):
  462.         '''Takes a chuser object as an argument. And bans them. Derp.'''
  463.         self._send("block", user.umid if user.umid else "", user.ip if user.ip else "", user.username)
  464.  
  465.    
  466.     def unban(self, user):
  467.         '''Under contruction. Kinda low priority. Leave faggots banned.'''
  468.         if type(user)==type(""):
  469.             self._send("removeblock", "", "", user)
  470.         else:
  471.             self._send("removeblock", user.umid if user.umid else "", user.ip if user.ip else "", user.username)
  472.  
  473.    
  474.     def delete(self, msg):
  475.         '''Takes a chmessage object as an argument, and deletes that
  476.         single message.'''
  477.         self._send("delmsg", msg.mid)
  478.    
  479.     def deleteall(self, username):
  480.         '''Delete all posts made by someone with the given username.'''
  481.         username = username.lower()
  482.         matches = self.find_user(lambda x: x.username == username)
  483.         for match in matches:
  484.             self._send("delallmsg", match.umid)
  485.    
  486.     # -------------------------
  487.      # Manipulate room settings
  488.    
  489.     def keep_history(self, size):
  490.         '''Control the number of messages to keep in the room's history.'''
  491.         size = int(size)
  492.         if size < 10:
  493.             size = 10
  494.         self._history_limit = size
  495.    
  496.     def obey_badwords(self, value=True):
  497.         '''Control whether or not you can avoid word filters.'''
  498.         self._obey_badwords = bool(value)
  499.    
  500.     def silent(self, mode=True):
  501.         '''Set whether or not say() works. For turning off bots.'''
  502.         self._silenced = bool(mode)
  503.    
  504.     def ignore(self, keyname, key):
  505.         '''Add a function to be applied to new messages.
  506.         If the function returns True, the message is ignored.
  507.        
  508.         Ex: ignore("anons", lambda x: x.user.type == chuser.ANON)'''
  509.         if key != None and isinstance(key, type(lambda x: None)):
  510.             self._ignore_messages[keyname] = key
  511.    
  512.     def unignore(self, keyname):
  513.         '''Provide a keyname associated with an ignore function
  514.         to stop applying that function to incoming messages.'''
  515.         try:
  516.             self._ignore_messages.pop(keyname)
  517.         except:
  518.             pass
  519.    
  520.     def set_font(self, size=None, family=None, color=None, name=None):
  521.         '''Independently or simultaneously set the size, family,
  522.         and color of the font to be displayed. Color and name must
  523.         be html color codes.'''
  524.         if isinstance(size, int):
  525.             if self._premium and size > 22:
  526.                 size = 22
  527.             elif not self._premium and size > 14:
  528.                 size = 14
  529.         if size != None: self._font["size"] = size
  530.         if name != None: self._font["name"] = color
  531.         if color != None: self._font["color"] = color
  532.         if family != None: self._font["family"] = family
  533.    
  534.     def use_bg(self, value=True):
  535.         '''Turn your background on or off.'''
  536.         if self._premium:
  537.             self._send("msgbg", 1 if bool(value) else 0)
  538.             return True
  539.         return False
  540.    
  541.     def set_bg(self, color="000000", image=None, transparency=None):
  542.         '''Set your background. The color must be an html color code.
  543.         The image parameter takes a boolean to turn the picture off or on.
  544.         Transparency is a float less than one or an integer between 1-100.'''
  545.         if self._premium:
  546.             if color and len(color) == 1:
  547.                 color = color*6
  548.             if color and len(color) == 3:
  549.                 color += color
  550.             elif color and len(color) != 6:
  551.                 return False
  552.             if transparency != None and abs(transparency) > 1:
  553.                 transparency = abs(transparency) / 100
  554.             # Get the original settings
  555.             letter1 = self._user.username[0]
  556.             letter2 = self._user.username[1] if len(self._user.username) > 1 else self._user.username[0]
  557.             data = urllib.request.urlopen("http://fp.chatango.com/profileimg/%s/%s/%s/msgbg.xml" % (letter1, letter2, self._user.username)).read().decode()
  558.             data = dict([x.replace('"', '').split("=") for x in re.findall('(\w+=".*?")', data)[1:]])
  559.             # Add the necessary shiz
  560.             data["p"] = self._user.password
  561.             data["lo"] = self._user.username
  562.             if color: data["bgc"] = color
  563.             if transparency != None: data["bgalp"] = abs(transparency) * 100
  564.             if image != None: data["useimg"] = 1 if bool(image) else 0
  565.             # Send the request
  566.             data = urllib.parse.urlencode(data)
  567.             try:
  568.                 urllib.request.urlopen("http://chatango.com/updatemsgbg", data).read()
  569.             except:
  570.                 return False
  571.             else:
  572.                 self._send("miu")
  573.                 return True
  574.    
  575.     # ---------------
  576.      # Helper methods
  577.    
  578.     def _ping(self, session):
  579.         time.sleep(60)
  580.         while self._connected and session == self._session:
  581.             self._send("")
  582.             time.sleep(60)
  583.    
  584.     def _main(self):
  585.         while self._connected:
  586.             event, args = self._recv()
  587.             try:
  588.                 self._handle(event, args)
  589.             except Exception as details:
  590.                 print(_get_tb())
  591.    
  592.     def _recv(self):
  593.         if not self._connected:
  594.             raise NotConnected
  595.         while self._buffer.startswith(b'\x00'):
  596.             self._buffer = self._buffer[1:]
  597.         while not b'\x00' in self._buffer:
  598.             successful = False
  599.             while not successful:
  600.                 dc_count = 0
  601.                 try:
  602.                     next = self._sock.recv(8192)
  603.                 except socket.error:
  604.                     if self._connected:
  605.                         self._reconnect()
  606.                     else:
  607.                         return [None, None]
  608.                 if next == b'':
  609.                     dc_count += 1
  610.                     if dc_count > 5:
  611.                         self._reconnect()
  612.                         continue
  613.                 self._buffer += next
  614.                 successful = True
  615.         buffer = self._buffer.split(b'\x00')
  616.         data = b'\r\n'
  617.         while data == b'\r\n':
  618.             data = buffer.pop(0)
  619.         data = data.strip(b'\r\n').decode()
  620.         self._buffer = b'\x00'.join(buffer)
  621.         event = data.split(":")[0]
  622.         args = data.split(":")[1:]
  623.         if _DEBUG: print(self.name, "<<", data.encode())
  624.         return [event, args]
  625.    
  626.     def _send(self, *args, terminator="\r\n\x00"):
  627.         if not self._connected:
  628.             raise NotConnected
  629.         args = ":".join([_to_str(x) for x in args])
  630.         args += terminator
  631.         args = args.encode()
  632.         sent = False
  633.         while not sent:
  634.             try:
  635.                 self._sock.send(args)
  636.             except:
  637.                 self._reconnect()
  638.             else:
  639.                 sent = True
  640.         if _DEBUG: print(self.name, ">>", args)
  641.        
  642.     def _reconnect(self):
  643.         # Start a new connection
  644.         self._sock = socket.socket()
  645.         self._sock.connect((self.server, 443))
  646.        
  647.         # Send the login info
  648.         if self._user.username and self._user.password:
  649.             self._send("bauth", self.name, self._user.uid, self._user.username, self._user.password)
  650.         else:
  651.             self._send("bauth", self.name, terminator="\x00")
  652.        
  653.         # Handle messages differently evermore
  654.         self._reconnected = True
  655.        
  656.         # Wait to get inited
  657.         event = None
  658.         while event != "inited":
  659.             event, args = self._recv()
  660.             self._handle(event, args)
  661.    
  662.     def _add_history(self, msg):
  663.         if self._reconnected and msg.type == chmessage.HISTORY:
  664.             # Go through the list and make sure that this message doesn't already exist
  665.             append = True
  666.             for message in self._history:
  667.                 if msg.mid == message.mid:
  668.                     append = False
  669.             if append:
  670.                 msg.type = chmessage.NEW
  671.                 self._history.append(msg)
  672.                 self._history = sorted(self._history, key=lambda x: x.posttime)
  673.             else:
  674.                 return
  675.         else:
  676.             self._history.append(msg)
  677.         if msg.type == chmessage.HISTORY:
  678.             self._history = sorted(self._history, key=lambda x: x.posttime)
  679.         if msg.type == chmessage.NEW:
  680.             addq = True
  681.             for key in self._ignore_messages:
  682.                 func = self._ignore_messages.get(key)
  683.                 if func(msg):
  684.                     addq = False
  685.                     break
  686.             if addq:
  687.                 self._q.put({"event": "message", "message": msg, "room": self, "reply": lambda x: self.say(x)})
  688.         if len(self._history) > self._history_limit:
  689.             self._history = self._history[-self._history_limit:]
  690.    
  691.     # -----------------------
  692.      # Chatroom Event Handler
  693.    
  694.     def _handle(self, event, args):
  695.         if event == "ok":
  696.             self._connected = True
  697.             self.admin = args[0]
  698.             self._user.uid = int(args[1])
  699.             self._user.logintime = float(args[4])
  700.             self._user.ip = args[5]
  701.             self._mods = args[6].split(";")
  702.            
  703.             if args[2] == "M":
  704.                 self._user.type = chuser.REGD
  705.             elif args[2] == "C":
  706.                 self._user.type = chuser.TEMP
  707.             elif args[2] == "N":
  708.                 self._user.type = chuser.ANON
  709.         elif event == "denied":
  710.             self.disconnect()
  711.         elif event == "inited":
  712.             # Set up full name alerts and shit
  713.             self._send("g_participants:start")
  714.             # Get updated with the list of badwords
  715.             self._send("getbannedwords")
  716.             self._send("checkbannedwords")
  717.             # Check for premium status
  718.             self._send("getpremium", 1)
  719.             # Log in with a temp name if need be
  720.             if self._user.type == chuser.TEMP:
  721.                 self._send("blogin", self._user.displayname)
  722.         elif event == "pwdok":
  723.             self._user.type = chuser.REGD
  724.             self._send("getpremium", 1)
  725.         elif event == "aliasok":
  726.             self._user.type = chuser.TEMP
  727.             self._send("getpremium", 1)
  728.         elif event == "logoutok":
  729.             self._user.type = chuser.ANON
  730.             self._send("getpremium", 1)
  731.         elif event =="show_fw" or event == "show_tb":
  732.             self._reconnect()
  733.         elif event == "ubw":
  734.             self._send("getbannedwords")
  735.         elif event == "bw":
  736.             bw = args[1]
  737.             if not bw:
  738.                 self.badwords = []
  739.             else:
  740.                 bw = urllib.parse.unquote(bw)
  741.                 bw = bw.strip(",").split(",")
  742.                 self.badwords = bw
  743.                 special_chars = "\\.^$*+?{}[]|()"
  744.                 self._bw_regx = []
  745.                 for x in range(0, len(self.badwords)):
  746.                     word = self.badwords[x]
  747.                     for char in special_chars:
  748.                         word = word.replace(char, "\\" + char)
  749.                     self._bw_regx.append(word)
  750.         elif event == "premium":
  751.             if args[1] != '0':
  752.                 self._premium = True
  753.             else:
  754.                 self._premium = False
  755.         elif event == "n":
  756.             self.size = int(args[0], 16)
  757.         elif event == "mods":
  758.             self._mods = args
  759.         elif event == "b" or event == "i":
  760.             posttime, reg_name, tmp_name, uid, umid, index, ip, x = args[:8]
  761.             msg = ":".join(args[8:])
  762.             ts = re.findall("^<n(\d+)/>", msg)
  763.             ts = ts[0] if ts else ""
  764.            
  765.             if reg_name == tmp_name == "":
  766.                 user_type = chuser.ANON
  767.                 username = ""
  768.             elif reg_name == "":
  769.                 user_type = chuser.TEMP
  770.                 username = tmp_name
  771.             else:
  772.                 user_type = chuser.REGD
  773.                 username = reg_name
  774.            
  775.             plaintext = re.sub("<[^>]+>", "", msg)
  776.             plaintext = _unescape(plaintext)
  777.            
  778.             u = chuser(username=username, uid=uid, umid=umid, ip=ip, type=user_type, ts=ts)
  779.             msg = chmessage(posttime=posttime, formatted=msg, content=plaintext, umid=umid, index=index, user=u)
  780.            
  781.             if event == "b":
  782.                 msg.type = chmessage.NEW
  783.                 self._noid_messages[msg.index] = msg
  784.             elif event == "i":
  785.                 msg.type = chmessage.HISTORY
  786.                 del msg.index
  787.                 msg.mid = index
  788.                 self._add_history(msg)
  789.         elif event == "u":
  790.             index, mid = args
  791.             msg = self._noid_messages.get(index)
  792.             if msg:
  793.                 self._noid_messages.pop(msg.index)
  794.                 msg.mid = mid
  795.                 self._add_history(msg)
  796.         elif event == "g_participants":
  797.             args = ":".join(args)
  798.             args = args.split(";")
  799.             for infoz in args:
  800.                 session, logintime, uid, reg_name, tmp_name, null = infoz.split(":")
  801.                
  802.                 # Determine the user type before doing anything else, reducing unecessary overhead
  803.                 if reg_name == tmp_name == "None":
  804.                     user_type = chuser.ANON
  805.                     username = ""
  806.                 elif reg_name == "None":
  807.                     user_type = chuser.TEMP
  808.                     username = tmp_name
  809.                 else:
  810.                     user_type = chuser.REGD
  811.                     username = reg_name
  812.                
  813.                 if user_type == chuser.REGD:
  814.                     u = chuser(session=session, uid=uid, logintime=logintime, username=username, type=user_type)
  815.                     self._online.append(u)
  816.         elif event == "participant":
  817.             p_event, session, uid, reg_name, tmp_name, ip, logintime = args
  818.             session = int(session)
  819.            
  820.             # Determine the user type before doing anything else, reducing unecessary overhead
  821.             if reg_name == tmp_name == "None":
  822.                 user_type = chuser.ANON
  823.                 username = ""
  824.             elif reg_name == "None":
  825.                 user_type = chuser.TEMP
  826.                 username = tmp_name
  827.             else:
  828.                 user_type = chuser.REGD
  829.                 username = reg_name
  830.            
  831.             u = chuser(session=session, uid=uid, username=username, type=user_type, logintime=logintime, ip=ip)
  832.            
  833.             if p_event == "0":
  834.                 # The user logged out
  835.                 for user_ in self._online:
  836.                     if user_.session == session:
  837.                         self._online.remove(user_)
  838.                         if user_.type == chuser.REGD:
  839.                             self._q.put({"event": "logout", "username": u.username, "user": u, "room": self, "reply": lambda x: self.say(x)})
  840.             elif p_event == "1":
  841.                 # The user logged in
  842.                 self._online.append(u)
  843.                 if u.type == chuser.REGD:
  844.                     self._q.put({"event": "login", "username": u.username, "user": u, "room": self, "reply": lambda x: self.say(x)})
  845.             elif p_event == "2":
  846.                 for user_ in self._online:
  847.                     if user_.session == session:
  848.                         self._online.remove(user_)
  849.                         self._online.append(u)
  850.                         self._q.put({"event": "nickchange", "old": user_, "new": u, "room": self, "reply": lambda x: self.say(x)})
  851.  
  852. # --------------
  853. # HELPER METHODS
  854. # --------------
  855.  
  856. def _anon_name(uid, ts=None):
  857.     uid = str(uid)[4:8]
  858.     aid = ""
  859.     ts = ts or "3452"
  860.     for x in range(0, len(uid)):
  861.         v4 = int(uid[x:x + 1])
  862.         v3 = int(ts[x:x + 1])
  863.         v2 = str(v4 + v3)
  864.         aid += v2[len(v2) - 1:]
  865.     return "Anon" + aid
  866.  
  867. def _get_server_num(name):
  868.     roomname = name.lower()
  869.     server = _server_weights['specials'].get(roomname)
  870.    
  871.     if not server:
  872.         roomname = "q".join(roomname.split("_"))
  873.         roomname = "q".join(roomname.split("-"))
  874.         base36 = int(roomname[0:min(5, len(roomname))], 36)
  875.         r10 = roomname[6:(6 + (min(3, (len(roomname) - 5))))]
  876.  
  877.         try:
  878.             r7 = int(r10, 36)
  879.         except:
  880.             r7 = 1000
  881.         else:
  882.             if r7 <= 1000: r7 = 1000
  883.        
  884.         r4 = 0
  885.         r5 = {}
  886.         r6 = sum([x[1] for x in _server_weights["weights"]])
  887.        
  888.         for x in range(0, len(_server_weights["weights"])):
  889.             r4 = r4 + _server_weights["weights"][x][1] / r6
  890.             r5[_server_weights["weights"][x][0]] = r4
  891.        
  892.         for x in range(0, len(_server_weights["weights"])):
  893.             if ((base36 % r7 / r7) <= r5[_server_weights["weights"][x][0]]):
  894.                 server = _server_weights["weights"][x][0];
  895.                 break
  896.    
  897.     return int(server)
  898.  
  899. def _get_auth(username, password):     
  900.     data = urllib.parse.urlencode({'user_id' : username, 'password' : password, 'storecookie' : 'on', 'checkerrors' : 'yes'})
  901.     while 1:
  902.         try:
  903.             headers = urllib.request.urlopen('http://chatango.com/login', data).headers.items()
  904.         except:
  905.             continue
  906.         else:
  907.             break
  908.     auth = None
  909.     for header in headers:
  910.         if header[0] == 'Set-Cookie' and header[1].startswith('auth.chatango.com'):
  911.             auth = header[1].split('=')[1].split(';')[0]
  912.     if not auth:
  913.         return None
  914.     else:
  915.         return auth
  916.  
  917. def _unescape(text):
  918.     text = text.replace("&apos;", "'")
  919.     text = text.replace("&quot;", '"')
  920.     text = text.replace("&amp;", "&")
  921.     def fixup(m):
  922.         text = m.group(0)
  923.         if text[:2] == "&#":
  924.             # character reference
  925.             try:
  926.                 if text[:3] == "&#x":
  927.                     return chr(int(text[3:-1], 16))
  928.                 else:
  929.                     return chr(int(text[2:-1]))
  930.             except ValueError:
  931.                 pass
  932.         else:
  933.             # named entity
  934.             try:
  935.                 text = chr(html.entities.name2codepoint[text[1:-1]])
  936.             except KeyError:
  937.                 pass
  938.         return text # leave as is
  939.     return re.sub("&#?\w+;", fixup, text)
  940.  
  941. def _to_str(obj):
  942.     '''Manipulate any data type to safely be a string'''
  943.     if isinstance(obj, bytes):
  944.         obj = obj.decode()
  945.     return str(obj)
  946.  
  947. def _get_tb():
  948.     try:
  949.         et, ev, tb = sys.exc_info()
  950.     except Exception as details:
  951.         print(details)
  952.     if not tb: return None
  953.     while tb:
  954.         line_no = tb.tb_lineno
  955.         fn = tb.tb_frame.f_code.co_filename
  956.         tb = tb.tb_next
  957.     try:
  958.         return "%s: %i: %s(%s)" % (fn, line_no, et.__name__, str(ev))
  959.     except Exception as details:
  960.         print(details)
  961.  
  962. def debug(value):
  963.     global _DEBUG
  964.     _DEBUG = bool(value)
  965.  
  966. _DEBUG = True
  967. _server_weights = {'specials': {'mitvcanal': 26, 'spaceshuttle': 18, 'livenfree': 18, 'animalog24': 8, 'bleachmedia': 19, 'desiplug7': 18, 'freelivesportsonline': 22, 'pinoy-online-tv-chat': 22, 'animeready': 10, 'narutowire': 10, 'anivide2': 19, 'cebicheros': 21, 'direttacalcio2010': 18, 'chia-anime': 12, 'narutochatt': 20, 'bvls-chat1': 22, 'stream2watch3': 26, 'baterixat': 21, 'ver-anime': 34, 'fezzer': 18, 'extracovernet': 22, 'worldfootballusch2': 18, 'soccerjumbo': 21, 'myfoxdfw': 22, 'eplsite': 22, 'animelinkz': 20, 'worldfootballdotus': 26, 'as-chatroom': 10, 'flowhot-chat-online': 12, 'watch-dragonball': 19, 'tvanimefreak': 27}, 'weights': [['5', 61], ['6', 61], ['7', 61], ['8', 61], ['16', 61], ['17', 61], ['9', 90], ['11', 90], ['13', 90], ['14', 90], ['15', 90], ['23', 110], ['24', 110], ['25', 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]]}
  968. _font_family = {"arial": "0", "comic": "1", "georgia": "2", "handwriting": "3", "impact": "4", "palatino": "5", "papyrus": "6", "times": "7", "typewriter": "8"}
  969. _font_family_nums = {'1': 'comic', '0': 'arial', '3': 'handwriting', '2': 'georgia', '5': 'palatino', '4': 'impact', '7': 'times', '6': 'papyrus', '8': 'typewriter'}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement