class TestChat(DCSATestCase): ################################################################################################################### # BASIC TESTS def test_should_start(self): self.c.start() self._registerStartedChatSession(self.c) def test_should_stop_if_started(self): self.test_should_start() self.c.stop() def test_should_raise_exception_if_not_started(self): self.assertRaises(Exception, self.c.stop) def test_should_open_listen_socket_on_start(self): self.test_should_start() self._try_to_connect(self.c.getListenAddress()) def test_should_not_have_open_socket_until_start(self): self.assertRaises(socket.error, self._try_to_connect, self.c.getListenAddress()) def test_should_close_socket_on_chat_stop(self): self.test_should_stop_if_started() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.assertRaises(socket.error, s.connect, self.c.getListenAddress()) def test_stop_should_reset_connected_status(self): self.c.start() assert(self.c._startComplete) time.sleep(0.1) self.c.stop() assert(not self.c._startComplete) def test_shouldnt_allow_multiple_instances_with_same_listen_address(self): self.test_should_start() self.c2 = Chat((Chat.DEFAULT_LISTEN_IP, getUnusedListenPort())) self.assertRaises(Exception, self.c2.start()) def test_shouldnt_create_group_if_not_started(self): self.assertRaises(Exception, self.c.createGroup) def test_should_allow_multiple_instances_with_different_listen_address(self): self.test_should_start() self.c2 = Chat((Chat.DEFAULT_LISTEN_IP, getUnusedListenPort())) self.c2.start() self._registerStartedChatSession(self.c2) self._try_to_connect(self.c2.getListenAddress()) def test_should_be_able_to_create_group_if_not_already_in_a_group(self): self.test_should_start() self.c.createGroup() def test_shouldnt_allow_to_create_group_if_already_joined_a_group(self): self.test_agent_who_added_someone_should_turn_on_active_flag_if_new_user_receives_the_initial_updated_groupview_from_him() self.assertRaises(Exception, self.c2.createGroup()) def test_shouldnt_be_able_to_create_group_if_already_created_a_group(self): self.test_should_be_able_to_create_group_if_not_already_in_a_group() self.assertRaises(Exception, self.c.createGroup()) def test_should_be_able_to_join_group_if_not_already_in_a_group(self): self.test_should_allow_multiple_instances_with_different_listen_address() # Both "c" and "c2" are listening now self.c.createGroup() self.c.addUser(self.c2.getListenAddress()) def test_new_user_should_initially_appear_offline_in_groupview_of_agent_that_added_him(self): self.test_should_allow_multiple_instances_with_different_listen_address() # Both "c" and "c2" are listening now self.c2.stop() self.assertRaises(socket.error, self._try_to_connect, self.c2.getListenAddress()) time.sleep(0.1) self.c.createGroup() self.c.addUser(self.c2.getListenAddress()) time.sleep(0.1) self.assertEqual(Chat.OFFLINE, self.c.userStatus(self.c2.getListenAddress())) def test_new_user_should_initially_appear_online_in_groupview_of_agent_that_added_him_if_online(self): self.test_should_be_able_to_join_group_if_not_already_in_a_group() time.sleep(0.1) self.assertEqual(Chat.ONLINE, self.c.userStatus(self.c2.getListenAddress())) def test_user_should_be_able_to_permanently_leave_the_group(self): self.test_new_user_should_initially_appear_online_in_groupview_of_agent_that_added_him_if_online() time.sleep(0.1) self.c2.leaveGroup() time.sleep(0.1) self.assertFalse(self.c2.getListenAddress() in self.c.groupView.getGroup()) def test_should_log_at_leavers_log_when_user_leaves_group(self): self.test_user_should_be_able_to_permanently_leave_the_group() self.assertLogEntryContains('Left the group', self.c2._logfile) def test_should_log_at_others_log_when_user_leaves_group(self): self.test_user_should_be_able_to_permanently_leave_the_group() self.assertLogEntryContains('Member %s left the group' % str(self.c2.getListenAddress()), self.c._logfile) def test_new_user_should_receive_updated_groupview_command_from_agent_who_added_him(self): self.test_should_be_able_to_join_group_if_not_already_in_a_group() time.sleep(0.1) self.assertLogEntryContains('InitialGroupView received from %s' % str(self.c.getListenAddress()), self.c2._logfile) self.assertEqual(2, len(self.c2.groupView.getGroup())) def test_agent_who_added_someone_should_turn_on_active_flag_if_new_user_receives_the_initial_updated_groupview_from_him(self): self.test_new_user_should_receive_updated_groupview_command_from_agent_who_added_him() self.assertEqual(Chat.ONLINE, self.c.userStatus(self.c2.getListenAddress())) def test_someone_who_is_logged_on_should_appear_as_online_in_other_agents_lists(self): self.test_agent_who_added_someone_should_turn_on_active_flag_if_new_user_receives_the_initial_updated_groupview_from_him() self.c3 = Chat((Chat.DEFAULT_LISTEN_IP, getUnusedListenPort())) self.c3.start() self._registerStartedChatSession(self.c3) self.c.addUser(self.c3.getListenAddress()) time.sleep(0.5) assert(self.c3.address in self.c.getOnlineUsers()) assert(self.c3.address in self.c2.getOnlineUsers()) def test_should_periodically_ping_everyone_on_the_list_and_dont_notify_if_no_changes(self): self.test_agent_who_added_someone_should_turn_on_active_flag_if_new_user_receives_the_initial_updated_groupview_from_him() count = len(self.c.sentPackets) self.c.setPeriodicPingSleep(0.3) time.sleep(0.2 + PeriodicPingThread.POLL_INTERVAL) self.assertEqual(count, len(self.c.sentPackets)) def test_should_periodically_ping_everyone_on_the_list_and_notify_if_changes(self): self._startThreeAgents() count = len(self.c.sentPackets) self.c3.logout() time.sleep(0.1) assert(self.c3.getListenAddress() in self.c.getOfflineUsers()) assert(self.c3.getListenAddress() in self.c2.getOfflineUsers()) self.c3.silentStart() self.c.setPeriodicPingSleep(0.3) time.sleep(0.5 + PeriodicPingThread.POLL_INTERVAL) self.c.setPeriodicPingSleep(60.0) assert(self.c3.getListenAddress() in self.c.getOnlineUsers()) assert(self.c3.getListenAddress() in self.c2.getOnlineUsers()) self.assertEqual('InitialGroupView', self.c3.receivedPackets()[-3].__class__.__name__) assert(len(self.c.sentPackets) > count) def test_should_properly_log_offline_members_that_are_now_online_at_others(self): self.test_should_periodically_ping_everyone_on_the_list_and_notify_if_changes() self.assertLogEntryContains('Member %s is online' % self.c3.getNick(), self.c._logfile) self.assertLogEntryContains('Member %s is online' % self.c3.getNick(), self.c2._logfile) def test_offline_agent_with_copy_of_groupview_should_try_connecting_to_everybody_in_his_list_after_logging_in(self): self._startThreeAgents() self.c.logout() time.sleep(0.1) self.c.silentStart() # don't try to connect to anyone but do open your listen port self.c2.logout() # now c3 is online and thinks c2 and c are both offline time.sleep(0.1) count1 = len(self.c.receivedPackets()) count2 = len(self.c2.receivedPackets()) count3 = len(self.c3.receivedPackets()) self.c2.start() self._registerStartedChatSession(self.c2) time.sleep(0.1) assert((len(self.c.receivedPackets()) == count1 + 1) or (len(self.c3.receivedPackets()) == count3 + 1)) def test_agent_should_list_online_agents(self): self.test_agent_who_added_someone_should_turn_on_active_flag_if_new_user_receives_the_initial_updated_groupview_from_him() assert(self.c2.getListenAddress() in self.c.getOnlineUsers()) assert(self.c2.getListenAddress() not in self.c.getOfflineUsers()) def test_agent_should_list_offline_agents(self): self.test_agent_who_added_someone_should_turn_on_active_flag_if_new_user_receives_the_initial_updated_groupview_from_him() self.c2.logout() time.sleep(0.1) assert(self.c2.getListenAddress() in self.c.getOfflineUsers()) assert(self.c2.getListenAddress() not in self.c.getOnlineUsers()) def test_should_ignore_messages_from_someone_not_in_the_group(self): self.test_should_be_able_to_create_group_if_not_already_in_a_group() self.c2 = Chat((Chat.DEFAULT_LISTEN_IP, getUnusedListenPort())) # send a message from c2 to c c1msgs = len(self.c.messages) c2rcv = len(self.c2.receivedPackets()) c2nick = GroupView.defaultNickFromAddress(self.c2.getListenAddress()) net.send(Message('hi', c2nick, 'lobby'), self.c2.getListenAddress(), self.c.getListenAddress()) time.sleep(0.1) self.assertEqual(c1msgs, len(self.c.messages)) self.assertEqual(c2rcv, len(self.c2.receivedPackets())) def test_shouldnt_be_able_to_create_group_if_already_joined_a_group(self): self.test_should_be_able_to_join_group_if_not_already_in_a_group() self.assertRaises(Exception, self.c2.createGroup()) def test_should_send_updated_groupview_if_error_when_sending_message_to_supposedly_online_agent(self): self.test_someone_who_is_logged_on_should_appear_as_online_in_other_agents_lists() self.c3.stop() self.c.sendMessage('hello world', 'lobby') time.sleep(0.1) assert(self.c3.getListenAddress() in self.c.getOfflineUsers()) assert(self.c3.getListenAddress() in self.c2.getOfflineUsers()) def test_broadcast_message_should_arrive_to_all_online_agents(self): self._startThreeAgents() time.sleep(0.1) self.c.sendMessage('hello world') time.sleep(0.1) self.assertEqual(1, len(self.c.messages)) self.assertEqual(1, len(self.c2.messages)) self.assertEqual(1, len(self.c3.messages)) # LOGGING TESTS def test_should_log_chat_started(self): self.test_should_start() a = self.c.getListenAddress() self.assertLastLogEntryContains('Client started', self.c._logfile) def test_should_log_new_member_added(self): self.test_should_be_able_to_join_group_if_not_already_in_a_group() self.assertLogEntryContains('New member added %s' % str(self.c2.getListenAddress()), self.c._logfile) def test_should_log_joined_group(self): self.test_should_be_able_to_join_group_if_not_already_in_a_group() self.assertLogEntryContains('Joined Group through %s' % str(self.c.getListenAddress()), self.c2._logfile) def test_should_log_when_member_comes_online_at_others_log(self): self.test_new_user_should_receive_updated_groupview_command_from_agent_who_added_him() a = self.c2.getListenAddress() self.c3 = Chat((Chat.DEFAULT_LISTEN_IP, getUnusedListenPort())) self.c3.start() self._registerStartedChatSession(self.c3) time.sleep(0.1) self.c.addUser(self.c3.getListenAddress()) time.sleep(0.1) self.assertLogEntryContains('New member added %s' % str(self.c3.getListenAddress()), self.c._logfile) def test_should_log_when_member_logs_out_at_members_log(self): self.test_agent_should_list_offline_agents() self.assertLogEntryContains('Logged out', self.c2._logfile) def test_should_log_when_member_logs_out_at_others_log(self): self.test_agent_should_list_offline_agents() self.assertLastLogEntryContains('Member %s logged out' % self.c2.getNick(), self.c._logfile) def test_should_log_updated_groupview_received(self): self.test_should_send_updated_groupview_if_error_when_sending_message_to_supposedly_online_agent() self.assertLogEntryContains('GroupUpdate received from %s' % self.c.getNick(), self.c2._logfile) def test_should_log_updated_groupview_sent(self): self.test_should_send_updated_groupview_if_error_when_sending_message_to_supposedly_online_agent() self.assertLogEntryContains('GroupUpdate sent', self.c._logfile) def test_should_log_member_turns_offline_violently(self): self.test_should_send_updated_groupview_if_error_when_sending_message_to_supposedly_online_agent() self.assertLogEntryContains('Member %s disconnected' % str(self.c3.getListenAddress()), self.c._logfile) def test_should_log_command_reception_from_unknown_agents(self): self.test_should_ignore_messages_from_someone_not_in_the_group() self.assertLogEntryContains('Packet received from unauthorized agent %s' % str(self.c2.getListenAddress()), self.c._logfile) def test_should_log_message_received(self): self.test_broadcast_message_should_arrive_to_all_online_agents() self.assertLogEntryContains('Message delivered from %s (#lobby): hello world' % self.c2.getNickOfAddress(self.c.getListenAddress()), self.c2._logfile) self.assertLogEntryContains('Message delivered from %s (#lobby): hello world' % self.c3.getNickOfAddress(self.c.getListenAddress()), self.c3._logfile)
class MainWindow(wx.Frame): def __init__(self, parent, id, title): self.chat = None wx.Frame.__init__(self, parent, id, title, size=(800,600)) font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT) font.SetPointSize(12) # MENUS filemenu = wx.Menu() fileAbout = filemenu.Append(wx.ID_ANY, "&About DSCA"," Information about this program") filemenu.AppendSeparator() fileExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program") managemenu = wx.Menu() createGroup = managemenu.Append(wx.ID_ANY, "Create Group", "Create a new group if not already in a group") leaveGroup = managemenu.Append(wx.ID_ANY, "Leave Group", "Leave the group") addUser = managemenu.Append(wx.ID_ANY, "Add User", "Add user to group") managemenu.AppendSeparator() channelInfo = managemenu.Append(wx.ID_ANY, "Channel Info", "Get channels and channel membership info") channelMembership = managemenu.Append(wx.ID_ANY, "Join/Leave Channel", "Join or leave a channel") channelLog = managemenu.Append(wx.ID_ANY, "Channel Log History", "Get message history of a channel") menubar = wx.MenuBar() menubar.Append(filemenu, "&File") menubar.Append(managemenu, "Manage") self.SetMenuBar(menubar) # Set events. self.Bind(wx.EVT_MENU, self.OnAbout, fileAbout) self.Bind(wx.EVT_MENU, self.OnExit, fileExit) self.Bind(wx.EVT_MENU, self.OnCreateGroup, createGroup) self.Bind(wx.EVT_MENU, self.OnLeaveGroup, leaveGroup) self.Bind(wx.EVT_MENU, self.OnAddUser, addUser) self.Bind(wx.EVT_MENU, self.OnChannelInfo, channelInfo) self.Bind(wx.EVT_MENU, self.OnChannelMembership, channelMembership) self.Bind(wx.EVT_MENU, self.OnLogHistory, channelLog) mainPanel = wx.Panel(self, wx.ID_ANY) # Beginning of main window vbox = wx.BoxSizer(wx.VERTICAL) # Top button bar hbox0 = wx.BoxSizer(wx.HORIZONTAL) stxt = wx.StaticText(mainPanel, wx.ID_ANY, "IP Address: ") stxt.SetFont(font) hbox0.Add(stxt, 0, wx.ALL, 5) self.ip = wx.TextCtrl(mainPanel, wx.ID_ANY) hbox0.Add(self.ip, 2, wx.EXPAND | wx.ALL, 5) stxt1 = wx.StaticText(mainPanel, wx.ID_ANY, "Port: ") stxt1.SetFont(font) hbox0.Add(stxt1, 0, wx.ALL, 5) self.port = wx.TextCtrl(mainPanel, wx.ID_ANY) hbox0.Add(self.port, 1, wx.EXPAND | wx.ALL, 5) startButton = wx.Button(mainPanel, wx.ID_ANY, label="start") hbox0.Add(startButton, 0, wx.EXPAND | wx.ALL, 5) startButton.Bind(wx.EVT_BUTTON, self.OnStart) stopButton = wx.Button(mainPanel, wx.ID_ANY, label="stop") hbox0.Add(stopButton, 0, wx.EXPAND | wx.ALL, 5) stopButton.Bind(wx.EVT_BUTTON, self.OnStop) logoutButton = wx.Button(mainPanel, wx.ID_ANY, label="logout") hbox0.Add(logoutButton, 0, wx.EXPAND | wx.ALL, 5) logoutButton.Bind(wx.EVT_BUTTON, self.OnLogout) vbox.Add(hbox0, 0, wx.EXPAND) hbox02 = wx.BoxSizer(wx.HORIZONTAL) vbox02 = wx.BoxSizer(wx.VERTICAL) self.curNick = wx.StaticText(mainPanel, wx.ID_ANY, "No Nick") self.curNick.SetFont(font) self.curNick.SetForegroundColour('BLUE') vbox02.Add(self.curNick, 0, wx.LEFT | wx.RIGHT, 20) self.curAddr = wx.StaticText(mainPanel, wx.ID_ANY, "No Address") self.curAddr.SetFont(font) self.curAddr.SetForegroundColour('BLUE') vbox02.Add(self.curAddr, 0, wx.LEFT | wx.RIGHT, 20) hbox02.Add(vbox02, 2, wx.EXPAND) self.newNick = wx.TextCtrl(mainPanel, wx.ID_ANY) hbox02.Add(self.newNick, 1, wx.EXPAND | wx.LEFT, 50) nickButton = wx.Button(mainPanel, wx.ID_ANY, label="Change Nick") hbox02.Add(nickButton, 0, wx.EXPAND | wx.ALL, 5) nickButton.Bind(wx.EVT_BUTTON, self.OnNickChange) vbox.Add(hbox02, 0, wx.EXPAND) # main section of window (chat/group view) mainHbox = wx.BoxSizer(wx.HORIZONTAL) panel1 = wx.Panel(mainPanel, -1) panel1.SetBackgroundColour(wx.LIGHT_GREY) mainHbox.Add(panel1, 7, wx.EXPAND | wx.ALL, 5) vbox1 = wx.BoxSizer(wx.VERTICAL) # chat tabs, 1 tab per channel + a network tab for debugging info self.nb = wx.Notebook(panel1) # initially only lobby and network tabs exist self.lobby = wx.TextCtrl(self.nb, -1, style= wx.TE_MULTILINE | wx.TE_READONLY) self.network = wx.TextCtrl(self.nb, -1, style= wx.TE_MULTILINE | wx.TE_READONLY) # initialize tab dictionary self.channelTabs = {} self.nb.AddPage(self.lobby, 'lobby') self.nb.AddPage(self.network, 'network') vbox1.Add(self.nb, 1, wx.EXPAND) # MESSAGE SENDING INTERFACE panel11 = wx.Panel(panel1, -1) hbox1 = wx.BoxSizer(wx.HORIZONTAL) # channel selection control self.channelSel = wx.Choice(panel11) hbox1.Add(self.channelSel, 0, wx.LEFT | wx.TOP, 5) # message to send box self.msg = wx.TextCtrl(panel11, -1) hbox1.Add(self.msg, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 10) # send button send = wx.Button(panel11, wx.ID_ANY, label='send') hbox1.Add(send, 0, wx.TOP | wx.RIGHT, 5) send.Bind(wx.EVT_BUTTON, self.OnSendMsg) panel11.SetSizer(hbox1) vbox1.Add(panel11, 0, wx.EXPAND | wx.BOTTOM, 5) panel1.SetSizer(vbox1) # group view (online and offline users) groupVbox = wx.BoxSizer(wx.VERTICAL) headerPanel1 = wx.Panel(mainPanel, -1) headerHbox1 = wx.BoxSizer(wx.HORIZONTAL) onlineHeader = wx.StaticText(headerPanel1, -1, "ONLINE") onlineHeader.SetFont(font) headerHbox1.Add(onlineHeader, 0, wx.EXPAND | wx.ALL, 5) headerPanel1.SetBackgroundColour('GREEN') onlineHeader.SetForegroundColour('WHITE') headerPanel1.SetSizer(headerHbox1) groupVbox.Add(headerPanel1, 0, wx.EXPAND) self.onlineList = wx.ListBox(mainPanel, wx.ID_ANY, style=wx.LB_SINGLE) groupVbox.Add(self.onlineList, 1, wx.EXPAND) headerPanel2 = wx.Panel(mainPanel, -1) headerHbox2 = wx.BoxSizer(wx.HORIZONTAL) offlineHeader = wx.StaticText(headerPanel2, -1, "OFFLINE") offlineHeader.SetFont(font) headerHbox2.Add(offlineHeader, 0, wx.EXPAND | wx.ALL, 5) headerPanel2.SetBackgroundColour('RED') offlineHeader.SetForegroundColour('WHITE') headerPanel2.SetSizer(headerHbox2) groupVbox.Add(headerPanel2, 0, wx.EXPAND) self.offlineList = wx.ListBox(mainPanel, wx.ID_ANY, style=wx.LB_SINGLE) groupVbox.Add(self.offlineList, 1, wx.EXPAND) mainHbox.Add(groupVbox, 2, wx.EXPAND | wx.ALL, 5) vbox.Add(mainHbox, 3, wx.EXPAND | wx.ALL, 5) # FILE TRANSFER INTERFACE filePanel = wx.Panel(mainPanel, -1) fileVbox = wx.BoxSizer(wx.VERTICAL) # Change download directory controls fhbox0 = wx.BoxSizer(wx.HORIZONTAL) st0 = wx.StaticText(filePanel, -1, "Download Directory: ") st0.SetFont(font) fhbox0.Add(st0, 0, wx.ALL, 5) self.dldir = wx.TextCtrl(filePanel, wx.ID_ANY, style=wx.TE_READONLY) fhbox0.Add(self.dldir, 1, wx.EXPAND | wx.ALL, 5) st = wx.StaticText(filePanel, -1, "New Directory: ") st.SetFont(font) fhbox0.Add(st, 0, wx.ALL, 5) self.newdir = wx.TextCtrl(filePanel, wx.ID_ANY) fhbox0.Add(self.newdir, 1, wx.EXPAND | wx.ALL, 5) changeDir = wx.Button(filePanel, wx.ID_ANY, label="Change") fhbox0.Add(changeDir, 0, wx.RIGHT | wx.TOP, 5) changeDir.Bind(wx.EVT_BUTTON, self.OnChangeDir) fileVbox.Add(fhbox0, 0, wx.EXPAND) # "Offered Files" label fhbox1 = wx.BoxSizer(wx.HORIZONTAL) st1 = wx.StaticText(filePanel, -1, "Offered Files") st1.SetFont(font) fhbox1.Add(st1, 0) fileVbox.Add(fhbox1, 0, wx.LEFT | wx.TOP, 5) # List of offered files and accept button fhbox2 = wx.BoxSizer(wx.HORIZONTAL) self.offeredList = wx.ListBox(filePanel, wx.ID_ANY, style=wx.LB_SINGLE) fhbox2.Add(self.offeredList, 1, wx.LEFT | wx.EXPAND) acceptButton = wx.Button(filePanel, wx.ID_ANY, label="Accept File") fhbox2.Add(acceptButton, 0, wx.TOP | wx.BOTTOM | wx.RIGHT, 5) acceptButton.Bind(wx.EVT_BUTTON, self.OnAcceptFile) fileVbox.Add(fhbox2, 1, wx.LEFT | wx.RIGHT | wx.EXPAND) # File sending controls fhbox3 = wx.BoxSizer(wx.HORIZONTAL) # File field st2 = wx.StaticText(filePanel, -1, "File: ") st2.SetFont(font) fhbox3.Add(st2, 0, wx.TOP | wx.LEFT, 5) self.file = wx.TextCtrl(filePanel, wx.ID_ANY) fhbox3.Add(self.file, 2, wx.EXPAND | wx.ALL, 5) # To field st3 = wx.StaticText(filePanel, -1, "To: ") st3.SetFont(font) fhbox3.Add(st3, 0, wx.TOP | wx.LEFT, 5) self.fileTo = wx.TextCtrl(filePanel, wx.ID_ANY) fhbox3.Add(self.fileTo, 1, wx.EXPAND | wx.ALL, 5) # send button offerFile = wx.Button(filePanel, wx.ID_ANY, label="Offer File") fhbox3.Add(offerFile, 0, wx.RIGHT | wx.TOP, 5) offerFile.Bind(wx.EVT_BUTTON, self.OnOfferFile) fileVbox.Add(fhbox3, 0, wx.LEFT | wx.RIGHT | wx.EXPAND) filePanel.SetSizer(fileVbox) vbox.Add(filePanel, 1, wx.EXPAND) mainPanel.SetSizer(vbox) self.Centre() self.Show(True) pub.subscribe(self.__OnLog, 'log') pub.subscribe(self.__OnMessage, 'message') pub.subscribe(self.__OnUpdate, 'update') pub.subscribe(self.__OnLeave, 'group.leave') def OnAbout(self, e): dlg = wx.MessageDialog(self, "Distributed Secure Chat Application", "About DSCA", wx.OK) dlg.ShowModal() dlg.Destroy() def OnExit(self, e): self.Close(True) def OnCreateGroup(self, e): self.chat.createGroup() def OnLeaveGroup(self, e): self.chat.leaveGroup() def OnAddUser(self, e): if self.chat: dlg = AddUser(self, wx.ID_ANY, "Add User", self.chat) dlg.ShowModal() dlg.Destroy() def OnChannelInfo(self, e): if self.chat: dlg = ChannelInfo(self, wx.ID_ANY, 'Channel Info', self.chat) dlg.ShowModal() dlg.Destroy() def OnChannelMembership(self, e): if self.chat: dlg = ChannelMembership(self, wx.ID_ANY, 'Channel Membership', self.chat) dlg.ShowModal() dlg.Destroy() self.UpdateChannels() def OnLogHistory(self, e): if self.chat: dlg = ChannelLog(self, wx.ID_ANY, 'Channel Log History', self.chat) dlg.ShowModal() dlg.Destroy() def UpdateChannels(self): channels = self.chat.getChannels() items = channels.keys() items.append('lobby') self.channelSel.SetItems(items) tabs = self.channelTabs.keys() for chan in items: if (chan not in tabs) and (chan != 'lobby'): index = self.nb.GetPageCount() - 1 self.channelTabs[chan] = ChannelPage(self.nb, index) self.UpdateChannel(chan) self.nb.InsertPage(index, self.channelTabs[chan], chan) for tab in tabs: if tab not in items: page = self.channelTabs[tab] self.nb.SetSelection(0) index = page.index self.nb.DeletePage(index) del self.channelTabs[tab] for i in range(index, (self.nb.GetPageCount() - 1)): page2 = self.nb.GetPage(i) page2.index = i def OnStart(self, e): '''Starts a chat session. Not necessary to specifically enable output to the GUI. Output is dependent upon subscribing to events published by Chat.''' atexit.register(self.quiet_stop) if not self.chat: if (not self.ip.IsEmpty()) and (not self.port.IsEmpty()): ipString = str(self.ip.GetLineText(0)) ipString = ipString.strip() portString = str(self.port.GetLineText(0)) portString = portString.strip() listen_address = (str(ipString), int(portString)) self.chat = Chat(listen_address) else: self.chat = Chat() self.ip.Clear() self.port.Clear() self.curAddr.SetLabel(str(self.chat.getListenAddress())) self.dldir.Clear() self.dldir.AppendText(os.path.abspath(self.chat.getDownloadDir())) elif (not self.ip.IsEmpty()) and (not self.port.IsEmpty()): dlg = wx.MessageDialog(self, 'Start failed.\nChat already started.', "WARNING", wx.OK) dlg.ShowModal() dlg.Destroy() return try: self.chat.start() except: self.chat = None raise def quiet_stop(self): try: self.chat.stop() self.chat = None except: pass def OnStop(self, e): if self.chat: self.chat.stop() self.chat = None def OnLogout(self, e): self.chat.logout() def OnSendMsg(self, e): channel = self.channelSel.GetStringSelection() if not channel: channel = 'lobby' self.chat.sendMessage(self.msg.GetLineText(0), channel) self.msg.Clear() def OnChangeDir(self, e): if not self.newdir.IsEmpty(): self.chat.setDownloadDir(self.newdir.GetLineText(0)) self.newdir.Clear() self.dldir.Clear() self.dldir.AppendText(os.path.abspath(self.chat.getDownloadDir())) def OnAcceptFile(self, e): selection = str(self.offeredList.GetStringSelection()) cookie = (selection.split(':'))[1] cookie = cookie.lstrip() self.network.AppendText("I made you a cookie... %s" % cookie) try: self.chat.acceptFileOffer(cookie) except InvalidFileCookieException: dlg = wx.MessageDialog(self, "File Accept Failed", "FAIL", wx.OK) dlg.ShowModal() dlg.Destroy() def OnOfferFile(self, e): fpath = os.path.abspath(self.file.GetLineText(0)) nick = str(self.fileTo.GetLineText(0)) self.file.Clear() self.fileTo.Clear() try: target_addr = self.chat.getAddressOfNick(nick) except NickNotFoundException: dlg = wx.MessageDialog(self, "'%s' is not a valid user" % nick, "ERROR", wx.OK) dlg.ShowModal() dlg.Destroy() else: try: self.chat.offerFile(fpath, target_addr) except FileNotFoundException: dlg = wx.MessageDialog(self, "File '%s' does not exist" % fpath, "ERROR", wx.OK) dlg.ShowModal() dlg.Destroy() def OnNickChange(self, e): if not self.newNick.IsEmpty(): newNick = str(self.newNick.GetLineText(0)) newNick = newNick.strip() if newNick != '': self.newNick.Clear() self.chat.changeNick(newNick) def __OnLog(self, message): channel = message.data['channel'] msg = message.data['msg'] if 'time' in message.data: sec = message.data['time'] tstring = time.strftime("%H:%M:%S ", time.localtime(sec)) msg = tstring + msg wx.CallAfter(self.AfterLog, channel, msg) def AfterLog(self, channel, msg): if channel == 'lobby': self.lobby.AppendText(msg + '\n') elif channel in self.channelTabs: tab = self.channelTabs[channel] tab.text.AppendText(msg + '\n') self.network.AppendText(msg + '\n') def __OnMessage(self, message): channel = message.data['channel'] msg = message.data['msg'] if 'time' in message.data: sec = message.data['time'] tstring = time.strftime("%H:%M:%S ", time.localtime(sec)) msg = tstring + msg wx.CallAfter(self.AfterMessage, channel, msg) def AfterMessage(self, channel, msg): if channel == 'lobby': self.lobby.AppendText(msg + '\n') elif channel in self.channelTabs: tab = self.channelTabs[channel] tab.text.AppendText(msg + '\n') def __OnUpdate(self, message): field = message.data['field'] if 'value' in message.data: value = message.data['value'] if field == 'myNick': wx.CallAfter(self.UpdateMyNick, value) elif field == 'nick': wx.CallAfter(self.UpdateNick, value) elif field == 'channel': wx.CallAfter(self.UpdateChannel, value) elif field == 'group': wx.CallAfter(self.UpdateGroup) elif field == 'fileOffers': wx.CallAfter(self.UpdateOfferedFiles) def UpdateMyNick(self, nick): try: self.curNick.SetLabel(nick) except: pass self.UpdateNick(self.chat.getListenAddress()) def UpdateNick(self, sender): for channelName in self.chat.channels: channel = self.chat.getChannel(channelName) if sender in channel.getUserAddresses(): self.UpdateChannel(channelName) self.UpdateGroup() def UpdateChannel(self, channelName): if channelName in self.channelTabs: tab = self.channelTabs[channelName] chan = self.chat.getChannel(channelName) tab.users.SetItems(chan.getUsers()) def UpdateGroup(self): if self.chat: online = self.chat.getOnlineUsers() offline = self.chat.getOfflineUsers() onlineNicks = [] for addr in online: nick = self.chat.getNickOfAddress(addr) onlineNicks.append(nick) offlineNicks = [] for addr in offline: nick = self.chat.getNickOfAddress(addr) offlineNicks.append(nick) self.onlineList.SetItems(onlineNicks) self.offlineList.SetItems(offlineNicks) else: self.onlineList.Clear() self.offlineList.Clear() def UpdateOfferedFiles(self): foss = self.chat.getFileOffers() now = time.time() files = [] for cookie in foss: fof = foss[cookie] if fof['expires_on'] < now: continue files.append("%s: %s" % (os.path.basename(fof['filename']), cookie)) self.offeredList.SetItems(files) def __OnLeave(self, message=None): wx.CallAfter(self.Leave) def Leave(self): self.curNick.SetLabel("No Nick") self.curAddr.SetLabel("No Address") for i in range(1, (self.nb.GetPageCount() -1)): self.nb.DeletePage(1) self.lobby.Clear() self.network.Clear() self.onlineList.Clear() self.offlineList.Clear() self.chat = None