Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import ch
- import curses
- import thread
- import sys
- import base64
- import random
- # Chatango client by MegaLoler
- # Chatango library by Lumirayz
- # Version 0.2
- activeRoom = None
- generalBuffer = []
- contents = ["", "", ""]
- focus = 1
- raw = False
- disguise = "lol"
- screen = curses.initscr()
- curses.noecho()
- curses.start_color()
- HELP_MSG = "Press TAB to switch between the three text feilds at the bottom. Type in room names on the left to connect to rooms. Once connected, type in messages in the middle. Type in private messages on the right. To toggle between open rooms press \"`\". To toggle between private message recipients press \"~\". The selected recipient will be highlighted in red. Type /commands in the middle when connected to a room to get a list of commands that you can use. Press ESC twice to exit the client."
- size = screen.getmaxyx()
- WIDTH = size[1]
- HEIGHT = size[0]
- HALF = WIDTH / 2
- QUARTER = WIDTH / 4
- RED = 1
- YELLOW = 2
- GREEN = 3
- CYAN = 4
- BLUE = 5
- MAGENTA = 6
- NORMAL = 7
- SECRET = 8
- curses.init_pair(RED, curses.COLOR_RED, curses.COLOR_BLACK)
- curses.init_pair(YELLOW, curses.COLOR_YELLOW, curses.COLOR_BLACK)
- curses.init_pair(GREEN, curses.COLOR_GREEN, curses.COLOR_BLACK)
- curses.init_pair(CYAN, curses.COLOR_CYAN, curses.COLOR_BLACK)
- curses.init_pair(BLUE, curses.COLOR_BLUE, curses.COLOR_BLACK)
- curses.init_pair(MAGENTA, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
- curses.init_pair(NORMAL, curses.COLOR_WHITE, curses.COLOR_BLACK)
- curses.init_pair(SECRET, curses.COLOR_BLACK, curses.COLOR_WHITE)
- def printLine(string, color=NORMAL):
- generalBuffer.append((string, color))
- while len(generalBuffer) > HEIGHT - 3: del generalBuffer[0]
- def addMessage(string, color=NORMAL):
- for string in string.split("\n"):
- buf = ""
- for i in string:
- buf += i
- if len(buf) >= HALF:
- printLine(buf, color)
- buf = ""
- if buf != "": printLine(buf, color)
- if activeRoom == None:
- drawChat()
- screen.refresh()
- def hexToDec(h):
- h = h.lower()
- if h == "f":
- return 15
- elif h == "e":
- return 14
- elif h == "d":
- return 13
- elif h == "c":
- return 12
- elif h == "b":
- return 11
- elif h == "a":
- return 10
- else:
- try:
- return int(h)
- except:
- return 0
- def hexToAnsi(col):
- if col[0] == "#": col = col[1:]
- if len(col) == 3:
- r = hexToDec(col[0])
- g = hexToDec(col[1])
- b = hexToDec(col[2])
- elif len(col) == 6:
- r = hexToDec(col[0])
- g = hexToDec(col[2])
- b = hexToDec(col[4])
- else:
- return NORMAL
- r = r > 7
- g = g > 7
- b = b > 7
- if r and g and b:
- return NORMAL
- if r and g:
- return YELLOW
- if g and b:
- return CYAN
- if r and b:
- return MAGENTA
- if r:
- return RED
- if g:
- return GREEN
- if b:
- return BLUE
- else:
- return NORMAL
- def printLineR(r, string, color=NORMAL):
- r.chatBuffer.append((string, color))
- while len(r.chatBuffer) > HEIGHT - 3: del r.chatBuffer[0]
- def addMessageR(r, string, color=NORMAL):
- for string in string.split("\n"):
- buf = ""
- for i in string:
- buf += i
- if len(buf) >= HALF:
- printLineR(r, buf, color)
- buf = ""
- if buf != "": printLineR(r, buf, color)
- if activeRoom == r:
- drawChat()
- screen.refresh()
- else:
- r.new = True
- drawRooms()
- screen.refresh()
- def logMessage(message):
- f = open("log.raw", "a")
- f.write(message.user.name + ": " + message.raw + "\n")
- f.close()
- def secretEncrypt(message, k):
- message = k + message
- message = base64.b64encode(message)
- insert = base64.b64encode(k*len(k))[:-2]
- location = random.randint(1, len(message))
- first = message[:location]
- if location == len(message):
- last = ""
- else:
- last = message[location:]
- message = first + insert + last
- message = base64.b64encode(message + k)
- return message
- def secretDecrypt(message, k):
- m = message
- try:
- message = base64.b64decode(message)[:-len(k)]
- insert = base64.b64encode(k*len(k))[:-2]
- location = message.find(insert)
- first = message[:location]
- if location == len(message):
- last = ""
- else:
- last = message[location + len(insert):]
- message = first + last
- message = base64.b64decode(message)
- if message.startswith(k):
- return message[len(k):]
- else:
- raise Exception
- except:
- return "ERROR DECRYPTING: " + m
- def checkSecret(room, user, message):
- if message.raw.find("<msg=\"") == -1: return
- msg = message.raw.split("<msg=\"")[1]
- msg2 = ""
- p = None
- for char in msg:
- if char == "\"" and p != "\\": break
- if char == "\\":
- if p == "\\": msg2 += char
- else:
- msg2 += char
- p = char
- addMessageR(room, user.name + ": " + secretDecrypt(msg2, user.name.lower()), SECRET)
- class RoomManager(ch.RoomManager):
- def onHistoryMessage(self, room, user, message):
- checkSecret(room, user, message)
- addMessageR(room, user.name + ": " + message.body, hexToAnsi(message.fontColor))
- drawFields()
- screen.refresh()
- def onMessage(self, room, user, message):
- logMessage(message)
- checkSecret(room, user, message)
- addMessageR(room, user.name + ": " + message.body, hexToAnsi(message.fontColor))
- drawFields()
- screen.refresh()
- def onPMMessage(self, pm, user, body):
- addMessageR(room, "@" + NICK + ": " + user.name + ": " + body, NORMAL)
- drawFields()
- screen.refresh()
- def onLeave(self, room, user):
- addMessageR(room, user.name + " left the room.")
- drawOnline()
- drawFields()
- screen.refresh()
- def onJoin(self, room, user):
- addMessageR(room, user.name + " entered the room.")
- drawOnline()
- drawFields()
- screen.refresh()
- def onConnect(self, room):
- addMessageR(room, "You have connected to " + room.name + ".")
- drawFields()
- screen.refresh()
- def onUserCountChange(self, room):
- drawOnline()
- screen.refresh()
- def centerString(string, length):
- off = length - len(string)
- if off > 0:
- l = off / 2
- if off % 2:
- r = l + 1
- else:
- r = l
- return " " * l + string + " " * r
- elif off < 0:
- return string[:length]
- def leftString(string, length):
- if len(string) > length:
- return string[:length]
- else:
- off = length - len(string)
- return string + " " * off
- def rightString(string, length):
- if len(string) > length:
- return string[:length]
- else:
- off = length - len(string)
- return string + off * " "
- def fieldString(string, length):
- if len(string) > length:
- return string[-length:]
- else:
- off = length - len(string)
- return string + off * " "
- def fieldLength(string, length):
- if len(string) > length:
- return length
- else:
- return len(string)
- def drawRooms():
- y = 0
- for y in range(len(chatango.roomnames)):
- if y >= HEIGHT - 2: break
- room = list(chatango.roomnames)[y]
- if chatango.getRoom(room).new:
- attr = curses.color_pair(YELLOW) | curses.A_BOLD
- else:
- attr = curses.color_pair(NORMAL)
- if room == activeRoom.name: attr |= curses.A_REVERSE
- screen.addstr(y + 1, 0, leftString(room, QUARTER), attr)
- if len(chatango.roomnames) > 0: y += 1
- while y < HEIGHT - 2:
- screen.addstr(y + 1, 0, leftString("", QUARTER), curses.color_pair(NORMAL))
- y += 1
- def drawOnline():
- if not activeRoom:
- users = []
- else:
- users = sorted(activeRoom.usernames)
- y = 0
- for y in range(len(users)):
- if y >= HEIGHT - 2: break
- nick = users[y]
- if activeRoom and activeRoom.activeUser == users[y]:
- attr = curses.color_pair(RED) | curses.A_REVERSE
- else:
- attr = curses.color_pair(NORMAL)
- if nick == activeRoom.name: attr |= curses.A_REVERSE
- screen.addstr(y + 1, HALF + QUARTER, rightString(nick, QUARTER), attr)
- if len(users) > 0: y += 1
- while y < HEIGHT - 2:
- screen.addstr(y + 1, HALF + QUARTER, rightString("", QUARTER), curses.color_pair(NORMAL))
- y += 1
- def drawChat():
- if not activeRoom:
- chatBuffer = generalBuffer
- else:
- chatBuffer = activeRoom.chatBuffer
- y = 0
- for y in range(len(chatBuffer)):
- if y >= HEIGHT - 3: break
- message = chatBuffer[y]
- screen.addstr(y + 1, QUARTER, leftString(message[0], HALF), curses.color_pair(message[1]))
- if len(chatBuffer) > 0: y += 1
- while y < HEIGHT - 3:
- screen.addstr(y + 1, QUARTER, leftString("", HALF), curses.color_pair(NORMAL))
- y += 1
- def drawField(y, x, content, width, selected, color=NORMAL):
- attr = curses.color_pair(color)
- if selected: attr |= curses.A_REVERSE
- screen.addstr(y, x, fieldString(content, width), attr)
- if selected:
- return (y, x + fieldLength(content, width))
- else:
- return None
- def drawFields():
- if activeRoom:
- color = hexToAnsi(chatango.user.fontColor)
- else:
- color = NORMAL
- f1 = drawField(HEIGHT - 1, 0, contents[0], QUARTER - 1, focus == 0)
- f2 = drawField(HEIGHT - 1, QUARTER, contents[1], HALF - 1, focus == 1, color)
- f3 = drawField(HEIGHT - 1, HALF + QUARTER, contents[2], QUARTER - 1, focus == 2, color)
- if f1:
- screen.move(f1[0], f1[1])
- elif f2:
- screen.move(f2[0], f2[1])
- elif f3:
- screen.move(f3[0], f3[1])
- def drawHeaders():
- screen.addstr(0, 0, centerString("ROOMS", QUARTER), curses.color_pair(NORMAL) | curses.A_REVERSE)
- screen.addstr(0, QUARTER, centerString("CHATANGO", HALF), curses.color_pair(NORMAL) | curses.A_REVERSE)
- screen.addstr(0, HALF + QUARTER, centerString("ONLINE", QUARTER), curses.color_pair(NORMAL) | curses.A_REVERSE)
- def drawContent():
- drawRooms()
- drawOnline()
- drawChat()
- def drawInterface():
- drawHeaders()
- drawContent()
- drawFields()
- screen.refresh()
- def alreadyConnected(room):
- chatango.getRoom(room)
- def switchRoom(room):
- global activeRoom
- activeRoom = room
- room.new = False
- drawContent()
- drawHeaders()
- def hide(message, hidden):
- if hidden:
- return "*" * len(message)
- else:
- return message
- def dialogue(prompt, hidden=False):
- screen.border(0)
- screen.addstr(HEIGHT / 2, HALF - len(prompt), prompt)
- screen.refresh()
- RESULT = ""
- while True:
- c = screen.getch()
- if c == 10 and RESULT != "":
- RESULT = RESULT.strip()
- break
- elif c == 127:
- if RESULT != "": RESULT = RESULT[:-1]
- screen.addstr(HEIGHT / 2, HALF, leftString(hide(RESULT, hidden), HALF))
- screen.border(0)
- screen.move(HEIGHT / 2, HALF + len(RESULT))
- screen.refresh()
- elif c == 27:
- curses.endwin()
- sys.exit()
- else:
- if len(RESULT) < HALF - 1:
- RESULT += chr(c)
- if hidden:
- display = "*" * len(RESULT)
- else:
- display = RESULT
- screen.addstr(HEIGHT / 2, HALF, leftString(hide(RESULT, hidden), HALF))
- screen.border(0)
- screen.move(HEIGHT / 2, HALF + len(RESULT))
- screen.refresh()
- screen.erase()
- return RESULT
- NICK = dialogue("Enter your username: ")
- PASS = dialogue("Enter your password: ", True)
- chatango = RoomManager(NICK, PASS)
- thread.start_new_thread(chatango.main, ())
- drawInterface()
- addMessage("Welcome to MegaLoler's Chatango client!\nJoin a room to get started.")
- #todo
- #moderator commands
- #deal with nonexistant rooms
- #add command history with up arrow
- #disconnection error handling and stuff
- #dynamic sizing
- #secret messages to individual people instead of everyone as well
- #custom skins
- esc = False
- while True:
- drawFields() #perhaps make more effient later
- c = screen.getch()
- if c == 10: # Enter
- msg = contents[focus].strip()
- if msg != "":
- contents[focus] = ""
- if focus == 0:
- r = alreadyConnected(msg)
- if r == None:
- chatango.joinRoom(msg)
- room = chatango.getRoom(msg)
- room.chatBuffer = []
- room.activeUser = None
- room.new = False
- switchRoom(room)
- else:
- switchRoom(r)
- elif focus == 1:
- if activeRoom:
- if msg[0] == "/":
- msg = msg[1:]
- if msg != "":
- parts = msg.split(" ")
- cmd = parts[0].lower()
- if len(parts) == 1:
- pars = []
- else:
- pars = parts[1:]
- par = " ".join(pars)
- if cmd == "color":
- chatango.setFontColor(par)
- drawChat()
- elif cmd == "namecolor":
- chatango.setNameColor(par)
- drawOnline()
- elif cmd == "msg":
- activeRoom.message("<msg=\"" + secretEncrypt(par, NICK.lower()) + "\"></msg>" + disguise, True)
- elif cmd == "help":
- addMessageR(activeRoom, HELP_MSG)
- elif cmd == "disguise":
- disguise = par
- addMessageR(activeRoom, "Disguise set to \"" + disguise + "\".")
- elif cmd == "clear":
- activeRoom.chatBuffer = []
- addMessageR(activeRoom, "Cleared the screen.")
- elif cmd == "raw":
- raw = not raw
- if raw:
- addMessageR(activeRoom, "Raw mode is now ON.")
- else:
- addMessageR(activeRoom, "Raw mode is now OFF.")
- elif cmd == "part":
- for i in range(len(chatango._rooms)):
- if list(chatango.roomnames)[i] == activeRoom.name: break
- chatango.leaveRoom(activeRoom.name)
- if len(chatango.roomnames) > 0:
- i %= len(chatango.roomnames)
- switchRoom(list(chatango.rooms)[i])
- else:
- activeRoom = None
- drawContent()
- else:
- addMessageR(activeRoom, "Commands: /color [color] (sets your font color), /namecolor [color] (sets your name color), /part (disconnect from the current room), /help (get help on how to use this client), /raw (toggles raw mode which allows you to type with html formatting), /clear (clears the screen), /msg [message] (sends a secret message that only special people can see, and the message will appear to others as defined by the /disguise command to obfuscate the fact that you are sending secret messages), /disguise [message] (sets the disguise message for use with the /msg command")
- else:
- activeRoom.message(msg, raw)
- else:
- if msg == "/help":
- addMessage(HELP_MSG)
- else:
- addMessage("You are not connected to any rooms! Type /help for help.")
- elif focus == 2:
- if activeRoom and activeRoom.activeUser:
- chatango.pm.message(ch.User(activeRoom.activeUser), msg)
- addMessageR(activeRoom, "@" + activeRoom.activeUser + ": " + NICK + ": " + msg, hexToAnsi(chatango.user.fontColor))
- drawFields()
- screen.refresh()
- elif c == 9: # Tab
- focus = (focus + 1) % 3
- drawFields()
- screen.refresh()
- elif c == 96: # `
- if len(chatango.roomnames) > 0:
- for i in range(len(chatango.roomnames)):
- if list(chatango.roomnames)[i] == activeRoom.name: break
- i = (i + 1) % len(chatango.roomnames)
- switchRoom(list(chatango.rooms)[i])
- elif c == 126: # ~
- if activeRoom:
- if len(activeRoom.usernames) > 0:
- users = sorted(activeRoom.usernames)
- for i in range(len(users)):
- if users[i] == activeRoom.activeUser: break
- i = (i + 1) % (len(activeRoom.usernames))
- activeRoom.activeUser = users[i]
- drawOnline()
- elif c == 127: # Backspace
- if contents[focus] != "": contents[focus] = contents[focus][:-1]
- drawFields()
- screen.refresh()
- elif c == 27: # Esc
- if esc:
- break
- else:
- esc = True
- continue
- else:
- contents[focus] += chr(c)
- drawFields()
- screen.refresh()
- esc = False
- chatango.stop()
- curses.endwin()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement