PageRenderTime 64ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/pyzok02.py

https://github.com/vivekn/pyzok
Python | 381 lines | 351 code | 8 blank | 22 comment | 5 complexity | 53691a145fb531ca75032b9297690c2c MD5 | raw file
  1. #!/usr/bin/python
  2. #
  3. # pyzok chat server v0.2 (August 1st 2010)
  4. # by
  5. # Vivek Narayanan<mail@vivekn.co.cc>
  6. #
  7. # released under GNU GPL 2.0
  8. #
  9. #
  10. # This is a text based chat server,to use it simply execute this .py file
  11. # From the client side,connect using pChat or any Mud/Moo client or design your own client
  12. #
  13. # You can add new commands by creating a function do_xxxx in the class definition of ChatRoom,
  14. # replace xxxx with the command
  15. #
  16. __author__="Vivek"
  17. __date__ ="$14 May, 2010 8:08:22 PM$"
  18. from socket import *
  19. import asyncore
  20. import socket
  21. from asyncore import dispatcher
  22. from asynchat import async_chat
  23. #Message Codes
  24. ERR = '!!Error\r\n'
  25. MSG = '!!Msg\r\n'
  26. SERV = '!!SM\r\n'
  27. LIST = '!!List\r\n'
  28. ADDR = '!!Addr\r\n'
  29. STAT = '!!Stat\r\n'
  30. if __name__ == "__main__":
  31. class EndSession(Exception): pass #This is used for handling a user logging out
  32. class CommandHandler:
  33. server=None
  34. def unknown(self, session, cmd,line):
  35. session.push(ERR + 'Unknown command: %s\r\n' % cmd)
  36. def handle(self, session, line):
  37. '''
  38. This function handles the data received by the server.If the incoming
  39. text contains a command , it checks a function do_command exists and if it does
  40. it calls the function.
  41. '''
  42. ori=line
  43. print ori
  44. self.server.log+='%s:%s\r\n'%(ori,line) #appends data to server log
  45. if not line.strip():
  46. return
  47. parts = line.split(' ', 1)
  48. cmd = parts[0]
  49. try: line = parts[1].strip()
  50. except IndexError: line = ''
  51. meth = getattr(self, 'do_'+cmd, None)
  52. if callable(meth):
  53. meth(session, line)
  54. else:
  55. self.unknown(session, cmd,ori)
  56. class Room(CommandHandler):
  57. '''
  58. Class extending a CommandHandler,forms the basis for a chatroom
  59. '''
  60. def __init__(self, server,name='',msg=''''''):
  61. self.server = server
  62. self.name = name
  63. self.sessions = []
  64. self.msg=msg
  65. def add(self, session):
  66. self.sessions.append(session)
  67. def remove(self, session):
  68. self.sessions.remove(session)
  69. def broadcast(self, line):
  70. for session in self.sessions:
  71. session.push(MSG+line)
  72. def do_logout(self, session, line):
  73. raise EndSession
  74. class LoginRoom(Room):
  75. '''
  76. The user first logs in to this room when he or she connects to the server.
  77. '''
  78. def add(self, session):
  79. Room.add(self, session)
  80. self.broadcast('Welcome to %s\r\n' % (self.server.name))
  81. print session
  82. def unknown(self, session, cmd,line):
  83. session.push(SERV+'Please log in\nUse "login <nick>"\r\n')
  84. def do_login(self, session, line):
  85. name = line.strip()
  86. if not name:
  87. session.push(ERR+'Please enter a name\r\n')
  88. elif name in self.server.users:
  89. session.push(ERR+'The name "%s" is taken.\r\n' % name)
  90. session.push(ERR+'Please try again.\r\n')
  91. else:
  92. session.name = name
  93. session.enter(self.server.rooms[0])
  94. session.push(SERV+"Welcome to "+self.server.name+','+line.strip()+'\r\n')
  95. def do_admin(self,session,line):
  96. #used to authenticate an admin user
  97. name=line.split(' ', 1)
  98. if name[0]in self.server.admins:
  99. try:
  100. if self.server.admins[name[0]]==name[1]:
  101. session.isAdmin=True
  102. session.name=name[0]
  103. session.enter(self.server.rooms[0])
  104. session.push(SERV+"Welcome to "+self.server.name+','+name[0]+'\r\nYou now have admin privileges\r\n')
  105. else:
  106. session.push(ERR+"Authentication Failed. \r\n")
  107. except Exception,e:session.push(ERR+"Error:"+str(e)+'\r\n')
  108. else:
  109. session.push(ERR+"Authentication Failed. \r\n")
  110. class ChatRoom(Room):
  111. def add(self, session):
  112. self.broadcast(session.name + ' has entered the room.\r\n')
  113. self.server.users[session.name] = session
  114. Room.add(self, session)
  115. if len(self.msg):
  116. self.play_welcome_message(session, self.msg)
  117. def remove(self, session):
  118. Room.remove(self, session)
  119. self.broadcast(session.name + ' has left the room.\r\n')
  120. def do_say(self, session, line):
  121. # 1 to all message,format:say message
  122. self.broadcast(session.name+': '+line+'\r\n')
  123. def do_pm(self,session,line):
  124. # 1 on 1 chat,format:say user message
  125. sent=0
  126. user = line.split(' ',1)
  127. for a in self.sessions:
  128. if a.name==user[0]:
  129. a.push(MSG+'pm from '+session.name+': '+user[1]+'\r\n')
  130. sent=1
  131. break
  132. if not sent:
  133. session.push(ERR+'User %s not found\r\n'%user[0])
  134. def do_ulist(self, session, line):
  135. #lists all users in the room
  136. session.push(LIST)
  137. for other in self.sessions:
  138. session.push(other.name + '\r\n')
  139. def do_sulist(self, session, line):
  140. #lists all users connected to the server
  141. session.push(LIST)
  142. for name in self.server.users:
  143. session.push(name +'~~' + self.server.users[name].status + '\r\n')
  144. def unknown(self,session,cmd,line):
  145. #when no specific command is given,it is treated as a normal (1 to many) chat message,format:message
  146. self.broadcast(session.name+': '+line+'\r\n')
  147. def do_newroom(self,session,line):
  148. #for creating a new room,requires the user to be admin,format:newroom room_name
  149. if session.isAdmin==True:
  150. try:
  151. self.server.new_room(line.strip())
  152. session.push(SERV+'A new room %s has been created.\r\n'%line.strip())
  153. except Exception,e:
  154. session.push(ERR+'Error occured:'+str(e)+'\r\n')
  155. else:
  156. session.push(ERR+'You do not have the required permissions.\r\n')
  157. def do_delroom(self,session,line):
  158. #for deleting a room,requires the user to be admin,format:delroom room_name
  159. if session.isAdmin==True and line.strip()!='Home':
  160. try:
  161. self.server.del_room(line.strip())
  162. session.push(SERV+'The room %s has been deleted\r\n'%line.strip())
  163. except Exception,e:
  164. session.push(ERR+'Error occured:'+str(e)+'\r\n')
  165. else:
  166. session.push(ERR+'You do not have the required permissions.\r\n')
  167. def do_serverlogs(self,session,line):
  168. #for writing the string log,which stores the activity log to a file,format:serverlogs [filename]
  169. if session.isAdmin==True:
  170. try:
  171. if len(line.strip()):
  172. self.server.writelogs(line.strip())
  173. else: self.server.writelogs()
  174. except Exception:pass
  175. else:server.push(SERV+"Server logs written to file successfully\r\n")
  176. else:
  177. session.push(ERR+'You do not have the required permissions.\r\n')
  178. def do_listrooms(self,session,line):
  179. #lists all rooms on the server
  180. session.push(LIST+self.server.list_rooms()+'\r\n')
  181. def do_joinroom(self,session,line):
  182. #for the user to join another room,format:joinroom room_name
  183. flag=0
  184. for ele in self.server.rooms:
  185. if ele.name==line.strip():
  186. flag=1
  187. session.enter(ele)
  188. session.push(SERV+"Joined room %s"%ele.name)
  189. if not flag:
  190. session.push(ERR+'No such room,%s\r\n'%line.strip())
  191. def do_reqaddr(self,session,line):
  192. #request the ip address of another user,can be used for filesharing between clients
  193. if line.strip() in self.server.users:
  194. self.server.users[line.strip()].push_address(session)
  195. else:
  196. session.push(ERR+'User %s not found\r\n'%line.strip())
  197. def do_setmsg(self,session,line):
  198. if session.isAdmin:
  199. self.msg=line.strip()
  200. session.push(SERV+'Welcome message set\r\n')
  201. else:
  202. session.push(ERR+'You do not have the required permissions.\r\n')
  203. def do_statset(self,session,line):
  204. session.set_status(line)
  205. def do_fsetmsg(self,session,line):
  206. if session.isAdmin:
  207. try:
  208. f=open(line.strip())
  209. self.msg=f.read()
  210. except Exception,e:
  211. session.push(ERR+str(e)+'\r\n')
  212. else:
  213. session.push(SERV+'%s set as welcome message file\r\n'%line.strip())
  214. else:
  215. session.push(ERR+'You do not have the required permissions.\r\n')
  216. def play_welcome_message(self,session,msg):
  217. #plays welcome message when user enters the room
  218. session.push(MSG+msg)
  219. class LogoutRoom(Room):
  220. #used for logging the user out
  221. def add(self, session):
  222. try: del self.server.users[session.name]
  223. except KeyError: pass
  224. class ChatSession(async_chat):
  225. #Object identifying each user
  226. def __init__(self, server, sock,addr):
  227. async_chat.__init__(self, sock)
  228. self.server = server
  229. self.set_terminator("\r\n")
  230. self.data = []
  231. self.addr=addr[0]
  232. self.status = ''
  233. self.name=None
  234. self.isAdmin=False
  235. self.enter(LoginRoom(server))
  236. self.accept_file_flag=True
  237. def enter(self, room):
  238. #user enters a new room,quits the current room
  239. try: cur = self.room
  240. except AttributeError: pass
  241. else: cur.remove(self)
  242. self.room = room
  243. room.add(self)
  244. def set_status(self,status):
  245. self.status=status
  246. def push_address(self,session):
  247. #used for reqaddr command
  248. session.push(ADDR+(self.addr)+'\r\n')
  249. def collect_incoming_data(self, data):
  250. #reads data from user's socket
  251. self.data.append(data)
  252. def found_terminator(self):
  253. #the user's request is handled as soon as a line terminator is reached.
  254. line = ''.join(self.data)
  255. self.data = []
  256. try:
  257. self.room.handle(self,line)
  258. except EndSession:
  259. self.handle_close() #raised when logging out
  260. def handle_close(self):
  261. #destroys the session upon logging out
  262. #self.push(MSG+'Closing session\r\n')
  263. async_chat.handle_close(self)
  264. self.enter(LogoutRoom(self.server))
  265. class ChatServer(dispatcher):
  266. def __init__(self,port,name,max=5):
  267. dispatcher.__init__(self)
  268. self.log=''''''
  269. self.name=name
  270. self.sessions=[]
  271. self.rooms=[]
  272. self.admins={'root':'pw1'}
  273. #user/password(or hash) combinations,you can make the password a hash and
  274. #modify do_admin for more security
  275. self.create_socket(socket.AF_INET,socket.SOCK_STREAM)
  276. self.set_reuse_addr()
  277. self.bind(('127.0.0.1',port))
  278. self.listen(max)
  279. self.users = {}
  280. self.rooms.append(ChatRoom(self,"Home"))
  281. def handle_accept(self):
  282. conn, addr = self.accept()
  283. y=ChatSession(self,conn,addr)
  284. self.sessions.append(y)
  285. def new_room(self,name):
  286. self.rooms.append(ChatRoom(self,name))
  287. def del_room(self,room):
  288. if len(self.rooms)>1:
  289. for i in range(len(self.rooms)):
  290. if room==self.rooms[i].name:
  291. for session in self.rooms[i].sessions:
  292. session.handle_close()
  293. del self.rooms[i]
  294. def whois(self):
  295. i=0
  296. for user in self.users:
  297. if i:
  298. yield '::'
  299. yield user
  300. i=1
  301. def writelogs(self,file='logs.txt'):
  302. f=open(file,'a')
  303. f.write(self.log)
  304. f.close()
  305. self.log=''''''
  306. def list_rooms(self):
  307. str=''
  308. for room in self.rooms:
  309. str+=room.name+'\r\n'
  310. return str[:-1]
  311. s = ChatServer(7777,"pyzok chat server")
  312. try:
  313. asyncore.loop()
  314. except KeyboardInterrupt: pass