rfc1459.py
'''
'' PyIRCIoT (PyLayerIRC class)
''
'' Copyright (c) 2018-2020 Alexey Y. Woronov
''
'' By using this file, you agree to the terms and conditions set
'' forth in the LICENSE file which can be found at the top level
'' of this package
''
'' Authors:
'' Alexey Y. Woronov <alexey@woronov.ru>
'''
# Those Global options override default behavior and memory usage
#
DO_debug_library = False
DO_default_draft = "ircu" # Integrator must define IRC software
import socket
import select
import random
import re
import threading
import ssl
try:
import json
except:
import simplejson as json
from queue import Queue
from time import sleep
try: # insecure, but for development
from irciot_shared import *
except:
from PyIRCIoT.irciot_shared import *
if DO_debug_library:
from pprint import pprint
import datetime
class PyLayerIRC( irciot_shared_ ):
class CONST( irciot_shared_.CONST ):
#
irciot_protocol_version = '0.3.33'
#
irciot_library_version = '0.0.229'
#
# Bot specific constants
#
irc_first_wait = 28
irc_micro_wait = 0.12
irc_ident_wait = 8
irc_default_wait = 28
irc_latency_wait = 1
#
irc_default_debug = DO_debug_library
#
irc_default_nick = "MyBot"
irc_default_info = "IRC-IoT Bot"
irc_default_quit = "Bye!"
#
irc_default_server = "irc-iot.nsk.ru"
irc_default_port = 6667
irc_default_ssl_port = 6697
irc_default_password = None
irc_default_ssl = False
irc_default_ident = False
#
irc_default_proxy = None
irc_default_proxy_server = None
irc_default_proxy_port = None
irc_default_proxy_password = None
#
# Will be replaced to channel-list:
irc_default_channel = "#myhome"
irc_default_chankey = None
#
irc_default_silence = 8 # count of irc_default_wait
#
# User options:
irc_aop = 101 # give (+o) him channel operator status
irc_aban = 102 # ban (+b) him on these channels
irc_avo = 103 # give (+v) him a voice on channels
irc_akick = 130 # kick it from these channels
irc_adeop = 131 # take away (-o) his channel operator status
irc_unban = 132 # unban (-b) mask on channels when banned
irc_adevo = 133 # take away (-v) his voice on channels
#
# 0. Unique User ID
# 1. IRC User Mask
# 2. IRC Channel Name
# 3. User Options
# 4. Encryption Private or Secret Key
# 5. Blockchain Private Key
# 6. Last Message ID
# 7. Encryption Key Timeout
# 8. Blockchain Key Timeout
# 9. My last Message ID
#
# Deault Message ID pipeline size:
irc_default_mid_pipeline_size = 16
#
irc_default_users = [
( 1, "iotBot!*irc@irc-iot.nsk.ru", irc_default_channel,
None, None, None, None, None, None, None ),
( 2, "FaceBot!*irc@faceserv*.nsk.ru", irc_default_channel,
irc_aop, None, None, None, None, None, None ),
( 3, "noobot!*bot@irc-iot.nsk.ru", irc_default_channel,
[ irc_aop, irc_unban ], None, None, None, None, None, None ) ]
#
irc_default_talk_with_strangers = False
#
irc_queue_input = 0
irc_queue_output = 1
#
irc_recon_steps = 8
#
irc_input_buffer = ""
#
irc_buffer_size = 3072
#
irc_mode_CLIENT = "CLIENT"
# ^ Connects to IRC server over the network as an IRC client
irc_mode_SERVICE = "SERVICE"
# ^ Connects to IRC server over the network as an IRC service
irc_mode_SERVER = "SERVER"
# ^ Act as an IRC server, accepting connections of IRC clients
irc_layer_modes = [
irc_mode_CLIENT,
irc_mode_SERVICE,
irc_mode_SERVER ]
irc_default_mode = irc_mode_CLIENT
#
irc_default_nick_retry = 3600 # in seconds
irc_default_join_retry = 32 # trys
irc_default_nick_pause = 16 # trys
#
irc_default_network_tag = "IRC-IoT"
#
# According RFC 1459
#
irc_ascii_lowercase = "abcdefghijklmnopqrstuvwxyz"
irc_ascii_uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
irc_ascii_letters = irc_ascii_lowercase + irc_ascii_uppercase
irc_ascii_digits = "0123456789"
irc_special_chars = "-[]\\`^{}"
irc_nick_first_char = irc_ascii_letters + "[]\\`^{}"
irc_nick_chars = irc_ascii_letters \
+ irc_ascii_digits + irc_special_chars
irc_translation = "".maketrans( \
irc_ascii_uppercase + "[]\\^",
irc_ascii_lowercase + "{}|~")
irc_transmocker = "".maketrans( \
"aAoOBEGgIlSsT-_05891",
"4400836911557_-OSBgl" )
irc_mode_add = "+"
irc_mode_del = "-"
irc_change_modes \
= irc_mode_add \
+ irc_mode_del
irc_umode_op = "o"
irc_umode_voice = "v"
irc_umode_ban = "b"
irc_user_modes \
= irc_umode_op \
+ irc_umode_voice\
+ irc_umode_ban
irc_channel_modes = "psitnm"
irc_extra_modes = "lk"
irc_all_modes \
= irc_user_modes \
+ irc_channel_modes \
+ irc_extra_modes
irc_all_modes_chars \
= irc_change_modes \
+ irc_all_modes
#
irc_nick_regexp = "^[" + irc_ascii_letters \
+ "_`\^\\\[\]\{\}][" + irc_ascii_letters \
+ irc_ascii_digits + "\-_`\^\\\[\]\{\}]{1,12}$"
irc_channel_regexp = "^#[" + irc_ascii_letters \
+ irc_ascii_digits + "\-_\^\[\]\{\}]{1,24}$"
#
irc_default_encoding = irciot_shared_.CONST.enc_UTF8
irc_fallback_encoding = irciot_shared_.CONST.enc_ISO1
#
irc_default_draft = DO_default_draft
irc_additional_drafts = []
#
# 1. "RFC1459" Internet Relay Chat Protocol '1993
# 2. "RFC2812" IRC Draft: Client Protocol '2000
# 3. "asp" -- AspIRCd (Charybdis fork) '2019
# 4. "Bahamut" -- Bahamut, @ DALnet, ver. 2.1.6, '1999-2020
# 5. "beware" -- beware ircd, Delphi based, ver. 2.2.0
# 6. "Charybdis" -- charybdis-ircd, ver. 3.5.0, '2007-2020
# 7. "ConfRoom" -- Conference Room, ver. 1.7.6, '2014
# 8. "discord" -- discordIRCd, js based, ver. 0.5.0 '2018
# 9. "Elemental" -- Elemental-IRCd, ver. 6.6.2, '2016
# 10. "Ergo" -- Ergo (was Oragono), Golang based, ver. 2.7.0, '2012-2021
# 11. "hybrid" -- ircd-hybrid, @ EFNet, ver. 8.2.29
# 12. "Insp" -- Inspircd, ver. 2.0.20, '2015
# 13. "IRCNet" -- IRCNet ircd, @ IRCNet, ver. 2.12.2
# 14. "IRCPlus" -- IRCPlus, for Windows, ver. 5.0, '2001
# 15. "ircu" -- ircd-ircu aka Undernet IRCd, ver. 2.10.12.18
# 16. "Kine" -- KineIRCd, C++, '2002-2005
# 17. "miniircd" -- miniircd, Python based, ver. 1.3, '2003
# 18. "Nefarious" -- Nefarious ircd
# 19. "Nefarious2" -- Nefarious IRCu (ircu fork), ver. 2.0-288, '2020
# 20. "ng" -- ngIRCd aka Next Generation IRCd, ver. 25, '2019
# 21. "plexus" -- PleXusIRCd, C++, '2003-2006
# 22. "pircd" -- Perl IRCd, Perl based, '2002
# 23. "Provision" -- ProvisionIRCd, Python based, '2006
# 24. "pure" -- pureIRCd, CSharp based, '2008
# 25. "Rabbit" -- RabbitIRCD, (UnrealIRCd fork), @ Wheresource '2014
# 26. "ratbox" -- ircd-ratbox, @ EFNet, ver. 3.0.8, '2006
# 27. "Rock" -- rock-ircd aka RockIRCd (UnrealIRCd fork), '2009
# 28. "Rubi" -- RubiIRCd, Ruby based '2009
# 29. "RusNet" -- ircd RusNet, @ RusNet, ver. 1.4.25, '2011
# 30. "seven" -- ircd-seven, ver. 1.1.3, '2007-2019
# 31. "Shadow" -- ShadowIRCd, ver. 6.3.3, '2003
# 32. "snircd" -- snircd (ircu fork), @ QuakeNet, ver. 1.3.4
# 33. "solid" -- solid-ircd (Bahamut fork), ver. 3.4.8, '2004-2013
# 34. "Synchronet" -- Synchronet IRCd, js based, ver. 3.11, '2010-2019
# 35. "Unreal" -- UnrealIRCd, ver. 5.0.9, '1999-2021
# 36. "We" -- WeIRCd, ver. 0.8.2, '2010
# 37. "PyIRCIoT" (when it works in IRC server mode)
#
# Additional drafts extending Internet Relay Chat protocol:
irc_add_plus = "IRC+" # IRC+ Services Protocol
irc_add_v3 = "IRCv3" # Specification 3.2 build on top of the IRC protocol
#
irc_max_nick_length = 15
if irc_default_draft == "ircu":
irc_max_nick_length = 12
irc_max_topic_length = 160
irc_max_network_name_length = 80
#
ircd_Ch_se = [ "Charybdis", "seven" ]
ircd_Ch_se_ra = ircd_Ch_se + [ "ratbox" ]
ircd_Ch_se_ra_pl = ircd_Ch_se_ra + [ "plexus" ]
ircd_Un_Ch_se = [ "Unreal", "Charybdis", "seven" ]
ircd_Un_Ba = [ "Unreal", "Bahamut" ]
ircd_iu_Un_Ba = ircd_Un_Ba + [ "ircu" ]
ircd_iu_sn = [ "ircu", "snircd" ]
ircd_iu_Un_sn = ircd_iu_sn + [ "Unreal" ]
ircd_iu_Un_Ba_sn = ircd_iu_Un_sn + [ "Bahamut" ]
#
if irc_default_draft in ircd_Un_Ch_se:
irc_additional_drafts += [ irc_add_v3 ]
#
irc_default_MTU = 480
if irc_default_draft == "ircu":
irc_default_MTU = 440
if irc_add_v3 in irc_additional_drafts:
#irc_default_MTU = 1024 (line-length-3.3)
pass
#
RPL_WELCOME = "001"
RPL_YOURHOST = "002"
RPL_CREATED = "003"
RPL_MYINFO = "004"
if irc_default_draft == "RFC2812":
RPL_BOUNCE = "005"
else:
RPL_ISUPPORT = "005"
if irc_default_draft == "Unreal":
RPL_MAP = "006"
RPL_MAPEND = "007"
if irc_default_draft == "ircu":
RPL_SNOMASK = "008"
RPL_STATMEMTOT = "009"
RPL_STATMEM = "010"
if irc_default_draft in [ "Unreal", "Charybdis", "hybrid", \
"seven", "IRCNet", "plexus", "ratbox" ]:
RPL_REDIR = "010"
if irc_default_draft == "ircu":
RPL_MAP = "015"
RPL_MAPMORE = "016"
RPL_MAPEND = "017"
if irc_default_draft == "IRCNet":
RPL_MAPSTART = "018"
RPL_HELLO = "020"
if irc_default_draft in ircd_iu_sn:
RPL_APASSWARN_SET = "030"
RPL_APASSWARN_SECRET = "031"
RPL_APASSWARN_CLEAR = "032"
if irc_default_draft == "Unreal":
RPL_YOURID = "042"
ERR_REMOTEISUPPORT = "105"
RPL_TRACELINK = "200"
RPL_TRACECONNECTING = "201"
RPL_TRACEHANDSHAKE = "202"
RPL_TRACEUNKNOWN = "203"
RPL_TRACEOPERATOR = "204"
RPL_TRACEUSER = "205"
RPL_TRACESERVER = "206"
if irc_default_draft == "plexus":
RPL_TRACECAPTURED = "207"
else:
RPL_TRACESERVICE = "207"
RPL_TRACENEWTYPE = "208"
RPL_TRACECLASS = "209"
if irc_default_draft == "Unreal":
RPL_STATSHELP = "210"
if irc_default_draft == "IRCNet":
RPL_TRACERECONNECT = "210"
RPL_STATSLINKINFO = "211"
RPL_STATSCOMMANDS = "212"
RPL_STATSCLINE = "213"
RPL_STATSOLDNLINE = "214"
RPL_STATSILINE = "215"
RPL_STATSKLINE = "216"
if irc_default_draft in ircd_iu_sn:
RPL_STATSPLINE = "217"
else:
RPL_STATSQLINE = "217"
RPL_STATSYLINE = "218"
RPL_ENDOFSTATS = "219"
if irc_default_draft == "Unreal":
RPL_STATSBLINE = "220"
else:
RPL_STATSWLINE = "220"
RPL_UMODEIS = "221"
if irc_default_draft in ircd_iu_sn:
RPL_STATSJLINE = "222"
if irc_default_draft == "Unreal":
RPL_SQLINE_NICK = "222"
if irc_default_draft == "Bahamut":
RPL_STATSELINE = "223"
if irc_default_draft == "Unreal":
RPL_STATSGLINE = "223"
RPL_STATSTLINE = "224"
if irc_default_draft == "Bahamut":
RPL_STATSCLONE = "225"
RPL_STATSCOUNT = "226"
if irc_default_draft in [ "ircu", "hybrid", "plexus", "snircd" ]:
RPL_STATALINE = "226"
if irc_default_draft == "Unreal":
RPL_STATSELINE = "225"
RPL_STATSNLINE = "226"
RPL_STATSVLINE = "227"
RPL_STATSBANVER = "228"
RPL_SERVICEINFO = "231"
RPL_ENDOFSERVICES = "232"
RPL_SERVICE = "233"
RPL_SERVLIST = "234"
RPL_SERVLISTEND = "235"
if irc_default_draft == "IRCNet":
RPL_STATSIAUTH = "239"
elif irc_default_draft == "RFC2812":
RPL_STATSVLINE = "240"
RPL_STATSLLINE = "241"
RPL_STATSUPTIME = "242"
RPL_STATSOLINE = "243"
if irc_default_draft == "RFC2812":
RPL_STATSSLINE = "244"
else:
RPL_STATSHLINE = "244"
if irc_default_draft in [ "Unreal", "Bahamut", "Charybdis", \
"IRCNet", "plexus", "seven", "ratbox" ]:
RPL_STATSSLINE = "245"
if irc_default_draft == "ircu":
RPL_STATSTLINE = "246"
RPL_STATSGLINE = "247"
if irc_default_draft == "Unreal":
RPL_STATSXLINE = "247"
if irc_default_draft == "ircu":
RPL_STATSULINE = "248"
RPL_STATSDEBUG = "249" # Unknown
RPL_LUSERCONNS = "250" # '1998
RPL_LUSERCLIENT = "251"
RPL_LUSEROP = "252"
RPL_LUSERUNKNOWN = "253"
RPL_LUSERCHANNELS = "254"
RPL_LUSERME = "255"
RPL_ADMINME = "256"
RPL_ADMINLOC1 = "257"
RPL_ADMINLOC2 = "258"
RPL_ADMINEMAIL = "259"
RPL_TRACELOG = "261"
RPL_ENDOFTRACE = "262" # '1997
if irc_default_draft in [ "RFC2812", "IRCNet" ]:
RPL_TRYAGAIN = "263"
else:
RPL_LOAD2HI = "263"
RPL_N_LOCAL = "265" # '1997
RPL_N_GLOBAL = "266" # '1997
if irc_default_draft in ircd_iu_Un_Ba_sn:
RPL_SILELIST = "271"
RPL_ENDOFSILELIST = "272"
if irc_default_draft in ircd_iu_Un_sn:
RPL_STATUSDLINE = "275"
if irc_default_draft == "Bahamut":
RPL_USIGNSSL = "275"
if irc_default_draft in [ "Charybdis", "seven", "hybrid", "plexus" ]:
RPL_WHOISCERTFP = "276"
if irc_default_draft in ircd_iu_sn:
RPL_STATSRLINE = "276"
RPL_GLIST = "280"
RPL_ENDOFGLIST = "281"
if irc_default_draft == "Unreal":
RPL_HELPHDR = "290"
RPL_HELPOP = "291"
RPL_HELPTLR = "292"
RPL_HELPHLP = "293"
RPL_HELPFWD = "294"
RPL_HELPIGN = "295"
if irc_default_draft == "snircd":
RPL_DATASTR = "290"
RPL_ENDOFCHECK = "291"
RPL_NONE = "300" # Unused?
RPL_AWAY = "301"
RPL_USERHOST = "302"
RPL_ISON = "303"
RPL_TEXT = "304"
RPL_UNAWAY = "305"
RPL_NOAWAY = "306"
if irc_default_draft == "ircu":
RPL_USERIP = "307"
if irc_default_draft in [ "Bahamut", "hybrid" ]:
RPL_WHOISADMIN = "308"
if irc_default_draft == "Unreal":
RPL_RULESSTART = "308"
RPL_ENDOFRULES = "309"
if irc_default_draft == "Bahamut":
RPL_WHOISSADMIN = "309"
if irc_default_draft == "Unreal":
RPL_WHOISHELPOP = "310"
elif irc_default_draft == "Bahamut":
RPL_WHOISSVCMSG = "310"
elif irc_default_draft in [ "hybrid", "plexus" ]:
RPL_WHOISMODES = "310"
else:
RPL_WHOISHELP = "310" # Unknown
RPL_WHOISUSER = "311"
RPL_WHOISSERVER = "312"
RPL_WHOISOPERATOR = "313"
RPL_WHOWASUSER = "314"
RPL_ENDOFWHO = "315"
RPL_WHOISCHANOP = "316"
RPL_WHOISIDLE = "317"
RPL_ENDOFWHOIS = "318"
RPL_WHOISCHANNELS = "319"
RPL_WHOISWORLD = "320" # Unknown
RPL_LISTSTART = "321"
RPL_LIST = "322"
RPL_LISTEND = "323"
RPL_CHANNELMODEIS = "324"
if irc_default_draft in ircd_Ch_se:
RPL_CHANNELMLOCK = "325"
RPL_CHANNELURL = "328"
else:
RPL_UNIQOPIS = "325" # Unknown
if irc_default_draft == "Insp":
RPL_CHANNELCREATED = "329"
if irc_default_draft == "Insp":
RPL_NOTOPICSET = "331"
else:
RPL_NOTOPIC = "331"
RPL_CURRENTTOPIC = "332"
RPL_TOPICINFO = "333"
if irc_default_draft in ircd_iu_sn:
RPL_LISTUSAGE = "334"
if irc_default_draft in ircd_Un_Ba:
RPL_COMMANDSYNTAX = "334"
if irc_default_draft == "Unreal":
RPL_LISTSYNTAX = "334"
RPL_WHOISBOT = "335"
if irc_default_draft in [ "Bahamut", "Charybdis", \
"hybrid", "seven" ]:
RPL_WHOISTEXT = "337"
RPL_WHOISACTUALLY = "338"
if irc_default_draft in ircd_iu_Un_sn:
RPL_USERIP = "340"
RPL_INVITING = "341"
RPL_SUMMONING = "342"
RPL_INVITED = "354" # GameSurge only?
if irc_default_draft in [ "Unreal", "ratbox", "seven", \
"Bahamut", "Charybdis", "hybrid", "plexus" ]:
RPL_INVITELIST = "346"
RPL_ENDOFINVITELIST = "347"
RPL_EXCEPTLIST = "348"
RPL_ENDOFEXCEPTLIST = "349"
RPL_VERSION = "351"
RPL_WHOREPLY = "352"
RPL_NAMREPLY = "353"
if irc_default_draft == "Bahamut":
RPL_RWHOREPLY = "354"
elif irc_default_draft in [ "ircu", "seven", \
"Charybdis", "snircd" ]:
RPL_WHOSPCRPL = "354"
if irc_default_draft in ircd_iu_sn:
RPL_DELNAMREPLY = "355"
RPL_KILLDONE = "361"
RPL_CLOSING = "362"
RPL_CLOSEEND = "363"
RPL_LINKS = "364"
RPL_ENDOFLINKS = "365"
RPL_ENDOFNAMES = "366"
RPL_BANLIST = "367"
RPL_ENDOFBANLIST = "368"
RPL_ENDOFWHOWAS = "369"
RPL_INFO = "371"
RPL_MOTD = "372"
RPL_INFOSTART = "373"
RPL_ENDOFINFO = "374"
RPL_MOTDSTART = "375"
RPL_ENDOFMOTD = "376"
RPL_MOTD2 = "377" # Unknown
RPL_AUSTMOTD = "378" # Austnet?
if irc_default_draft == "Unreal":
RPL_WHOISMODES = "379"
RPL_YOUREOPER = "381"
RPL_REHASHING = "382"
if irc_default_draft in [ "Unreal", "IRCNet", "RFC2812" ]:
RPL_YOURESERVICE = "383"
RPL_MYPORTIS = "384"
if irc_default_draft in [ "Unreal", "Bahamut", "IRCNet", \
"Charybdis", "seven", "ratbox" ]:
RPL_NOTOPERANYMORE = "385"
if irc_default_draft == "Unreal":
RPL_QLIST = "386"
RPL_ENDOFQLIST = "387"
RPL_ALIST = "388"
RPL_ENDOFALIST = "389"
RPL_TIME = "391"
RPL_USERSSTART = "392"
RPL_USERS = "393"
RPL_ENDOFUSERS = "394"
RPL_NOUSERS = "395"
if irc_default_draft == "ircu":
RPL_HOSTHIDDEN = "396"
ERR_UNKNOWNERROR = "400" # Unknown
ERR_NOSUCHNICK = "401"
ERR_NOSUCHSERVER = "402"
ERR_NOSUCHCHANNEL = "403"
ERR_CANNOTSENDTOCHAN = "404"
ERR_TOOMANYCHANNELS = "405"
ERR_WASNOSUCHNICK = "406"
ERR_TOOMANYTARGETS = "407"
if irc_default_draft == "Unreal":
ERR_NOSUCHSERVICE = "408"
ERR_NOORIGIN = "409"
if irc_default_draft in ircd_iu_sn:
ERR_UNKNOWNCAPCMD = "410"
else:
ERR_INVALIDCAPCMD = "410"
ERR_NORECIPIENT = "411"
ERR_NOTEXTTOSEND = "412"
ERR_NOTOPLEVEL = "413"
ERR_WILDTOPLEVEL = "414"
if irc_default_draft == "RFC2812":
ERR_BADMASK = "415"
if irc_default_draft in ircd_iu_sn:
ERR_QUERYTOOLONG = "416"
elif irc_default_draft == "IRCNet":
ERR_TOOMANYMATCHES = "416"
if irc_add_v3 in irc_additional_drafts:
ERR_INPUTTOOLONG = "417"
ERR_UNKNOWNCOMMAND = "421"
ERR_NOMOTD = "422"
ERR_NOADMININFO = "423"
ERR_FILEERROR = "424"
if irc_default_draft == "Unreal":
ERR_NOOPERMOTD = "425"
elif irc_default_draft == "Bahamut":
ERR_TOOMANYAWAY = "429"
ERR_NONICKNAMEGIVEN = "431"
ERR_ERRONEUSNICKNAME = "432"
ERR_NICKNAMEINUSE = "433"
if irc_default_draft == "Unreal":
ERR_NORULES = "434"
if irc_default_draft in [ "Unreal", "IRCNet" ]:
ERR_SERVICECONFUSED = "435"
ERR_NICKCOLLISION = "436"
if irc_default_draft in [ "Charybdis", "RFC2812", \
"hybrid", "IRCNet", "ratbox", "seven" ]:
ERR_UNAVAILRESOURCE = "437"
if irc_default_draft == "ircu":
ERR_BANNICKCHANGE = "437"
ERR_NICKCHANGETOOFAST = "438"
if irc_default_draft in [ "Unreal", "Charybdis", \
"hybrid", "ratbox", "seven", "plexus", "snircd" ]:
ERR_NICKTOOFAST = "438"
if irc_default_draft in [ "ircu", "Bahamut", "Unreal", \
"plexus", "snircd" ]:
ERR_TARGETTOOFAST = "439"
if irc_default_draft == "Bahamut":
ERR_SERVICESDOWN = "440"
ERR_USERNOTINCHANNEL = "441"
ERR_NOTONCHANNEL = "442"
ERR_USERONCHANNEL = "443"
ERR_NOLOGIN = "444"
ERR_SUMMONDISABLED = "445"
ERR_USERSDISABLED = "446"
if irc_default_draft in [ "Unreal", "Insp" ]:
ERR_NONICKCHANGE = "447"
ERR_NOTREGISTERED = "451"
if irc_default_draft == "Unreal":
ERR_HOSTILENAME = "455"
ERR_NOHIDING = "459"
ERR_NOTFORHALFOPS = "460"
ERR_NEEDMOREPARAMS = "461"
ERR_ALREADYREGISTERED = "462"
ERR_NOPERMFORHOST = "463"
ERR_PASSWDMISMATCH = "464"
ERR_YOUREBANNEDCREEP = "465"
ERR_YOUWILLBEBANNED = "466"
ERR_KEYSET = "467"
if irc_default_draft in ircd_iu_sn:
ERR_INVALIDUSERNAME = "468"
if irc_default_draft == "Unreal":
ERR_LINKSET = "469"
if irc_default_draft in ircd_Un_Ch_se:
ERR_LINKCHANNEL = "470"
ERR_CHANNELISFULL = "471"
ERR_UNKNOWNMODE = "472"
ERR_INVITEONLYCHAN = "473"
ERR_BANNEDFROMCHAN = "474"
ERR_BADCHANNELKEY = "475"
ERR_BADCHANNELMASK = "476"
if irc_default_draft in ircd_iu_Un_Ba:
ERR_NEEDREGGEDNICK = "477"
if irc_default_draft == "RFC2812":
ERR_NOCHANMODES = "477"
ERR_BANLISTFULL = "478"
if irc_default_draft == "pircd":
ERR_SECUREONLYCHANNEL = "479"
if irc_default_draft == "Unreal":
ERR_LINKFAIL = "479"
ERR_CANNOTKNOCK = "480"
ERR_NOPRIVILEGES = "481"
ERR_CHANOPRIVSNEEDED = "482"
ERR_CANTKILLSERVER = "483"
if irc_default_draft == "ircu":
ERR_ISCHANSERVICE = "484"
elif irc_default_draft in [ "RFC2812", "hybrid", "IRCNet" ]:
ERR_RESTRICTED = "484"
if irc_default_draft == "Unreal":
ERR_ATTACKDENY = "484"
ERR_KILLDENY = "485"
else:
ERR_UNIQOPPRIVSNEEDED = "485" # Unknown
if irc_default_draft == "unreal":
ERR_HTMDISABLED = "486"
if irc_default_draft == "IRCNet":
ERR_CHANTOORECENT = "487"
ERR_TSLESSCHAN = "488"
elif irc_default_draft == "Bahamut":
ERR_NOSSL = "488"
if irc_default_draft == "Unreal":
ERR_SECUREONLYCHAN = "489"
ERR_NOSWEAR = "490"
ERR_NOOPERHOST = "491"
ERR_NOSERVICEHOST = "492"
ERR_UMODEUNKNOWNFLAG = "501"
ERR_USERSDONTMATCH = "502"
if irc_default_draft in ircd_iu_Un_Ba_sn:
ERR_SILELISTFULL = "511"
if irc_default_draft in ircd_iu_sn:
ERR_NOSUCHGLINE = "512"
else:
ERR_TOOMANYWATCH = "512" # Unknown
if irc_default_draft in ircd_iu_sn:
ERR_BADPING = "513"
else:
ERR_NOSUCHGLINE = "513"
if irc_default_draft == "Unreal":
ERR_NEEDPONG = "513"
ERR_NOINVITE = "518"
ERR_ADMONLY = "519"
ERR_OPERONLY = "520"
ERR_LISTSYNTAX = "521"
ERR_WHOSYNTAX = "522"
ERR_WHOLIMEXCEED = "523"
ERR_OPERSPVERIFY = "524"
if irc_default_draft in ircd_Un_Ba:
RPL_LOGON = "600"
RPL_LOGOFF = "601"
if irc_default_draft == "Unreal":
RPL_WATCHOFF = "602"
RPL_WATCHSTAT = "603"
elif irc_default_draft == "Bahamut":
RPL_NOWON = "604"
RPL_NOWOFF = "605"
if irc_default_draft == "Unreal":
RPL_WATCHLIST = "606"
RPL_ENDOFWATCHLIST = "607"
RPL_MAPMORE = "610"
if irc_default_draft in ircd_Un_Ba:
RPL_DCCSTATUS = "617"
if irc_default_draft == "Unreal":
RPL_DUMPING = "640"
RPL_DUMPRPL = "641"
RPL_EODUMP = "642"
RPL_SPAMCMDFWD = "659"
if irc_default_draft == "Kine":
RPL_TRACEROUTE_HOP = "660"
RPL_TRACEROUTE_START = "661"
RPL_MODECHANGEWARN = "662"
RPL_CHANREDIR = "663"
RPL_SERVMODEIS = "664"
RPL_OTHERUMODEIS = "665"
if irc_add_v3 in irc_additional_drafts:
RPL_STARTTLS = "670"
if irc_default_draft == "Kine":
RPL_WHOISSTAFF = "689"
RPL_WHOISLANGUAGE = "690"
if irc_default_draft == "ratbox":
RPL_MODLIST = "702"
RPL_ENDOFMODLIST = "703"
RPL_HELPSTART = "704"
RPL_HELPTXT = "705"
RPL_ENDOFHELP = "706"
RPL_ETRACEFULL = "708"
RPL_ETRACE = "709"
RPL_KNOCK = "710"
RPL_KNOCKDLVR = "711"
ERR_TOOMANYKNOCK = "712"
ERR_CHANOPEN = "713"
ERR_KNOCKONCHAN = "714"
ERR_KNOCKDISABLED = "715"
RPL_TARGUMODEG = "716"
RPL_TARGNOTIFY = "717"
RPL_UMODEGMSG = "718"
RPL_OMOTDSTART = "720"
RPL_OMOTD = "721"
RPL_ENDOFOMOTD = "722"
ERR_NOPRIVS = "723"
RPL_TESTMARK = "724"
RPL_TESTLINE = "725"
RPL_NOTESTLINE = "726"
if irc_default_draft in ircd_Ch_se_ra_pl:
RPL_TESTMASK = "724"
RPL_TESTLINE = "725"
RPL_NOTESTLINE = "726"
if irc_default_draft == "plexus":
RPL_ISCAPTURED = "727"
if irc_default_draft in ircd_Ch_se_ra:
RPL_TESTMASKGECOS = "727"
if irc_default_draft == "plexus":
RPL_ISUNCAPTURED = "728"
if irc_default_draft in ircd_Ch_se:
RPL_QUIETLIST = "728"
RPL_ENDOFQUIETLIST = "729"
if irc_default_draft in ircd_Ch_se_ra:
RPL_MONONLINE = "730"
RPL_MONOFFLINE = "731"
RPL_MONLIST = "732"
RPL_ENDOFMONLIST = "733"
ERR_MONLISTFULL = "734"
RPL_RSACHALLENGE2 = "740"
RPL_ENDOFRSACHALLNGE2 = "741"
if irc_default_draft in ircd_Un_Ch_se:
ERR_MLOCKRESTRICTED = "742"
if irc_default_draft in ircd_Ch_se:
ERR_INVALIDBAN = "743"
ERR_TOPICLOCK = "744"
RPL_SCANMATCHED = "750"
RPL_SCANUMODES = "751"
if irc_default_draft == "IRCNet":
RPL_ETRACEEND = "759"
if irc_add_plus in irc_additional_drafts:
RPL_SERVICES_SUPPORTS_IRCPLUS = "800"
RPL_SERVICES_NEEDPASS = "801"
RPL_SERVICES_PASSOK = "802"
RPL_SERVICES_BADPASS = "803"
RPL_SERVICES_COMMAND_SUCCESS = "804"
RPL_SERVICES_COMMAND_ERROR = "805"
RPL_SERVICES_INFO = "806"
RPL_SERVICES_INFO_END = "807"
RPL_SERVICES_ERROR_NEEDREGISTRATION = "808"
RPL_SERVICES_NICKSTATUS = "809"
RPL_SERVICES_MEMO_READ = "810"
RPL_SERVICES_HELP_START = "811"
RPL_SERVICES_HELP = "812"
RPL_SERVICES_HELP_END = "813"
RPL_SERVICES_LIST_START = "814"
RPL_SERVICES_LIST = "815"
RPL_SERVICES_LIST_END = "816"
RPL_SERVICES_GLIST_START = "817"
RPL_SERVICES_GLIST = "818"
RPL_SERVICES_GLIST_END = "819"
RPL_SERVICES_MEMO_START = "820"
RPL_SERVICES_MEMO = "821"
RPL_SERVICES_MEMO_END = "822"
RPL_SERVICES_CHANSERV_CHANKEY = "823"
if irc_default_draft == "PyIRCIoT":
RPL_JSON = "851"
if irc_default_draft in ircd_Un_Ch_se:
RPL_LOGGEDIN = "900"
RPL_LOGGEDOUT = "901"
ERR_NICKLOCKED = "902"
RPL_SASLSUCCESS = "903"
if irc_add_v3 in irc_additional_drafts:
ERR_SASLFAIL = "904"
ERR_SASLTOOLONG = "905"
ERR_SASLABORTED = "906"
ERR_SASLALREADY = "907"
if irc_default_draft in ircd_Ch_se:
RPL_SASLMECHS = "908"
if irc_default_draft == "Insp":
RPL_AUTOOPLIST = "910"
RPL_ENDOFAUTOOPLIST = "911"
ERR_WORDFILTERED = "936"
RPL_SPAMFILTERLIST = "940"
ERR_ENDOFSPAMFILTERLIST = "941"
RPL_EXEMPTCHANOPSLIST = "953"
ERR_ENDOFEXEMPTCHANOPSLIST = "954"
if irc_default_draft in [ "Unreal", "plexus" ]:
ERR_CANNOTDOCOMMAND = "972"
elif irc_default_draft == "Insp":
ERR_CANTUNLOADMODULE = "972"
RPL_UNLOADEDMODULE = "973"
ERR_CANTLOADMODULE = "974"
RPL_LOADEDMODULE = "975"
elif irc_default_draft == "Bahamut":
ERR_NUMERICERROR = "999"
#
# v this set will be regrouped ...
#
cmd_ADMIN = "ADMIN"
cmd_AWAY = "AWAY"
cmd_CACTION = "CACTION"
cmd_CCLIENTINF = "CCLIENTINFO"
cmd_CDCC = "CDCC"
cmd_CERRMSG = "CERRMSG"
cmd_CFINGER = "CFINGER"
cmd_CHAT = "CHAT"
cmd_CPING = "CPING"
cmd_CRCLIENTIN = "CRCLIENTINFO"
cmd_CRFINGER = "CRFINGER"
cmd_CRPING = "CRPING"
cmd_CRTIME = "CRTIME"
cmd_CRUSERINFO = "CRUSERINFO"
cmd_CSOURCE = "CSOURCE"
cmd_CTCP = "CTCP"
cmd_CTCPREPLY = "CTCPREPLY"
cmd_CTIME = "CTIME"
cmd_CUSERINFO = "CUSERINFO"
cmd_CVERSION = "CVERSION"
cmd_DCC_CLOSE = "DCC_CLOSE"
cmd_DCC_CON = "DCC_CONNECT"
cmd_DCC_DISCON = "DCC_DISCONNECT"
cmd_DCC_MSG = "DCCMSG"
cmd_DCC_OPEN = "DCC_OPEN"
cmd_DCC_UPDATE = "DCC_UPDATE"
cmd_DISCONNECT = "DISCONNECT"
cmd_ERROR = "ERROR"
cmd_INFO = "INFO"
cmd_INVITE = "INVITE"
cmd_ISON = "ISON"
cmd_JOIN = "JOIN"
cmd_KICK = "KICK"
cmd_KILL = "KILL"
cmd_LEAVING = "LEAVING"
cmd_LINKS = "LINKS"
cmd_LIST = "LIST"
cmd_MODE = "MODE"
cmd_MOTD = "MOTD"
cmd_MSG = "MSG"
cmd_NAMES = "NAMES"
cmd_NICK = "NICK"
cmd_NOTICE = "NOTICE"
cmd_NJOIN = "NJOIN"
cmd_OPER = "OPER"
cmd_PART = "PART"
cmd_PASS = "PASS"
cmd_PING = "PING"
cmd_PONG = "PONG"
cmd_PRIVMSG = "PRIVMSG"
cmd_PRIVNOTICE = "PRIVNOTICE"
cmd_PUBLIC = "PUBLIC"
cmd_PUBMSG = "PUBMSG"
cmd_PUBNOTICE = "PUBNOTICE"
cmd_REHASH = "REHASH"
cmd_RESTART = "RESTART"
cmd_QUIT = "QUIT"
cmd_SERVER = "SERVER"
cmd_SQUIT = "SQUIT"
cmd_STATS = "STATS"
cmd_SUMMON = "SUMMON"
cmd_TIME = "TIME"
cmd_TOPIC = "TOPIC"
cmd_TRACE = "TRACE"
cmd_UMODE = "UMODE"
cmd_USER = "USER"
cmd_USERS = "USERS"
cmd_USERHOST = "USERHOST"
cmd_VERSION = "VERSION"
cmd_WALLOPS = "WALLOPS"
cmd_WHOIS = "WHOIS"
cmd_WHOWAS = "WHOWAS"
cmd_WHO = "WHO"
if irc_default_draft == "ircu":
cmd_ACCOUNT = "ACCOUNT"
cmd_CLARMODE = "CLEARMODE"
cmd_CLOSE = "CLOSE"
cmd_CNOTICE = "CNOTICE"
cmd_CONNECT = "CONNECT"
cmd_CPRIVMSG = "CPRIVMSG"
cmd_CREATE = "CREATE"
cmd_DESTRUCT = "DESCTRUCT"
cmd_DESYNCH = "DESYNCH"
cmd_DIE = "DIE"
cmd_GLINE = "GLINE"
cmd_HASH = "HASH"
cmd_HELP = "HELP"
cmd_JUPE = "JUPE"
cmd_LUSERS = "LUSERS"
cmd_MAP = "MAP"
cmd_OPMODE = "OPMODE"
cmd_PRIVS = "PRIVS"
cmd_PROTO = "PROTO"
cmd_RESET = "RESET"
cmd_RPING = "RPING"
cmd_RPONG = "RPONG"
cmd_SET = "SET"
cmd_SETTIME = "SETTIME"
cmd_SILENCE = "SILENCE"
cmd_UPING = "UPING"
cmd_USERIP = "USERIP"
cmd_WALLCHOPS = "WALLCHOPS"
cmd_WALLUSERS = "WALLUSERS"
cmd_WALLVOICE = "WALLVOICE"
if irc_add_v3 in irc_additional_drafts:
cmd_ACC = "ACC"
cmd_AUTHENTICATE = "AUTHENTICATE"
cmd_BATCH = "BATCH"
cmd_CAP = "CAP"
cmd_FAIL = "FAIL"
#cmd_MAXLINE = "MAXLINE" (line-length-3.3)
cmd_SETNAME = "SETNAME"
cmd_STARTTLS = "STARTTLS"
cmd_TAGMSG = "TAGMSG"
cmd_WARN = "WARN"
cmd_WEBIRC = "WEBIRC"
cmd_MULTILINE_MAX_BYTES = "MULTILINE_MAX_BYTES"
cmd_MULTILINE_MAX_LINES = "MULTILINE_MAX_LINES"
cmd_MULTILINE_INVALID = "MULTILINE_INVALID"
cmd_MULTILINE_INVALID_TARGET = "MULTILINE_INVALID_TARGET"
#
if irc_default_draft == "ircu":
feature_AWAYLEN = "AWAYLEN"
feature_CASEMAPPING = "CAEMAPPING"
if irc_default_draft == "ircu":
feature_CHANNELLEN = "CHANNELLEN"
feature_CHANMODES = "CHANMODES"
feature_CHANTYPES = "CHANTYPES"
if irc_default_draft == "ircu":
feature_CNOTICE = "CNOTICE"
feature_CPRIVMSG = "CPRIVMSG"
feature_MAXCHANLEN = "MAXCHANNELLEN"
feature_KICKLEN = "KICKLEN"
feature_MODES = "MODES"
feature_MAXCHANS = "MAXCHANNELS"
feature_MAXBNANS = "MAXBANS"
feature_MAXNICKLEN = "MAXNICKLEN"
feature_NETWORK = "NETWORK"
feature_NICKLEN = "NICKLEN"
feature_PREFIX = "PREFIX"
if irc_default_draft == "ircu":
feature_SILENCE = "SILENCE"
feature_STATUSMSG = "STATUSMSG"
feature_TOPICLEN = "TOPICLEN"
feature_USERIP = "USERIP"
feature_WALLCHOPS = "WALLCHOPS"
feature_WALLVOICES = "WALLVOICES"
feature_WHOX = "WHOX"
#
featt_EMPTY = 0
featt_FLAGS = 1
featt_STRING = 2
featt_NUMBER = 3
#
ident_default_ip = '0.0.0.0'
ident_default_port = 113
#
err_NOT_IRCIOT_NET = 2019
#
err_DESCRIPTIONS = irciot_shared_.CONST.err_DESCRIPTIONS
err_DESCRIPTIONS.update({
err_NOT_IRCIOT_NET : "Warning! Not an IRC-IoT network: '{}'"
})
#
def __setattr__(self, *_):
pass
def __init__(self, in_mode = None):
#
self.CONST = self.CONST()
#
super(PyLayerIRC, self).__init__()
#
self.irc_encoding = self.CONST.irc_default_encoding
self.irc_MTU = self.CONST.irc_default_MTU
#
self.__irc_nick_matcher \
= re.compile(self.CONST.irc_nick_regexp, re.IGNORECASE)
self.__irc_channel_matcher \
= re.compile(self.CONST.irc_channel_regexp, re.IGNORECASE)
#
self.__irc_nick = self.CONST.irc_default_nick
self.irc_user = self.irc_tolower_(self.CONST.irc_default_nick)
self.irc_info = self.CONST.irc_default_info
self.irc_quit = self.CONST.irc_default_quit
self.irc_nick_old = self.__irc_nick
self.irc_nick_base = self.__irc_nick
self.irc_nick_try = ""
#
self.irc_nick_length = self.CONST.irc_max_nick_length
self.irc_topic_length = self.CONST.irc_max_topic_length
#
self.irc_ssl = self.CONST.irc_default_ssl
self.irc_server = self.CONST.irc_default_server
self.irc_port = self.CONST.irc_default_port
if self.irc_ssl:
self.irc_port = self.CONST.irc_default_ssl_port
self.__irc_password = self.CONST.irc_default_password
self.irc_ident = self.CONST.irc_default_ident
#
# This variable is not used to connect, if you don't have a server name
# and you want to use the IP, put its text value into self.irc_server
self.irc_server_ip = None
self.__irc_local_port = 0
self.irc_network_name = None
#
self.irc_proxy = None
if self.CONST.irc_default_proxy != None:
self.irc_proxy_server = self.CONST.irc_default_proxy_server
self.irc_proxy_port = self.CONST.irc_default_proxy_port
self.__irc_proxy_password = self.CONST.irc_default_proxy_password
#
self.irc_status = 0
self.__irc_recon = 1
self.irc_last = None
#
self.irc_servers = [ ( \
self.irc_server, self.irc_port, \
self.__irc_password, self.irc_ssl, 0, None ) ]
#
self.irc_proxies = []
if self.irc_proxy != None:
self.irc_proxies = [ ( \
self.irc_proxy_server, self.irc_proxy_port, \
self.__irc_proxy_password, 0, None ) ]
#
self.irc_channel = self.CONST.irc_default_channel
self.irc_chankey = self.CONST.irc_default_chankey
self.__join_retry = 0
self.__join_retry_max = self.CONST.irc_default_join_retry
#
self.__nick_pause = 0
#
# ( irc channel, irc channel key, join retry count )
self.irc_channels = [ ( \
self.irc_channel, self.irc_chankey, 0 ) ]
#
self.irc_users = self.CONST.irc_default_users
self.irc_anons = []
self.irc_nicks = []
#
self.irc_talk_with_strangers = \
self.CONST.irc_default_talk_with_strangers
self.irc_last_temporal_vuid = \
self.CONST.api_first_temporal_vuid
#
self.__irc_queue = [0, 0]
self.__irc_queue[self.CONST.irc_queue_input ] = Queue(maxsize=0)
self.__irc_queue[self.CONST.irc_queue_output ] = Queue(maxsize=0)
#
self.__irc_queue_lock = [0, 0]
self.__irc_queue_lock[self.CONST.irc_queue_input ] = False
self.__irc_queue_lock[self.CONST.irc_queue_output ] = False
#
self.irc_commands = []
self.irc_codes = []
self.irc_features = []
#
if in_mode in self.CONST.irc_layer_modes:
self.__irc_layer_mode = in_mode
else:
self.__irc_layer_mode = self.CONST.irc_default_mode
#
self.__irc_task = None
self.irc_run = False
self.irc_debug = self.CONST.irc_default_debug
#
self.__ident_task = None
self.ident_run = False
self.ident_ip = self.CONST.ident_default_ip
self.ident_port = self.CONST.ident_default_port
#
self.irc_mid_pipeline_size \
= self.CONST.irc_default_mid_pipeline_size
#
self.irc_silence_max = self.CONST.irc_default_silence
self.__irc_silence = 0
#
self.time_now = datetime.datetime.now()
self.__time_ping = self.time_now
self.__delta_time = 0
self.__delta_ping = 0
#
# Supporting eXtended WHO command:
self.__whox = False
# Supporting of WALLCHOPS command:
self.__wallchops = False
#
self.__os_name = self.get_os_name_()
#
self.update_irc_host_()
#
self.lang = self.CONST.hl_default
#
self.errors = self.CONST.err_DESCRIPTIONS
#
self.irciot_set_locale_(self.lang)
#
# End of __init__()
def update_irc_host_(self):
try:
my_ip = self.get_src_ip_by_dst_ip_(self.irc_server_ip)
my_host = self.dns_reverse_resolver_(my_ip)
if socket.gethostbyname(my_host) != my_ip:
my_host = None
except:
my_host = None
if my_host == None:
try:
my_host = socket.gethostname()
except:
my_host = "localhost";
self.irc_host = my_host
def ident_server_(self):
def ident_ok_():
if not self.irc_run:
self.ident_run = False
if not self.ident_run:
return False
return True
if not self.is_ip_address_(self.ident_ip):
return
if not self.is_ip_port_(self.ident_port):
return
while (self.ident_run):
try:
if self.is_ipv4_address_(self.ident_ip):
my_af_inet = socket.AF_INET
else:
my_af_inet = socket.AF_INET6
my_socket = socket.socket(my_af_inet, socket.SOCK_STREAM)
my_socket.settimeout(self.CONST.irc_ident_wait)
my_socket.bind((self.ident_ip, self.ident_port))
my_socket.listen(1)
except:
my_socket.close()
sleep(self.CONST.irc_default_wait)
if not ident_ok_():
break
continue
while (ident_ok_()):
try:
try:
my_conn, my_addr = my_socket.accept()
except:
break
if not ident_ok_():
break
if not my_addr[0] in [ self.irc_server_ip, '127.0.0.1', '::1' ]:
my_conn.close()
break
while (ident_ok_()):
my_ready = select.select([my_socket], [], [], 0)
if my_ready[0] == [] and ident_ok_():
my_data = my_conn.recv(self.CONST.irc_buffer_size \
).decode(self.irc_encoding)
if my_data:
for my_char in [ '\n', '\r', ' ' ]:
my_data = my_data.replace(my_char, '')
my_split = my_data.split(',')
my_ok = True
my_port = "{}".format(self.irc_port)
if my_split[0] == "" or my_split[1] != my_port:
break
if self.is_ip_port_(self.__irc_local_port):
my_port = "{}".format(self.__irc_local_port)
if my_split[0] != my_port:
my_ok = False
my_out = "{} , {} : ".format(my_split[0], my_split[1])
if my_ok:
my_out += "USERID : UNIX : {}\n".format(self.irc_user)
else:
my_out += "ERROR : NO-USER\n"
my_conn.send(bytes(my_out, self.irc_encoding))
self.ident_run = False
break
else:
break
else:
sleep(self.CONST.irc_micro_wait)
my_conn.close()
sleep(self.CONST.irc_micro_wait)
except:
my_conn.close()
sleep(self.CONST.irc_micro_wait)
try:
my_socket.close()
except:
pass
sleep(self.CONST.irc_micro_wait)
#
# End of ident_server_()
def start_IRC_(self):
if self.__irc_layer_mode in [
self.CONST.irc_mode_CLIENT,
self.CONST.irc_mode_SERVICE ]:
my_target = self.irc_process_client_
elif self.__irc_layer_mode == self.COSNT.irc_mode_SERVER:
my_target = self.irc_process_server_
else:
return False
self.irc_run = True
self.__irc_task = threading.Thread(target = my_target)
self.__irc_task.start()
return True
#
# End of start_IRC_()
def stop_IRC_(self):
self.irc_run = False
self.ident_run = False
self.irc_debug = False
self.__irc_password \
= self.wipe_string_(self.__irc_password)
if self.CONST.irc_default_proxy != None:
self.__irc_proxy_password \
= self.wipe_string_(self.__irc_proxy_password)
sleep(self.CONST.irc_micro_wait)
self.irc_disconnect_()
self.stop_ident_()
if self.__irc_task != None:
sleep(self.CONST.irc_micro_wait)
try:
self.__irc_task.join()
except:
pass
#
# End of stop_IRC_()
def start_ident_(self):
#
self.ident_run = True
self.__ident_task = threading.Thread(target = self.ident_server_)
self.__ident_task.start()
#
# End of start_ident_()
def stop_ident_(self):
#
self.ident_run = False
if self.__ident_task != None:
sleep(self.CONST.irc_micro_wait)
try:
self.__ident_task.join()
except:
pass
def __del__(self):
self.stop_IRC_()
try:
import signal
signal.alarm(0)
except:
pass
def to_log_(self, msg):
if not self.irc_debug:
return
print(msg)
def irciot_protocol_version_(self):
return self.CONST.irciot_protocol_version
def irciot_library_version_(self):
return self.CONST.irciot_library_version
def irc_handler (self, in_compatibility, in_message_pack):
# Warning: interface may be changed
(in_protocol, in_library) = in_compatibility
if not self.irciot_protocol_version_() == in_protocol \
or not self.irciot_library_version_() == in_library:
return False
my_message_pack = in_message_pack
if isinstance(in_message_pack, tuple):
my_message_pack = [ in_message_pack ]
if isinstance(my_message_pack, list):
for my_pack in my_message_pack:
(my_message, my_vuid) = my_pack
self.irc_add_to_queue_( \
self.CONST.irc_queue_output, my_message, \
self.CONST.irc_micro_wait, my_vuid)
return True
def user_handler (self, in_compatibility, in_action, in_vuid, in_params):
# Warning: interface may be changed
(in_protocol, in_library) = in_compatibility
if not self.irciot_protocol_version_() == in_protocol \
or not self.irciot_library_version_() == in_library \
or not isinstance(in_action, int) \
or not isinstance(in_vuid, str) \
or not (isinstance(in_params, str) or in_params == None):
return (False, None)
my_vt = None # VUID Type
my_user = None
my_anon = None
if in_vuid in self.CONST.api_vuid_not_srv:
my_vt = in_vuid
else:
my_re = re.search("{}(\d+)".format( \
self.CONST.api_vuid_cfg), in_vuid)
if my_re:
my_vt = self.CONST.api_vuid_cfg
my_user = self.irc_cfg_get_user_struct_by_vuid_(in_vuid)
if my_user != None:
( my_uid, my_mask, my_chan, my_opt, \
my_ekey, my_bkey, my_lmid, \
my_ekto, my_bkto, my_omid ) = my_user
else:
my_re = re.search("{}(\d+)".format( \
self.CONST.api_vuid_tmp), in_vuid)
if my_re:
my_vt = self.CONST.api_vuid_tmp
my_anon = self.irc_track_get_anons_by_vuid_(in_vuid)
if my_anon != None:
( an_id, an_mask, an_chan, an_opt, \
an_ekey, an_bkey, an_lmid, \
an_ekto, an_bkto, an_omid ) = my_anon
else:
return (False, None)
if in_action == self.CONST.api_GET_LMID:
if my_vt == self.CONST.api_vuid_cfg:
if my_user != None:
return (True, my_lmid)
elif my_vt == self.CONST.api_vuid_tmp:
if my_anon != None:
return (True, an_lmid)
elif in_action == self.CONST.api_SET_LMID:
if my_vt == self.CONST.api_vuid_cfg:
self.irc_track_update_ucfgs_by_vuid_(in_vuid, \
None, None, in_params, None, None, None)
elif my_vt == self.CONST.api_vuid_tmp:
self.irc_track_update_anons_by_vuid_(in_vuid, \
None, None, None, None, None, in_params, \
None, None, None)
elif in_action == self.CONST.api_GET_OMID:
if my_vt == self.CONST.api_vuid_cfg:
if my_user != None:
return (True, my_omid)
elif my_vt == self.CONST.api_vuid_tmp:
if my_anon != None:
return (True, an_omid)
elif in_action == self.CONST.api_SET_OMID:
if my_vt == self.CONST.api_vuid_cfg:
self.irc_track_update_ucfgs_by_vuid_(in_vuid, \
None, None, None, None, None, in_params)
elif my_vt == self.CONST.api_vuid_tmp:
self.irc_track_update_anons_by_vuid_(in_vuid, \
None, None, None, None, None, None, \
None, None, in_params)
elif in_action == self.CONST.api_GET_VUID:
if in_vuid in self.CONST.api_vuid_not_srv:
my_vuid_list = []
for my_nick in self.irc_nicks:
(in_nick, my_mask, my_vuid, my_info) = my_nick
if not self.irc_talk_with_strangers:
if my_vuid[0] != self.CONST.api_vuid_cfg:
continue
if my_vt in [
self.CONST.api_vuid_cfg,
self.CONST.api_vuid_tmp ]:
if my_vuid[0] != my_vt:
continue
my_vuid_list.append(my_vuid)
return (True, my_vuid_list)
elif in_action == self.CONST.api_GET_BKEY:
if my_vt == self.CONST.api_vuid_cfg:
if my_user != None:
return (True, my_bkey)
elif my_vt == self.CONST.api_vuid_tmp:
if my_anon != None:
return (True, an_bkey)
elif in_action == self.CONST.api_SET_BKEY:
if my_vt == self.CONST.api_vuid_cfg:
self.irc_track_update_ucfgs_by_vuid_(in_vuid, \
None, in_params, None, None, None, None)
return (True, None)
elif my_vt == self.CONST.api_vuid_tmp:
self.irc_track_update_anons_by_vuid_(in_vuid, \
None, None, None, None, in_params, \
None, None, None, None)
return (True, None)
elif in_action == self.CONST.api_GET_EKEY:
if my_vt == self.CONST.api_vuid_cfg:
if my_user != None:
return (True, my_ekey)
elif my_vt == self.CONST.api_vuid_tmp:
if my_anon != None:
return (True, an_ekey)
elif in_action == self.CONST.api_SET_EKEY:
if my_vt == self.CONST.api_vuid_cfg:
self.irc_track_update_ucfgs_by_vuid_(in_vuid, \
in_params, None, None, None, None, None)
elif my_vt == self.CONST.api_vuid_tmp:
self.irc_track_update_anons_by_vuid_(in_vuid, \
None, None, None, in_params, None, \
None, None, None, None)
elif in_action == self.CONST.api_GET_EKTO:
if my_vt == self.CONST.api_vuid_cfg:
if my_user != None:
return (True, my_ekto)
elif my_vt == self.CONST.api_vuid_tmp:
if my_anon != None:
return (True, an_ekto)
elif in_action == self.CONST.api_SET_EKTO:
if my_vt == self.CONST.api_vuid_cfg:
self.irc_track_update_ucfgs_by_vuid_(in_vuid, \
None, None, None, in_params, None, None)
elif my_vt == self.CONST.api_vuid_tmp:
self.irc_track_update_anons_by_vuid_(in_vuid, \
None, None, None, None, None, \
None, in_params, None, None)
elif in_action == self.CONST.api_GET_BKTO:
if my_vt == self.CONST.api_vuid_cfg:
if my_user != None:
return (True, my_bkto)
elif my_vt == self.CONST.api_vuid_tmp:
if my_anon != None:
return (True, an_bkto)
elif in_action == self.CONST.api_SET_BKTO:
if my_vt == self.CONST.api_vuid_cfg:
self.irc_track_update_ucfgs_by_vuid_(in_vuid, \
None, None, None, None, in_params, None)
elif my_vt == self.CONST.api_vuid_tmp:
self.irc_track_update_anons_by_vuid_(in_vuid, \
None, None, None, None, None, \
None, None, in_params, None)
elif in_action == self.CONST.api_GET_iMTU:
return (True, self.irc_MTU)
elif in_action == self.CONST.api_GET_iENC:
return (True, self.irc_encoding)
return (False, None)
#
# End of user_handler_()
def irciot_set_locale_(self, in_lang):
if not isinstance(in_lang, str):
return
self.lang = in_lang
my_desc = {}
try:
from PyIRCIoT.irciot_errors \
import irciot_get_common_error_descriptions_
my_desc = irciot_get_common_error_descriptions_(in_lang)
my_dsec = self.validate_descriptions_(my_desc)
if my_desc != {}:
self.errors.update(my_desc)
except:
pass
my_desc = {}
try:
from PyIRCIoT.irciot_errors \
import irciot_get_rfc1459_error_descriptions_
my_desc = irciot_get_rfc1459_error_descriptions_(in_lang)
my_desc = self.validate_descriptions_(my_desc)
if my_desc != {}:
self.errors.update(my_desc)
except:
pass
#
# End of irciot_set_locale_()
def irc_set_password_(self, in_password):
self.__irc_password = self.copy_string_(in_password)
in_password = self.wipe_string_(in_password)
def irc_set_proxy_password_(self, in_password):
self.__irc_proxy_password = self.copy_string_(in_password)
in_password = self.wipe_string_(in_password)
def irc_tolower_(self, in_input):
return in_input.translate(self.CONST.irc_translation)
def irc_tomock_(self, in_input):
return in_input.translate(self.CONST.irc_transmocker)
def irc_get_list_(self, in_input):
if in_input == None:
return []
if isinstance(in_input, list):
return in_input
else:
return [ in_input ]
def is_irc_nick_(self, in_nick):
if not isinstance(in_nick, str):
return False
if len(in_nick) > self.CONST.irc_max_nick_length:
return False
return self.__irc_nick_matcher.match(in_nick)
def is_irc_channel_(self, in_channel):
if not isinstance(in_channel, str):
return False
return self.__irc_channel_matcher.match(in_channel)
def irc_compare_channels_(self, ref_channel, cmp_channel):
if not self.is_irc_channel_(ref_channel):
return False
if not self.is_irc_channel_(cmp_channel):
return False
return (self.irc_tolower_(ref_channel) \
== self.irc_tolower_(cmp_channel))
def irc_compare_nicks_(self, ref_nick, cmp_nick):
if not self.is_irc_nick_(ref_nick):
return False
if not self.is_irc_nick_(cmp_nick):
return False
return (self.irc_tolower_(ref_nick) \
== self.irc_tolower_(cmp_nick))
def irc_define_nick_(self, in_nick):
if not self.is_irc_nick_(in_nick):
return
self.__irc_nick = in_nick
self.irc_nick_old = in_nick
self.irc_nick_base = in_nick
if self.irc_run:
self.irc_send_(self.CONST.cmd_NICK + " " + in_nick)
def irc_get_nick_(self):
return self.__irc_nick
def irc_get_delta_(self):
return self.__delta_time
def irc_get_local_port_(self):
if self.is_ip_port_(self.__irc_local_port):
return self.__irc_local_port
else:
return None
def irc_check_mask_(self, in_from, in_mask):
str_from = self.irc_tolower_(in_from)
str_mask = self.irc_tolower_(in_mask).replace("\\", "\\\\")
for char in ".$|[](){}+":
str_mask = str_mask.replace(char, "\\" + char)
str_mask = str_mask.replace("?", ".")
str_mask = str_mask.replace("*", ".*")
irc_regexp = re.compile(str_mask, re.IGNORECASE)
my_result = irc_regexp.match(str_from)
if my_result != None:
if my_result:
return True
return False
def irc_track_cleanup_anons_(self):
for my_anon in self.irc_anons:
( an_id, an_mask, an_chan, an_opt, \
an_ekey, an_bkey, an_lmid, \
an_ekto, an_bkto, an_omid ) = my_anon
an_vuid = "{:s}{}".format(self.CONST.api_vuid_tmp, an_id)
an_ok = False
for my_nick in self.irc_nicks:
(in_nick, my_mask, my_vuid, my_info) = my_nick
if my_vuid == an_vuid:
an_ok = True
if not an_ok:
self.irc_anons.remove(my_anon)
#
# End of irc_track_cleanup_anons_()
def irc_track_update_ucfgs_by_vuid_(self, in_vuid, \
in_ekey, in_bkey, in_lmid, in_ekto, in_bkto, in_omid):
if not isinstance(in_vuid, str):
return
# Configured users must be setup from the local config,
# but some of the fields may be missing, in this case,
# the needed values will be taken from the network
for my_index, my_ucfg in enumerate(self.irc_users):
( my_id, my_mask, my_channel, my_opt, \
my_ekey, my_bkey, my_lmid, \
my_ekto, my_bkto, my_omid ) = my_ucfg
my_vuid = self.CONST.api_vuid_cfg
my_vuid += "{:d}".format(my_id)
if in_vuid == my_vuid:
# Updating crypto keys only if they are not defined
if my_ekey == None and isinstance(in_ekey, str):
my_ekey = in_ekey
if my_bkey == None and isinstance(in_bkey, str):
my_bkey = in_bkey
if my_ekto == None and isinstance(in_ekto, int):
my_ekto = in_ekto
if my_bkto == None and isinstance(in_bkto, int):
my_bkto = in_bkto
# Only the last message ID can be updated in pipeline
if isinstance(in_lmid, str):
if isinstance(my_lmid, list):
if in_lmid not in my_lmid:
my_lmid.append(in_lmid)
if len(my_lmid) > self.irc_mid_pipeline_size:
del my_lmid[0]
else:
my_lmid = [ in_lmid ]
if isinstance(in_omid, str):
if isinstance(my_omid, list):
if in_omid not in my_omid:
my_omid.append(in_omid)
if len(my_omid) > self.irc_mid_pipeline_size:
del my_omid[0]
else:
my_omid = [ in_omid ]
my_cfgs = ( my_id, my_mask, my_channel, \
my_opt, my_ekey, my_bkey, my_lmid, \
my_ekto, my_bkto, my_omid )
self.irc_users[my_index] = my_cfgs
break
#
# End of irc_track_update_ucfgs_by_vuid_()
def irc_track_update_anons_by_vuid_(self, in_vuid, \
in_mask, in_chan, in_opt, in_ekey, in_bkey, \
in_lmid, in_ekto, in_bkto, in_omid ):
if not isinstance(in_vuid, str):
return
my_re = re.search("{}(\d+)".format( \
self.CONST.api_vuid_tmp), in_vuid)
if my_re:
my_id = my_re.group(1)
else:
return
my_ok = False
for my_index, my_anon in enumerate(self.irc_anons):
( an_id, my_mask, my_chan, my_opt, \
my_ekey, my_bkey, my_lmid, my_ekto, \
my_bkto, my_omid ) = my_anon
if my_id == an_id:
my_ok = True
if isinstance(in_mask, str):
my_mask = in_mask
if self.is_irc_channel_(in_chan):
my_chan = in_chan
if in_opt != None:
my_opt = in_opt
if isinstance(in_ekey, str):
my_ekey = in_ekey
if isinstance(in_bkey, str):
my_bkey = in_bkey
if isinstance(in_lmid, str):
if isinstance(my_lmid, list):
if in_lmid not in my_lmid:
my_lmid.append(in_lmid)
if len(my_lmid) > self.irc_mid_pipeline_size:
del my_lmid[0]
else:
my_lmid = [ in_lmid ]
if isinstance(in_ekto, int):
my_ekto = in_ekto
if isinstance(in_bkto, int):
my_bkto = in_bkto
if isinstance(in_omid, str):
if isinstance(my_omid, list):
if in_omid not in my_omid:
my_omid.append(in_omid)
if len(my_omid) > self.irc_mid_pipeline_size:
del my_omid[0]
else:
my_omid = [ in_omid ]
my_anon = ( an_id, my_mask, my_chan, my_opt, my_ekey, \
my_bkey, my_lmid, my_ekto, my_bkto, my_omid )
self.irc_anons[my_index] = my_anon
break
if not my_ok:
for my_anon in self.irc_anons:
if my_anon[1] == in_mask:
my_ok = True
if not my_ok:
my_lmid = None
my_omid = None
if isinstance(my_lmid, str):
my_lmid = [ in_lmid ]
if isinstance(my_omid, str):
my_omid = [ in_omid ]
self.irc_anons.append( ( my_id, in_mask, \
in_chan, in_opt, in_ekey, in_bkey, my_lmid,
in_ekto, in_bkto, my_omid ) )
#
# End of irc_track_update_anons_by_vuid_()
def irc_track_get_anons_by_vuid_(self, in_vuid):
if not isinstance(in_vuid, str):
return None
my_re = re.search("{}(\d+)".format( \
self.CONST.api_vuid_tmp), in_vuid)
if my_re:
my_id = my_re.group(1)
else:
return None
for my_anon in self.irc_anons:
( an_id, an_mask, an_chan, an_opt, \
an_ekey, an_bkey, an_lmid, \
an_ekto, an_bkto, an_omid ) = my_anon
if my_id == an_id:
return my_anon
return None
#
# End of irc_track_get_anons_by_vuid_()
def irc_track_fast_nick_(self, in_nick, in_mask):
my_ok = True
for my_struct in self.irc_nicks:
if my_struct[0] == in_nick:
my_ok = False
if my_ok:
self.irc_track_add_nick_(in_nick, in_mask, None, None)
#
# End of irc_track_fast_nick_()
def irc_track_add_nick_(self, in_nick, in_mask, in_vuid, in_info):
if not self.is_irc_nick_(in_nick):
return
if in_nick == self.__irc_nick:
return
my_struct = self.irc_track_get_nick_struct_by_nick_(in_nick)
if my_struct == None:
self.irc_nicks.append((in_nick, in_mask, in_vuid, in_info))
else:
self.irc_track_update_nick_(in_nick, in_mask, in_vuid, in_info)
#
# End of irc_track_add_nick_()
def irc_track_update_nick_(self, in_nick, in_mask, in_vuid, in_info):
if not self.is_irc_nick_(in_nick):
return
if in_nick == self.__irc_nick:
return
for my_index, my_struct in enumerate(self.irc_nicks):
(my_nick, my_mask, my_vuid, my_info) = my_struct
# comparing of the masks will be here ...
# self.irc_check_mask_(in_from, in_mask)
if self.irc_compare_nicks_(my_nick, in_nick):
if isinstance(in_mask, str):
my_mask = in_mask
if in_vuid == None:
my_vuid = self.irc_get_vuid_by_mask_(my_mask, self.irc_channel)
if isinstance(in_vuid, str):
my_vuid = in_vuid
if isinstance(in_info, str):
my_info = in_info
self.irc_nicks[my_index] = (in_nick, my_mask, my_vuid, my_info)
if self.irc_talk_with_strangers:
self.irc_track_update_anons_by_vuid_(my_vuid, \
my_mask, self.irc_channel, \
None, None, None, None, None, None, None)
break
#
# End of irc_track_update_nick_()
def irc_track_clear_anons_(self):
self.irc_anons = []
def irc_track_clear_nicks_(self):
self.irc_nicks = []
def irc_track_delete_nick_(self, in_nick):
if not self.is_irc_nick_(in_nick):
return
for my_struct in self.irc_nicks:
(my_nick, my_mask, my_vuid, my_info) = my_struct
if self.irc_compare_nicks_(my_nick, in_nick):
self.irc_nicks.remove(my_struct)
if self.irc_talk_with_strangers:
self.irc_track_cleanup_anons_()
break
#
# End of irc_track_delete_nick_()
def irc_track_get_nick_struct_(self, in_position):
try:
my_struct = self.irc_nicks[in_position]
except:
my_struct = None
return my_struct
def irc_track_get_nick_struct_by_nick_(self, in_nick):
if not self.is_irc_nick_(in_nick):
return None
for my_struct in self.irc_nicks:
(my_nick, my_mask, my_vuid, my_info) = my_struct
if self.irc_compare_nicks_(my_nick, in_nick):
return my_struct
return None
def irc_track_get_nick_struct_by_vuid_(self, in_vuid):
if not isinstance(in_vuid, str):
return None
for my_struct in self.irc_nicks:
(my_nick, my_mask, my_vuid, my_info) = my_struct
if my_vuid == in_vuid:
return my_struct
return None
def irc_track_get_nick_by_vuid_(self, in_vuid):
if not isinstance(in_vuid, str):
return None
for my_struct in self.irc_nicks:
(my_nick, my_mask, my_vuid, my_info) = my_struct
if my_vuid == in_vuid:
return my_nick
return None
def irc_track_clarify_nicks_(self):
for my_struct in self.irc_nicks:
(my_nick, my_mask, my_vuid, my_info) = my_struct
if my_mask == None or my_info == None:
self.irc_whois_nick_(my_nick)
if my_mask == None:
my_mask = ""
if my_info == None:
my_info = ""
self.irc_track_update_nick_(my_nick, my_mask, my_vuid, my_info)
break
#
# End of irc_track_clarify_nicks_()
def irc_cfg_get_user_mask_(self, in_position):
if not isinstance(in_position, int):
return None
try:
my_user = self.irc_users[ in_position ]
( my_id, my_mask, my_chan, my_opt, \
my_ekey, my_bkey, my_lmid, my_ekto, \
my_bkto, my_omid ) = my_user
return my_mask
except:
return None
#
# End of irc_cfg_get_user_mask_()
def irc_cfg_get_user_struct_(self, in_position):
if not isinstance(in_position, int):
return None
try:
my_struct = self.irc_users[ in_position ]
return my_struct
except:
return None
#
# End of irc_cfg_get_user_struct_()
def irc_cfg_get_vuid_(self, in_position):
if not isinstance(in_position, int):
return None
try:
my_user = self.irc_users[ in_position ]
( my_id, my_mask, my_chan, my_opt, \
my_ekey, my_bkey, my_lmid, my_ekto, \
my_bkto, my_omid ) = my_user
return "{:s}{:d}".format(self.CONST.api_vuid_cfg, my_id)
except:
return None
#
# End of irc_cfg_get_vuid_()
def irc_cfg_get_user_struct_by_vuid_(self, in_vuid):
if not isinstance(in_vuid, str):
return None
for my_user in self.irc_users:
if in_vuid == "{:s}{:d}".format( \
self.CONST.api_vuid_cfg, my_user[0]):
return my_user
return None
#
# End of irc_cfg_get_user_strcut_by_vuid_()
def irc_cfg_check_user_(self, in_from, in_channel, \
irciot_parameters = None):
if not self.is_irc_channel_(in_channel):
return None
in_opt = None
in_ekey = None
in_bkey = None
in_lmid = None
in_ekto = None
in_bkto = None
in_omid = None
if irciot_parameters != None:
( in_opt, in_ekey, in_bkey, in_lmid, \
in_ekto, in_bkto, in_omid ) = irciot_parameters
for my_user in self.irc_users:
( my_uid, my_mask, my_chan, my_opt, \
my_ekey, my_bkey, my_lmid, my_ekto, \
my_bkto, my_omid ) = my_user
if in_channel == "*" or \
self.irc_compare_channels_(in_channel, my_chan):
if self.irc_check_mask_(in_from, my_mask):
return "{:s}{:d}".format(self.CONST.api_vuid_cfg, my_uid)
return None
#
# End of irc_cfg_check_user_()
def irc_get_unique_temporal_vuid_(self, in_mask):
max_id = self.irc_last_temporal_vuid
tmp_id = random.randint(max_id + 1, max_id + 100)
my_id = max_id
for my_nick_struct in self.irc_nicks:
(my_nick, my_mask, my_vuid, my_info) = my_nick_struct
if not isinstance(my_vuid, str):
continue
my_re = re.search("{}(\d+)".format( \
self.CONST.api_vuid_tmp), my_vuid)
if my_re:
if my_mask == in_mask:
return my_vuid
my_id = my_re.group(1)
my_id = int(my_id)
if my_id > max_id:
max_id = my_id
self.irc_last_temporal_vuid = tmp_id
return "{:s}{:d}".format(self.CONST.api_vuid_tmp, tmp_id)
def irc_get_vuid_by_mask_(self, in_mask, in_channel):
if not self.is_irc_channel_(in_channel):
return None
my_vuid = self.irc_cfg_check_user_(in_mask, in_channel)
if my_vuid == None and self.irc_talk_with_strangers:
my_vuid = self.irc_get_unique_temporal_vuid_(in_mask)
return my_vuid
def irc_get_vuid_type_(self, in_vuid):
if isinstance(in_vuid, str):
if len(in_vuid) > 0:
return in_vuid[0]
return None
def irc_get_useropts_from_user_struct_(self, in_user_struct):
if not isinstance(in_user_struct, tuple):
return []
if len(in_user_struct) < 4:
return []
my_opts = in_user_struct[3]
if not isinstance(my_opts, list):
my_opts = [ my_opts ]
return my_opts
def irc_disconnect_(self):
try:
self.irc.shutdown(2)
except:
pass
self.stop_ident_()
self.irc_track_clear_nicks_()
self.irc_track_clear_anons_()
try:
self.irc.close()
except:
pass
#
# End of irc_disconnect_()
def irc_reconnect_(self):
if not self.irc_run:
return
self.irc_disconnect_()
self.to_log_(self.errors[self.CONST.err_CLOSED] + ", " \
+ self.errors[self.CONST.err_RECONN] + "IRC" \
+ self.errors[self.CONST.err_TRY].format( \
self.__irc_recon) + " ...")
my_mult = self.__irc_recon
if self.__join_retry > self.__join_retry_max:
my_mult = 1
sleep(self.CONST.irc_first_wait * my_mult)
self.__irc_recon += 1
if self.__irc_recon > self.CONST.irc_recon_steps:
self.__irc_recon = 1
self.__irc_silence = 0
self.irc = self.irc_socket_(self.irc_server)
def irc_send_(self, irc_out):
if not isinstance(irc_out, str):
return -1
try:
if irc_out == "":
return -1
if self.irc_debug:
self.to_log_(self.errors[self.CONST.err_SENDTO] + "IRC: [" \
+ irc_out.replace('\r','\\r').replace('\n','\\n') + "\\n]")
self.irc.send(bytes(irc_out + "\n", self.irc_encoding))
sleep(self.CONST.irc_micro_wait)
irc_out = ""
return 0
except socket.error:
self.to_log_("socket.error in irc_send_() ...")
return -1
except ValueError:
self.to_log_("ValueError in irc_send_() ...")
return -1
except:
return -1
#
# End of irc_send_()
def irc_recv_(self, recv_timeout):
try:
time_in_recv = datetime.datetime.now()
ready = select.select([self.irc], [], [], 0)
my_timerest = recv_timeout
while ready[0] == [] and my_timerest > 0 and self.irc_run:
my_timeout = my_timerest % self.CONST.irc_latency_wait
if my_timeout == 0:
my_timeout = self.CONST.irc_latency_wait
ready = select.select([self.irc], [], [], my_timeout)
if not self.irc_run:
return (-1, "", 0)
if not self.__irc_queue[self.CONST.irc_queue_output].empty():
break
my_timerest -= my_timeout
time_out_recv = datetime.datetime.now()
delta_time_in = self.td2ms_(time_out_recv - time_in_recv)
delta_time = self.CONST.irc_default_wait
if recv_timeout < self.CONST.irc_default_wait:
delta_time = 0
if delta_time_in < recv_timeout:
delta_time = recv_timeout - delta_time_in
if delta_time_in < 0:
delta_time = 0
if ready[0] and self.irc_run:
irc_input = self.irc.recv(self.CONST.irc_buffer_size \
).decode(self.irc_encoding, 'ignore')
if irc_input != "":
if self.irc_debug:
self.to_log_("Received from IRC: [" \
+ irc_input.replace('\r',"\\r").replace('\n',"\\n\n").rstrip() + "]")
return (0, irc_input, delta_time)
return (-1, "", delta_time)
return (0, "", delta_time)
except socket.error:
return (-1, "", 0)
except ValueError:
return (-1, "", 0)
#
# End of irc_recv_()
def irc_pong_(self, irc_input):
irc_string = irc_input.split(":")
ret = self.irc_send_("{} {}\r".format( \
self.CONST.cmd_PONG, irc_string[1]))
return ret
def irc_quit_(self):
ret = self.irc_send_("{} :{}\r".format( \
self.CONST.cmd_QUIT, self.irc_quit))
sleep(self.CONST.irc_latency_wait)
return ret
def irc_umode_(self, in_channel, in_nicks, in_change, in_umode):
if not self.is_irc_channel_(in_channel):
return None
if isinstance(in_nicks, str):
my_nicks = [ in_nicks ]
elif isinstance(in_nicks, list):
my_nicks = in_nicks
else:
return None
my_str = ''
for my_nick in my_nicks:
if not self.is_irc_nick_(my_nick):
return None
my_str += in_umode
for my_nick in my_nicks:
my_str += ' ' + my_nick
ret = self.irc_send_("{} {} {}{}\r\n".format( \
self.CONST.cmd_MODE, in_channel, in_change, my_str))
return ret
#
# End of irc_umode_()
def irc_op_(self, in_channel, in_nicks):
return self.irc_umode_(in_channel, in_nicks, \
self.CONST.irc_mode_add, self.CONST.irc_umode_op)
def irc_deop_(self, in_channel, in_nicks):
return self.irc_umode_(in_channel, in_nicks, \
self.CONST.irc_mode_del, self.CONST.irc_umode_op)
def irc_voice_(self, in_channel, in_nicks):
return self.irc_umode_(in_channel, in_nicks, \
self.CONST.irc_mode_add, self.CONST.irc_umode_voice)
def irc_devoice_(self, in_channel, in_nicks):
return self.irc_umode_(in_channel, in_nicks, \
self.CONST.irc_mode_del, self.CONST.irc_umode_voice)
def irc_extract_single_(self, in_string):
try:
irc_single = in_string.split()[3]
except:
return None
return irc_single
def irc_extract_nick_mask_(self, in_string):
try:
my_mask = in_string.split(' ', 1)[0][1:]
my_nick = my_mask.split('!', 1)[0]
except:
my_mask = "!@"
my_nick = ""
return (my_nick, my_mask)
def irc_extract_message_(self, in_string):
try:
irc_msg = in_string.split( \
self.CONST.cmd_PRIVMSG, 1)[1].split(':', 1)[1]
return irc_msg.strip()
except:
return None
def irc_extract_code_params_(self, in_string):
try:
my_out = ""
my_idx = 0
for my_item in in_string.split(' '):
if my_idx == 1 and len(my_item) != 3:
return None
if my_idx > 2:
if my_out != "":
my_out += " "
my_out += my_item
my_idx += 1
return my_out
except:
return None
def irc_whois_nick_(self, in_nick):
if not self.is_irc_nick_(in_nick):
return -1
ret = self.irc_send_(self.CONST.cmd_WHOIS + " " + in_nick)
return ret
def irc_who_channel_(self, in_channel):
if not self.is_irc_channel_(in_channel):
return -1
ret = self.irc_send_(self.CONST.cmd_WHO + " " + in_channel)
return ret
def irc_random_user_(self):
return ''.join( \
random.choice(self.CONST.irc_ascii_lowercase) \
for i in range(random.randint(3, 8)))
def irc_random_nick_(self, in_nick, in_force = False):
if not self.is_irc_nick_(in_nick):
return -1
random.seed()
irc_nick = self.irc_tomock_(in_nick)
if irc_nick == in_nick:
irc_nick = "{}{:d}".format(in_nick, random.randint(0, 999))
if self.__join_retry > 2 or in_force:
nick_length = random.randint(2, self.irc_nick_length)
irc_nick = random.choice(self.CONST.irc_nick_first_char)
irc_nick += ''.join( \
random.choice(self.CONST.irc_nick_chars) \
for i in range(nick_length - 1))
ret = self.irc_send_(self.CONST.cmd_NICK + " " + irc_nick)
self.irc_nick_try = irc_nick
if ret == 0:
self.irc_nick_old = self.__irc_nick
self.__irc_nick = irc_nick
return ret
#
# End of irc_random_nick_()
def irc_socket_(self, in_server_name):
try:
my_server_ip = socket.gethostbyname(in_server_name)
if self.is_ipv6_address_(my_server_ip):
my_af_inet = socket.AF_INET6
else:
my_af_inet = socket.AF_INET
irc_socket = socket.socket(my_af_inet, socket.SOCK_STREAM)
if self.irc_ssl:
irc_socket = ssl.wrap_socket(irc_socket)
except socket.error:
self.to_log_("Cannot create socket for IRC")
return None
self.irc_server_ip = my_server_ip
self.update_irc_host_()
return irc_socket
def irc_connect_(self, in_server_ip, in_port):
if self.irc_ident:
self.start_ident_()
try:
self.irc.connect((in_server_ip, in_port))
except:
return
self.__irc_local_port = self.irc.getsockname()[1]
# self.irc.setblocking(False)
def irc_check_queue_(self, in_queue_id):
old_queue_lock = self.__irc_queue_lock[in_queue_id]
if not old_queue_lock:
check_queue = self.__irc_queue[in_queue_id]
self.__irc_queue_lock[in_queue_id] = True
if not check_queue.empty():
(irc_message, irc_wait, irc_vuid) = check_queue.get()
self.__irc_queue_lock[in_queue_id] = old_queue_lock
return (irc_message, irc_wait, irc_vuid)
else:
if old_queue_lock:
check_queue.task_done()
self.__irc_queue_lock[in_queue_id] = old_queue_lock
try:
sleep(self.CONST.irc_micro_wait)
except:
pass
return ("", self.CONST.irc_default_wait, self.CONST.api_vuid_all)
#
# End of irc_check_queue_()
def irc_add_to_queue_(self, in_queue_id, in_message, in_wait, in_vuid):
old_queue_lock = self.__irc_queue_lock[in_queue_id]
self.__irc_queue_lock[in_queue_id] = True
self.__irc_queue[in_queue_id].put((in_message, in_wait, in_vuid))
self.__irc_queue_lock[in_queue_id] = old_queue_lock
def irc_check_and_restore_nick_(self):
if self.__irc_nick != self.irc_nick_base:
if self.irc_send_(self.CONST.cmd_NICK \
+ " " + self.irc_nick_base) != -1:
self.irc_nick_old = self.__irc_nick
self.__irc_nick = self.irc_nick_base
def irc_umode_by_nick_mask_(self, in_nick, in_mask, in_vuid):
if self.irc_get_vuid_type_(in_vuid) == self.CONST.api_vuid_cfg:
my_user = self.irc_cfg_get_user_struct_by_vuid_(in_vuid)
if my_user == None:
return
my_opts = self.irc_get_useropts_from_user_struct_(my_user)
if self.CONST.irc_aop in my_opts:
self.irc_op_(self.irc_channel, in_nick)
if self.CONST.irc_avo in my_opts:
self.irc_voice_(self.irc_channel, in_nick)
# CLIENT Hooks:
def func_feature_network_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
if in_string not in [ "", None ]:
my_string = in_string
my_max = self.CONST.irc_max_network_name_length
if len(in_string) > my_max:
my_string = in_string[:my_max]
if not self.CONST.irc_default_network_tag in my_string:
self.to_log_(self.errors[self.CONST.err_NOT_IRCIOT_NET].format( \
my_string))
self.irc_network_name = my_string
return (in_ret, in_init, in_wait)
def func_feature_wallchops_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
self.__wallchops = True
return (in_ret, in_init, in_wait)
def func_feature_topiclen_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
try:
my_len = int(in_string)
if my_len > 0 and my_len < self.CONST.irc_max_topic_length:
self.irc_topic_length = my_len
except:
pass
return (in_ret, in_init, in_wait)
def func_feature_nicklen_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
try:
my_len = int(in_string)
if my_len > 0 and my_len < self.CONST.irc_max_nick_length:
self.irc_nick_length = my_len
except:
pass
return (in_ret, in_init, in_wait)
def func_feature_whox_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
self.__whox = True
return (in_ret, in_init, in_wait)
# incomplete
def func_featurelist_(self, in_args):
''' RPL_ISUPPORT handler '''
(in_string, in_ret, in_init, in_wait) = in_args
my_string = self.irc_extract_code_params_(in_string)
if my_string == None:
return (in_ret, in_init, in_wait)
my_string = my_string.split(':')[0]
for my_item in my_string.split(' '):
if my_item != "":
my_split = my_item.split('=')
my_param = ""
my_feature = my_split[0]
if len(my_split) == 2:
my_param = my_split[1]
for irc_pack in self.irc_features:
(irc_feature, featt_type, irc_function) = irc_pack
if irc_function != None:
if my_feature == irc_feature:
if featt_type == self.CONST.featt_EMPTY \
and my_param != "":
continue
if featt_type == self.CONST.featt_NUMBER \
and not my_param.isdigit():
continue
if featt_type in [ self.CONST.featt_STRING, \
self.CONST.featt_FLAGS ] and my_param == "":
continue
irc_args = (my_param, in_ret, in_init, in_wait)
(in_ret, in_init, in_wait) = irc_function(irc_args)
return (in_ret, in_init, in_wait)
def func_nick_in_use_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
if self.irc_random_nick_(self.irc_nick_base) == 1:
return (-1, 0, in_wait)
return (in_ret, in_init, in_wait)
def func_restore_nick_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
self.__irc_nick = self.irc_nick_old
return (in_ret, 3, in_wait)
def func_bad_ping_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
# This is not a fact, and not according to the RFC, but the
# last word in the comment may be a parameter for the PONG
my_split = in_string.split(' ')
self.irc_pong_(my_split[-1])
return (in_ret, in_init, self.CONST.irc_default_wait)
def func_not_reg_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
#if self.irc_random_nick_(self.__irc_nick) == 1:
# return (-1, 0, in_wait)
return (in_ret, 1, self.CONST.irc_default_wait)
def func_registered_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
return (in_ret, 3, self.CONST.irc_default_wait)
def func_banned_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
if self.__join_retry > 1:
if self.__join_retry > self.__join_retry_max:
# Now perhaps we were banned by the username,
# here, we should know this for sure how, and
# maybe connect to another server or from a
# different IP address
self.irc_reconnect_()
return (-1, 0, in_wait)
if self.__nick_pause > 0:
self.__nick_pause -= 1
elif self.irc_random_nick_(self.__irc_nick) == 1:
return (-1, 0, in_wait)
return (in_ret, 3, self.CONST.irc_default_wait)
def func_on_kick_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
return (in_ret, 3, self.CONST.irc_default_wait)
def func_on_kill_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
return (in_ret, in_init, self.CONST.irc_default_wait)
def func_on_quit_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
(irc_nick, irc_mask) = self.irc_extract_nick_mask_(in_string)
self.irc_track_delete_nick_(irc_nick)
return (in_ret, in_init, self.CONST.irc_default_wait)
def func_no_such_nick_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
irc_nick = self.irc_extract_single_(in_string)
self.irc_track_delete_nick_(irc_nick)
return (in_ret, in_init, self.CONST.irc_default_wait)
def func_on_nick_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
(irc_nick, irc_mask) = self.irc_extract_nick_mask_(in_string)
if irc_nick == self.irc_nick_base:
self.irc_check_and_restore_nick_()
my_split = in_string.split(':', 3)
if len(my_split) > 2:
new_nick = my_split[2]
if self.is_irc_nick_(new_nick):
new_mask = new_nick + irc_mask[len(irc_nick):]
# checking the new mask with new nick for belong to the
# registered user, and, if necessary, give him rights
my_vuid = self.irc_get_vuid_by_mask_(new_mask, self.irc_channel)
self.irc_umode_by_nick_mask_(new_nick, new_mask, my_vuid)
return (in_ret, in_init, self.CONST.irc_default_wait)
def func_fast_nick_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
my_seconds = 0
if self.CONST.irc_default_draft == "ircu":
# Calculating from code 438 comments, not by RFC 1459
my_split = in_string.split(' ')
if len(my_split) > 11:
if my_split[-3] == 'wait' and my_split[-1] == 'seconds.':
try:
my_seconds = int(my_split[-2])
except:
pass
if my_seconds > 0 \
and my_seconds < self.CONST.irc_default_nick_pause * 2:
self.__nick_pause = my_seconds # trys != seconds, but ...
else:
self.__nick_pause = self.CONST.irc_default_nick_pause
return (in_ret, 3, self.CONST.irc_default_wait)
#
# End of func_fast_nick_()
def func_chan_nicks_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
try:
my_array = in_string.split(":")
if my_array[0] == "":
my_array = my_array[2].split(" ")
for my_nick in my_array:
if my_nick[0] == '@':
my_nick = my_nick[1:]
self.irc_track_add_nick_(my_nick, None, None, None)
except:
return (in_ret, in_init, in_wait)
return (in_ret, in_init, self.CONST.irc_default_wait)
#
# End of func_chan_nicks_()
def func_end_nicks_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
try:
my_array = in_string.split(" ")
in_ret = self.irc_who_channel_(my_array[3])
except:
return (in_ret, in_init, in_wait)
return (in_ret, in_init, self.CONST.irc_default_wait)
def func_who_user_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
# Here will be a check of self.__whox
try:
my_array = in_string.split(":")
if my_array[0] == "":
my_info = my_array[2][2:]
my_array = my_array[1].split(" ")
my_nick = my_array[7]
my_user = my_array[4]
my_host = my_array[5]
my_mask = my_nick + "!" + my_user + "@" + my_host
my_vuid = self.irc_get_vuid_by_mask_(my_mask, self.irc_channel)
self.irc_track_update_nick_(my_nick, my_mask, my_vuid, my_info)
except:
return (in_ret, in_init, in_wait)
return (in_ret, in_init, self.CONST.irc_default_wait)
#
# End of func_who_user_()
def func_whois_user_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
try:
my_array = in_string.split(":")
if my_array[0] == "":
my_info = my_array[2]
my_array = my_array[1].split(" ")
my_nick = my_array[3]
my_user = my_array[4]
my_host = my_array[5]
my_mask = my_nick + "!" + my_user + "@" + my_host
my_vuid = self.irc_get_vuid_by_mask_(my_mask, self.irc_channel)
self.irc_track_update_nick_(my_nick, my_mask, my_vuid, my_info)
except:
return (in_ret, in_init, in_wait)
return (in_ret, in_init, self.CONST.irc_default_wait - 1)
#
# End of func_whois_user_()
def func_on_join_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
(irc_nick, irc_mask) = self.irc_extract_nick_mask_(in_string)
my_vuid = self.irc_get_vuid_by_mask_(irc_mask, self.irc_channel)
self.irc_umode_by_nick_mask_(irc_nick, irc_mask, my_vuid)
self.irc_track_add_nick_(irc_nick, irc_mask, my_vuid, None)
return (in_ret, in_init, self.CONST.irc_default_wait)
def func_on_part_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
(irc_nick, irc_mask) = self.irc_extract_nick_mask_(in_string)
self.irc_track_delete_nick_(irc_nick)
if irc_nick == self.irc_nick_base:
self.irc_check_and_restore_nick_()
return (in_ret, in_init, self.CONST.irc_default_wait)
def func_on_mode_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
(irc_nick, irc_mask) = self.irc_extract_nick_mask_(in_string)
try:
my_array = in_string.split(" ")
if len(my_array) < 5:
return (in_ret, in_init, in_wait)
if my_array[1] != self.CONST.cmd_MODE:
return (in_ret, in_init, in_wait)
my_channel = my_array[2]
if not self.is_irc_channel_(my_channel):
return (in_ret, in_init, in_wait)
my_mode_string = my_array[3]
if len(my_mode_string) < 2:
return (in_ret, in_init, in_wait)
for my_char in my_mode_string:
if my_char not in self.CONST.irc_all_modes_chars:
return (in_ret, in_init, in_wait)
my_change = self.CONST.irc_mode_add
my_index = 0
my_nick = False
my_unban = None
for my_char in my_mode_string:
if my_char in self.CONST.irc_change_modes:
my_change = my_char
elif my_char in self.CONST.irc_user_modes:
my_mask = my_array[my_index + 4]
self.to_log_( \
"mode change '{}','{}' for '{}' on '{}'".format( \
my_change, my_char, my_mask, my_channel))
if my_change == self.CONST.irc_mode_del \
and my_char == self.CONST.irc_umode_op:
my_vuid = self.irc_get_vuid_by_mask_(irc_mask, \
self.irc_channel)
self.irc_umode_by_nick_mask_(my_mask, irc_mask, \
my_vuid)
if my_change == self.CONST.irc_mode_add \
and my_char == self.CONST.irc_umode_ban:
my_mask_array = my_mask.split("!")
my_pseudo = self.__irc_nick + '!'
my_pseudo += my_mask_array[1]
if self.irc_check_mask_(my_pseudo, my_mask):
my_nick = True
for my_item in self.irc_nicks:
(n_nick, n_mask, n_vuid, n_info) = my_item
if n_vuid[0] == self.CONST.api_vuid_cfg:
if self.irc_check_mask_(n_mask, my_mask):
my_unban = n_vuid
break
if not my_unban:
for my_num in range(len(self.irc_users)):
u_mask = self.irc_cfg_get_user_mask_(my_num)
if isinstance(u_mask, str):
u_mask = u_mask.replace('*', '_')
if self.irc_check_mask_(u_mask, my_mask):
u_vuid = self.irc_cfg_get_vuid_(my_num)
if u_vuid != None:
my_unban = u_vuid
break
my_index += 1
elif my_char in self.CONST.irc_channel_modes:
self.to_log_( \
"mode change '{}','{}' for '{}'".format( \
my_change, my_char, my_channel))
elif my_char in self.CONST.irc_extra_modes:
my_extra = my_array[my_index + 4]
self.to_log_( \
"mode change '{}','{}' extra '{}' for '{}'".format( \
my_change, my_char, my_extra, my_channel))
my_index += 1
if my_unban != None:
my_user = self.irc_cfg_get_user_struct_by_vuid_(my_unban)
if my_user != None:
my_opts = self.irc_get_useropts_from_user_struct_(my_user)
if self.CONST.irc_unban in my_opts:
in_ret = self.irc_send_("{} {} {}{} {}\r\n".format( \
self.CONST.cmd_MODE, my_channel, \
self.CONST.irc_mode_del, \
self.CONST.irc_umode_ban, my_mask))
if my_nick:
self.irc_random_nick_(self.__irc_nick, True)
if my_nick or my_unban:
return (in_ret, in_init, 0)
except:
return (in_ret, in_init, in_wait)
return (in_ret, in_init, self.CONST.irc_default_wait)
#
# End of func_on_mode_()
def func_on_error_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
if in_string.find("Closing ") or in_string.find("imeout"):
return (-1, 0, in_wait)
return (in_ret, 1, self.CONST.irc_default_wait)
# SERVICE Hooks:
def func_on_srv_info_(self, in_args):
(in_string, in_ret, in_init, in_wait) = in_args
return (in_ret, in_init, in_wait)
def init_rfc1459_(self):
#
C = self.CONST
#
self.irc_codes = [
(C.ERR_NICKNAMEINUSE, "ERR_NICKNAMEINUSE", self.func_nick_in_use_),
(C.ERR_NOTREGISTERED, "ERR_NOTREGISTERED", self.func_not_reg_),
(C.ERR_BANNEDFROMCHAN, "ERR_BANNEDFROMCHAN", self.func_banned_),
(C.ERR_NICKCHANGETOOFAST,"ERR_NICKCHANGETOOFAST",self.func_fast_nick_),
(C.RPL_NAMREPLY, "RPL_NAMREPLY", self.func_chan_nicks_),
(C.RPL_ISUPPORT, "RPL_ISUPPORT", self.func_featurelist_),
(C.RPL_WHOISUSER, "RPL_WHOISUSER", self.func_whois_user_),
(C.RPL_ENDOFNAMES, "RPL_ENDOFNAMES", self.func_end_nicks_),
(C.RPL_WHOREPLY, "RPL_WHOREPLY", self.func_who_user_),
(C.ERR_NOSUCHNICK, "ERR_NOSUCHNICK", self.func_no_such_nick_),
(C.ERR_CHANNELISFULL, "ERR_CHANNELISFULL", self.func_banned_),
(C.ERR_BADCHANNELKEY, "ERR_BADCHANNELKEY", self.func_banned_),
(C.ERR_ERRONEUSNICKNAME, "ERR_ERRONEUSNICKNAME", self.func_nick_in_use_),
(C.ERR_NOSUCHCHANNEL, "ERR_NOSUCHCHANNEL", self.func_banned_),
(C.ERR_NICKCOLLISION, "ERR_NICKCOLLISION", self.func_nick_in_use_),
(C.ERR_ALREADYREGISTERED,"ERR_ALREADYREGISTERED",self.func_registered_),
(C.RPL_WELCOME, "RPL_WELCOME", None),
(C.RPL_CREATED, "RPL_CREATED", None),
(C.RPL_MYINFO, "RPL_MYINFO", None),
(C.RPL_LUSERCHANNELS, "RPL_LUSERCHANNELS", None),
(C.RPL_LUSERME, "RPL_LUSERME", None),
(C.ERR_NOSUCHSERVER, "ERR_NOSUCHSERVER", None),
(C.ERR_CANNOTSENDTOCHAN, "ERR_CANNOTSENDTOCHAN", None),
(C.ERR_TOOMANYCHANNELS, "ERR_TOOMANYCHANNELS", None),
(C.ERR_WASNOSUCHNICK, "ERR_WASNOSUCHNICK", None),
(C.ERR_TARGETTOOFAST, "ERR_TARGETTOOFAST", None),
(C.ERR_TOOMANYTARGETS, "ERR_TOOMANYTARGETS", None),
(C.ERR_NOORIGIN, "ERR_NOORIGIN", None),
(C.ERR_NORECIPIENT, "ERR_NORECIPIENT", None),
(C.ERR_NOTEXTTOSEND, "ERR_NOTEXTTOSEND", None),
(C.ERR_NOTOPLEVEL, "ERR_NOOPLEVEL", None),
(C.ERR_WILDTOPLEVEL, "ERR_WILDTOPLEVEL", None),
(C.ERR_UNKNOWNCOMMAND, "ERR_UNKNOWNCOMMAND", None),
(C.ERR_NOMOTD, "ERR_NOMOTD", None),
(C.ERR_NOADMININFO, "ERR_NOADMININFO", None),
(C.ERR_FILEERROR, "ERR_FILEERROR", None),
(C.ERR_NONICKNAMEGIVEN, "ERR_NONICKNAMEGIVEN", None),
(C.ERR_USERNOTINCHANNEL, "ERR_USERNOTINCHANNEL", None),
(C.ERR_NOTONCHANNEL, "ERR_NOTONCHANNEL", None),
(C.ERR_NOLOGIN, "ERR_NOLOGIN", None),
(C.ERR_SUMMONDISABLED, "ERR_SUMMONDISABLED", None),
(C.ERR_USERSDISABLED, "ERR_USERSDISABLED", None),
(C.ERR_NEEDMOREPARAMS, "ERR_NEEDMOREPARAMS", None),
(C.ERR_USERSDONTMATCH, "ERR_USERSDONTMATCH", None),
(C.ERR_PASSWDMISMATCH, "ERR_PASSWDMISMATCH", None),
(C.ERR_YOUREBANNEDCREEP, "ERR_YOUREBANNEDCREEP", None),
(C.ERR_YOUWILLBEBANNED, "ERR_YOUWILLBEBANNED", None),
(C.ERR_KEYSET, "ERR_KEYSET", None),
(C.ERR_UNKNOWNMODE, "ERR_UNKNOWNMODE", None),
(C.ERR_INVITEONLYCHAN, "ERR_INVITEONLYCHAN", None),
(C.ERR_BADCHANNELMASK, "ERR_BADCHANNELMASK", None),
(C.ERR_BANLISTFULL, "ERR_BANLISTFULL", None),
(C.ERR_NOPRIVILEGES, "ERR_NOPRIVILEGES", None),
(C.ERR_CANTKILLSERVER, "ERR_CANTKILLSERVER", None),
(C.ERR_UNIQOPPRIVSNEEDED,"ERR_UNIQOPPRIVSNEEDED",None),
(C.ERR_NOOPERHOST, "ERR_NOOPERHOST", None),
(C.ERR_NOSERVICEHOST, "ERR_NOSERVICEHOST", None),
(C.ERR_UMODEUNKNOWNFLAG, "ERR_UMODEUNKNOWNFLAG", None) ]
if self.CONST.irc_default_draft == "PyIRCIoT":
self.irc_codes.extend( [
(C.RPL_JSON, "RPL_JSON", None) ] )
elif self.CONST.irc_default_draft == "ircu":
self.irc_codes.extend( [
(C.ERR_BADPING, "ERR_BADPING", self.func_bad_ping_),
(C.ERR_BANNICKCHANGE, "ERR_BANNICKCHANGE", self.func_restore_nick_),
(C.RPL_USERIP, "RPL_USERIP", None),
(C.ERR_INVALIDUSERNAME,"ERR_INVALIDUSERNAME", None) ] )
elif self.CONST.irc_default_draft == "Unreal":
self.irc_codes.extend( [
(C.ERR_NONICKCHANGE, "ERR_NONICKCHANGE", self.func_restore_nick_),
(C.RPL_WHOISBOT, "RPL_WHOISBOT", None),
(C.RPL_USERIP, "RPL_USERIP", None),
(C.RPL_REDIR, "RPL_REDIR", None)
(C.ERR_NOSUCHSERVICE, "ERR_NOSUCHSERVICE", None),
(C.ERR_NOINVITE, "ERR_NOINVITE", None),
(C.RPL_COMMANDSYNTAX, "RPL_COMMANDSYNTAX", None),
(C.RPL_STARTLS, "RPL_STARTLS", None),
(C.RPL_DCCSTATUS, "RPL_DCCSTATUS", None),
(C.RPL_TEXT, "RPL_TEXT", None) ] )
elif self.CONST.irc_default_draft == "Bahamut":
self.irc_codes.extend( [
(C.RPL_USIGNSSL, "RPL_USIGNSSL", None),
(C.ERR_NEEDREGGEDNICK, "ERR_NEEDREGGEDNICK", None),
(C.RPL_STATSCLONE, "RPL_STATSCLONE", None),
(C.RPL_TEXT, "RPL_TEXT", None) ] )
elif self.CONST.irc_default_draft == "Insp":
self.irc_codes.extend( [
(C.RPL_AUTOOPLIST, "RPL_AUTOOPLIST", None),
(C.RPL_ENDOFAUTOOPLIST,"RPL_ENDOFAUTOOPLIST", None),
(C.ERR_WORDFILTERED, "ERR_WORDFILTERED", None) ] )
elif self.CONST.irc_default_draft == "IRCNet":
self.irc_codes.extend( [
(C.ERR_NOCHANMODES, "ERR_NOCHANMODES", None),
(C.ERR_RESTRICTED, "ERR_RESTRICTED", None) ] )
else: # Unknown extending
pass
#
if self.__irc_layer_mode == self.CONST.irc_mode_CLIENT:
self.irc_commands = [
(C.cmd_INVITE, None),
(C.cmd_JOIN, self.func_on_join_),
(C.cmd_KICK, self.func_on_kick_),
(C.cmd_KILL, self.func_on_kill_),
(C.cmd_MODE, self.func_on_mode_),
(C.cmd_NICK, self.func_on_nick_),
(C.cmd_NOTICE, None),
(C.cmd_PART, self.func_on_part_),
(C.cmd_PONG, None),
(C.cmd_PRIVMSG, None),
(C.cmd_QUIT, self.func_on_quit_),
(C.cmd_ERROR, self.func_on_error_) ]
#
elif self.__irc_layer_mode == self.CONST.irc_mode_SERVER: # RFC 2813
self.irc_cmmands = [
(C.cmd_PASS, None), (C.cmd_SERVER, None),
(C.cmd_NICK, None), (C.cmd_QUIT, None),
(C.cmd_SQUIT, None), (C.cmd_JOIN, None),
(C.cmd_NJOIN, None), (C.cmd_MODE, None),
(C.cmd_LINKS, None), (C.cmd_KILL, None),
(C.cmd_NAMES, None), (C.cmd_INVITE, None),
(C.cmd_STATS, None), (C.cmd_CONNECT, None),
(C.cmd_TRACE, None), (C.cmd_ADMIN, None),
(C.cmd_WHO, None), (C.cmd_INFO, self.func_on_srv_info_),
(C.cmd_WHOIS, None), (C.cmd_WHOWAS, None),
(C.cmd_AWAY, None), (C.cmd_RESTART, None),
(C.cmd_SUMMON, None), (C.cmd_USERS, None),
(C.cmd_WALLOPS, None), (C.cmd_USERHOST, None),
(C.cmd_TOPIC, None), (C.cmd_KICK, None),
(C.cmd_PONG, None), (C.cmd_PART, None),
(C.cmd_ERROR, None), (C.cmd_PRIVMSG, None),
(C.cmd_PUBMSG, None), (C.cmd_PUBNOTICE, None),
(C.cmd_NOTICE, None), (C.cmd_PRIVNOTICE, None),
(C.cmd_ISON, None), (C.cmd_REHASH, None) ]
#
self.irc_features = [
(C.feature_CASEMAPPING, C.featt_STRING, None),
(C.feature_CHANMODES, C.featt_FLAGS, None),
(C.feature_CHANTYPES, C.featt_FLAGS, None),
(C.feature_NICKLEN, C.featt_NUMBER, self.func_feature_nicklen_),
(C.feature_PREFIX, C.featt_FLAGS, None) ]
if self.CONST.irc_default_draft == "ircu":
self.irc_features.extend( [
(C.feature_AWAYLEN, C.featt_NUMBER, None),
(C.feature_CHANNELLEN, C.featt_NUMBER, None),
(C.feature_CNOTICE, C.featt_EMPTY, None),
(C.feature_CPRIVMSG, C.featt_EMPTY, None),
(C.feature_MAXCHANLEN, C.featt_NUMBER, None),
(C.feature_KICKLEN, C.featt_NUMBER, None),
(C.feature_MODES, C.featt_NUMBER, None),
(C.feature_MAXCHANS, C.featt_NUMBER, None),
(C.feature_MAXBNANS, C.featt_NUMBER, None),
(C.feature_MAXNICKLEN, C.featt_NUMBER, self.func_feature_nicklen_),
(C.feature_NETWORK, C.featt_STRING, self.func_feature_network_),
(C.feature_SILENCE, C.featt_NUMBER, None),
(C.feature_STATUSMSG, C.featt_FLAGS, None),
(C.feature_TOPICLEN, C.featt_NUMBER, self.func_feature_topiclen_),
(C.feature_USERIP, C.featt_EMPTY, None),
(C.feature_WALLCHOPS, C.featt_EMPTY, self.func_feature_wallchops_),
(C.feature_WALLVOICES, C.featt_EMPTY, None),
(C.feature_WHOX, C.featt_EMPTY, self.func_feature_whox_) ] )
#
# End of init_rfc1459_()
def irc_output_all_(self, in_messages_packs, in_wait = None):
if not isinstance(in_messages_packs, list):
return
if not isinstance(in_wait, int) and \
not isinstance(in_wait, float):
in_wait = self.CONST.irc_default_wait
for my_pack in in_messages_packs:
(my_messages, my_vuid) = my_pack
if isinstance(my_messages, str):
my_messages = [ my_messages ]
if isinstance(my_messages, list):
for my_message in my_messages:
self.irc_add_to_queue_( \
self.CONST.irc_queue_output, \
my_message, in_wait, my_vuid)
#
# End of irc_output_all_()
# incomplete
def irc_process_server_(self):
#
self.init_rfc1459_()
#
try:
pass
except:
pass
self.irc_run = False
#
# End of irc_process_server_()
def irc_process_client_(self):
#
self.init_rfc1459_()
#
irc_init = 0
irc_wait = self.CONST.irc_first_wait
irc_input_buffer = ""
irc_ret = 0
irc_vuid = "{:s}0".format(self.CONST.api_vuid_cfg)
self.__delta_time = 0
# app.run(host='0.0.0.0', port=50000, debug=True)
# must be FIXed for Unprivileged user
self.irc = self.irc_socket_(self.irc_server)
while (self.irc_run):
try:
if not self.irc:
if self.__join_retry == 0:
sleep(self.CONST.irc_first_wait)
self.irc = self.irc_socket_(self.irc_server)
irc_init = 0
if irc_init < 6:
irc_init += 1
if irc_init == 1:
# self.to_log_(self.errors[self.CONST.err_CONNTO] \
# + "'{}:{}'".format(self.irc_server_ip, self.irc_port))
self.__irc_silnece = 0
try:
self.irc_connect_(self.irc_server_ip, self.irc_port)
except socket.error:
self.irc_disconnect_()
self.irc = self.irc_socket_(self.irc_server)
irc_init = 0
elif irc_init == 2:
if self.__irc_password:
self.irc_send_(self.CONST.cmd_PASS \
+ " " + self.__irc_password)
if self.__join_retry > self.__join_retry_max:
self.irc_user = self.irc_random_user_()
# Random username can override ban, but can
# destroy own IRC mask, it must be restored
else:
self.irc_user = self.irc_tolower_(self.__irc_nick)
if self.irc_send_(self.CONST.cmd_USER \
+ " " + self.irc_user \
+ " " + self.irc_host + " 1 :" \
+ self.irc_info) == -1:
irc_init = 0
elif irc_init == 3:
self.__join_retry = 0
if self.irc_send_(self.CONST.cmd_NICK \
+ " " + self.__irc_nick) == -1:
irc_init = 0
elif irc_init == 4:
if not self.is_irc_channel_(self.irc_channel): continue
irc_wait = self.CONST.irc_default_wait
self.__join_retry += 1
if self.irc_send_(self.CONST.cmd_JOIN \
+ " " + self.irc_channel + str(" " \
+ self.irc_chankey if self.irc_chankey else "")) == -1:
irc_init = 0
elif irc_init == 5:
if not self.is_irc_channel_(self.irc_channel): continue
irc_wait = self.CONST.irc_default_wait
self.__join_retry += 1
if self.irc_send_(self.CONST.cmd_JOIN \
+ " {}{}\r".format(self.irc_channel, str(" " \
+ self.irc_chankey if self.irc_chankey else ""))) == -1:
irc_init = 0
elif irc_init == 6:
self.ident_run = False
if irc_init > 0:
(irc_ret, irc_input_buffer, self.__delta_time) \
= self.irc_recv_(irc_wait)
else:
irc_ret = -1
irc_wait = self.CONST.irc_default_wait
if irc_init > 3 and self.__irc_silence >= self.irc_silence_max \
and self.is_irc_channel_(self.irc_channel):
if self.__irc_silence == self.irc_silence_max:
# To provoke TCP interaction, we take some action
if self.irc_who_channel_(self.irc_channel) == -1:
irc_init = 0
else:
self.irc_check_and_restore_nick_()
elif self.__irc_silence > self.irc_silence_max:
irc_init = 0
if irc_init == 0:
irc_ret = -1
self.__irc_silence += 1
if self.__delta_time > 0:
irc_wait = self.__delta_time
else:
if irc_init == 6:
self.irc_track_clarify_nicks_()
if irc_ret == -1:
self.irc_reconnect_()
irc_init = 0
continue
for irc_input_split in re.split(r'[\r\n]', irc_input_buffer):
if irc_input_split == "":
irc_input_buff = ""
continue
self.__irc_silence = 0
if irc_input_split[:5] == self.CONST.cmd_PING + " ":
self.__delta_ping \
= self.td2ms_(self.time_now - self.__time_ping)
self.__time_ping = self.time_now
if self.irc_pong_(irc_input_split) == -1:
self.irc_reconnect_()
irc_init = 0
break
else:
self.irc_track_clarify_nicks_()
try:
irc_input_cmd = irc_input_split.split(' ')[1]
except:
irc_input_cmd = ""
if irc_input_split[0] == ':':
for irc_cod_pack in self.irc_codes:
(irc_code, code_name, irc_function) = irc_cod_pack
if irc_function != None:
if irc_input_cmd == irc_code:
irc_args = (irc_input_split, \
irc_ret, irc_init, irc_wait)
(irc_ret, irc_init, irc_wait) = irc_function(irc_args)
for irc_cmd_pack in self.irc_commands:
(irc_cmd, irc_function) = irc_cmd_pack
if irc_function != None:
if irc_input_cmd == irc_cmd:
irc_args = (irc_input_split, irc_ret, irc_init, irc_wait)
(irc_ret, irc_init, irc_wait) = irc_function(irc_args)
if irc_input_cmd == self.CONST.cmd_PRIVMSG \
or irc_input_split == "":
irc_nick = ""
irc_mask = "!@"
irc_vuid = None
irc_message = None
if irc_input_split != "":
(irc_nick, irc_mask) \
= self.irc_extract_nick_mask_(irc_input_split)
self.irc_track_fast_nick_(irc_nick, irc_mask)
self.time_now = datetime.datetime.now()
irc_message = self.irc_extract_message_(irc_input_split)
if irc_message == None and irc_input_buffer == "":
self.time_now = datetime.datetime.now()
irc_message = ""
if irc_message != None:
irc_vuid = self.irc_get_vuid_by_mask_(irc_mask, self.irc_channel)
if irc_vuid != None and irc_init > 3 \
and self.is_json_(irc_message):
if self.irc_talk_with_strangers:
self.irc_track_update_anons_by_vuid_(irc_vuid, \
irc_mask, self.irc_channel, \
None, None, None, None, None, None, None)
self.irc_add_to_queue_(self.CONST.irc_queue_input, \
irc_message, self.CONST.irc_default_wait, irc_vuid)
irc_input_split = ""
irc_input_buff = ""
if irc_init > 5:
(irc_message, irc_wait, irc_vuid) \
= self.irc_check_queue_(self.CONST.irc_queue_output)
irc_message = str(irc_message)
if irc_message != "":
my_private = False
if irc_vuid != self.CONST.api_vuid_all:
my_nick = self.irc_track_get_nick_by_vuid_(irc_vuid)
if self.is_irc_nick_(my_nick):
my_private = True
if my_private:
self.irc_send_(self.CONST.cmd_PRIVMSG + " " \
+ my_nick + " :" + irc_message)
else:
self.irc_send_(self.CONST.cmd_PRIVMSG + " " \
+ self.irc_channel + " :" + irc_message)
irc_message = ""
if self.td2ms_(self.time_now - self.__time_ping) \
> self.__delta_ping * 2 and self.__delta_ping > 0:
if self.irc_who_channel_(self.irc_channel) == -1:
self.irc_reconnect_()
irc_init = 0
else:
self.irc_check_and_restore_nick_()
self.__delta_ping = 0
except socket.error:
self.irc_disconnect()
self.irc = None
#
# End of irc_process_client_()
[ Get back ]
|
IRC-IoT
|