raw
genesis                 1 import socket
genesis 2 import time
genesis 3 import sys
genesis 4 import re
genesis 5 import string
genesis 6 import os
genesis 7 import base64
9990-keep-ephemer... 8 import traceback
9990-keep-ephemer... 9 from lib.message import Message
genesis 10 from lib.server import VERSION
genesis 11 from funcs import *
genesis 12 from lib.commands import BROADCAST
genesis 13 from lib.commands import DIRECT
genesis 14
genesis 15 class Client(object):
genesis 16 __linesep_regexp = re.compile(r"\r?\n")
genesis 17 # The RFC limit for nicknames is 9 characters, but what the heck.
genesis 18 __valid_nickname_regexp = re.compile(
genesis 19 r"^[][\`_^{|}A-Za-z][][\`_^{|}A-Za-z0-9-]{0,50}$")
genesis 20 __valid_channelname_regexp = re.compile(
genesis 21 r"^[&#+!][^\x00\x07\x0a\x0d ,:]{0,50}$")
genesis 22
genesis 23 def __init__(self, server, socket):
genesis 24 self.server = server
genesis 25 self.socket = socket
genesis 26 self.channels = {} # irc_lower(Channel name) --> Channel
genesis 27 self.nickname = None
genesis 28 self.user = None
genesis 29 self.realname = None
genesis 30 (self.host, self.port) = socket.getpeername()
genesis 31 self.__timestamp = time.time()
genesis 32 self.__readbuffer = ""
genesis 33 self.__writebuffer = ""
genesis 34 self.__sent_ping = False
genesis 35 if self.server.password:
genesis 36 self.__handle_command = self.__pass_handler
genesis 37 else:
genesis 38 self.__handle_command = self.__registration_handler
genesis 39
genesis 40 def is_addressed_to_me(self, message):
genesis 41 command = self.__parse_udp_message(message)
genesis 42 if command[0] == 'PRIVMSG':
genesis 43 if command[1][0][0] == '#' or command[1][0] == self.nickname:
genesis 44 return True
genesis 45 else:
genesis 46 return False
genesis 47 else:
genesis 48 return True
genesis 49
genesis 50 def get_prefix(self):
9989-show-wot-nicks 51 return "%s" % (self.nickname)
genesis 52 prefix = property(get_prefix)
genesis 53
genesis 54 def check_aliveness(self):
genesis 55 now = time.time()
genesis 56 if self.__timestamp + 180 < now:
genesis 57 self.disconnect("ping timeout")
genesis 58 return
genesis 59 if not self.__sent_ping and self.__timestamp + 90 < now:
genesis 60 if self.__handle_command == self.__command_handler:
genesis 61 # Registered.
genesis 62 self.message("PING :%s" % self.server.name)
genesis 63 self.__sent_ping = True
genesis 64 else:
genesis 65 # Not registered.
genesis 66 self.disconnect("ping timeout")
genesis 67
genesis 68 def write_queue_size(self):
genesis 69 return len(self.__writebuffer)
genesis 70
genesis 71 def __parse_udp_message(self, message):
genesis 72 data = " ".join(message.split()[1:]) + "\r\n"
genesis 73 lines = self.__linesep_regexp.split(data)
genesis 74 lines = lines[:-1]
genesis 75 commands = []
genesis 76 for line in lines:
genesis 77 if not line:
genesis 78 # Empty line. Ignore.
genesis 79 continue
genesis 80 x = line.split(" ", 1)
genesis 81 command = x[0].upper()
genesis 82 if len(x) == 1:
genesis 83 arguments = []
genesis 84 else:
genesis 85 if len(x[1]) > 0 and x[1][0] == ":":
genesis 86 arguments = [x[1][1:]]
genesis 87 else:
genesis 88 y = string.split(x[1], " :", 1)
genesis 89 arguments = string.split(y[0])
genesis 90 if len(y) == 2:
genesis 91 arguments.append(y[1])
genesis 92 commands.append([command, arguments])
genesis 93 return commands[0]
genesis 94
genesis 95 def __parse_read_buffer(self):
genesis 96 lines = self.__linesep_regexp.split(self.__readbuffer)
genesis 97 self.__readbuffer = lines[-1]
genesis 98 lines = lines[:-1]
genesis 99 for line in lines:
genesis 100 if not line:
genesis 101 # Empty line. Ignore.
genesis 102 continue
genesis 103 x = line.split(" ", 1)
genesis 104 command = x[0].upper()
genesis 105 if len(x) == 1:
genesis 106 arguments = []
genesis 107 else:
genesis 108 if len(x[1]) > 0 and x[1][0] == ":":
genesis 109 arguments = [x[1][1:]]
genesis 110 else:
genesis 111 y = string.split(x[1], " :", 1)
genesis 112 arguments = string.split(y[0])
genesis 113 if len(y) == 2:
genesis 114 arguments.append(y[1])
genesis 115 self.__handle_command(command, arguments)
genesis 116
genesis 117 def __pass_handler(self, command, arguments):
genesis 118 server = self.server
genesis 119 if command == "PASS":
genesis 120 if len(arguments) == 0:
genesis 121 self.reply_461("PASS")
genesis 122 else:
genesis 123 if arguments[0].lower() == server.password:
genesis 124 self.__handle_command = self.__registration_handler
genesis 125 else:
genesis 126 self.reply("464 :Password incorrect")
genesis 127 elif command == "QUIT":
genesis 128 self.disconnect("Client quit")
genesis 129 return
genesis 130
genesis 131 def __registration_handler(self, command, arguments):
genesis 132 server = self.server
genesis 133 if command == "NICK":
genesis 134 if len(arguments) < 1:
genesis 135 self.reply("431 :No nickname given")
genesis 136 return
genesis 137 nick = arguments[0]
genesis 138 if server.get_client(nick):
genesis 139 self.reply("433 * %s :Nickname is already in use" % nick)
genesis 140 elif not self.__valid_nickname_regexp.match(nick):
genesis 141 self.reply("432 * %s :Erroneous nickname" % nick)
genesis 142 else:
genesis 143 self.nickname = nick
genesis 144 server.client_changed_nickname(self, None)
genesis 145 elif command == "USER":
genesis 146 if len(arguments) < 4:
genesis 147 self.reply_461("USER")
genesis 148 return
genesis 149 self.user = arguments[0]
genesis 150 self.realname = arguments[3]
genesis 151 elif command == "QUIT":
genesis 152 self.disconnect("Client quit")
genesis 153 return
genesis 154 if self.nickname and self.user:
9990-keep-ephemer... 155 self.reply("001 %s :Hi, welcome to Pest" % self.nickname)
genesis 156 self.reply("002 %s :Your host is %s, running version blatta-%s"
genesis 157 % (self.nickname, server.name, VERSION))
genesis 158 self.reply("003 %s :This server was created sometime"
genesis 159 % self.nickname)
genesis 160 self.reply("004 %s :%s blatta-%s o o"
genesis 161 % (self.nickname, server.name, VERSION))
genesis 162 self.send_lusers()
genesis 163 self.send_motd()
genesis 164 self.__handle_command = self.__command_handler
genesis 165
genesis 166 def __command_handler(self, command, arguments):
genesis 167 def away_handler():
genesis 168 pass
genesis 169
genesis 170 def ison_handler():
genesis 171 if len(arguments) < 1:
genesis 172 self.reply_461("ISON")
genesis 173 return
genesis 174 nicks = arguments
genesis 175 online = [n for n in nicks if server.get_client(n)]
genesis 176 self.reply("303 %s :%s" % (self.nickname, " ".join(online)))
genesis 177
genesis 178 def join_handler():
genesis 179 if len(arguments) < 1:
genesis 180 self.reply_461("JOIN")
genesis 181 return
genesis 182 if arguments[0] == "0":
genesis 183 for (channelname, channel) in self.channels.items():
genesis 184 self.message_channel(channel, "PART", channelname, True)
genesis 185 self.channel_log(channel, "left", meta=True)
genesis 186 server.remove_member_from_channel(self, channelname)
genesis 187 self.channels = {}
genesis 188 return
genesis 189 channelnames = arguments[0].split(",")
genesis 190 if len(arguments) > 1:
genesis 191 keys = arguments[1].split(",")
genesis 192 else:
genesis 193 keys = []
genesis 194 keys.extend((len(channelnames) - len(keys)) * [None])
genesis 195 for (i, channelname) in enumerate(channelnames):
genesis 196 if irc_lower(channelname) in self.channels:
genesis 197 continue
genesis 198 if not valid_channel_re.match(channelname):
genesis 199 self.reply_403(channelname)
genesis 200 continue
genesis 201 channel = server.get_channel(channelname)
genesis 202 if channel.key is not None and channel.key != keys[i]:
genesis 203 self.reply(
genesis 204 "475 %s %s :Cannot join channel (+k) - bad key"
genesis 205 % (self.nickname, channelname))
genesis 206 continue
genesis 207 channel.add_member(self)
genesis 208 self.channels[irc_lower(channelname)] = channel
genesis 209 self.message_channel(channel, "JOIN", channelname, True)
genesis 210 self.channel_log(channel, "joined", meta=True)
genesis 211 if channel.topic:
genesis 212 self.reply("332 %s %s :%s"
genesis 213 % (self.nickname, channel.name, channel.topic))
genesis 214 else:
genesis 215 self.reply("331 %s %s :No topic is set"
genesis 216 % (self.nickname, channel.name))
genesis 217 self.reply("353 %s = %s :%s"
genesis 218 % (self.nickname,
genesis 219 channelname,
9989-show-wot-nicks 220 " ".join(sorted(x
9989-show-wot-nicks 221 for x in self.server.state.get_peer_handles()))))
genesis 222 self.reply("366 %s %s :End of NAMES list"
genesis 223 % (self.nickname, channelname))
genesis 224
genesis 225 def list_handler():
genesis 226 if len(arguments) < 1:
genesis 227 channels = server.channels.values()
genesis 228 else:
genesis 229 channels = []
genesis 230 for channelname in arguments[0].split(","):
genesis 231 if server.has_channel(channelname):
genesis 232 channels.append(server.get_channel(channelname))
genesis 233 channels.sort(key=lambda x: x.name)
genesis 234 for channel in channels:
genesis 235 self.reply("322 %s %s %d :%s"
genesis 236 % (self.nickname, channel.name,
genesis 237 len(channel.members), channel.topic))
genesis 238 self.reply("323 %s :End of LIST" % self.nickname)
genesis 239
genesis 240 def lusers_handler():
genesis 241 self.send_lusers()
genesis 242
genesis 243 def mode_handler():
genesis 244 if len(arguments) < 1:
genesis 245 self.reply_461("MODE")
genesis 246 return
genesis 247 targetname = arguments[0]
genesis 248 if server.has_channel(targetname):
genesis 249 channel = server.get_channel(targetname)
genesis 250 if len(arguments) < 2:
genesis 251 if channel.key:
genesis 252 modes = "+k"
genesis 253 if irc_lower(channel.name) in self.channels:
genesis 254 modes += " %s" % channel.key
genesis 255 else:
genesis 256 modes = "+"
genesis 257 self.reply("324 %s %s %s"
genesis 258 % (self.nickname, targetname, modes))
genesis 259 return
genesis 260 flag = arguments[1]
genesis 261 if flag == "+k":
genesis 262 if len(arguments) < 3:
genesis 263 self.reply_461("MODE")
genesis 264 return
genesis 265 key = arguments[2]
genesis 266 if irc_lower(channel.name) in self.channels:
genesis 267 channel.key = key
genesis 268 self.message_channel(
genesis 269 channel, "MODE", "%s +k %s" % (channel.name, key),
genesis 270 True)
genesis 271 self.channel_log(
genesis 272 channel, "set channel key to %s" % key, meta=True)
genesis 273 else:
genesis 274 self.reply("442 %s :You're not on that channel"
genesis 275 % targetname)
genesis 276 elif flag == "-k":
genesis 277 if irc_lower(channel.name) in self.channels:
genesis 278 channel.key = None
genesis 279 self.message_channel(
genesis 280 channel, "MODE", "%s -k" % channel.name,
genesis 281 True)
genesis 282 self.channel_log(
genesis 283 channel, "removed channel key", meta=True)
genesis 284 else:
genesis 285 self.reply("442 %s :You're not on that channel"
genesis 286 % targetname)
genesis 287 else:
genesis 288 self.reply("472 %s %s :Unknown MODE flag"
genesis 289 % (self.nickname, flag))
genesis 290 elif targetname == self.nickname:
genesis 291 if len(arguments) == 1:
genesis 292 self.reply("221 %s +" % self.nickname)
genesis 293 else:
genesis 294 self.reply("501 %s :Unknown MODE flag" % self.nickname)
genesis 295 else:
genesis 296 self.reply_403(targetname)
genesis 297
genesis 298 def motd_handler():
genesis 299 self.send_motd()
genesis 300
genesis 301 def nick_handler():
genesis 302 if len(arguments) < 1:
genesis 303 self.reply("431 :No nickname given")
genesis 304 return
genesis 305 newnick = arguments[0]
genesis 306 client = server.get_client(newnick)
genesis 307 if newnick == self.nickname:
genesis 308 pass
genesis 309 elif client and client is not self:
genesis 310 self.reply("433 %s %s :Nickname is already in use"
genesis 311 % (self.nickname, newnick))
genesis 312 elif not self.__valid_nickname_regexp.match(newnick):
genesis 313 self.reply("432 %s %s :Erroneous Nickname"
genesis 314 % (self.nickname, newnick))
genesis 315 else:
genesis 316 for x in self.channels.values():
genesis 317 self.channel_log(
genesis 318 x, "changed nickname to %s" % newnick, meta=True)
genesis 319 oldnickname = self.nickname
genesis 320 self.nickname = newnick
genesis 321 server.client_changed_nickname(self, oldnickname)
genesis 322 self.message_related(
genesis 323 ":%s!%s@%s NICK %s"
genesis 324 % (oldnickname, self.user, self.host, self.nickname),
genesis 325 True)
genesis 326
genesis 327 def notice_and_privmsg_handler():
genesis 328 if len(arguments) == 0:
genesis 329 self.reply("411 %s :No recipient given (%s)"
genesis 330 % (self.nickname, command))
genesis 331 return
genesis 332 if len(arguments) == 1:
genesis 333 self.reply("412 %s :No text to send" % self.nickname)
genesis 334 return
genesis 335 targetname = arguments[0]
genesis 336 message = arguments[1]
genesis 337 client = server.get_client(targetname)
genesis 338
genesis 339 if server.has_channel(targetname):
genesis 340 channel = server.get_channel(targetname)
genesis 341 self.message_channel(
genesis 342 channel, command, "%s :%s" % (channel.name, message))
genesis 343 self.channel_log(channel, message)
genesis 344 else:
genesis 345 formatted_message = ":%s %s %s :%s" % (self.prefix, command, targetname, message)
9990-keep-ephemer... 346 self.server.peer_message(Message({
genesis 347 "speaker": self.nickname,
genesis 348 "handle": targetname,
genesis 349 "body": formatted_message,
genesis 350 "bounces": 0,
genesis 351 "command": DIRECT
9990-keep-ephemer... 352 }, self.server))
genesis 353 if(client):
genesis 354 client.message(formatted_message)
genesis 355
genesis 356 def part_handler():
genesis 357 if len(arguments) < 1:
genesis 358 self.reply_461("PART")
genesis 359 return
genesis 360 if len(arguments) > 1:
genesis 361 partmsg = arguments[1]
genesis 362 else:
genesis 363 partmsg = self.nickname
genesis 364 for channelname in arguments[0].split(","):
genesis 365 if not valid_channel_re.match(channelname):
genesis 366 self.reply_403(channelname)
genesis 367 elif not irc_lower(channelname) in self.channels:
genesis 368 self.reply("442 %s %s :You're not on that channel"
genesis 369 % (self.nickname, channelname))
genesis 370 else:
genesis 371 channel = self.channels[irc_lower(channelname)]
genesis 372 self.message_channel(
genesis 373 channel, "PART", "%s :%s" % (channelname, partmsg),
genesis 374 True)
genesis 375 self.channel_log(channel, "left (%s)" % partmsg, meta=True)
genesis 376 del self.channels[irc_lower(channelname)]
genesis 377 server.remove_member_from_channel(self, channelname)
genesis 378
genesis 379 def ping_handler():
genesis 380 if len(arguments) < 1:
genesis 381 self.reply("409 %s :No origin specified" % self.nickname)
genesis 382 return
genesis 383 self.reply("PONG %s :%s" % (server.name, arguments[0]))
genesis 384
genesis 385 def pong_handler():
genesis 386 pass
genesis 387
genesis 388 def quit_handler():
genesis 389 if len(arguments) < 1:
genesis 390 quitmsg = self.nickname
genesis 391 else:
genesis 392 quitmsg = arguments[0]
genesis 393 self.disconnect(quitmsg)
genesis 394
genesis 395 def topic_handler():
genesis 396 if len(arguments) < 1:
genesis 397 self.reply_461("TOPIC")
genesis 398 return
genesis 399 channelname = arguments[0]
genesis 400 channel = self.channels.get(irc_lower(channelname))
genesis 401 if channel:
genesis 402 if len(arguments) > 1:
genesis 403 newtopic = arguments[1]
genesis 404 channel.topic = newtopic
genesis 405 self.message_channel(
genesis 406 channel, "TOPIC", "%s :%s" % (channelname, newtopic),
genesis 407 True)
genesis 408 self.channel_log(
genesis 409 channel, "set topic to %r" % newtopic, meta=True)
genesis 410 else:
genesis 411 if channel.topic:
genesis 412 self.reply("332 %s %s :%s"
genesis 413 % (self.nickname, channel.name,
genesis 414 channel.topic))
genesis 415 else:
genesis 416 self.reply("331 %s %s :No topic is set"
genesis 417 % (self.nickname, channel.name))
genesis 418 else:
genesis 419 self.reply("442 %s :You're not on that channel" % channelname)
genesis 420
genesis 421 def wallops_handler():
genesis 422 if len(arguments) < 1:
genesis 423 self.reply_461(command)
genesis 424 message = arguments[0]
genesis 425 for client in server.clients.values():
genesis 426 client.message(":%s NOTICE %s :Global notice: %s"
genesis 427 % (self.prefix, client.nickname, message))
genesis 428
genesis 429 def who_handler():
genesis 430 if len(arguments) < 1:
genesis 431 return
genesis 432 targetname = arguments[0]
genesis 433 if server.has_channel(targetname):
genesis 434 channel = server.get_channel(targetname)
genesis 435 for member in channel.members:
genesis 436 self.reply("352 %s %s %s %s %s %s H :0 %s"
genesis 437 % (self.nickname, targetname, member.user,
genesis 438 member.host, server.name, member.nickname,
genesis 439 member.realname))
genesis 440 self.reply("315 %s %s :End of WHO list"
genesis 441 % (self.nickname, targetname))
genesis 442
genesis 443 def whois_handler():
genesis 444 if len(arguments) < 1:
genesis 445 return
genesis 446 username = arguments[0]
genesis 447 user = server.get_client(username)
genesis 448 if user:
genesis 449 self.reply("311 %s %s %s %s * :%s"
genesis 450 % (self.nickname, user.nickname, user.user,
genesis 451 user.host, user.realname))
genesis 452 self.reply("312 %s %s %s :%s"
genesis 453 % (self.nickname, user.nickname, server.name,
genesis 454 server.name))
genesis 455 self.reply("319 %s %s :%s"
genesis 456 % (self.nickname, user.nickname,
genesis 457 " ".join(user.channels)))
genesis 458 self.reply("318 %s %s :End of WHOIS list"
genesis 459 % (self.nickname, user.nickname))
genesis 460 else:
genesis 461 self.reply("401 %s %s :No such nick"
genesis 462 % (self.nickname, username))
genesis 463
genesis 464 def wot_handler():
genesis 465 if len(arguments) < 1:
genesis 466 # Display the current WOT
9992-handle-edge-... 467 peers = self.server.state.get_peers()
9992-handle-edge-... 468 if len(peers) > 0:
9992-handle-edge-... 469 for peer in peers:
9992-handle-edge-... 470 self.pest_reply("%s %s:%s" % (string.join(peer.handles, ","), peer.address, peer.port))
9992-handle-edge-... 471 else:
9992-handle-edge-... 472 self.pest_reply("WOT is empty")
genesis 473 elif len(arguments) == 1:
genesis 474 # Display all WOT data concerning the peer identified by HANDLE,
genesis 475 # including all known keys, starting with the most recently used, for that peer.
genesis 476 handle = arguments[0]
genesis 477 peer = self.server.state.get_peer_by_handle(handle)
9992-handle-edge-... 478 if peer:
9992-handle-edge-... 479 self.pest_reply("keys:")
9992-handle-edge-... 480 for key in peer.keys:
9992-handle-edge-... 481 self.pest_reply("%s" % key)
9992-handle-edge-... 482 else:
9992-handle-edge-... 483 self.pest_reply("unknown peer: %s" % handle)
genesis 484
genesis 485 else:
genesis 486 pass
genesis 487
genesis 488 def peer_handler():
genesis 489 if len(arguments) == 1:
9991-improved-log... 490 try:
9991-improved-log... 491 self.server.state.add_peer(arguments[0])
9991-improved-log... 492 self.pest_reply("added new peer %s" % arguments[0])
9989-show-wot-nicks 493 self.message(":%s JOIN %s" % (arguments[0], self.server.channel_name))
9991-improved-log... 494 except:
9991-improved-log... 495 self.pest_reply("error attempting to add peer %s" % arguments[0])
genesis 496 else:
genesis 497 self.pest_reply("Usage: PEER <HANDLE>")
genesis 498
genesis 499 def unpeer_handler():
genesis 500 if len(arguments) == 1:
genesis 501 try:
genesis 502 self.server.state.remove_peer(arguments[0])
genesis 503 self.pest_reply("removed peer %s" % arguments[0])
9989-show-wot-nicks 504 self.message(":%s PART %s" % (arguments[0], self.server.channel_name))
9992-handle-edge-... 505 except Exception, e:
9992-handle-edge-... 506 self.server.print_debug(e)
genesis 507 self.pest_reply("Error attempting to remove peer")
genesis 508 else:
genesis 509 self.pest_reply("Usage: UNPEER <HANDLE>")
genesis 510
genesis 511 def genkey_handler():
genesis 512 self.pest_reply(base64.b64encode(os.urandom(64)))
genesis 513
genesis 514 def key_handler():
genesis 515 if len(arguments) != 2:
genesis 516 self.pest_reply("Usage: KEY <HANDLE> <KEY>")
genesis 517 else:
genesis 518 handle = arguments[0]
genesis 519 key = arguments[1]
genesis 520 try:
genesis 521 self.server.state.add_key(handle, key)
9992-handle-edge-... 522 self.pest_reply("added key: %s" % key)
genesis 523 except:
genesis 524 self.pest_reply("Error attempting to add key")
genesis 525
genesis 526 def unkey_handler():
genesis 527 if len(arguments) != 1:
genesis 528 self.pest_reply("Usage: UNKEY <KEY>")
genesis 529 else:
genesis 530 try:
genesis 531 self.server.state.remove_key(arguments[0])
9992-handle-edge-... 532 self.pest_reply("removed key: %s" % arguments[0])
9992-handle-edge-... 533 except Exception, e:
genesis 534 self.pest_reply("Error attempting to remove key")
9992-handle-edge-... 535 self.server.print_debug(e)
genesis 536
genesis 537 def at_handler():
genesis 538 if len(arguments) == 0:
genesis 539 at = self.server.state.get_at()
genesis 540 elif len(arguments) == 1:
genesis 541 handle = arguments[0]
genesis 542 at = self.server.state.get_at(handle)
genesis 543 elif len(arguments) == 2:
9990-keep-ephemer... 544 try:
9990-keep-ephemer... 545 handle, address = arguments
9990-keep-ephemer... 546 address_ip, port = string.split(address, ":")
9990-keep-ephemer... 547 self.server.state.update_address_table({"handle": handle,
9990-keep-ephemer... 548 "address": address_ip,
9990-keep-ephemer... 549 "port": port},
9990-keep-ephemer... 550 False)
9990-keep-ephemer... 551 self.pest_reply("updated address table: %s %s" % (handle, address))
9990-keep-ephemer... 552 except Exception as ex:
9990-keep-ephemer... 553 self.pest_reply("Error attempting to update address table")
9990-keep-ephemer... 554 stack = traceback.format_exc()
9990-keep-ephemer... 555 print(stack)
genesis 556 return
genesis 557 elif len(arguments) > 2:
genesis 558 self.pest_reply("Usage: AT [<HANDLE>] [<ADDRESS>]")
genesis 559 return
9992-handle-edge-... 560 if len(at) > 0:
9992-handle-edge-... 561 for address in at:
9992-handle-edge-... 562 self.pest_reply("%s %s %s" % (address["handle"],
9992-handle-edge-... 563 address["address"],
9991-improved-log... 564 address["active_at"]))
9992-handle-edge-... 565 else:
9992-handle-edge-... 566 self.pest_reply("no results")
genesis 567
genesis 568 handler_table = {
genesis 569 "AWAY": away_handler,
genesis 570 "AT": at_handler,
genesis 571 "GENKEY": genkey_handler,
genesis 572 "ISON": ison_handler,
genesis 573 "JOIN": join_handler,
genesis 574 "KEY": key_handler,
genesis 575 "LIST": list_handler,
genesis 576 "LUSERS": lusers_handler,
genesis 577 "MODE": mode_handler,
genesis 578 "MOTD": motd_handler,
genesis 579 "NICK": nick_handler,
genesis 580 "NOTICE": notice_and_privmsg_handler,
genesis 581 "PART": part_handler,
genesis 582 "PEER": peer_handler,
genesis 583 "PING": ping_handler,
genesis 584 "PONG": pong_handler,
genesis 585 "PRIVMSG": notice_and_privmsg_handler,
genesis 586 "QUIT": quit_handler,
genesis 587 "TOPIC": topic_handler,
genesis 588 "UNKEY": unkey_handler,
genesis 589 "UNPEER": unpeer_handler,
genesis 590 "WALLOPS": wallops_handler,
genesis 591 "WHO": who_handler,
genesis 592 "WHOIS": whois_handler,
genesis 593 "WOT": wot_handler
genesis 594 }
genesis 595 server = self.server
genesis 596 valid_channel_re = self.__valid_channelname_regexp
genesis 597 try:
genesis 598 handler_table[command]()
genesis 599 except KeyError:
9990-keep-ephemer... 600 self.reply("421 %s %s :Unknown command" % (self.nickname, command))
9990-keep-ephemer... 601 stack = traceback.format_exc()
9990-keep-ephemer... 602 print(stack)
genesis 603
genesis 604 def socket_readable_notification(self):
genesis 605 try:
genesis 606 data = self.socket.recv(2 ** 10)
genesis 607 self.server.print_debug(
genesis 608 "[%s:%d] -> %r" % (self.host, self.port, data))
genesis 609 quitmsg = "EOT"
genesis 610 except socket.error as x:
genesis 611 data = ""
genesis 612 quitmsg = x
genesis 613 if data:
genesis 614 self.__readbuffer += data
genesis 615 self.__parse_read_buffer()
genesis 616 self.__timestamp = time.time()
genesis 617 self.__sent_ping = False
genesis 618 else:
genesis 619 self.disconnect(quitmsg)
genesis 620
genesis 621 def socket_writable_notification(self):
genesis 622 try:
genesis 623 sent = self.socket.send(self.__writebuffer)
genesis 624 self.server.print_debug(
genesis 625 "[%s:%d] <- %r" % (
genesis 626 self.host, self.port, self.__writebuffer[:sent]))
genesis 627 self.__writebuffer = self.__writebuffer[sent:]
genesis 628 except socket.error as x:
genesis 629 self.disconnect(x)
genesis 630
genesis 631 def disconnect(self, quitmsg):
genesis 632 self.message("ERROR :%s" % quitmsg)
genesis 633 self.server.print_info(
genesis 634 "Disconnected connection from %s:%s (%s)." % (
genesis 635 self.host, self.port, quitmsg))
genesis 636 self.socket.close()
genesis 637 self.server.remove_client(self, quitmsg)
genesis 638
genesis 639 def message(self, msg):
genesis 640 self.__writebuffer += msg + "\r\n"
genesis 641
genesis 642 def reply(self, msg):
genesis 643 self.message(":%s %s" % (self.server.name, msg))
genesis 644
genesis 645 def pest_reply(self, msg):
genesis 646 self.message("NOTICE %s :%s" % (self.nickname, msg))
genesis 647
genesis 648 def reply_403(self, channel):
genesis 649 self.reply("403 %s %s :No such channel" % (self.nickname, channel))
genesis 650
genesis 651 def reply_461(self, command):
genesis 652 nickname = self.nickname or "*"
genesis 653 self.reply("461 %s %s :Not enough parameters" % (nickname, command))
genesis 654
genesis 655 def message_channel(self, channel, command, message, include_self=False):
genesis 656 line = ":%s %s %s" % (self.prefix, command, message)
genesis 657 for client in channel.members:
genesis 658 if client != self or include_self:
genesis 659 client.message(line)
genesis 660 # send the channel message to peers as well
9990-keep-ephemer... 661 self.server.peer_message(
9990-keep-ephemer... 662 Message(
9990-keep-ephemer... 663 {
genesis 664 "speaker": self.nickname,
genesis 665 "command": BROADCAST,
genesis 666 "bounces": 0,
genesis 667 "body": line
9990-keep-ephemer... 668 }, self.server))
genesis 669
genesis 670 def channel_log(self, channel, message, meta=False):
genesis 671 if not self.server.logdir:
genesis 672 return
genesis 673 if meta:
genesis 674 format = "[%s] * %s %s\n"
genesis 675 else:
genesis 676 format = "[%s] <%s> %s\n"
genesis 677 timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
genesis 678 logname = channel.name.replace("_", "__").replace("/", "_")
genesis 679 fp = open("%s/%s.log" % (self.server.logdir, logname), "a")
genesis 680 fp.write(format % (timestamp, self.nickname, message))
genesis 681 fp.close()
genesis 682
genesis 683 def message_related(self, msg, include_self=False):
genesis 684 clients = set()
genesis 685 if include_self:
genesis 686 clients.add(self)
genesis 687 for channel in self.channels.values():
genesis 688 clients |= channel.members
genesis 689 if not include_self:
genesis 690 clients.discard(self)
genesis 691 for client in clients:
genesis 692 client.message(msg)
genesis 693
genesis 694 def send_lusers(self):
genesis 695 self.reply("251 %s :There are %d users and 0 services on 1 server"
genesis 696 % (self.nickname, len(self.server.clients)))
genesis 697
genesis 698 def send_motd(self):
genesis 699 server = self.server
genesis 700 motdlines = server.get_motd_lines()
genesis 701 if motdlines:
genesis 702 self.reply("375 %s :- %s Message of the day -"
genesis 703 % (self.nickname, server.name))
genesis 704 for line in motdlines:
genesis 705 self.reply("372 %s :- %s" % (self.nickname, line.rstrip()))
genesis 706 self.reply("376 %s :End of /MOTD command" % self.nickname)
genesis 707 else:
genesis 708 self.reply("422 %s :MOTD File is missing" % self.nickname)