- 259E95AF9FD927FA7A5733E3485ED3F1D4C11CE76DA8D093320878914F48149E06A3D9800F39BD978BCC910D8586B8FA0671AA38EDCBBF432FC5ED14259624FE
+ CE97A842DF4D7C328976CA4DCD0E99E9FF0C5E56FBA68ECB094055089B81A35C303B492FBAB33116FD5BE2213D75976259F7A947E7E4E538BA273C7D42698125
blatta/lib/client.py
(1 . 19)(1 . 17)
536 import socket
537 import time
538 import sys
539 import re
540 import string
541 import os
542 import base64
543 import traceback
544 import logging
545 from state import State
546 from state import KNOBS
547 from message import Message
548 from server import VERSION
549 import datetime
550 from message import Message, PEST_VERSION
551 from broadcast import Broadcast
552 from direct import Direct
553 from station import VERSION
554 from funcs import *
555 from commands import BROADCAST
556 from commands import DIRECT
557 from commands import BROADCAST, DIRECT
558
559 class Client(object):
560 __linesep_regexp = re.compile(r"\r?\n")
(25 . 7)(23 . 7)
562
563 def __init__(self, server, socket):
564 self.server = server
565 self.state = State.get_instance()
566 self.state = None
567 self.socket = socket
568 self.channels = {} # irc_lower(Channel name) --> Channel
569 self.nickname = None
(44 . 7)(42 . 12)
571 def message_from_station(self, msg):
572 targetname = self.server.channel_name if msg.command == BROADCAST else self.nickname
573 pest_prefix = msg.prefix if msg.prefix else msg.speaker
574 formatted_message = ":%s PRIVMSG %s :%s" % (pest_prefix, targetname, msg.body)
575 formatted_message = ":%s PRIVMSG %s :%s%s" % (
576 pest_prefix,
577 targetname,
578 msg.warning if msg.warning else "",
579 msg.body
580 )
581 self.__writebuffer += formatted_message + "\r\n"
582
583 def get_prefix(self):
(76 . 20)(79 . 24)
585 if not line:
586 # Empty line. Ignore.
587 continue
588 x = line.split(" ", 1)
589 command = x[0].upper()
590 if len(x) == 1:
591 arguments = []
592 else:
593 if len(x[1]) > 0 and x[1][0] == ":":
594 arguments = [x[1][1:]]
595 else:
596 y = string.split(x[1], " :", 1)
597 arguments = string.split(y[0])
598 if len(y) == 2:
599 arguments.append(y[1])
600 command, arguments = self.__parse_command_arguments(line)
601 self.__handle_command(command, arguments)
602
603 def __parse_command_arguments(self, line):
604 x = line.split(" ", 1)
605 command = x[0].upper()
606 if len(x) == 1:
607 arguments = []
608 else:
609 if len(x[1]) > 0 and x[1][0] == ":":
610 arguments = [x[1][1:]]
611 else:
612 y = string.split(x[1], " :", 1)
613 arguments = string.split(y[0])
614 if len(y) == 2:
615 arguments.append(y[1])
616 return command, arguments
617
618 def __pass_handler(self, command, arguments):
619 server = self.server
620 if command == "PASS":
(117 . 6)(124 . 7)
622 self.reply("432 * %s :Erroneous nickname" % nick)
623 else:
624 self.nickname = nick
625 self.state.set_knob("nick", nick)
626 server.client_changed_nickname(self, None)
627 elif command == "USER":
628 if len(arguments) < 4:
(128 . 11)(136 . 11)
630 self.disconnect("Client quit")
631 return
632 if self.nickname and self.user:
633 self.reply("001 %s :Hi, welcome to Pest" % self.nickname)
634 self.reply("002 %s :Your host is %s, running version blatta-%s"
635 % (self.nickname, server.name, VERSION))
636 self.reply("003 %s :This server was created sometime"
637 % self.nickname)
638 self.reply("001 %s :Hi, welcome to PestNet" % self.nickname)
639 self.reply("002 %s :Your host is %s, running Blatta %d and Pest 0x%X"
640 % (self.nickname, server.name, VERSION, PEST_VERSION))
641 self.reply("003 %s :This server was created %s"
642 % (self.nickname, datetime.datetime.now()))
643 self.reply("004 %s :%s blatta-%s o o"
644 % (self.nickname, server.name, VERSION))
645 self.send_motd()
(171 . 12)(179 . 6)
647 channel.add_member(self)
648 self.channels[irc_lower(channelname)] = channel
649 self.message_channel(channel, "JOIN", channelname, True)
650 if channel.topic:
651 self.reply("332 %s %s :%s"
652 % (self.nickname, channel.name, channel.topic))
653 else:
654 self.reply("331 %s %s :No topic is set"
655 % (self.nickname, channel.name))
656 self.reply("353 %s = %s :%s"
657 % (self.nickname,
658 channelname,
(185 . 73)(187 . 13)
660 self.reply("366 %s %s :End of NAMES list" % (self.nickname, channelname))
661
662 def list_handler():
663 if len(arguments) < 1:
664 channels = server.channels.values()
665 else:
666 channels = []
667 for channelname in arguments[0].split(","):
668 if server.has_channel(channelname):
669 channels.append(server.get_channel(channelname))
670 channels.sort(key=lambda x: x.name)
671 for channel in channels:
672 self.reply("322 %s %s %d :%s"
673 % (self.nickname, channel.name,
674 len(channel.members), channel.topic))
675 self.reply("323 %s :End of LIST" % self.nickname)
676 pass
677
678 def lusers_handler():
679 pass
680 pass
681
682 def mode_handler():
683 if len(arguments) < 1:
684 self.reply_461("MODE")
685 return
686 targetname = arguments[0]
687 if server.has_channel(targetname):
688 channel = server.get_channel(targetname)
689 if len(arguments) < 2:
690 if channel.key:
691 modes = "+k"
692 if irc_lower(channel.name) in self.channels:
693 modes += " %s" % channel.key
694 else:
695 modes = "+"
696 self.reply("324 %s %s %s"
697 % (self.nickname, targetname, modes))
698 return
699 flag = arguments[1]
700 if flag == "+k":
701 if len(arguments) < 3:
702 self.reply_461("MODE")
703 return
704 key = arguments[2]
705 if irc_lower(channel.name) in self.channels:
706 channel.key = key
707 self.message_channel(
708 channel, "MODE", "%s +k %s" % (channel.name, key),
709 True)
710 else:
711 self.reply("442 %s :You're not on that channel"
712 % targetname)
713 elif flag == "-k":
714 if irc_lower(channel.name) in self.channels:
715 channel.key = None
716 self.message_channel(
717 channel, "MODE", "%s -k" % channel.name,
718 True)
719 else:
720 self.reply("442 %s :You're not on that channel"
721 % targetname)
722 else:
723 self.reply("472 %s %s :Unknown MODE flag"
724 % (self.nickname, flag))
725 elif targetname == self.nickname:
726 if len(arguments) == 1:
727 self.reply("221 %s +" % self.nickname)
728 else:
729 self.reply("501 %s :Unknown MODE flag" % self.nickname)
730 else:
731 self.reply_403(targetname)
732 pass
733
734 def motd_handler():
735 self.send_motd()
(278 . 6)(220 . 7)
737 ":%s!%s@%s NICK %s"
738 % (oldnickname, self.user, self.host, self.nickname),
739 True)
740 self.state.set_knob('nick', self.nickname)
741
742 def notice_and_privmsg_handler():
743 if len(arguments) == 0:
(290 . 27)(233 . 31)
745 targetname = arguments[0]
746 message = arguments[1]
747
748 # check for pest commands before handling this as a message
749 if message[0] is "%":
750 pest_command, pest_arguments = self.__parse_command_arguments(message[1:])
751 self.__handle_command(pest_command, pest_arguments)
752 return
753
754 if server.has_channel(targetname):
755 channel = server.get_channel(targetname)
756 self.message_channel(
757 channel, command, "%s :%s" % (channel.name, message))
758 # send the channel message to peers as well
759 self.server.station.infosec.message(
760 Message(
761 {
762 "speaker": self.nickname,
763 "command": BROADCAST,
764 "bounces": 0,
765 "body": message
766 }))
767 Broadcast(
768 {
769 "speaker": self.nickname,
770 "body": message,
771 "long_buffer": self.server.station.long_buffer
772 },
773 self.state).send()
774 else:
775 self.server.station.infosec.message(Message({
776 Direct({
777 "speaker": self.nickname,
778 "handle": targetname,
779 "body": message,
780 "bounces": 0,
781 "command": DIRECT
782 }))
783 "long_buffer": self.server.station.long_buffer
784 }, self.state).send()
785
786 def part_handler():
787 if len(arguments) < 1:
(351 . 71)(298 . 16)
789 self.disconnect(quitmsg)
790
791 def topic_handler():
792 if len(arguments) < 1:
793 self.reply_461("TOPIC")
794 return
795 channelname = arguments[0]
796 channel = self.channels.get(irc_lower(channelname))
797 if channel:
798 if len(arguments) > 1:
799 newtopic = arguments[1]
800 channel.topic = newtopic
801 self.message_channel(
802 channel, "TOPIC", "%s :%s" % (channelname, newtopic),
803 True)
804 else:
805 if channel.topic:
806 self.reply("332 %s %s :%s"
807 % (self.nickname, channel.name,
808 channel.topic))
809 else:
810 self.reply("331 %s %s :No topic is set"
811 % (self.nickname, channel.name))
812 else:
813 self.reply("442 %s :You're not on that channel" % channelname)
814 pass
815
816 def wallops_handler():
817 if len(arguments) < 1:
818 self.reply_461(command)
819 message = arguments[0]
820 for client in server.clients.values():
821 client.message(":%s NOTICE %s :Global notice: %s"
822 % (self.prefix, client.nickname, message))
823 pass
824
825 def who_handler():
826 if len(arguments) < 1:
827 return
828 targetname = arguments[0]
829 if server.has_channel(targetname):
830 channel = server.get_channel(targetname)
831 for member in channel.members:
832 self.reply("352 %s %s %s %s %s %s H :0 %s"
833 % (self.nickname, targetname, member.user,
834 member.host, server.name, member.nickname,
835 member.realname))
836 self.reply("315 %s %s :End of WHO list"
837 % (self.nickname, targetname))
838 pass
839
840 def whois_handler():
841 if len(arguments) < 1:
842 return
843 username = arguments[0]
844 user = server.get_client(username)
845 if user:
846 self.reply("311 %s %s %s %s * :%s"
847 % (self.nickname, user.nickname, user.user,
848 user.host, user.realname))
849 self.reply("312 %s %s %s :%s"
850 % (self.nickname, user.nickname, server.name,
851 server.name))
852 self.reply("319 %s %s :%s"
853 % (self.nickname, user.nickname,
854 " ".join(user.channels)))
855 self.reply("318 %s %s :End of WHOIS list"
856 % (self.nickname, user.nickname))
857 else:
858 self.reply("401 %s %s :No such nick"
859 % (self.nickname, username))
860 pass
861
862 def wot_handler():
863 if len(arguments) < 1:
(427 . 7)(319 . 8)
865 address = "%s:%s" % (peer.address, peer.port)
866 else:
867 address = "<address not configured>"
868 self.pest_reply("%s %s" % (string.join(peer.handles, ","), address))
869 self.pest_reply("%s %s" % (string.join(peer.handles, ","),
870 address))
871 else:
872 self.pest_reply("WOT is empty")
873 elif len(arguments) == 1:
(540 . 7)(433 . 7)
875 self.pest_reply("no knobs configured")
876 elif len(arguments) == 1:
877 knob_value = self.state.get_knob(arguments[0])
878 if knob:
879 if knob_value:
880 self.pest_reply("%s %s" % (arguments[0], knob_value))
881 else:
882 self.pest_reply("no such knob")
(549 . 6)(442 . 18)
884 self.pest_reply("set %s to %s" % (arguments[0], arguments[1]))
885 else:
886 self.pest_reply("Usage: KNOB [<NAME>] [<VALUE>]")
887
888 def resolve_handler():
889 if len(arguments) == 1:
890 handle = arguments[0]
891 peer = self.state.get_peer_by_handle(handle)
892 if peer:
893 self.state.resolve(handle)
894 self.pest_reply("resolved %s" % handle)
895 else:
896 self.pest_reply("peer with handle %s not found" % handle)
897 else:
898 self.pest_reply("Usage: RESOLVE <HANDLE>")
899
900 handler_table = {
901 "AWAY": away_handler,
(557 . 6)(462 . 7)
903 "ISON": ison_handler,
904 "JOIN": join_handler,
905 "KEY": key_handler,
906 "KNOB": knob_handler,
907 "LIST": list_handler,
908 "LUSERS": lusers_handler,
909 "MODE": mode_handler,
(569 . 6)(475 . 7)
911 "PONG": pong_handler,
912 "PRIVMSG": notice_and_privmsg_handler,
913 "QUIT": quit_handler,
914 "RESOLVE": resolve_handler,
915 "TOPIC": topic_handler,
916 "UNKEY": unkey_handler,
917 "UNPEER": unpeer_handler,
(576 . 7)(483 . 6)
919 "WHO": who_handler,
920 "WHOIS": whois_handler,
921 "WOT": wot_handler,
922 "KNOB": knob_handler
923 }
924 server = self.server
925 valid_channel_re = self.__valid_channelname_regexp
(590 . 8)(496 . 9)
927 def socket_readable_notification(self):
928 try:
929 data = self.socket.recv(2 ** 10)
930 logging.debug(
931 "[%s:%d] -> %r" % (self.host, self.port, data))
932 if os.environ.get("LOG_CLIENT_MESSAGES"):
933 logging.debug(
934 "[%s:%d] -> %r" % (self.host, self.port, data))
935 quitmsg = "EOT"
936 except socket.error as x:
937 data = ""
(607 . 9)(514 . 10)
939 def socket_writable_notification(self):
940 try:
941 sent = self.socket.send(self.__writebuffer)
942 logging.debug(
943 "[%s:%d] <- %r" % (
944 self.host, self.port, self.__writebuffer[:sent]))
945 if os.environ.get("LOG_CLIENT_MESSAGES"):
946 logging.debug(
947 "[%s:%d] <- %r" % (
948 self.host, self.port, self.__writebuffer[:sent]))
949 self.__writebuffer = self.__writebuffer[sent:]
950 except socket.error as x:
951 self.disconnect(x)
(629 . 7)(537 . 7)
953 self.message(":%s %s" % (self.server.name, msg))
954
955 def pest_reply(self, msg):
956 self.message("NOTICE %s :%s" % (self.nickname, msg))
957 self.message(":Pest NOTICE %s :%s" % (self.nickname, msg))
958
959 def reply_403(self, channel):
960 self.reply("403 %s %s :No such channel" % (self.nickname, channel))