/
main.py
305 lines (267 loc) · 9.72 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# Copyright (c) 2015 Gregory Gaston
# License: https://opensource.org/licenses/MIT
# This file contains the main() function for the TauNet system as
# well as many of the basic functions involved with sending messages
# recieving messages, and the program interface.
# Built in libraries
import socket, threading, time, os
# my libraries
import protocol, saber, messages, user_func
# <<<< <<<< <<<< Globals Variable >>>> >>>> >>>> #
port = 6283
myip = socket.gethostbyname(socket.gethostname())
my_user_name = ''
TauNet_version = '1.0'
protocol_version = '0.2'
filename = ''
input_message = '' #Global variable
TIMEOUT = 8
MAX_MESSAGE_LENGTH = 600
key = ''
# <<<< <<<< <<<< MESSAGING FUNCTIONS >>>> >>>> >>>> #
# Functions dealing with the sending and recieveing of messages.
# Sends a message based on the user_info
def send_message(user_info, my_info, message, key):
# Package
pay = protocol.write_message(user_info, my_info, message, protocol_version)
# Encrypt
enc_pay = saber.encrypt(pay.encode(), 20, key)
# Convert to string
str_enc_pay = ''
for i in range(len(enc_pay)):
str_enc_pay = str_enc_pay + chr(enc_pay[i])
# Send payload
s = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
s.settimeout(TIMEOUT)
s.connect((user_info[1], port)) # connet() takes tuple (user_ip, port#)
assert s
s.send(str_enc_pay.encode()) #encode converts message to bin
s.shutdown(1)
s.close()
return
# Listens for incoming messages
# Run as a seporate thread
def listen(user_list, message_hist):
s = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
assert s
s.bind(('', 6283))
while 1:
s.listen(1)
assert s
(conn , addr) = s.accept()
mess = conn.recv(1024).decode() #decode convers from bin to string
#Hangs untill message is recieved
assert mess
## FORK HERE TO DECODE WHILE STILL BEING ABLE TO ACCEPT A NEW MESSAGE
#convert to list
mess_list = [ord(mess[i]) for i in range(len(mess))]
# decrypt
dec_mess = saber.decrypt(mess_list, 20, user_list.key)
# convert to string
message = ''
for i in range(len(dec_mess)):
message = message + chr(dec_mess[i])
rec_mess = protocol.read_message(message) #piece out message
assert rec_mess
if not rec_mess or rec_mess[2] == '' or rec_mess[2] == '\n': ##Empty message recieved
None
elif(user_list.search_users(rec_mess[0][0])):
print('\n' + rec_mess[0][0] + ':\t' + rec_mess[2] + '\n' + input_message, end = '')
message_hist.add_message(rec_mess[0][0], rec_mess[1][0], rec_mess[2])
else:
#Send error message
print('\n<<Message recieved from unknon user and discarded>>\n' + input_message, end = '')
return
# <<<< <<<< <<<< COMMAND FUNCTIONS >>>> >>>> >>>> #
# This section contains functions pertaining to the different
# commands that are accepted by the TauNet command prompt.
# Breaks a command in to it's pieces
def read_command(command):
if not command:
return None
length = len(command)
i = 1
part1 = part2 = None
while i < length and command[i] != ' ':
i = i + 1
part1 = command[1:i]
part2 = command[i+1:length]
return (part1, part2)
#@user message
def at(user_info, message):
message_end = None
while message:
if len(message) > MAX_MESSAGE_LENGTH:
message_end = message[MAX_MESSAGE_LENGTH:]
message = message[:MAX_MESSAGE_LENGTH]
else:
message_end = None
resend = True
while resend:
try:
send_message(user_info, (my_user_name, myip), message, key)
except:# TimeoutError:
if input("Error:\n * Unable to send message to " + user_info[0] + ". Attempt to resend message? (y/n) " ) == 'n':
resend = False
else:
resend = False
message = message_end
time.sleep(0.1) #make sure we don't overload someone else's reciever
return None
# Help menu
def help_menu():
print(" Command | Description")
print(" ----------------------+-------------------------------------------------------")
print(" ? | Displays this dialogue")
print(" @user_name Message | Sends 'user_name' 'Message'")
print(" @ Message | Sends 'Message' to the last 'user_name' messaged")
print(" +user_name ip_address | Adds 'user_name' to the list of users at 'ip_address.'")
print(" -user_name | Remove 'user_name' from the list of users.")
print(" #n | Displays the last 'n' messages from 1 to 20")
print(" | if n is not specified prints the last message")
# print(" #user_name n | Displays the last 'n' messages (to and) from user_name")
print(" ~ | Displays all networked users and their address")
# print(" ~user_name | Displays user_name's information")
print(" !CLEAR | Clear the Screen")
print(" !EXIT | Exit the program")
print(" ----------------------+-------------------------------------------------------")
return None
# Clear the display:
def clear():
try:
if os.name == 'nt':
clear = os.system('cls')
else:
clear = os.system('clear')
except: None
return None
# <<<< <<<< <<<< MAIN >>>> >>>> >>>> #
# The main execution branch for TauNet.
def main(LMT= False):
# Declair Globals that will be set
global my_user_name, key, filename, input_message
# LONG MESSAGE TESTING:
if LMT:
assert open("test_file.txt")
user_list = user_func.u_list("test_file.txt")
message_hist = messages.message_list()
my_user_name = user_list.me
key = user_list.key
user_info = old_user = None
listen_thread = threading.Thread(target=listen, args = (user_list, message_hist,))
listen_thread.daemon = True
listen_thread.start()
message = ''
l = int(input("Message Max Length == " + str(MAX_MESSAGE_LENGTH) +"\nLength of string to send: "))
n = int(input("Number of times to send full message: "))
for i in range(l):
message = message + str(i%10)
for i in range(n):
at(('user1', '127.0.0.1'), message)
return None
# END LONG MESSAGE TESTING
# Main proper
print(" _ __ __ ____ ____ \n" +
" _____ ___ __ __/ | / /__ / /_ _ __ \ // __ \ \n" +
" / __/ __ `/ / / / |/ / _ \/ __/ | | / / / // / / / \n" +
" / /_/ /_/ / /_/ / /| / __/ /_ | |/ / / // /_/ / \n" +
" \__/\__,_/\__,_/_/ |_/\___/\__/ |___/ /_(_)____/ \n" +
"\n")
## ASCII TEXT ART FROM: http://patorjk.com/software/taag/#p=display&f=Slant
# Select file to open
while True:
filename = input("Enter TauNet filename, type 'new' to create new TauNet, or type '!EXIT' to exit.\n: >> ")
if filename == '!EXIT':
return None
elif filename == 'new':
user_list = user_func.u_list()
user_list.input_u_list()
else:
try:
open(filename)
except IOError:
print(filename + " does not exist.")
if input("Would you like to create it? (y/n): ") == 'y':
user_list = user_func.u_list()
user_list.input_u_list(filename)
break
else:
user_list = user_func.u_list(filename)
break
# Set up local variables
message_hist = messages.message_list()
user_info = old_user = None
# Set up global variable
my_user_name = user_list.me
key = user_list.key
filename = user_list.filename
input_message = "TauNet (" + filename + ") v" + TauNet_version + ">> "
# Start Listening for incoming messages
listen_thread = threading.Thread(target=listen, args = (user_list, message_hist,))
listen_thread.daemon = True
listen_thread.start()
# Menu loop
while True:
split_command = None
command = input('\n' + input_message)
if command == '':
None# Do nothing
# Send a message to a user
elif command[0] == '@':
user_name, message = read_command(command)
if(user_name != ''):
old_user = user_info
user_info = None
user_info = user_list.search_users(user_name)
if user_info: #send the message
at(user_info, message)
else:
user_info = old_user
print("Error:\n * Invalid Command. ? for help.") ##Invalid user_name
# Add a user to the list
elif command[0] == '+':
split_command = read_command(command)
if (split_command[0] != '' and split_command[1] != '' and
user_func.valid_user(split_command[0]) and
user_list.add_user(split_command)):
user_list.write_file()
else:
print("Error:\n * Users name may only contain uppercase and lowercase letters from a-z, the numbers from 0-9, and the - symbol.\n * User names must also not have already been added to the list.")
# Remove a user from the list
elif command[0] == '-':
if command == '-':
print("Error:\n * Invalid Command. ? for help.")
elif user_list.remove_user(command[1:]):
user_list.write_file()
user_info = None
# Display the last n messages
# or the last message
elif command[0] == '#':
try:
lines = int(command[1:])
except:
lines = -1
if lines > 0 and lines < 21:
message_hist.print_n(lines)
else:
print("Error:\n * n must be a whole number from 1 to 20 represented in digits.")
# Display the list of users
elif command == '~':
user_list.print_users(); print()
# Display help menue
elif command == '?':
help_menu()
# Clear the Screen
elif command == '!CLEAR':
clear()
# Exit the program
elif command == '!EXIT':
return
#Invalid command
else:
print("Error:\n * Invalid Command. ? for help.")
return None
if __name__ == "__main__":
clear()
main()
clear()