def guirun(self, screen): """ Runs the client in a GUI mode """ (height, width) = screen.getmaxyx() if height < 10 or width < 50: logging.warning("Screen size too small") self.stop() else: self.__gui = ClientGUI(self, screen) self.__gui.update() self.run(shutdown=False)
def __init__(self, host, port, userinput=sys.stdin, autoQuit=False): """ Initialize Client""" self.__nick = "NEWUSER" super(IRCClient, self).__init__(self.__nick, host, port) self.__cmdProc = CommandProcessor() self.__server = None self.__noneChannel = self.__currentChannel = ClientChannel("None") self.__input = userinput self.__gui = ClientConsole(self) self.__tempNames = [] self.__tempChannels = [] self.__autoQuit = autoQuit self.__allUsers = {} self.__allChannels = {self.__noneChannel.getName(): self.__noneChannel} self.__noneChannel.addUser(self.findOrCreateUser(self.__nick))
class IRCClient(IRC.Handler.IRCHandler): """ The IRC Client Takes the base IRCHandler and uses it to produce a fully formed Client for the IRC protocol. """ def __init__(self, host, port, userinput=sys.stdin, autoQuit=False): """ Initialize Client""" self.__nick = "NEWUSER" super(IRCClient, self).__init__(self.__nick, host, port) self.__cmdProc = CommandProcessor() self.__server = None self.__noneChannel = self.__currentChannel = ClientChannel("None") self.__input = userinput self.__gui = ClientConsole(self) self.__tempNames = [] self.__tempChannels = [] self.__autoQuit = autoQuit self.__allUsers = {} self.__allChannels = {self.__noneChannel.getName(): self.__noneChannel} self.__noneChannel.addUser(self.findOrCreateUser(self.__nick)) def getNoneChannel(self): return self.__noneChannel def connect(self): """ Attempt to connect to a given server""" try: logging.info("Attempting to start client.") self.__server = sockmod.socket(sockmod.AF_INET, sockmod.SOCK_STREAM) self.__server.connect((self.getHost(), self.getPort())) self.__server = SocketBuffer(self.__server) logging.info("Client Connected to server.") return True except sockmod.error as e: if e.errno == 111: logging.critical( "Can't connect to {host}:{port}. Is the server running?".format( host=self.getHost(), port=self.getPort() ) ) return False else: raise e def getNick(self): """ Get's the client nickname""" return self.__nick def getJoined(self): """ Return list of joined rooms """ return [ c for c in self.__allChannels.values() if c.userInChannel(self.findOrCreateUser(self.__nick)) ] def getChats(self): """ Return a dictionary of chat messages for rooms""" return self.__chats def isGUI(self): """ Returns if GUI enabled """ return self.__gui.isGUI() def updateChat(self, msg, channels=None): """ Update the corresponding chat messages Keeps a record of the chat messages in a given channel so that the user can read the transcripts """ if channels == None: self.currentChannel().addHistory(msg) else: for c in channels: c.addHistory(msg) if not self.__gui.isGUI(): print msg else: self.__gui.updateChat() def guirun(self, screen): """ Runs the client in a GUI mode """ (height, width) = screen.getmaxyx() if height < 10 or width < 50: logging.warning("Screen size too small") self.stop() else: self.__gui = ClientGUI(self, screen) self.__gui.update() self.run(shutdown=False) def setInput(self, newinput): """ Sets the input stream for the client""" self.__input = newinput def getUserInput(self): """ Reads from the current input stream a new line""" return self.__input.readline() def getChannels(self): """ Gets the known available channels""" return self.__allChannels.values() def currentChannel(self): """ Returns users current channel""" return self.__currentChannel def setChannel(self, chan): """ Sets the current channel""" self.__currentChannel = chan self.__gui.update() def getInputSocketList(self): """ Returns the list of input sockets to listen""" return [self.__input, self.__server] def getOutputSocketList(self): """Returns a list of sockets ready to send messages""" return filter(lambda s: s.readyToSend(), [self.__server]) def serverSocket(self): """ Returns the current server socket""" return self.__server def inputCmd(self, line): """ Attempts to execute a given user input line""" try: cmd = self.__cmdProc.processCmd(line) if cmd: cmd.execute(self) except CommandParseError as e: self.notify("Error Encountered Parsing Command: %s" % (e)) def socketInputReady(self, socket): """ Determine what to do with a given socket input""" if socket == self.__input: line = self.__gui.keypress() if line and len(line) > 0: self.inputCmd(line) else: self.receiveMsg(socket) def socketExceptReady(self, socket): """ Notify client of socket exception""" pass #does the client care? def connectionDrop(self, socket): """ Server Disconnect, shutdown client. """ if socket == self.__server: self.notify("*** Server Disconnect ***") if self.__autoQuit and socket == self.__server: self.stop() def notify(self, msg): """ Notify the GUI that there is a new message """ self.updateChat(msg) def findOrCreateUser(self, name): """ Find or create a user reference """ if name in self.__allUsers: return self.__allUsers[name] else: newuser = ClientUser(name) self.__allUsers[name] = newuser return newuser def findChannel(self, name): """ Find a a channel with the possibility of failure """ if name in self.__allChannels: return self.__allChannels[name] else: return None def findOrCreateChannel(self, name): """ Find and potentially create channel """ if self.findChannel(name): return self.findChannel(name) else: newchannel = ClientChannel(name) self.__allChannels[name] = newchannel return newchannel def allChannelsWithName(self, name): """ Return a list of all channels with a user in them """ chans = [] user = self.findOrCreateUser(name) for c in self.__allChannels.values(): if c.userInChannel(user): chans.append(c) return chans def receivedNick(self, socket, src, newnick): """ Received a nickname. If it's for the client, update the nickname. Otherwise update the nickname of the specified clients """ notify = self.allChannelsWithName(src) user = self.findOrCreateUser(src) user.updateName(newnick) self.__allUsers[newnick] = user del self.__allUsers[src] if self.__nick == src: self.__nick = newnick self._ircmsg.updateSrc(newnick) self.updateChat( "*** You ({oldnick}) are now {newnick} ****".format( oldnick=src, newnick=newnick ), notify ) else: self.updateChat( "*** {oldnick} is now {newnick} ****".format( oldnick=src, newnick=newnick ), notify ) self.__gui.update() def receivedQuit(self, socket, src, msg): """ Received a quit command If it's for the client, shutdown. If it's for another client, remove them from chats. """ user = self.findOrCreateUser(src) if src == "SERVER": notify = self.__allChannels.values() else: notify = self.allChannelsWithName(src) for c in notify: c.removeUser(user) if src in self.__allUsers: del self.__allUsers[src] self.updateChat( "*** {src} quit ({msg})".format( src=src, msg=msg ), notify ) self.__gui.updateUsers() if src == self.__nick: self.stop() def receivedSQuit(self, socket, msg): """ Unused server command """ pass def receivedJoin(self, socket, src, channels): """ Received join If the join is for the user, add them to the channel. If it's for another user, store them in the channel. """ user = self.findOrCreateUser(src) notify_chan = [] for c in channels: chan = self.findOrCreateChannel(c) chan.addUser(user) notify_chan.append(chan) if src == self.__nick: self.updateChat( "*** You joined the channel(s) {channels}".format( channels=",".join(channels) ), notify_chan + [self.__noneChannel] ) else: self.updateChat( "*** {src} joined the channel".format(src=src), notify_chan ) self.__gui.update() def receivedLeave(self, socket, src, channels, msg): """ Received Leave If it's for the user, remove from specified channels. If it's for someone else, remove them from channels. """ user = self.findOrCreateUser(src) notify_chan = [] for c in channels: chan = self.findOrCreateChannel(c) if chan.userInChannel(user): chan.removeUser(user) notify_chan.append(chan) if src == self.__nick and self.__currentChannel in notify_chan: self.__currentChannel = self.__noneChannel self.updateChat( "*** {src} left the channel(s) {chans} ({msg})".format( src=src, msg=msg, chans=", ".join([c.getName() for c in notify_chan]) ), [self.__noneChannel] + notify_chan ) self.__gui.update() @clientIgnore def receivedChannels(self, socket): """ Client does not receive channels messages""" pass @clientIgnore def receivedUsers(self, socket, channels, client_req): """ Client does not receive users requests""" pass def filterChannels(self, c): return re.match("^#", c) != None def receivedMsg(self, socket, src, targets, msg): """ Update the chats with the new message depending on target""" channels = filter(lambda t: self.filterChannels(t), targets) channels = map(lambda c: self.findOrCreateChannel(c), channels) if self.__nick in targets: self.notify("*** {src}: {msg}".format(src=src, msg=msg)) elif len(channels) > 0: self.updateChat("{src}: {msg}".format(src=src, msg=msg), channels) def receivedPing(self, socket, msg): """ Reply to ping with pong """ self.sendMsg(socket, self._ircmsg.cmdPong(msg)) @clientIgnore def receivedPong(self, socket, msg): """ Client does not recieve pongs""" pass def receivedNames(self, socket, channel, names, client): """ Receive the names list If the user is in GUI mode, update the users window. Otherwise print out the user information """ if self.__gui.isGUI() and not client: self.__tempNames.extend(names) if len(names) == 0: c = self.findOrCreateChannel(channel) newusers = [] for n in self.__tempNames: newusers.append(self.findOrCreateUser(n)) c.receivedNames(newusers) self.__tempNames = [] self.__gui.update() elif len(names) > 0: self.notify( "{chan}: {users}".format( chan=channel, users=" ".join(names) ) ) def receivedChannelsReply(self, socket, channels): """ Receive the channels list If the user is in gui mode update the channels window. Otherwise print out the channels list. """ if self.__gui.isGUI(): self.__tempChannels.extend(channels) if channels == []: new_set = set(self.__tempChannels) old_set = set(self.__allChannels.keys()) remove = old_set - new_set add = new_set - old_set for d in remove: del self.__allChannels[d] for a in add: self.findOrCreateChannel(a) self.__gui.update() elif len(channels) > 0: self.notify("CHANNELS: {chans}".format(chans=" ".join(channels))) def receivedError(self, socket, error_name, error_msg): """ Notify user of error""" self.notify( "ERROR: {error_t}: {error_m}".format( error_t=error_name, error_m=error_msg ) ) def receivedInvalid(self, socket, msg): """ Notify user of invalid server message""" self.notify("BAD SERVER MSG: {msg}".format(msg=msg)) def receivedSignal(self, sig, frame): """ Handle signal gradefully """ if sig == signal.SIGINT: msg = "Client interrupted with Ctrl-C." logging.info(msg) self.notify(msg) self.stop() def sentInvalid(self, socket, msg): """ Notify user that invalid message was sent""" self.notify("CLIENT ERROR: {msg}".format(msg=msg)) def shutdown(self): """ Shutdown client""" self.notify("*** Shutting Down Client ***") self.__server.close()