├── README.md
└── PocketChatIRC.py
/README.md:
--------------------------------------------------------------------------------
1 | # PocketChat
2 | PocketChat is a light weight IRC client that I wrote in python with a UI made for the PocketChip, but
3 | it can also be used on windows and linux.
4 |
5 |
6 |
7 | # COMMANDS:
8 | - Join a channel: /join #channel
9 | - Leave a channel: /leave in the window of the channel you want to leave
10 | - Send a pm: /msg user message
11 | - Change you nick: /nick newname
12 | - Close the client: /quit
13 | - Auto join channels by adding them to the box seperated by commas no spaces e.g.(#chipsters,#nextthingco,#linux)
14 |
15 | # Dependencies:
16 |
17 | - sudo apt-get install python3
18 | - sudo apt-get install python3-tk
19 | - run the program:
20 | python3 PocketChatIRC.py
21 |
--------------------------------------------------------------------------------
/PocketChatIRC.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from tkinter import *
3 | from tkinter import messagebox, ttk
4 | from tkinter.scrolledtext import ScrolledText
5 | from socket import socket
6 | from select import select
7 | import sys, threading, time, ssl
8 | import configparser
9 |
10 | class Window(Frame):
11 | def __init__(self, master):
12 | Frame.__init__(self, master)
13 | self.root = master
14 | self.sckt = socket()
15 | self.parser = configparser.ConfigParser()
16 | self.parser.read('settings.ini')
17 | self.grid()
18 | self.tabs = {}
19 | self.init_window()
20 | self.getuser_popup()
21 |
22 | def getuser_popup(self):# Builds the UI for the username entry window
23 | self.checkSSL = IntVar()
24 | self.checkSSL.set(0)
25 | self.top = Toplevel()
26 | self.top.transient(root)
27 | w = 280
28 | h = 240
29 | sw = self.top.winfo_screenwidth()
30 | sh = self.top.winfo_screenheight()
31 | x = (sw - w)/2
32 | y = (sh - h)/2
33 | self.top.geometry('%dx%d+%d+%d' % (w, h, x, y))
34 |
35 | self.SERVERIP = Entry(self.top, width=24)
36 | self.SERVERIP.place(x=75, y=10)
37 | self.SERVERIP.insert(0, 'weber.freenode.net')
38 | self.SERVERLB = Label(self.top, text = 'Server IP')
39 | self.SERVERLB.place(x=5, y=10)
40 |
41 | self.enterUser = Entry(self.top, width=24)
42 | self.enterUser.place(x=75, y=32)
43 | self.enterUser.focus_force()
44 | self.enterUsername = Label(self.top, text = 'Nickname')
45 | self.enterUsername.place(x=5, y=32)
46 |
47 | self.enterIDENT = Entry(self.top, width=24)
48 | self.enterIDENT.place(x=75, y=54)
49 | self.enterIDENTLb = Label(self.top, text = 'Identity')
50 | self.enterIDENTLb.place(x=5, y=54)
51 |
52 | self.enterREALNAME = Entry(self.top, width=24)
53 | self.enterREALNAME.place(x=75, y=76)
54 | self.enterREALNAMELb = Label(self.top, text = 'Realname')
55 | self.enterREALNAMELb.place(x=5, y=76)
56 |
57 | self.enterPASSWORD = Entry(self.top, show="*", width=24)
58 | self.enterPASSWORD.place(x=75, y=98)
59 | self.enterPASSWORDLb = Label(self.top, text = '*Password')
60 | self.enterPASSWORDLb.place(x=5, y=98)
61 |
62 | self.autoJoin = Entry(self.top, width=32)
63 | self.autoJoin.place(x=10, y=142)
64 | self.autoJoinLb = Label(self.top, text = '*Auto join channels seperated by a ","')
65 | self.autoJoinLb.place(x=5, y=120)
66 |
67 | self.sslCHECKBOX = Checkbutton(self.top, variable=self.checkSSL, onvalue=1, offvalue=0, text="Use SSL")
68 | self.sslCHECKBOX.place(x=5, y=160)
69 | self.sslCHECKBOX.select()
70 |
71 | self.OPTIONALLb = Label(self.top, text = '"*"optional sections')
72 | self.OPTIONALLb.place(x=140, y=160)
73 |
74 | self.usernameButton = Button(self.top, text='Connect', command = self.get_username, height=2, width=8)
75 | self.usernameButton.bind('', self.get_username)
76 | self.usernameButton.place(x=90, y=185)
77 |
78 | if self.parser.has_section("UserSettings"):
79 | self.enterUser.insert(0, self.parser.get('UserSettings', 'nickname'))
80 | self.enterIDENT.insert(0, self.parser.get('UserSettings', 'identity'))
81 | self.enterREALNAME.insert(0, self.parser.get('UserSettings', 'realname'))
82 | if self.parser.has_section("AutoJoin"):
83 | self.autoJoin.insert(0, self.parser.get('AutoJoin', 'channels'))
84 |
85 | def init_window(self):# Builds the UI for the main window
86 | self.n = ttk.Notebook(root)
87 | self.n.enable_traversal()
88 | root.title('Python Chat')
89 | w = 480
90 | h = 272
91 | sw = root.winfo_screenwidth()
92 | sh = root.winfo_screenheight()
93 | x = (sw - w)/2
94 | y = (sh - h)/2
95 | root.geometry('%dx%d+%d+%d' % (w, h, x, y))
96 |
97 | self.textboxframe = ttk.Frame(self.n)
98 | self.textboxframe.grid(row=0, column=0, sticky=N+S+E+W)
99 |
100 | self.textReceive = ScrolledText(self.textboxframe, height=24, width=47, wrap = WORD)
101 | self.textReceive.grid(row = 0, column= 0, padx=(10,0), pady=(10,5), sticky=N+S+E+W)
102 | self.textReceive.config(state=DISABLED)
103 |
104 | self.textEntry = ScrolledText(self.textboxframe, height=2, width=47, wrap = WORD)
105 | self.textEntry.grid(row = 2, column= 0, padx=(10,0), pady=(0,10), sticky=N+S+E+W)
106 | self.textEntry.bind('', self.check_pm_commands)
107 |
108 | Grid.rowconfigure(root, 0, weight=1)
109 | Grid.columnconfigure(root, 0, weight=1)
110 | Grid.rowconfigure(self.textboxframe, 0, weight=1)
111 | Grid.columnconfigure(self.textboxframe, 0, weight=1)
112 |
113 | self.tabs['Server Info'] = {}
114 | self.tabs['Server Info']['tab'] = self.textboxframe
115 | self.tabs['Server Info']['textbox'] = self.textReceive
116 | self.tabs['Server Info']['entrybox'] = self.textEntry
117 | self.tabs['Server Info']['onlineusers'] = ''
118 |
119 | self.n.add(self.textboxframe, text='Server Info')
120 | self.n.grid(row=0, column=0, sticky=N+S+E+W)
121 |
122 | def get_username(self, event=None):# Gets the initial username after hitting the enter chat button
123 | self.aliasName = self.enterUser.get()
124 | self.IDENT = self.enterIDENT.get()
125 | self.REALNAME = self.enterREALNAME.get()
126 | self.SERVER = self.SERVERIP.get()
127 | password = self.enterPASSWORD.get()
128 | self.Channels = self.autoJoin.get()
129 | if self.aliasName == '':
130 | messagebox.showinfo(message='You must enter a username', icon='warning')
131 | elif ' ' in self.aliasName:
132 | messagebox.showinfo(message='Username cannot contain spaces', icon='warning')
133 | elif not password and self.checkSSL.get() == 1:
134 | self.sckt = ssl.wrap_socket(self.sckt)
135 | self.PORT = 6697
136 | self.start_recv_loop()
137 | elif password and self.checkSSL.get() == 1:
138 | self.sckt = ssl.wrap_socket(self.sckt)
139 | self.PORT = 6697
140 | self.start_recv_loop()
141 | self.sckt.send(bytes('PRIVMSG NickServ : IDENTIFY %s\r\n' % password, "UTF-8"))
142 | else:
143 | self.PORT = 6667
144 | self.start_recv_loop()
145 | self.user_settings()
146 |
147 | def start_recv_loop(self):
148 | self.top.destroy()
149 | self.master.title('Python Chat - %s' % self.aliasName)
150 | self.sckt.connect((self.SERVER, self.PORT))
151 | thread = threading.Thread(target=self.recv_loop, args=[self.sckt])
152 | thread.daemon = True
153 | thread.start()
154 | self.root.after(500, lambda:self.sckt.send(bytes("NICK %s\r\n" % self.aliasName, "UTF-8")))
155 | self.root.after(500, lambda:self.sckt.send(bytes("USER %s %s bla :%s\r\n" % (self.IDENT, self.SERVER, self.REALNAME), "UTF-8")))
156 | self.textEntry.focus_force()
157 | self.root.after(8000, self.auto_join_chan)
158 |
159 | def check_pm_commands(self, event=None):
160 | tab = self.n.tab(self.n.select(), "text")
161 | textboxinc = self.tabs[tab]['textbox']
162 | message = self.tabs[tab]['entrybox'].get('1.0','end-1c')
163 | self.tabs[tab]['entrybox'].delete('1.0', END)
164 | self.tabs[tab]['entrybox'].focus_force()
165 | if len(message)>=1 and message[0] == '/':
166 | self.process_commands(message)
167 | else:
168 | self.post_pm_controls(self.aliasName + ':>' + message + '\n', textboxinc)# Post the received text to the window
169 | self.sckt.send(bytes("PRIVMSG %s %s \r\n" % (tab, ':' + message), "UTF-8"))
170 | return 'break'
171 |
172 | def process_commands(self, message):
173 | format = message.split(' ')
174 | if '/msg' in format:
175 | type = 'pm'
176 | message = " ".join(format[2:])
177 | tab_name = format[1].lower()
178 | if len(message) < 1:
179 | messagebox.showinfo(message='You must enter some text after /msg username', icon='warning')
180 | else:
181 | self.add_tab(tab_name, type)
182 | self.tabs[tab_name]['entrybox'].delete('1.0', END)
183 | self.find_window(tab_name, self.aliasName + ':>' + message + '\n')
184 | self.sckt.send(bytes("PRIVMSG %s %s \r\n" % (tab_name, ':' + message), "UTF-8"))
185 | elif '/join' in message:
186 | tab_name = format[1].lower()
187 | type = 'channel'
188 | self.add_tab(tab_name, type)
189 | elif '/leave' in message:
190 | self.leave_channel()
191 | elif '/nick' in message:
192 | self.name_change(self.aliasName, message)
193 | elif '/quit' in message:
194 | self.shutdownClient()
195 | else:
196 | messagebox.showinfo(message='Command not found.', icon='warning')
197 |
198 | def recv_loop(self, connection): # Main receiving loop for all incoming messages
199 | while True:
200 | (readable, writable, errored) = select([connection], [], [connection], 0.1)
201 | if readable:
202 | readbuffer=""
203 | readbuffer=readbuffer+self.sckt.recv(1024).decode("UTF-8")
204 | temp=str.split(readbuffer, "\n")
205 | readbuffer=temp.pop( )
206 | for line in temp:
207 | line=str.rstrip(line)
208 | line=str.split(line)
209 | self.root.after_idle(self.iterate_through_incoming, line)
210 |
211 | def iterate_through_incoming(self, line): # Look through the incoming messages for info from the server
212 | try:
213 | if line[0] == "PING":# Looks for PING from the server and replies with a PONG
214 | self.sckt.send(bytes("PONG %s\r\n" % line[1], "UTF-8"))
215 | elif self.aliasName + '!' in line[0]:
216 | pass
217 | elif line[0] == '353' or line[1] == '353': # Looks for NAMES list
218 | self.build_online_list(line)
219 | elif line[1] == '401': # Returns warning if user/channel doesn't exist
220 | messagebox.showinfo(message='No such user/channel %s'% line[3], icon='warning')
221 | elif line[1] == 'QUIT':
222 | self.remove_on_quit(line)
223 | elif line[1] == "PRIVMSG" and line[3] == ':\x01ACTION':
224 | message = line[3].lstrip(':')
225 | x = " ".join(line[4:]) # Grabbing everything after the 3rd index and joining the message.
226 | format_user1 = line[0].strip(':')
227 | finish_format = format_user1.split('!')
228 | user = finish_format[0]
229 | self.find_window(line[2].lower(), '*' + user + ' ' + x + '\n') # Post the received text to the window
230 | elif line[1] == "PRIVMSG": # If PRIVMSG is in line[1] position, its a message from a channel or a private message
231 | self.get_incoming_channel(line)
232 | elif line[1] == 'JOIN' and self.aliasName not in line[0]:# If JOIN is line[1], a new user joined the channel
233 | self.get_join_leave_name(line)
234 | elif line[1] == 'PART' and self.aliasName not in line[0]: # If PART is line[1] a user has left update the online user list
235 | self.get_join_leave_name(line)
236 | elif line[1] == 'NICK' and self.aliasName not in line[2]: # If NICK is line[1] a user has changed their name, update the online user list
237 | self.get_join_leave_name(line)
238 | elif line[1] == 'NOTICE' and line[2] == self.aliasName: # If line[1] is NOTICE and line[2] is the users name grab that message
239 | get_tab = line[3].split('[')
240 | get_tab_finish = get_tab[1].split(']')
241 | x = " ".join(line[4:]) # Grabbing everything after the 3rd index and join the message.
242 | self.find_window(get_tab_finish[0].lower(), x + '\n')
243 | elif line[1] == '328' or line[1] == '332' or line[1] == '333' or line[1] == '366': # Grabs server messages on joining. If the tab name is in line[3], grab the message
244 | x = " ".join(line[3:]) # Grabbing everything after the 3rd index and join the message.
245 | self.find_window(line[3].lower(), x + '\n')
246 | elif ':' in line[0]: # Grabs all message from the server and posts them to the main tab
247 | x = " ".join(line[3:]) # Grabbing everything after the 1st index and join the message.
248 | self.post_pm_controls(x + '\n', self.tabs['Server Info']['textbox'])
249 | else: # Grabs names that come through as a seperate list and rebuilds it and runs it back through this method to be reiterated
250 | tab = self.n.tab(self.n.select(), "text")
251 | strayusers = [':placeholder', '353', self.aliasName, '=', tab]
252 | for item in line:
253 | strayusers.append(item)
254 | self.iterate_through_incoming(strayusers)
255 | except IndexError: # Some times there is no data in the indexes of the incoming messages
256 | pass
257 |
258 | def get_incoming_channel(self, line):
259 | if "#" in line[2]: # Message from channel
260 | channel = "" # Get the incoming sender
261 | incomg_msg = line[0].split('!') # Split the message at the !
262 | channel += incomg_msg[0].lstrip(':') # Strip the : out
263 | x = " ".join(line[3:]) # Grabbing everything after the 3rd index and join the message.
264 | self.find_window(line[2].lower(), channel+':>'+ x.lstrip(':') + '\n') # Post the received text to the window
265 | else: # Private message from user
266 | type = 'pm'
267 | message = line[3].lstrip(':')
268 | x = " ".join(line[4:]) # Grabbing everything after the 3rd index and joining the message.
269 | format_sender1 = line[0].strip(':')
270 | finish_format = format_sender1.split('!')
271 | user = finish_format[0]
272 | self.add_tab(user.lower(), type)
273 | self.find_window(user.lower(), user + ':>' + message + ' ' + x + '\n')
274 |
275 | def add_tab(self, tab_name, type):
276 | if tab_name not in self.tabs:
277 | self.tab_generator(tab_name, type)
278 | else:
279 | if tab_name == self.n.tab(self.tabs[tab_name]['tab'], "text") and self.n.tab(self.tabs[tab_name]['tab'], "state") == 'hidden' and type == 'channel':
280 | self.n.tab(self.tabs[tab_name]['tab'], state='normal')
281 | self.n.select(self.tabs[tab_name]['tab'])
282 | self.tabs[tab_name]['onlineusers'].delete(1, 'end')
283 | self.tabs[tab_name]['textbox'].delete(0,'end-1c')
284 | self.tabs[tab_name]['entrybox'].focus_force()
285 | self.sckt.send(bytes("JOIN %s\r\n" % tab_name, "UTF-8"))
286 | elif tab_name == self.n.tab(self.tabs[tab_name]['tab'], "text") and self.n.tab(self.tabs[tab_name]['tab'], "state") == 'normal' and type == 'channel':
287 | self.n.select(self.tabs[tab_name]['tab'])
288 | self.tabs[tab_name]['entrybox'].focus_force()
289 |
290 | def tab_generator(self, tab_name, type): # Tab generator for creating channels/pms
291 | # Create channel tab
292 | self.tab_name = ttk.Frame(self.n)
293 | self.tab_name.grid(row=0, column=0, rowspan=2, sticky=N+S+E+W)
294 |
295 | self.receive_user = ScrolledText(self.tab_name, height=24, width=47, wrap = WORD)
296 | self.receive_user.grid(row=0, column=0, padx=(10,0), pady=(10,5), sticky=N+S+E+W)
297 | self.receive_user.config(state=DISABLED)
298 |
299 | self.pm_Entry = ScrolledText(self.tab_name, height=2, width=47, wrap = WORD)
300 | self.pm_Entry.grid(row=2, column=0, padx=(10,0), pady=(0,10), sticky=N+S+E+W)
301 | self.pm_Entry.bind('', self.check_pm_commands)
302 |
303 | if type == 'channel':
304 | self.pm_users_box = Listbox(self.tab_name, width=12)
305 | self.pm_users_box.grid(row = 0, column= 1, rowspan=3, padx=(0,10), pady=(10,10), sticky=N+S+E+W)
306 | self.pm_users_box.insert(0, 'Online [0]')
307 |
308 | self.tabs[tab_name] = {}
309 | self.tabs[tab_name]['tab'] = self.tab_name
310 | self.tabs[tab_name]['textbox'] = self.receive_user
311 | self.tabs[tab_name]['entrybox'] = self.pm_Entry
312 | self.tabs[tab_name]['onlineusers'] = self.pm_users_box
313 | self.sckt.send(bytes("JOIN %s\r\n" % tab_name, "UTF-8"))
314 | else:
315 | self.pm_Close = Button(self.tab_name, width=7, text='Close tab', command=lambda:self.remove_on_close())
316 | self.pm_Close.grid(row=0, column=1, padx=(5,5), pady=(5,150), sticky=N+S+E+W)
317 |
318 | self.tabs[tab_name] = {}
319 | self.tabs[tab_name]['tab'] = self.tab_name
320 | self.tabs[tab_name]['textbox'] = self.receive_user
321 | self.tabs[tab_name]['entrybox'] = self.pm_Entry
322 | self.tabs[tab_name]['onlineusers'] = ''
323 |
324 | Grid.rowconfigure(self.tab_name, 0, weight=1)
325 | Grid.columnconfigure(self.tab_name, 0, weight=1)
326 |
327 | self.n.add(self.tab_name, text = tab_name)
328 | self.n.select(self.tab_name)
329 | self.pm_Entry.focus_force()
330 |
331 | def remove_on_close(self): # Get the current active tab and close it on click
332 | current_tab = self.n.tab(self.n.select(), "text")
333 | if current_tab in self.tabs and current_tab != self.SERVER:
334 | if self.tabs[current_tab]['onlineusers'] == '':
335 | self.n.hide(self.n.select())
336 | current_tab = self.n.tab(self.n.select(), "text")
337 | self.tabs[current_tab]['entrybox'].focus_force()
338 | else:
339 | self.n.hide(self.n.select())
340 | current_tab = self.n.tab(self.n.select(), "text")
341 | self.tabs[current_tab]['entrybox'].focus_force()
342 |
343 | def find_window(self, tab_name, message): # Get the name of the tab so the message gets to the correct tab
344 | if tab_name == self.n.tab(self.tabs[tab_name]['tab'], "text"):
345 | if "No such channel" in self.tabs[tab_name]['textbox'].get("1.0",'end-1c'):
346 | pass
347 | else:
348 | self.n.tab(self.tabs[tab_name]['tab'], state='normal') # If the incoming user in the the current tabs change the state of the tab to normal if hidden
349 | self.post_pm_controls(message, self.tabs[tab_name]['textbox'])# Post the received text to the window
350 |
351 | def name_change(self, user, line): # Handles a name change if a user in the channel changes their name.
352 | tab_storage = []
353 | for tabs in self.tabs:
354 | if self.tabs[tabs]['onlineusers'] == '':
355 | pass
356 | else:
357 | tab_storage.append(tabs)
358 | for tabs in tab_storage:
359 | for item in self.tabs[tabs]['onlineusers'].get(0, 'end'):
360 | if user == item:
361 | incbox = self.tabs[tabs]['textbox']
362 | new_user = line[2].split(':')
363 | index = self.tabs[tabs]['onlineusers'].get(0, END).index(user)
364 | self.tabs[tabs]['onlineusers'].delete(index)
365 | if user in item and user == self.aliasName:
366 | new_user = line.split(' ')
367 | self.tabs[tabs]['onlineusers'].insert(END, new_user[1])
368 | self.post_pm_controls(('*You are now known as %s' % new_user[1]) + '\n', incbox)
369 | self.aliasName = new_user[1]
370 | self.sckt.send(bytes("NICK %s\r\n" % self.aliasName, "UTF-8"))
371 | else:
372 | self.tabs[tabs]['onlineusers'].insert(END, new_user[1])
373 | self.post_pm_controls('*User %s is now known as %s' % (user, new_user[1]) + '\n', incbox)
374 |
375 | def get_join_leave_name(self, line): # Gets the name of the user if they join, leave, or change their name
376 | tab = line[2].split(':') # Format the incoming name and remove the ":" and get the channel
377 | user = "" # Temp storage for incoming sender name
378 | incomg_msg = line[0].split('!') # Split is at the '!'
379 | user += incomg_msg[0].lstrip(":")# Remove the ':' from the string
380 | if(line[1] == 'JOIN'): # Check if the message is someone joining
381 | self.add_online_user(user, tab[1])
382 | elif(line[1] == 'PART'): # Check if the message is someone leaving
383 | self.remove_online_user(user, tab[0])
384 | elif(line[1] == 'NICK'): # Check is the message is someone changing their name
385 | self.name_change(user, line)
386 |
387 | def add_online_user(self, user, tab): # Adds users as they join
388 | inctab = self.tabs[tab]['textbox'] # Tells which tab to update
389 | self.tabs[tab]['onlineusers'].insert(END, user) # Add the new user to the online user Listbox
390 | self.post_pm_controls('*User %s has joined the channel' % user + '\n', inctab) # Post a message to the window that a user had joined
391 |
392 | def remove_online_user(self, user, tab): # Remove users as they leave an active channel
393 | inctab = self.tabs[tab.lower()]# Tells which tab to update
394 | try:
395 | index = inctab['onlineusers'].get(0,'end').index(user)
396 | inctab['onlineusers'].delete(index) # Try to remove the user from the onlinelist and post who left
397 | self.post_pm_controls('User %s has left the channel' % user + '\n', inctab['textbox'])
398 | except ValueError: # If the user's not in the dictionary list, post who left anyway
399 | self.post_pm_controls('*User %s has left the channel' % user + '\n', inctab['textbox'])
400 | try:
401 | index1 = inctab['onlineusers'].get(0,'end').index('@' + user) # For getting the index if the user is admin
402 | inctab['onlineusers'].delete(index1)
403 | self.post_pm_controls('*User %s has left the channel' % user + '\n', inctab['textbox'])
404 | except ValueError: # If the user's not in the dictionary list, post who left anyway
405 | pass
406 |
407 | def remove_on_quit(self, line): # Remove users as they quit an active channel
408 | tab_storage = []
409 | format = line[0].split('!')
410 | user = format[0].strip(':')
411 | for tabs in self.tabs:
412 | if self.tabs[tabs]['onlineusers'] == '':
413 | pass
414 | else:
415 | tab_storage.append(tabs)
416 | for tabs in tab_storage:
417 | for item in self.tabs[tabs]['onlineusers'].get(0, 'end'):
418 | if user == item:
419 | incbox = self.tabs[tabs]['textbox']
420 | index = self.tabs[tabs]['onlineusers'].get(0, END).index(user)
421 | self.tabs[tabs]['onlineusers'].delete(index)
422 | x = " ".join(line[2:])
423 | self.post_pm_controls('*User %s has quit. Reason: %s' % (user, x) + '\n', incbox)
424 |
425 | def leave_channel(self): # Called on /leave from user. Leaves the current tab that is focused
426 | tab = self.n.tab(self.n.select(), "text")
427 | if tab == self.SERVER:
428 | pass
429 | elif "No such channel" in self.tabs[tab]['textbox'].get("1.0",'end-1c'):
430 | self.remove_on_close()
431 | elif self.tabs[tab]['onlineusers'] == '':
432 | self.remove_on_close()
433 | else:
434 | self.sckt.send(bytes("PART %s\r\n" % tab, "UTF-8"))
435 | self.remove_on_close()
436 |
437 | def build_online_list(self, line):# Builds the online users list
438 | try:
439 | if self.tabs[line[4].lower()]['onlineusers'] == '': # If there are no users in that channel/users dictionary, pass
440 | pass
441 | else:
442 | users = [] # Temp storage for incoming names
443 | first_user = line[5].replace(':', '') # Formats the first username in the list
444 | users.append(first_user) # add user to temp list
445 | for items in line[6:]: # Get the rest of the incoming name and add them to the dictionaries users list
446 | users.append(items)
447 | for items in sorted(users):
448 | self.tabs[line[4].lower()]['onlineusers'].insert(END, items)
449 | self.count_online(line[4].lower())
450 | except KeyError:
451 | pass
452 |
453 | def count_online(self, tab_name): # counts the online users.
454 | user_count = self.tabs[tab_name]['onlineusers'].size()
455 | self.tabs[tab_name]['onlineusers'].delete(0)
456 | self.tabs[tab_name]['onlineusers'].insert(0, 'Online [%d]' % (user_count - 1))
457 |
458 | def post_pm_controls(self, pm, window):# Handles the state of the tabed text boxes as well as inserting text into the box
459 | window.config(state=NORMAL)
460 | window.insert(END, time.strftime("[%I:%M %p]") + pm)
461 | window.config(state=DISABLED)
462 | window.see(END)
463 |
464 | def shutdownClient(self): # Called on /quit from the user.
465 | for i in self.n.tabs():
466 | self.sckt.send(bytes("PART %s\r\n" % self.n.tab(i, "text"), "UTF-8"))
467 | self.root.destroy()
468 |
469 | def auto_join_chan(self):
470 | if self.Channels:
471 | get_channels = self.Channels.split(',')
472 | for item in get_channels:
473 | self.add_tab(item, 'channel')
474 |
475 | def user_settings(self):
476 | if not self.parser.has_section("UserSettings"):
477 | self.parser.add_section('UserSettings')
478 | self.parser.set('UserSettings', 'NickName', self.aliasName)
479 | self.parser.set('UserSettings', 'Identity', self.IDENT)
480 | self.parser.set('UserSettings', 'RealName', self.REALNAME)
481 | if not self.parser.has_section('AutoJoin'):
482 | self.parser.add_section('AutoJoin')
483 | self.parser.set('AutoJoin', 'Channels', self.Channels)
484 | with open("settings.ini", "w") as config:
485 | self.parser.write(config)
486 |
487 | if __name__ == '__main__':
488 | root = Tk()
489 | app = Window(root)
490 | root.mainloop()
491 |
--------------------------------------------------------------------------------