o b @sz dZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlmZddlmZddlmZddlmZmZmZddlmZddlmZdd lmZmZmZe dZ!e d Z"e d Z#e#Z$e d Z%d Z&dZ'Gddde(Z)Gddde(Z*Gddde+Z,ddZ-d{ddZ.d|ddZ/Gddde0Z1GdddZ2d}d!d"Z3Gd#d$d$ej4Z5Gd%d&d&e2Z6Gd'd(d(ej7Z8d)d*Z9Gd+d,d,ej4ej:Z;Gd-d.d.ej4ej:Zd1d2Z?Gd3d4d4ej7ej:Z@Gd5d6d6ejAZBd7d8ZCGd9d:d:e;ZDd;ZEdZHd?ZIeJeKgd@eLdAZMdBdCeMNDZOGdDdEdEejPZQeQZRGdFdGdGejSZTdHdIZUGdJdKdKe2ZVdLdMZWdNdOZXdPdQZYe dRZZdSdTZ[e dAZ\e!e\dUe#e\dVe"e\dWe\e\e\iZ]iZ^e]ND] \Z_Z`e_e^e`dX<q[_[`eaebe\dYejcZddZd[Zed\d]Zfd^ZgeZegd_egegegiZhiZiehND] \Z_Z`e_eie`dX<qeaebegdYejcZjd`daZkdbdcZldddeZmdfZndgZodhZpdiZqdjZrdkZsdlZtdmZudnZvdoZwdpZxdqZydrZzdsZ{dtZ|duZ}dvZ~dwZdxZdyZdzZd{Zd|Zd}Zd~ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZiddfddgddhddiddjddkddlddmddnddoddpddqddrddsddtdduddviddwddxddyddzdd{dd|d d}d d~d dd dd dddddddddddddiddddddddddddddddddddddddd dd!dd"dd#dd$did%dd&dd'dd(dd)dd*dd+dd,dd-dd.dd/dd0dd1dd2dd3dd4dd5did6dd7dd8dd9dd:dd;dddd?dd@ddAddBddCddDddEddFdidGddHddIddJddKddLddMddNd“dOdÓdPdēdQdœdRdƓdSdǓdTdȓdUdɓdVdʓdWd˓idXd̓dYd͓dZdΓd[dϓd\dГd]dѓd^dғd_dӓd`dԓdadՓdbd֓dcdדdddؓdedٓdfdړdgdۓdhdܓididݓdjdޓdkdߓdlddmddnddoddpddqddrddsddtdduddvddwddxddyddddddzZiZeND] \Z_Z`e_ee`<q1dS(~a* Internet Relay Chat protocol for client and server. Future Plans ============ The way the IRCClient class works here encourages people to implement IRC clients by subclassing the ephemeral protocol class, and it tends to end up with way more state than it should for an object which will be destroyed as soon as the TCP transport drops. Someone oughta do something about that, ya know? The DCC support needs to have more hooks for the client for it to be able to ask the user things like "Do you want to accept this session?" and "Transfer #2 is 67% done." and otherwise manage the DCC sessions. Test coverage needs to be better. @var MAX_COMMAND_LENGTH: The maximum length of a command, as defined by RFC 2812 section 2.3. @var attributes: Singleton instance of L{_CharacterAttributes}, used for constructing formatted text information. @author: Kevin Turner @see: RFC 1459: Internet Relay Chat Protocol @see: RFC 2812: Internet Relay Chat: Client Protocol @see: U{The Client-To-Client-Protocol } N)reduce)path)Optional)protocolreactortask)styles)basic)_textattributeslogreflect z&#!+c@ eZdZdS) IRCBadMessageN__name__ __module__ __qualname__rr=/usr/lib/python3/dist-packages/twisted/words/protocols/irc.pyrHrc@r)IRCPasswordMismatchNrrrrrrLrrc@eZdZdZdS) IRCBadModeszS A malformed mode was encountered while attempting to parse a mode string. Nrrr__doc__rrrrrPrcCsd}g}|s td|dddkr|dddd\}}|dd kr7|dd\}}|}||n|}|d}|||fS) z Breaks a message from an IRC server into its prefix, command, and arguments. @param s: The message to break. @type s: L{bytes} @return: A tuple of (prefix, command, args). @rtype: L{tuple} z Empty line.r:N  :)rsplitfindappendpop)sprefixtrailingargscommandrrrparsemsgVs    r/Pcsfdd|dDS)a Split a string into multiple lines. Whitespace near C{str[length]} will be preferred as a breaking point. C{"\n"} will also be used as a breaking point. @param str: The string to split. @type str: C{str} @param length: The maximum length which will be allowed for any string in the result. @type length: C{int} @return: C{list} of C{str} cs"g|] }t|D]}|q qSr)textwrapwrap).0linechunklengthrr s"zsplit.. r&)strr7rr6rr&qsr&c Cs,|rzt|WSttfyY|Sw|S)z Convert a value to an integer if possible. @rtype: C{int} or type of L{default} @return: An integer when C{value} can be converted to an integer, otherwise return C{default} )int TypeError ValueError)valuedefaultrrr _intOrDefaults rAc@r)UnhandledCommandzO A command dispatcher could not locate an appropriate command handler. NrrrrrrBrrBc@s*eZdZUdZdZeeed<ddZdS)_CommandDispatcherMixina Dispatch commands to handlers based on their name. Command handler names should be of the form C{prefix_commandName}, where C{prefix} is the value specified by L{prefix}, and must accept the parameters as given to L{dispatch}. Attempting to mix this in more than once for a single class will cause strange behaviour, due to L{prefix} being overwritten. @type prefix: C{str} @ivar prefix: Command handler prefix, used to locate handler attributes Nr+csffddfdd}||}|dur||S|d}|dur+td|d||g|RS) z2 Perform actual command dispatch. csjd|S)N_)r+)r.selfrr_getMethodNamez8_CommandDispatcherMixin.dispatch.._getMethodNamecst|dSN)getattr)namerGrFrr _getMethodrHz4_CommandDispatcherMixin.dispatch.._getMethodNunknownzNo handler for z could be found)rB)rF commandNamer-rMmethodrrLrdispatchs z _CommandDispatcherMixin.dispatch) rrrrr+rr;__annotations__rQrrrrrCs  rCr r c Cst|dkr td|ddvrtd|ggf}d}d}|D]D}|dvr:|dkr2td|d|}d}q!d}|||vrXz|d}WntyWtd|w||||f|d 7}q!t|dkrvtd |d ||dkrtd||S) a2 Parse an IRC mode string. The mode string is parsed into two lists of mode changes (added and removed), with each mode change represented as C{(mode, param)} where mode is the mode character, and param is the parameter passed for that mode, or L{None} if no parameter is required. @type modes: C{str} @param modes: Modes string to parse. @type params: C{list} @param params: Parameters specified along with L{modes}. @type paramModes: C{(str, str)} @param paramModes: A pair of strings (C{(add, remove)}) that indicate which modes take parameters when added or removed. @returns: Two lists of mode changes, one for modes added and the other for modes removed respectively, mode changes in each list are represented as C{(mode, param)}. rzEmpty mode stringz+-zMalformed modes string: Nr%zEmpty mode sequence: zNot enough parameters: r!zToo many parameters: r#)lenrindexr) IndexErrorr()modesparams paramModeschanges directioncountchparamrrr parseModess6       r_c@seZdZUdZdZdZdZeee d<ddZ ddZ d d Z d/d d Z d dZddZddZddZddZddZddZddZddZd0dd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Zd0d+d,Zd-d.ZdS)1IRCz. Internet Relay Chat server protocol. r NencodingcCs"g|_|jdurt|_dSdSrI)channelshostnamesocketgetfqdnrErrrconnectionMades zIRC.connectionMadecCs@|tt}t|tr|jr|jnd}||}|j|dSNutf-8)CRLF isinstancer;raencode transportwrite)rFr4 useEncodingrrrsendLine s   z IRC.sendLinecOs|stdd|vs|ddkrtd|d|gt|}d|vr,d|d|}||t|dkrDtd t||fd Sd S) a Send a line formatted as an IRC message. First argument is the command, all subsequent arguments are parameters to that command. If a prefix is desired, it may be specified with the keyword argument 'prefix'. The L{sendCommand} method is generally preferred over this one. Notably, this method does not support sending message tags, while the L{sendCommand} method does. IRC message requires a command.r#rr"zDSomebody screwed up, 'cuz this doesn't look like a command to me: %sr+z:{} {}-Message has %d parameters (RFC allows 15): %sN)r>joinlistformatrprTr msg)rFr.parameter_listr+r4rrr sendMessages&    zIRC.sendMessagecCs|stdd|vs|ddkrtd|d|duri}d|gt|}|r2d|d|}|rA||}d|d|}||t|d krYtd t||fdSdS) a Send to the remote peer a line formatted as an IRC message. @param command: The command or numeric to send. @type command: L{unicode} @param parameters: The parameters to send with the command. @type parameters: A L{tuple} or L{list} of L{unicode} parameters @param prefix: The prefix to send with the command. If not given, no prefix is sent. @type prefix: L{unicode} @param tags: A dict of message tags. If not given, no message tags are sent. The dict key should be the name of the tag to send as a string; the value should be the unescaped value to send with the tag, or either None or "" if no value is to be sent with the tag. @type tags: L{dict} of tags (L{unicode}) => values (L{unicode}) @see: U{https://ircv3.net/specs/core/message-tags-3.2.html} rqr#rr"zInvalid command: ""N@rrrs)r>rtru _stringTagsrprTr rw)rFr. parametersr+tagsr4tagStrrrr sendCommand4s(    zIRC.sendCommandcCsT||g}|D]\}}|r||d||q ||q d|S)z Converts a tag dictionary to a string. @param tags: The tag dict passed to sendMsg. @rtype: L{unicode} @return: IRCv3-format tag string =;) _validateTagsitemsr(_escapeTagValuert)rFr~ tagStringstagr?rrrr|cs   zIRC._stringTagscCsD|D]\}}|std|D]}|s|dvrtdqqdS)z Checks the tag dict for errors and raises L{ValueError} if an error is found. @param tags: The tag dict passed to sendMsg. zA tag name is required.)-/.z Tag contains invalid characters.N)rr>isalnum)rFr~rr?charrrrruszIRC._validateTagscCs,|ddddddddd d S) a< Escape the given tag value according to U{escaping rules in IRCv3 }. @param value: The string value to escape. @type value: L{str} @return: The escaped string for sending as a message value @rtype: L{str} \z\\rz\:r#z\s z\rr9z\n)replace)rFr?rrrrs zIRC._escapeTagValuecCst|tr |d}|j|t}||_|D]'}t|dkr"q|dtkr.|dd}t |\}}}| }| |||qdS)z This hack is to support mIRC, which sends LF only, even though the RFC says CRLF. (Also, the flexibility of LineReceiver to turn "line mode" on and off was not required.) rhr%N) rkbytesdecodebufferr&rjr)rTrir/upper handleCommand)rFdatalinesr4r+r.rXrrr dataReceiveds      zIRC.dataReceivedcCZt|d|d}z|dur|||WdS||||WdSty,tYdSwa Determine the function to call for the given command and call it with the given arguments. @param command: The IRC command to determine the function for. @type command: L{bytes} @param prefix: The prefix of the IRC message (as returned by L{parsemsg}). @type prefix: L{bytes} @param params: A list of parameters to call the function with. @type params: L{list} zirc_%sNrJ irc_unknown BaseExceptionr deferrrFr.r+rXrPrrrr zIRC.handleCommandcCs t|||)z Called by L{handleCommand} on a command that doesn't have a defined handler. Subclasses should override this method. NotImplementedErrorrFr+r.rXrrrr zIRC.irc_unknowncCs |d|dt|f|dS)a Send a message to a channel or user @type sender: C{str} or C{unicode} @param sender: Who is sending this message. Should be of the form username!ident@hostmask (unless you know better!). @type recip: C{str} or C{unicode} @param recip: The recipient of this message. If a channel, it must start with a channel prefix. @type message: C{str} or C{unicode} @param message: The message being sent. PRIVMSGr"N)rlowQuoterFsenderrecipmessagerrrprivmsg z IRC.privmsgcCs|d|d|f|dS)a Send a "notice" to a channel or user. Notices differ from privmsgs in that the RFC claims they are different. Robots are supposed to send notices and not respond to them. Clients typically display notices differently from privmsgs. @type sender: C{str} or C{unicode} @param sender: Who is sending this message. Should be of the form username!ident@hostmask (unless you know better!). @type recip: C{str} or C{unicode} @param recip: The recipient of this message. If a channel, it must start with a channel prefix. @type message: C{str} or C{unicode} @param message: The message being sent. NOTICEr"N)rrrrrnoticesz IRC.noticecCs |d|d|d|dS)a Send an action to a channel or user. @type sender: C{str} or C{unicode} @param sender: Who is sending this message. Should be of the form username!ident@hostmask (unless you know better!). @type recip: C{str} or C{unicode} @param recip: The recipient of this message. If a channel, it must start with a channel prefix. @type message: C{str} or C{unicode} @param message: The action being sent. r"z ACTION r$Nrprrrractionrz IRC.actionc Cst|dur(|dur|d|jt||dfdS|d|jt||t|fdS|d|d|dt|dS)a] Send the topic to a user. @type user: C{str} or C{unicode} @param user: The user receiving the topic. Only their nickname, not the full hostmask. @type channel: C{str} or C{unicode} @param channel: The channel for which this is the topic. @type topic: C{str} or C{unicode} or L{None} @param topic: The topic string, unquoted, or None if there is no topic. @type author: C{str} or C{unicode} @param author: If the topic is being changed, the full username and hostmask of the person changing it. N:%s %s %s %s :%szNo topic is set.r"z TOPIC r$)rprc RPL_NOTOPIC RPL_TOPICr)rFuserchanneltopicauthorrrrrs$z IRC.topicc Cs |d|jd||||fdS)a Send the author of and time at which a topic was set for the given channel. This sends a 333 reply message, which is not part of the IRC RFC. @type user: C{str} or C{unicode} @param user: The user receiving the topic. Only their nickname, not the full hostmask. @type channel: C{str} or C{unicode} @param channel: The channel for which this information is relevant. @type author: C{str} or C{unicode} @param author: The nickname (without hostmask) of the user who last set the topic. @type date: C{int} @param date: A POSIX timestamp (number of seconds since the epoch) at which the topic was last set. z:%s %d %s %s %s %diMNrprc)rFrrrdaterrr topicAuthor'szIRC.topicAuthorc Cst|t|d}d|}g}d}|D]1}|t|d|kr8|d|jt||d|f|g}t|}q|||t|d7}q|rX|d|jt||d|f|d|jt||fdS) a Send the names of a channel's participants to a user. @type user: C{str} or C{unicode} @param user: The user receiving the name list. Only their nickname, not the full hostmask. @type channel: C{str} or C{unicode} @param channel: The channel for which this is the namelist. @type names: C{list} of C{str} or C{unicode} @param names: The names to send. rrrr!z:%s %s %s = %s :%sr#z :%s %s %s %s :End of /NAMES listN)rTrprc RPL_NAMREPLYrtr(RPL_ENDOFNAMES) rFrrnames prefixLength namesLengthLr\nrrrrAs4   z IRC.namesc Csj|D]$}|\}}}}} } } | dvsJ|d|jt||||||| | | f q|d|jt||fdS)a Send a list of users participating in a channel. @type user: C{str} or C{unicode} @param user: The user receiving this member information. Only their nickname, not the full hostmask. @type channel: C{str} or C{unicode} @param channel: The channel for which this is the member information. @type memberInfo: C{list} of C{tuples} @param memberInfo: For each member of the given channel, a 7-tuple containing their username, their hostmask, the server to which they are connected, their nickname, the letter "H" or "G" (standing for "Here" or "Gone"), the hopcount from C{user} to this member, and this member's real name. )HGz":%s %s %s %s %s %s %s %s %s :%d %sz:%s %s %s %s :End of /WHO list.N)rprc RPL_WHOREPLY RPL_ENDOFWHO) rFrr memberInfoinfousernamehostmaskservernicknameflaghopsrealNamerrrwhojs0  zIRC.whoc Cs|d|jt|||||f|d|jt||||f|r+|d|jt||f|d|jt||| | f|d|jt||d| f|d|jt||fdS) aQ Send information about the state of a particular user. @type user: C{str} or C{unicode} @param user: The user receiving this information. Only their nickname, not the full hostmask. @type nick: C{str} or C{unicode} @param nick: The nickname of the user this information describes. @type username: C{str} or C{unicode} @param username: The user's username (eg, ident response) @type hostname: C{str} @param hostname: The user's hostmask @type realName: C{str} or C{unicode} @param realName: The user's real name @type server: C{str} or C{unicode} @param server: The name of the server to which the user is connected @type serverInfo: C{str} or C{unicode} @param serverInfo: A descriptive string about that server @type oper: C{bool} @param oper: Indicates whether the user is an IRC operator @type idle: C{int} @param idle: The number of seconds since the user last sent a message @type signOn: C{int} @param signOn: A POSIX timestamp (number of seconds since the epoch) indicating the time the user signed on @type channels: C{list} of C{str} or C{unicode} @param channels: A list of the channels which the user is participating in z:%s %s %s %s %s %s * :%sz:%s %s %s %s %s :%sz :%s %s %s %s :is an IRC operatorz-:%s %s %s %s %d %d :seconds idle, signon timerr#z :%s %s %s %s :End of WHOIS list.N) rprc RPL_WHOISUSERRPL_WHOISSERVERRPL_WHOISOPERATOR RPL_WHOISIDLERPL_WHOISCHANNELSrtRPL_ENDOFWHOIS) rFrnickrrcrr serverInfooperidlesignOnrbrrrwhoiss>4  z IRC.whoiscC|d|d|dS)a9 Send a join message. @type who: C{str} or C{unicode} @param who: The name of the user joining. Should be of the form username!ident@hostmask (unless you know better!). @type where: C{str} or C{unicode} @param where: The channel the user is joining. r"z JOIN Nr)rFrwhererrrrts zIRC.joincCs>|r|d|d|d|dS|d|d|dS)a Send a part message. @type who: C{str} or C{unicode} @param who: The name of the user joining. Should be of the form username!ident@hostmask (unless you know better!). @type where: C{str} or C{unicode} @param where: The channel the user is joining. @type reason: C{str} or C{unicode} @param reason: A string describing the misery which caused this poor soul to depart. r"z PART r$Nr)rFrrreasonrrrparts zIRC.partc Gs&|d|jt|||d|fdS)a Send information about the mode of a channel. @type user: C{str} or C{unicode} @param user: The user receiving the name list. Only their nickname, not the full hostmask. @type channel: C{str} or C{unicode} @param channel: The channel for which this is the namelist. @type mode: C{str} @param mode: A string describing this channel's modes. @param args: Any additional arguments required by the modes. z:%s %s %s %s %s %sr#N)rprcRPL_CHANNELMODEISrt)rFrrmoder-rrr channelModes zIRC.channelMode)NNrI)rrrrrrcrarr;rRrfrpryrr|rrrrrrrrrrrrrrtrrrrrrr`s4  "/  )+N r`c@seZdZdZdZddZed:ddZedd Zed d Z ed d Z eddZ d:ddZ ddZ ddZddZddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Z dS);ServerSupportedFeaturesz Handle ISUPPORT messages. Feature names match those in the ISUPPORT RFC draft identically. Information regarding the specifics of ISUPPORT was gleaned from . isupportc Cs,dtddd|d|gdd|_dS)Nz#& z(ovh)@+%)br lkr ) CHANNELLEN CHANTYPESMODESNICKLENPREFIX CHANMODES)tuple_parsePrefixParam_parseChanModesParam _featuresrErrr__init__&s  z ServerSupportedFeatures.__init__Ncs(durddfdd}t|S)a9 Split ISUPPORT parameter arguments. Values can optionally be processed by C{valueProcessor}. For example:: >>> ServerSupportedFeatures._splitParamArgs(['A:1', 'B:2']) (('A', '1'), ('B', '2')) @type params: C{iterable} of C{str} @type valueProcessor: C{callable} taking {str} @param valueProcessor: Callable to process argument values, or L{None} to perform no processing @rtype: C{list} of C{(str, object)} @return: Sequence of C{(name, processedValue)} NcSs|SrIr)xrrrJz9ServerSupportedFeatures._splitParamArgs..c3s>D]}d|vr |d7}|dd\}}||fVqdS)Nr"r!r:)r^arrXvalueProcessorrr_parseLsz7ServerSupportedFeatures._splitParamArgs.._parse)ru)clsrXrrrrr_splitParamArgs4s z'ServerSupportedFeatures._splitParamArgscs$fdd}dvr Sd|S)z Unescape an ISUPPORT parameter. The only form of supported escape is C{\xHH}, where HH must be a valid 2-digit hexadecimal number. @rtype: C{str} c 3szd}|dV|D],}|dd|dd}}zt|d}Wnty2td|wt||VqdS)N\xrrzInvalid hex octet: )r&r)r<r>chr)partsr*octetrestr?rr _unescape`s   z>ServerSupportedFeatures._unescapeParamValue.._unescaperr )rt)rr?rrrr_unescapeParamValueUs   z+ServerSupportedFeatures._unescapeParamValuecs<d|vr|d7}|dd\}}|fdd|dDfS)z Split an ISUPPORT parameter. @type param: C{str} @rtype: C{(str, list)} @return: C{(key, arguments)} rr!csg|]}|qSr)r)r3vrrrr8}z7ServerSupportedFeatures._splitParam..,r:)rr^keyr?rrr _splitParamps z#ServerSupportedFeatures._splitParamcCs`|sdS|ddkrd|vrtd|dd\}}t|tt|}|dd}tt||S)a Parse the ISUPPORT "PREFIX" parameter. The order in which the parameter arguments appear is significant, the earlier a mode appears the more privileges it gives. @rtype: C{dict} mapping C{str} to C{(str, int)} @return: A dictionary mapping a mode character to a two-tuple of C({symbol, priority)}, the lower a priority (the lowest being C{0}) the more privileges it gives Nr()zMalformed PREFIX parameterr!)r>r&ziprangerTdict)rr+rWsymbolsrrrrs  z)ServerSupportedFeatures._parsePrefixParamcCsDd}t|t|krtdt|t|ftdd||}t|S)z Parse the ISUPPORT "CHANMODES" parameter. See L{isupport_CHANMODES} for a detailed explanation of this parameter. ) addressModesr^setParamnoParamz9Expecting a maximum of %d channel mode parameters, got %dcSs ||pdfS)Nr r)r r?rrrrs z>ServerSupportedFeatures._parseChanModesParam..)rTr>mapr)rFrXrrrrrrsz,ServerSupportedFeatures._parseChanModesParamcCs|j||S)a Get a server supported feature's value. A feature with the value L{None} is equivalent to the feature being unsupported. @type feature: C{str} @param feature: Feature name @type default: C{object} @param default: The value to default to, assuming that C{feature} is not supported @return: Feature value )rget)rFfeaturer@rrr getFeaturesz"ServerSupportedFeatures.getFeaturecCs||duS)z[ Determine whether a feature is supported or not. @rtype: C{bool} N)r)rFrrrr hasFeaturesz"ServerSupportedFeatures.hasFeaturecCsP|D]#}||\}}|dr|j|dddq||||j|<qdS)a2 Parse ISUPPORT parameters. If an unknown parameter is encountered, it is simply added to the dictionary, keyed by its name, as a tuple of the parameters provided. @type params: C{iterable} of C{str} @param params: Iterable of ISUPPORT parameters to parse rr!N)r  startswithrr)rQ)rFrXr^r r?rrrparses   zServerSupportedFeatures.parsecCst|S)z- Unknown ISUPPORT parameter. r)rFr.rXrrrisupport_unknownz(ServerSupportedFeatures.isupport_unknowncC ||tS)zJ The maximum number of each channel type a user may join. rrArFrXrrrisupport_CHANLIMIT z*ServerSupportedFeatures.isupport_CHANLIMITcCs*z||WSty|dYSw)aA Available channel modes. There are 4 categories of channel mode:: addressModes - Modes that add or remove an address to or from a list, these modes always take a parameter. param - Modes that change a setting on a channel, these modes always take a parameter. setParam - Modes that change a setting on a channel, these modes only take a parameter when being set. noParam - Modes that change a setting on a channel, these modes never take a parameter. r)rr>rr"rrrisupport_CHANMODESs   z*ServerSupportedFeatures.isupport_CHANMODEScCt|d|dS)zG Maximum length of a channel name a client may create. rrrArr"rrrisupport_CHANNELLENz+ServerSupportedFeatures.isupport_CHANNELLENcC t|dS)z) Valid channel prefixes. rrr"rrrisupport_CHANTYPESr$z*ServerSupportedFeatures.isupport_CHANTYPEScC |dpdS)z Mode character for "ban exceptions". The presence of this parameter indicates that the server supports this functionality. rerr"rrrisupport_EXCEPTS z(ServerSupportedFeatures.isupport_EXCEPTScCs ||S)z Safe channel identifiers. The presence of this parameter indicates that the server supports this functionality. )rr"rrrisupport_IDCHANs z'ServerSupportedFeatures.isupport_IDCHANcCr,)z Mode character for "invite exceptions". The presence of this parameter indicates that the server supports this functionality. rIrr"rrrisupport_INVEXr/z&ServerSupportedFeatures.isupport_INVEXcCr*)zH Maximum length of a kick message a client may provide. rrAr"rrrisupport_KICKLENr$z(ServerSupportedFeatures.isupport_KICKLENcCr )z Maximum number of "list modes" a client may set on a channel at once. List modes are identified by the "addressModes" key in CHANMODES. r!r"rrrisupport_MAXLIST s z(ServerSupportedFeatures.isupport_MAXLISTcCr*)z Maximum number of modes accepting parameters that may be sent, by a client, in a single MODE command. rr3r"rrrisupport_MODES(rz&ServerSupportedFeatures.isupport_MODEScC|dS)z# IRC network name. rrr"rrrisupport_NETWORK/rz(ServerSupportedFeatures.isupport_NETWORKcCr&)zB Maximum length of a nickname the client may use. rrr'r"rrrisupport_NICKLEN5r)z(ServerSupportedFeatures.isupport_NICKLENcCs.z||dWSty|dYSw)zQ Mapping of channel modes that clients may have to status flags. rr)rr>rr"rrrisupport_PREFIX;s  z'ServerSupportedFeatures.isupport_PREFIXcCdS)z Flag indicating that a client may request a LIST without being disconnected due to the large amount of data generated. Trr"rrrisupport_SAFELISTDsz)ServerSupportedFeatures.isupport_SAFELISTcCr7)zv The server supports sending messages to only to clients on a channel with a specific status. rrr"rrrisupport_STATUSMSGKsz*ServerSupportedFeatures.isupport_STATUSMSGcCst||tS)zh Maximum number of targets allowable for commands that accept multiple targets. )rrrAr"rrrisupport_TARGMAXRsz(ServerSupportedFeatures.isupport_TARGMAXcCr*)z< Maximum length of a topic that may be set. rr3r"rrrisupport_TOPICLENYr$z)ServerSupportedFeatures.isupport_TOPICLENrI)!rrrrr+r classmethodrrr rrrrrrr#r%r(r+r.r0r2r4r5r6r8r9r:r<r=r>r?rrrrrsF            rc@sVeZdZdZdZdZdZdZdZdZ dZ dZ dZ dZ dZdZdZdZdZdZdZdZdZdZd Zd Zd ZdZd Zd dZddZddZddZ ddZ!ddZ"ddZ#ddZ$ddZ%dd Z&d!d"Z'd#d$Z(d%d&Z)d'd(Z*d)d*Z+d+d,Z,d-d.Z-d/d0Z.d1d2Z/d3d4Z0d5d6Z1d7d8Z2d9d:Z3d;d<Z4d=d>Z5d?d@Z6dAdBZ7dCdDZ8dEdFZ9dGdHZ:dIdJZ;dKdLZddQdRZ?ddSdTZ@ddUdVZAe@ZBdWdXZCddYdZZDdd[d\ZEdd]d^ZFd_d`ZGddadbZHdcddZIddedfZJdgdhZKddidjZLddmdnZMdodpZNddqdrZOdsdtZPdZQduZRddvdwZSdxdyZTdzd{ZUd|d}ZVd~dZWddZXddZYddZZddZ[ddZ\ddZ]ddZ^ddZ_ddZ`ddZaddZbddZcddZdddZeddZfddZgddZhddZiddZjddZkddZlddZmddZnddZoddZpddZqddZrddZsddZtddZuddZvddZwddZxddÄZyddńZzddDŽZ{ddɄZ|dd˄Z}dd̈́Z~ddτZddфZddӄZddՄZddׄZddلZddۄZdd݄Zdd߄ZddZddZddZddZddZddZddZddZddZddZddZddZddZddZddZdS( IRCClienta Internet Relay Chat client protocol, with sprinkles. In addition to providing an interface for an IRC client protocol, this class also contains reasonable implementations of many common CTCP methods. TODO ==== - Limit the length of messages sent (because the IRC server probably does). - Add flood protection/rate limiting for my CTCP replies. - NickServ cooperation. (a mix-in?) @ivar nickname: Nickname the client will use. @ivar password: Password used to log on to the server. May be L{None}. @ivar realname: Supplied to the server during login as the "Real name" or "ircname". May be L{None}. @ivar username: Supplied to the server during login as the "User name". May be L{None} @ivar userinfo: Sent in reply to a C{USERINFO} CTCP query. If L{None}, no USERINFO reply will be sent. "This is used to transmit a string which is settable by the user (and never should be set by the client)." @ivar fingerReply: Sent in reply to a C{FINGER} CTCP query. If L{None}, no FINGER reply will be sent. @type fingerReply: Callable or String @ivar versionName: CTCP VERSION reply, client name. If L{None}, no VERSION reply will be sent. @type versionName: C{str}, or None. @ivar versionNum: CTCP VERSION reply, client version. @type versionNum: C{str}, or None. @ivar versionEnv: CTCP VERSION reply, environment the client is running in. @type versionEnv: C{str}, or None. @ivar sourceURL: CTCP SOURCE reply, a URL where the source code of this client may be found. If L{None}, no SOURCE reply will be sent. @ivar lineRate: Minimum delay between lines sent to the server. If L{None}, no delay will be imposed. @type lineRate: Number of Seconds. @ivar motd: Either L{None} or, between receipt of I{RPL_MOTDSTART} and I{RPL_ENDOFMOTD}, a L{list} of L{str}, each of which is the content of an I{RPL_MOTD} message. @ivar erroneousNickFallback: Default nickname assigned when an unregistered client triggers an C{ERR_ERRONEUSNICKNAME} while trying to register with an illegal nickname. @type erroneousNickFallback: C{str} @ivar _registered: Whether or not the user is registered. It becomes True once a welcome has been received from the server. @type _registered: C{bool} @ivar _attemptedNick: The nickname that will try to get registered. It may change if it is illegal or already taken. L{nickname} becomes the L{_attemptedNick} that is successfully registered. @type _attemptedNick: C{str} @type supported: L{ServerSupportedFeatures} @ivar supported: Available ISUPPORT features on the server @type hostname: C{str} @ivar hostname: Host name of the IRC server the client is connected to. Initially the host name is L{None} and later is set to the host name from which the I{RPL_WELCOME} message is received. @type _heartbeat: L{task.LoopingCall} @ivar _heartbeat: Looping call to perform the keepalive by calling L{IRCClient._sendHeartbeat} every L{heartbeatInterval} seconds, or L{None} if there is no heartbeat. @type heartbeatInterval: C{float} @ivar heartbeatInterval: Interval, in seconds, to send I{PING} messages to the server as a form of keepalive, defaults to 120 seconds. Use L{None} to disable the heartbeat. Nircz#http://twistedmatrix.com/downloads/rr! z!unusednames=params,prefix,channelFr defaultnickxcCs2t|}t|tr|d}|d7}tj||S)Nrh )rrkr;rlr LineReceiverrp)rFr4 quoteLinerrr_reallySendLines   zIRCClient._reallySendLinecCs:|jdur ||dS|j||js|dSdSrI)lineRaterI_queuer(_queueEmptying _sendLinerFr4rrrrps   zIRCClient.sendLinecCs8|jr||jdt|j|j|_dSd|_dS)Nr)rKrIr)r callLaterrJrMrLrErrrrMs zIRCClient._sendLinecCstj|||dSrI)r rGconnectionLost stopHeartbeatrFrrrrrPs zIRCClient.connectionLostcCs t|jS)z6 Create the heartbeat L{LoopingCall}. )r LoopingCall_sendHeartbeatrErrr_createHeartbeatr$zIRCClient._createHeartbeatcCs|d|jdS)zR Send a I{PING} message to the IRC server as a form of keepalive. zPING NrrErrrrTr)zIRCClient._sendHeartbeatcCs"|jdur|jd|_dSdS)zy Stop sending I{PING} messages to keep the connection to the server alive. @since: 11.1 N) _heartbeatstoprErrrrQs   zIRCClient.stopHeartbeatcCs6||jdur dS||_|jj|jdddS)z Start sending I{PING} messages every L{IRCClient.heartbeatInterval} seconds to keep the connection to the server alive during periods of no activity. @since: 11.1 NF)now)rQheartbeatIntervalrUrVstartrErrrstartHeartbeat s   zIRCClient.startHeartbeatcCr;)z Called with creation date information about the server, usually at logon. @type when: C{str} @param when: A string describing when the server was created, probably. Nr)rFwhenrrrcreatedrzIRCClient.createdcCr;)z Called with daemon information about the server, usually at logon. @type info: C{str} @param info: A string describing what software the server is running, probably. NrrFrrrryourHost&rzIRCClient.yourHostcCr;)a Called with information about the server, usually at logon. @type servername: C{str} @param servername: The hostname of this server. @type version: C{str} @param version: A description of what software this server runs. @type umodes: C{str} @param umodes: All the available user modes. @type cmodes: C{str} @param cmodes: All the available channel modes. Nr)rF servernameversionumodescmodesrrrmyInfo.rzIRCClient.myInfocCr;)z Called with information about the number of connections, usually at logon. @type info: C{str} @param info: A description of the number of clients and servers connected to the network, probably. Nrr^rrr luserClient?rzIRCClient.luserClientcCr;)z Called with information about where the client should reconnect. @type info: C{str} @param info: A plaintext description of the address that should be connected to. Nrr^rrrbounceHrzIRCClient.bouncecCr;)z Called with various information about what the server supports. @type options: C{list} of C{str} @param options: Descriptions of features or limits of the server, possibly in the form "NAME=VALUE". Nr)rFoptionsrrrrQrzIRCClient.isupportcCr;)zl Called with the number of channels existent on the server. @type channels: C{int} Nr)rFrbrrr luserChannelsZrzIRCClient.luserChannelscCr;)zc Called with the number of ops logged on to the server. @type ops: C{int} Nr)rFopsrrrluserOparzIRCClient.luserOpcCr;)z Called with information about the server connected to. @type info: C{str} @param info: A plaintext string describing the number of users and servers connected to this server. Nrr^rrrluserMehrzIRCClient.luserMecCr;)zN Called when I have a message from a user to me or a channel. NrrFrrrrrrrszIRCClient.privmsgcCr;)z Called when I finish joining a channel. channel has the starting character (C{'#'}, C{'&'}, C{'!'}, or C{'+'}) intact. NrrFrrrrjoinedyrzIRCClient.joinedcCr;)z Called when I have left a channel. channel has the starting character (C{'#'}, C{'&'}, C{'!'}, or C{'+'}) intact. NrrnrrrleftrzIRCClient.leftcCr;)a Called when I have a notice from a user to me or a channel. If the client makes any automated replies, it must not do so in response to a NOTICE message, per the RFC:: The difference between NOTICE and PRIVMSG is that automatic replies MUST NEVER be sent in response to a NOTICE message. [...] The object of this rule is to avoid loops between clients automatically sending something in response to something it received. NrrlrrrnoticedrzIRCClient.noticedcCr;)a Called when users or channel's modes are changed. @type user: C{str} @param user: The user and hostmask which instigated this change. @type channel: C{str} @param channel: The channel where the modes are changed. If args is empty the channel for which the modes are changing. If the changes are at server level it could be equal to C{user}. @type set: C{bool} or C{int} @param set: True if the mode(s) is being added, False if it is being removed. If some modes are added and others removed at the same time this function will be called twice, the first time with all the added modes, the second with the removed ones. (To change this behaviour override the irc_MODE method) @type modes: C{str} @param modes: The mode or modes which are being changed. @type args: C{tuple} @param args: Any additional information required for the mode change. Nr)rFrrsetrWr-rrr modeChangedrzIRCClient.modeChangedcCr;)z? Called with the results of a CTCP PING query. Nr)rFrsecsrrrpongrmzIRCClient.pongcCr;)zE Called after successfully signing on to the server. NrrErrrsignedOnrmzIRCClient.signedOncCr;)z9 Called when I am kicked from a channel. Nr)rFrkickerrrrr kickedFromrmzIRCClient.kickedFromcC ||_dS)z7 Called when my nick has been changed. N)r)rFrrrr nickChangeds zIRCClient.nickChangedcCr;)zC Called when I see another user joining a channel. NrrFrrrrr userJoinedrmzIRCClient.userJoinedcCr;)zC Called when I see another user leaving a channel. Nrr{rrruserLeftrmzIRCClient.userLeftcCr;)zM Called when I see another user disconnect from the network. Nr)rFr quitMessagerrruserQuitrmzIRCClient.userQuitcCr;)zQ Called when I observe someone else being kicked from a channel. Nr)rFkickeerrwrrrr userKickedrmzIRCClient.userKickedcCr;)zJ Called when I see a user perform an ACTION on a channel. NrrFrrrrrrrrmzIRCClient.actioncCr;)zt In channel, user changed the topic to newTopic. Also called when first joining a channel. Nr)rFrrnewTopicrrr topicUpdatedszIRCClient.topicUpdatedcCr;)zD A user changed their name from oldname to newname. Nr)rFoldnamenewnamerrr userRenamedrmzIRCClient.userRenamedcCr;)a# I received a message-of-the-day banner from the server. motd is a list of strings, where each string was sent as a separate message from the server. To display, you might want to use:: '\n'.join(motd) to get a nicely formatted string. Nr)rFmotdrrr receivedMOTDs zIRCClient.receivedMOTDcCF|dtvr d|}|r|d|d|dS|d|dS)a Join a channel. @type channel: C{str} @param channel: The name of the channel to join. If it has no prefix, C{'#'} will be prepended to it. @type key: C{str} @param key: If specified, the key used to join the channel. r#zJOIN r#NCHANNEL_PREFIXESrp)rFrr rrrrt  zIRCClient.joincCr)a Leave a channel. @type channel: C{str} @param channel: The name of the channel to leave. If it has no prefix, C{'#'} will be prepended to it. @type reason: C{str} @param reason: If given, the reason for leaving. rrzPART r$Nr)rFrrrrrleaverzIRCClient.leavecCsR|dtvr d|}|r|d|d|d|dS|d|d|dS)a Attempt to kick a user from a channel. @type channel: C{str} @param channel: The name of the channel to kick the user from. If it has no prefix, C{'#'} will be prepended to it. @type user: C{str} @param user: The nick of the user to kick. @type reason: C{str} @param reason: If given, the reason for kicking the user. rrzKICK r#r$Nr)rFrrrrrrkick,s  zIRCClient.kickcCs.|dtvr d|}|d|d|dS)z Attempt to invite user to channel @type user: C{str} @param user: The user to invite @type channel: C{str} @param channel: The channel to invite the user too @since: 11.0 rrzINVITE r#Nrr{rrrinviteAs zIRCClient.invitecCsJ|dtvr d|}|dkr|d|d|dS|d|dS)a  Attempt to set the topic of the given channel, or ask what it is. If topic is None, then I sent a topic query instead of trying to set the topic. The server should respond with a TOPIC message containing the current topic of the given channel. @type channel: C{str} @param channel: The name of the channel to change the topic on. If it has no prefix, C{'#'} will be prepended to it. @type topic: C{str} @param topic: If specified, what to set the topic to. rrNzTOPIC r$r)rFrrrrrrPs zIRCClient.topiccCsx|r d|d|}nd|d|}|durd||f}n|dur*|d|}n |dur5|d|}||dS)a? Change the modes on a user or channel. The C{limit}, C{user}, and C{mask} parameters are mutually exclusive. @type chan: C{str} @param chan: The name of the channel to operate on. @type set: C{bool} @param set: True to give the user or channel permissions and False to remove them. @type modes: C{str} @param modes: The mode flags to set on the user or channel. @type limit: C{int} @param limit: In conjunction with the C{'l'} mode flag, limits the number of users on the channel. @type user: C{str} @param user: The user to change the mode on. @type mask: C{str} @param mask: In conjunction with the C{'b'} mode flag, sets a mask of users to be banned from the channel. zMODE z +z -Nz%s %dr#r)rFchanrrrWlimitrmaskr4rrrrfszIRCClient.modecCs&|dtvr d|}||||dS)a Send a message to a channel @type channel: C{str} @param channel: The channel to say the message on. If it has no prefix, C{'#'} will be prepended to it. @type message: C{str} @param message: The message to say. @type length: C{int} @param length: The maximum number of octets to send at a time. This has the effect of turning a single call to C{msg()} into multiple commands to the server. This is useful when long messages may be sent that would otherwise cause the server to kick us off or silently truncate the text we are sending. If None is passed, the entire message is always send in one command. rrN)rrw)rFrrr7rrrsays z IRCClient.saycCs0dd|jddd|}d}tt||S)a Estimate a safe maximum line length for the given command. This is done by assuming the maximum values for nickname length, realname and hostname combined with the command that needs to be sent and some guessing. A theoretical maximum value is used because it is possible that our nickname, username or hostname changes (on the server side) while the length is still being calculated. z :{}!{}@{} {}rr bbbbbbbbbb?cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccr)rv supportedrMAX_COMMAND_LENGTHrT)rFr. theoreticalfudgerrr_safeMaximumLineLengths  z IRCClient._safeMaximumLineLengthcCshd|d}|dur||}t|d}||kr!td||ft|||D] }|||q(dS)a Send a message to a user or channel. The message will be split into multiple commands to the server if: - The message contains any newline characters - Any span between newline characters is longer than the given line-length. @param user: Username or channel name to which to direct the message. @type user: C{str} @param message: Text to send. @type message: C{str} @param length: Maximum number of octets to send in a single command, including the IRC protocol framing. If L{None} is given then L{IRCClient._safeMaximumLineLength} is used to determine a value. @type length: C{int} zPRIVMSG r$Nrz/Maximum length must exceed %d for message to %s)rrTr>r&rp)rFrrr7fmt minimumLengthr4rrrrws   z IRCClient.msgcCr)a- Send a notice to a user. Notices are like normal message, but should never get automated replies. @type user: C{str} @param user: The user to send a notice to. @type message: C{str} @param message: The contents of the notice to send. zNOTICE r$Nr)rFrrrrrrs zIRCClient.noticecC|d|dS)z Mark this client as away. @type message: C{str} @param message: If specified, the away message. zAWAY :%sNrrFrrrrawayzIRCClient.awaycCs |dS)z( Clear the away status. N)rrErrrbackrzIRCClient.backcCs4|dur |d|dS|d|d|dS)z Retrieve user information about the given nickname. @type nickname: C{str} @param nickname: The nickname about which to retrieve information. @since: 8.2 NzWHOIS r#r)rFrrrrrrs zIRCClient.whoisfoobarcCsR|jdur |d|j|||jdur||_|d|j|||jdS)a? Login to the server. @type nickname: C{str} @param nickname: The nickname to register. @type hostname: C{str} @param hostname: If specified, the hostname to logon as. @type servername: C{str} @param servername: If specified, the servername to logon as. NzPASS %szUSER {} {} {} :{})passwordrpsetNickrrvrealname)rFrrcr`rrrregisters    zIRCClient.registercCs||_|d|dS)z Set this client's nickname. @type nickname: C{str} @param nickname: The nickname to change to. zNICK %sN)_attemptedNickrprFrrrrrszIRCClient.setNickcCr)z Disconnect from the server @type message: C{str} @param message: If specified, the message to give when quitting the server. zQUIT :%sNrrrrrquit%s zIRCClient.quitcCs||d|fgdS)a* Strike a pose. @type channel: C{str} @param channel: The name of the channel to have an action on. If it has no prefix, it is sent to the user of that name. @type action: C{str} @param action: The action to preform. @since: 9.0 ACTIONN ctcpMakeQuery)rFrrrrrdescribe2s zIRCClient.describe cs|jduri|_|dur$tjtjtjdfddtdD}nt|}t|j||f<| |d|fgt |j|j krgdd|j D}| t |j|j }t|D] }|j||d=q\dSdS) zA Measure round-trip delay to another IRC client. Nr csg|]}tqSr)randomchoice)r3icharsrrr8Kr z"IRCClient.ping..rPINGcSsg|]\}}||fqSrr)r3krrrrr8Ssr!)_pingsstring ascii_lettersdigits punctuationrtrr;timerrT _MAX_PINGRINGrsort)rFrtextr byValueexcessrrrrpingBs  zIRCClient.pingcCtd)aK This is supposed to send a user a file directly. This generally doesn't work on any client, and this method is included only for backwards compatibility and completeness. @param user: C{str} representing the user @param file: an open file (unknown, since this is not implemented) zXXX!!! Help! I need to bind a socket, have it listen, and tell me its address. (and stop accepting once we've made a single connection.)r)rFrfilerrrdccSendYs zIRCClient.dccSendcC||dd|||gfgdS)z< Send a DCC RESUME request to another user. DCCRESUMENrrFrfileNameport resumePosrrr dccResumegzIRCClient.dccResumecCr)zT Send a DCC ACCEPT response to clients who have requested a resume. rACCEPTNrrrrrdccAcceptResumemrzIRCClient.dccAcceptResumecCs||j|_||jdS)zg Called when we try to register or change to a nickname that is already taken. N)alterCollidedNickrrrFr+rXrrrirc_ERR_NICKNAMEINUSEwszIRCClient.irc_ERR_NICKNAMEINUSEcCs|dS)ar Generate an altered version of a nickname that caused a collision in an effort to create an unused related name for subsequent registration. @param nickname: The nickname a user is attempting to register. @type nickname: C{str} @returns: A string that is in some way different from the nickname. @rtype: C{str} rDrrrrrrs zIRCClient.alterCollidedNickcCs|js ||jdSdS)a Called when we try to register or change to an illegal nickname. The server should send this reply when the nickname contains any disallowed characters. The bot will stall, waiting for RPL_WELCOME, if we don't handle this during sign-on. @note: The method uses the spelling I{erroneus}, as it appears in the RFC, section 6.1. N) _registeredrerroneousNickFallbackrrrrirc_ERR_ERRONEUSNICKNAMEs z"IRCClient.irc_ERR_ERRONEUSNICKNAMEcCr)z6 Called when the login was incorrect. zPassword Incorrect.)rrrrrirc_ERR_PASSWDMISMATCHrz IRCClient.irc_ERR_PASSWDMISMATCHcCs(||_d|_|j|_||dS)zK Called when we have received the welcome from the server. TN)rcrrrrvr[rrrrirc_RPL_WELCOMEs  zIRCClient.irc_RPL_WELCOMEcCs>|dd}|d}||jkr||dS|||dS)z5 Called when a user joins a channel. !rr%N)r&rror|rFr+rXrrrrrirc_JOIN  zIRCClient.irc_JOINcCs>|dd}|d}||jkr||dS|||dS)z6 Called when a user leaves a channel. rrN)r&rrpr}rrrrirc_PARTrzIRCClient.irc_PARTcCs"|dd}|||ddS)z. Called when a user has quit. rrN)r&rrFr+rXrrrrirc_QUITszIRCClient.irc_QUITc Cs|d|d|dd}}}|ddvrd|}||jkr$|}n|}z t|||\}}WntyHtddd|fYdSw|r]t|\}}| ||d d |||rst|\}}| ||d d ||dSdS) z5 Parse a server mode change message. rr!rNz-++zCAn error occurred while parsing the following MODE message: MODE %sr#Tr F) rgetUserModeParamsgetChannelModeParamsr_rr errrtrrs) rFrrXrrWr-rYaddedremovedrrrirc_MODEs.         zIRCClient.irc_MODEcCs|d|ddS)z1 Called when some has pinged us. zPONG %sr%Nrrrrrirc_PINGszIRCClient.irc_PINGcCsv|}|d}|d}|sdS|dtkr2t|}|dr%||||d|ds+dSd|d}||||dS)z/ Called when we get a message. rr%Nextendednormalr#)X_DELIM ctcpExtract ctcpQueryrtrrFr+rXrrrmrrr irc_PRIVMSGs zIRCClient.irc_PRIVMSGcCsn|}|d}|d}|dtkr.t|}|dr!||||d|ds'dSd|d}||||dS)z3 Called when a user gets a notice. rr%rrNr#)rr ctcpReplyrtrqrrrr irc_NOTICEs zIRCClient.irc_NOTICEcCs@|ddd}||jkr||ddS|||ddS)z< Called when a user changes their nickname. rr!rN)r&rrzrrrrrirc_NICKs zIRCClient.irc_NICKcCs^|dd}|d}|d}|d}||jkr%||||dS|||||dS)z> Called when a user is kicked from a channel. rrr!r%N)r&lowerrrxr)rFr+rXrwrkickedrrrrirc_KICK$szIRCClient.irc_KICKcCs0|dd}|d}|d}||||dS)z7 Someone in the channel set the topic. rrr!Nr&rrFr+rXrrnewtopicrrr irc_TOPIC2szIRCClient.irc_TOPICcCs0|dd}|d}|d}||||dS)zt Called when the topic for a channel is initially reported or when it subsequently changes. rrr!rNrrrrr irc_RPL_TOPIC;szIRCClient.irc_RPL_TOPICcCs,|dd}|d}d}||||dS)Nrrr!r rrrrrirc_RPL_NOTOPICEszIRCClient.irc_RPL_NOTOPICcCs2|ddr|ddd|d<|dg|_dSNr%z- r)rrrrrrirc_RPL_MOTDSTARTKszIRCClient.irc_RPL_MOTDSTARTcCsF|ddr|ddd|d<|jdurg|_|j|ddSr)rrr(rrrr irc_RPL_MOTDPs  zIRCClient.irc_RPL_MOTDcCs|j}d|_||dS)z I{RPL_ENDOFMOTD} indicates the end of the message of the day messages. Deliver the accumulated lines to C{receivedMOTD}. N)rr)rFr+rXrrrrirc_RPL_ENDOFMOTDWszIRCClient.irc_RPL_ENDOFMOTDcC||ddSNr!)r]rrrrirc_RPL_CREATED`zIRCClient.irc_RPL_CREATEDcCrr)r_rrrrirc_RPL_YOURHOSTcrzIRCClient.irc_RPL_YOURHOSTcCs@|ddd}t|dkr|dt|dks|j|dS)Nr!r)r&rTr(rd)rFr+rXrrrrirc_RPL_MYINFOfs    zIRCClient.irc_RPL_MYINFOcCrr)rfrrrrirc_RPL_BOUNCElrzIRCClient.irc_RPL_BOUNCEcCs&|dd}|j|||dS)Nr!r%)rrr)rFr+rXr-rrrirc_RPL_ISUPPORTos  zIRCClient.irc_RPL_ISUPPORTcCrr)rerrrrirc_RPL_LUSERCLIENTxrzIRCClient.irc_RPL_LUSERCLIENTcC.z |t|dWdStyYdSwr)rjr<r>rrrrirc_RPL_LUSEROP{  zIRCClient.irc_RPL_LUSEROPcCr r)rhr<r>rrrrirc_RPL_LUSERCHANNELSrzIRCClient.irc_RPL_LUSERCHANNELScCrr)rkrrrrirc_RPL_LUSERMErzIRCClient.irc_RPL_LUSERMEcCdSrIrrrrrrzIRCClient.irc_unknowncCs`t}|D](\}}t|d|d}||vr(|dur ||||n|||||||qdS)z Dispatch method for any CTCP queries received. Duplicated CTCP queries are ignored and no dispatch is made. Unrecognized CTCP queries invoke L{IRCClient.ctcpUnknownQuery}. z ctcpQuery_%sN)rrrJctcpUnknownQueryadd)rFrrmessagesseenrrrPrrrrs  zIRCClient.ctcpQuerycCs td|d|d|dS)z Fallback handler for unrecognized CTCP queries. No CTCP I{ERRMSG} reply is made to remove a potential denial of service avenue. zUnknown CTCP query from : r#Nr rwrFrrrrrrrrs zIRCClient.ctcpUnknownQuerycCs||||dSrI)rrrrrctcpQuery_ACTIONrzIRCClient.ctcpQuery_ACTIONcCs$|dd}||d|fgdS)Nrrrr& ctcpMakeReplyrFrrrrrrrctcpQuery_PINGszIRCClient.ctcpQuery_PINGcCsl|dur|d|d|d|jsdSt|jr|}nt|j}|dd}||d|fgdS)NWhy did  send 'z' with a FINGER query?rrFINGER) quirkyMessage fingerReplycallabler;r&r)rFrrrreplyrrrrctcpQuery_FINGERs   zIRCClient.ctcpQuery_FINGERcCsf|dur|d|d|d|jr1|dd}||dd|j|jp%d|jp)dffgdSdS) Nrr z' with a VERSION query?rrVERSIONz%s:%s:%sr )r" versionNamer&r versionNum versionEnvrrrrctcpQuery_VERSIONs"zIRCClient.ctcpQuery_VERSIONcCsR|dur|d|d|d|jr'|dd}||d|jfdgdSdS)Nrr z' with a SOURCE query?rrSOURCE)r,N)r" sourceURLr&rrrrrctcpQuery_SOURCEs zIRCClient.ctcpQuery_SOURCEcCsP|dur|d|d|d|jr&|dd}||d|jfgdSdS)Nrr z' with a USERINFO query?rrUSERINFO)r"userinfor&rrrrrctcpQuery_USERINFOs zIRCClient.ctcpQuery_USERINFOc Cs|dd}|s tt|jd}||dd|fgdS|}t|d|dd}|sB||dd||dffgdSt|d d }||d|fgdS) a A master index of what CTCP tags this client knows. If no arguments are provided, respond with a list of known tags, sorted in alphabetical order. If an argument is provided, provide human-readable help on the usage of that tag. rr ctcpQuery_ CLIENTINFOr#NERRMSGz!CLIENTINFO %s :Unknown query '%s'rr )r&sortedr prefixedMethodNames __class__rrtrJ) rFrrrrrr-rPdocrrrctcpQuery_CLIENTINFOs"  zIRCClient.ctcpQuery_CLIENTINFOcCs(|dd}||dd|fgdS)Nrrr4z%s :No error has occurred.rrrrrctcpQuery_ERRMSG szIRCClient.ctcpQuery_ERRMSGc CsX|dur|d|d|d|dd}||ddtttfgdS)Nrr z' with a TIME query?rrTIMEz:%s)r"r&rrasctime localtimerrrrctcpQuery_TIME s zIRCClient.ctcpQuery_TIMEc Cs|sdS|ddd}t|d|d}|r2|jdur g|_|t|dd}||||dS|dd}||dd|d|d fg||d |dS) a+ Initiate a Direct Client Connection @param user: The hostmask of the user/client. @type user: L{bytes} @param channel: The name of the IRC channel. @type channel: L{bytes} @param data: The DCC request message. @type data: L{bytes} Nr!rdcc_rr4zDCC z :Unknown DCC type ''z offered unknown DCC type )r&rrJ dcc_sessionsrTrr")rFrrrdcctypehandlerrrrr ctcpQuery_DCC s zIRCClient.ctcpQuery_DCCcCst|}t|dkrtd||dd\}}}t|}zt|}Wnty3td|wd}t|dkrNzt|d}Wn tyMYnw|||||||dS)Nrzmalformed DCC SEND request: Indecipherable port r%r)shlexr&rTrdccParseAddressr<r> dccDoSend)rFrrrfilenameaddressrsizerrrdcc_SEND5 s$      zIRCClient.dcc_SENDcCtt|}t|dkrtd||dd\}}}z t|}t|}Wn ty/YdSw|||||dS)Nrz#malformed DCC SEND ACCEPT request: )rFr&rTrr<r>dccDoAcceptResumerFrrrrIrrrrr dcc_ACCEPTM     zIRCClient.dcc_ACCEPTcCrM)Nrz#malformed DCC SEND RESUME request: )rFr&rTrr<r> dccDoResumerOrrr dcc_RESUMEZ rQzIRCClient.dcc_RESUMEcCs~t|}t|dkrtd||dd\}}}t|}zt|}Wnty3td|w||||||dS)Nrzmalformed DCC CHAT request: rE)rFr&rTrrGr<r> dccDoChat)rFrrrrIrJrrrrdcc_CHATg s    zIRCClient.dcc_CHATcCr;)a Called when I receive a DCC SEND offer from a client. By default, I do nothing here. @param user: The hostmask of the requesting user. @type user: L{bytes} @param address: The IP address of the requesting user. @type address: L{bytes} @param port: An integer representing the port of the requesting user. @type port: L{int} @param fileName: The name of the file to be transferred. @type fileName: L{bytes} @param size: The size of the file to be transferred, which may be C{-1} if the size of the file was not specified in the DCC SEND request. @type size: L{int} @param data: A 3-list of [fileName, address, port]. @type data: L{list} Nr)rFrrJrrrKrrrrrHy rzIRCClient.dccDoSendcCr;)a Called when a client is trying to resume an offered file via DCC send. It should be either replied to with a DCC ACCEPT or ignored (default). @param user: The hostmask of the user who wants to resume the transfer of a file previously offered via DCC send. @type user: L{bytes} @param file: The name of the file to resume the transfer of. @type file: L{bytes} @param port: An integer representing the port of the requesting user. @type port: L{int} @param resumePos: The position in the file from where the transfer should resume. @type resumePos: L{int} NrrFrrrrrrrrR zIRCClient.dccDoResumecCr;)a] Called when a client has verified and accepted a DCC resume request made by us. By default it will do nothing. @param user: The hostmask of the user who has accepted the DCC resume request. @type user: L{bytes} @param file: The name of the file to resume the transfer of. @type file: L{bytes} @param port: An integer representing the port of the accepting user. @type port: L{int} @param resumePos: The position in the file from where the transfer should resume. @type resumePos: L{int} NrrVrrrrN rWzIRCClient.dccDoAcceptResumecCrrIr)rFrrrJrrrrrrT rzIRCClient.dccDoChatcC||t|dS)z Send one or more C{extended messages} as a CTCP reply. @type messages: a list of extended messages. An extended message is a (tag, data) tuple, where 'data' may be L{None}. N)r ctcpStringifyrFrrrrrr zIRCClient.ctcpMakeReplycCrX)z Send one or more C{extended messages} as a CTCP query. @type messages: a list of extended messages. An extended message is a (tag, data) tuple, where 'data' may be L{None}. N)rwrYrZrrrr r[zIRCClient.ctcpMakeQuerycCsP|D]#}t|d|dd}|r||||dq||||d|dqdS)z@ Dispatch method for any CTCP replies received. z ctcpReply_%srNr!)rJctcpUnknownReply)rFrrrrrPrrrr s zIRCClient.ctcpReplycCs^|ddd}|jr||f|jvrtd|d||j||f}||t|dS)Nrr!rzBogus PING response from r)r&rrrur)rFrrrrt0rrrctcpReply_PING s zIRCClient.ctcpReply_PINGc Cs"td|d|d|ddS)a Called when a fitting ctcpReply_ method is not found. @param user: The hostmask of the user. @type user: L{bytes} @param channel: The name of the IRC channel. @type channel: L{bytes} @param tag: The CTCP request tag for which no fitting method is found. @type tag: L{bytes} @param data: The CTCP message. @type data: L{bytes} zUnknown CTCP reply from rr#r9Nrrrrrr\ s"zIRCClient.ctcpUnknownReplyc Cs(t|tdt|||dS)a When I get a message that's so broken I can't use it. @param line: The indecipherable message. @type line: L{bytes} @param excType: The exception type of the exception raised by the message. @type excType: L{type} @param excValue: The exception parameter of excType or its associated value(the second argument to C{raise}). @type excValue: L{BaseException} @param tb: The Traceback as a traceback object. @type tb: L{traceback} r N)r rwrt tracebackformat_exception)rFr4excTypeexcValuetbrrr badMessage s zIRCClient.badMessagecCst|ddS)z This is called when I receive a message which is peculiar, but not wholly indecipherable. @param s: The peculiar message. @type s: L{bytes} r9NrrFr*rrrr"" szIRCClient.quirkyMessagecCs(t|_g|_|jr||jdSdSrI)rrrK performLoginrrrErrrrf. s zIRCClient.connectionMadecCs2t|tr |d}|dd}tj||dS)NrhrF)rkr;rlrr rGrrFrrrrr4 s   zIRCClient.dataReceivedcCsttkrt|tr|d}t|}zt|\}}}|tvr"t|}||||WdSty@|j |gt RYdSwrg) rr;rkr lowDequoter/numeric_to_symbolicrrrdsysexc_info)rFr4r+r.rXrrr lineReceived: s  zIRCClient.lineReceivedcCsddgS)z Get user modes that require parameters for correct parsing. @rtype: C{[str, str]} @return: C{[add, remove]} r rrErrrrH szIRCClient.getUserModeParamscCsddg}|jdi}d||d<|d<|jd}|durL|d|dd7<|d|dd7<|d|d<|d|d d7<|S) z Get channel modes that require parameters for correct parsing. @rtype: C{[str, str]} @return: C{[add, remove]} r rrr!rNrr^r)rrrtkeysr)rFrXprefixes chanmodesrrrrQ s   zIRCClient.getChannelModeParamscCrrrrrrrrf rzIRCClient.handleCommandcCs|j}d|d<d|d<|S)NrAr)__dict__copy)rFdctrrr __getstate__~ s zIRCClient.__getstate__rI)NNN)r )rr)rrrrrcrrrrrr0r#r(r)r*r- dcc_destdirrArfrJrKrL delimiter __pychecker__rrrrVrYrIrprMrPrUrTrQr[r]r_rdrerfrrhrjrkrrorprqrsrurvrxrzr|r}rrrrrrrtrrrrrrrrrwrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr r r r rrrrrrrr&r+r.r1r9r:r>rDrLrPrSrUrHrRrNrTrrrr^r\rdr"rfrrmrrrrtrrrrrA`s*Q           " %            !       "         rAcCstd|vr |Szt|}Wntytd|w|d?d@|d?d@|d?d@|d@f}dtt|}|S)NrzIndecipherable address r)r<r>rrtrr;)rJrrrrG s     rGc@s&eZdZdZdZdddZddZdS) DccFileReceiveBasica[ Bare protocol to receive a Direct Client Connection SEND stream. This does enough to keep the other guy talking, but you'll want to extend my dataReceived method to *do* something with the data I get. @ivar bytesReceived: An integer representing the number of bytes of data received. @type bytesReceived: L{int} rcCs||_|dk|_dS)z @param resumeOffset: An integer representing the amount of bytes from where the transfer of data should be resumed. @type resumeOffset: L{int} rN) bytesReceivedresume)rF resumeOffsetrrrr szDccFileReceiveBasic.__init__cCs*|jt||_|jtd|jdS)z See: L{protocol.Protocol.dataReceived} Warning: This just acknowledges to the remote host that the data has been received; it doesn't I{do} anything with the data, so you'll want to override this. z!iN)r|rTrmrnstructpackrhrrrr sz DccFileReceiveBasic.dataReceivedN)r)rrrrr|rrrrrrr{ s   r{c@sLeZdZdZdZdZdZdZdZddZ ddZ d d Z d d Z d dZ dS)DccSendProtocola Protocol for an outgoing Direct Client Connection SEND. @ivar blocksize: An integer representing the size of an individual block of data. @type blocksize: L{int} @ivar file: The file to be sent. This can be either a file object or simply the name of the file. @type file: L{file} or L{bytes} @ivar bytesSent: An integer representing the number of bytes sent. @type bytesSent: L{int} @ivar completed: An integer representing whether the transfer has been completed or not. @type completed: L{int} @ivar connected: An integer representing whether the connection has been established or not. @type connected: L{int} iNrcCst|tur t||_dSdSrI)typer;openrrFrrrrr s zDccSendProtocol.__init__cCsd|_|dSr) connected sendBlockrErrrrf s zDccSendProtocol.connectionMadecCs>td|}||jkr dS||jkr|jdS|dS)Nz!I)runpack bytesSentrmloseConnectionr)rFr bytesShesGotrrrr s     zDccSendProtocol.dataReceivedcCsF|j|j}|r|j||jt||_dS|jd|_dSr) rread blocksizermrnrrTr completed)rFblockrrrr s    zDccSendProtocol.sendBlockcCs$d|_t|jdr|jdSdS)Nrclose)rhasattrrrrRrrrrP s zDccSendProtocol.connectionLost)rrrrrrrrrrrfrrrPrrrrr s rc@s eZdZeZddZddZdS)DccSendFactorycCs ||_dSrI)rrrrrr s zDccSendFactory.__init__cCs||j}||_|SrI)rrfactory)rF connectionprrr buildProtocol s zDccSendFactory.buildProtocolN)rrrrrrrrrrrr s rc Csd}t|dr"|}z t|}|tj}W|Sty!Ynwt|dr@t|j r@z t |j }W|Sty?Ynwt|drqt|drqzz| dd| }W| ddW|S| ddwtypY|Sw|S)a3 I'll try my damndest to determine the size of this file object. @param file: The file object to determine the size of. @type file: L{io.IOBase} @rtype: L{int} or L{None} @return: The size of the file object as an integer if it can be determined, otherwise return L{None}. NfilenorKseektellrr) rrosfstatstatST_SIZErrexistsrKgetsizerr)rrKrstat_rrrfileSize s<        rc@sNeZdZdZdZededZdZ dZ dZ d ddZ ddZ d d ZdS) DccChataH Direct Client Connection protocol type CHAT. DCC CHAT is really just your run o' the mill basic.LineReceiver protocol. This class only varies from that slightly, accepting either LF or CR LF for a line delimeter for incoming messages while always using CR LF for outgoing. The lineReceived method implemented here uses the DCC connection's 'client' attribute (provided upon construction) to deliver incoming lines from the DCC chat via IRCClient's normal privmsg interface. That's something of a spoof, which you may well want to override. NasciirgcCs$||_|r||_|jd|_dSdS)aw Initialize a new DCC CHAT session. queryData is a 3-tuple of (fromUser, targetUserOrChannel, data) as received by the CTCP query. (To be honest, fromUser is the only thing that's currently used here. targetUserOrChannel is potentially useful, while the 'data' argument is solely for informational purposes.) rN)client queryData remotePartyrFrrrrrrR s  zDccChat.__init__cCsR|j||_|jt}||_|D]}|dtkr!|dd}||qdS)Nr%)rr&rjr)rirm)rFrrr4rrrrc s      zDccChat.dataReceivedcCs2td|jd||j|j|jj|dS)Nz DCC CHAT )r rwrrrrrNrrrrmo szDccChat.lineReceivedrI)rrrrrrirlNLrvrrrrrrmrrrrr= s  rc@s4eZdZeZdZddZddZddZdd Z d S) DccChatFactoryFcCs||_||_dSrIrrrrrrrx s zDccChatFactory.__init__cCs|j|j|jd}||_|S)Nr)rrrr)rFaddrrrrrr| szDccChatFactory.buildProtocolcC|jj|dSrIrrAremoverFunused_connector unused_reasonrrrclientConnectionFailed rz%DccChatFactory.clientConnectionFailedcCrrIrrrrrclientConnectionLost rz#DccChatFactory.clientConnectionLostN) rrrrrnoisyrrrrrrrrrt s rc Cs|}|}t|dkr|S|dd\}}}}d|vrn,zt|}Wn ty,Ynw|d?d@|d?d@|d?d@|d@f}dtt|}|dkrx|}d }t|d krnz t|d}d |f}Wn tymYnwd ||||} | S|d krd|d|} | S|} | S)z Given the data chunk from a DCC query, return a descriptive string. @param data: The data from a DCC query. @type data: L{bytes} @rtype: L{bytes} @return: A descriptive string. rNrrxryrrzSENDr z of size %d bytesz(SEND for file '{}'{} at host {}, port {}CHATzCHAT for host z, port )r&rTr<r>rtrr;rv) r orig_datarBargrJrrIsize_txtrKdcc_textrrr dccDescribe sP           rc@seZdZUdZdZdZdZdZdZe e e d<dZ ddd Z d d Zd d ZddZddZddZddZdefddZdefddZdS)DccFileReceivea Higher-level coverage for getting a file from DCC SEND. I allow you to change the file's name and destination directory. I won't overwrite an existing file unless I've been told it's okay to do so. If passed the resumeOffset keyword argument I will attempt to resume the file from that amount of bytes. XXX: I need to let the client know when I am finished. XXX: I need to decide how to keep a progress indicator updated. XXX: Client needs a way to tell me "Do not finish until I say so." XXX: I need to make sure the client understands if the file cannot be written. @ivar filename: The name of the file to get. @type filename: L{bytes} @ivar fileSize: The size of the file to get, which has a default value of C{-1} if the size of the file was not specified in the DCC SEND request. @type fileSize: L{int} @ivar destDir: The destination directory for the file to be received. @type destDir: L{bytes} @ivar overwrite: An integer representing whether an existing file should be overwritten or not. This initially is an L{int} but can be modified to be a L{bool} using the L{set_overwrite} method. @type overwrite: L{int} or L{bool} @ivar queryData: queryData is a 3-tuple of (user, channel, data). @type queryData: L{tuple} @ivar fromUser: This is the hostmask of the requesting user and is found at index 0 of L{queryData}. @type fromUser: L{bytes} dccr%rrNfromUsercCsDtj||d||_||_||_||_|r ||_|jd|_dSdS)N)r~r)r{rrIdestDirr _resumeOffsetrr)rFrIrrrr~rrrr szDccFileReceive.__init__cCs\t|s ttjd|t|sttjd|t|tj tj Bs)ttj d|||_ dS)a Set the directory where the downloaded file will be placed. May raise OSError if the supplied directory path is not suitable. @param directory: The directory where the file to be received will be placed. @type directory: L{bytes} zYou see no directory there.z>You cannot put a file into something which is not a directory.z*This directory is too hard to write in to.N) rrOSErrorerrnoENOENTisdirENOTDIRraccessX_OKW_OKEACCESr)rF directoryrrr set_directory s   zDccFileReceive.set_directorycCry)z Change the name of the file being transferred. This replaces the file name provided by the sender. @param filename: The new name for the file. @type filename: L{bytes} N)rI)rFrIrrr set_filename s zDccFileReceive.set_filenamecCry)z May I overwrite existing files? @param boolean: A boolean value representing whether existing files should be overwritten or not. @type boolean: L{bool} N) overwrite)rFbooleanrrr set_overwrite s zDccFileReceive.set_overwritecCstt|j|j}t|}|jr6|r6t|d|_|j |j |j t d|j|jfdS|jrB|sBttjd||jsG|sOt|d|_dSttjd|)Nzrb+z0Attempting to resume %s - starting from %d bytesz8You cannot resume writing to a file that does not exist!wbzBThere's a file in the way. Perhaps that's why you cannot open it.)rabspathrtrrIrr}rrrrtruncater rwrrrrrEEXIST)rFdstrrrrrf, s0      zDccFileReceive.connectionMadecCs|j|t||dSrI)rrnr{rrhrrrrH s zDccFileReceive.dataReceivedcCsd|_|d}|jdkr4d||j|jf}|j|jkrn|j|jkr.d||j|jf}n |d}nd||jf}t|drW|d|jjd }t|jd rY|jd Sd Sd S) z When the connection is lost, I close the file. @param reason: The reason why the connection was lost. @type reason: L{Failure} rz closed.z%s %d/%d bytes receivedz%s (Warning: %d bytes short)z (file larger than expected)z%s %d bytes receivedrz and written to z. rN)rrr|rrrKr)rFrlogmsgrrrrPN s.        zDccFileReceive.connectionLostreturncCsh|js dt|ddS|j}|dusJt|}|jdur)|jd|d}d|jd|}|S)Nz&z (rzDCC transfer of 'z' from )ridrmr;getPeerrrI)rFrmfrom_r*rrr__str__p s   zDccFileReceive.__str__cCs&d|jdt|dd|jd}|S)N r rc@s8eZdZdZeejeZeej eZ e e e dZdS)_CharacterAttributesa Factory for character attributes, including foreground and background color and non-color attributes such as bold, reverse video and underline. Character attributes are applied to actual text by using object indexing-syntax (C{obj['abc']}) after accessing a factory attribute, for example:: attributes.bold['Some text'] These can be nested to mix attributes:: attributes.bold[attributes.underline['Some text']] And multiple values can be passed:: attributes.normal[attributes.bold['Some'], ' text'] Non-color attributes can be accessed by attribute name, available attributes are: - bold - reverseVideo - underline Available colors are: 0. white 1. black 2. blue 3. green 4. light red 5. red 6. magenta 7. orange 8. yellow 9. light green 10. cyan 11. light cyan 12. light blue 13. light magenta 14. gray 15. light gray @ivar fg: Foreground colors accessed by attribute name, see above for possible names. @ivar bg: Background colors accessed by attribute name, see above for possible names. @since: 13.1 )bold reverseVideo underlineN)rrrrr _ColorAttribute_ForegroundColorAttr _IRC_COLORSfg_BackgroundColorAttrbg_BOLD_REVERSE_VIDEO _UNDERLINEattrsrrrrr s5rc@s2eZdZdZdZ      d ddZddZdS) _FormattingStatez Formatting state/attributes of a single character. Attributes include: - Formatting nullifier - Bold - Underline - Reverse video - Foreground color - Background color @since: 13.1 offrrr foreground backgroundFNcCs(||_||_||_||_||_||_dSrIr)rFrrrrrrrrrr s   z_FormattingState.__init__cCsg}|jr |t|jr|t|jr|t|jdus$|jdurGd}|jdur3|d|jf7}|jdur@|d|jf7}|t |t d t t |S)z Emit a mIRC control sequence that will set up all the attributes this formatting state has set. @return: A string containing mIRC control sequences that mimic this formatting state. Nr z%02dz,%02d)rr(rrrrrrr_COLOR_OFFrtrr;)rFrcrrrtoMIRCControlCodes s     z#_FormattingState.toMIRCControlCodes)FFFFNN)rrrrcompareAttributesrr rrrrr s  rcstfddt||S)aI Apply a function of two arguments cumulatively to the items of a sequence, from right to left, so as to reduce the sequence to a single value. @type f: C{callable} taking 2 arguments @param z: Initial value. @param xs: Sequence to reduce. @return: Single value resulting from reducing C{xs}. cs ||SrIr)ryfrrr6 s z_foldr..)rreversed)rzxsrrr_foldr( src @sdeZdZdZdZedededede diZ dd Z d d Z d d Z ddZddZddZddZdS)_FormattingParsera A finite-state machine that parses formatted IRC text. Currently handled formatting includes: bold, reverse, underline, mIRC color codes and the ability to remove all current formatting. @see: U{http://www.mirc.co.uk/help/color.txt} @type _formatCodes: C{dict} mapping C{str} to C{str} @cvar _formatCodes: Mapping of format code values to names. @type state: C{str} @ivar state: Current state of the finite-state machine. @type _buffer: C{str} @ivar _buffer: Buffer, containing the text content, of the formatting sequence currently being parsed, the buffer is used as the content for L{_attrs} before being added to L{_result} and emptied upon calling L{emit}. @type _attrs: C{set} @ivar _attrs: Set of the applicable formatting states (bold, underline, etc.) for the current L{_buffer}, these are applied to L{_buffer} when calling L{emit}. @type foreground: L{_ForegroundColorAttr} @ivar foreground: Current foreground color attribute, or L{None}. @type background: L{_BackgroundColorAttr} @ivar background: Current background color attribute, or L{None}. @ivar _result: Current parse result. staterrcolorrrcCs*d|_d|_t|_d|_d|_d|_dS)NTEXTr )r_bufferrr_attrs_resultrrrErrrrf s  z_FormattingParser.__init__cCs||j|dS)zs Handle input. @type ch: C{str} @param ch: A single character of input to process N)rQr)rFr]rrrprocessn rz_FormattingParser.processcCs ||jdur tj|_|jS)z Flush the current buffer and return the final parsed result. @return: Structured text and attributes. N)emitr attributesrrErrrcompletew s z_FormattingParser.completecCs|jrAdd|jD}|td|j|jg|s|tj||jt t j | |}|j dur7||_ n|j |d|_dSdS)z? Add the currently parsed input to the result. cSsg|]}tt|qSr)rJr)r3rKrrrr8 r z*_FormattingParser.emit..Nr )rrextendfilterrrr(rrroperatorgetitemr)r)rFrattrrrrr s     z_FormattingParser.emitcCsz|j|}|dkr|d|_dS|dur |j|7_dS||dkr4t|_d|_|_dS|j |gdS)z Handle the "text" state. Along with regular text, single token formatting codes are handled in this state too. @param ch: The character being processed. rCOLOR_FOREGROUNDNr) _formatCodesrrrrrrrrrsymmetric_difference_update)rFr] formatNamerrr state_TEXT s  z_FormattingParser.state_TEXTcCs|rt|jdkr|j|7_dS|jr*t|jtt}ttjt||_ nd|_ |_ |dkr?|jr?d|_d|_ dSd|_d|_ | | |dS)aF Handle the foreground color state. Foreground colors can consist of up to two digits and may optionally end in a I{,}. Any non-digit or non-comma characters are treated as invalid input and result in the state being reset to "text". @param ch: The character being processed. rNr r COLOR_BACKGROUNDr)isdigitrTrr<rrJrr_IRC_COLOR_NAMESrrrrrrFr]colrrrstate_COLOR_FOREGROUND s   z(_FormattingParser.state_COLOR_FOREGROUNDcCst|rt|jdkr|j|7_dS|jr,t|jtt}ttjt||_ d|_| d|_ | |dS)ad Handle the background color state. Background colors can consist of up to two digits and must occur after a foreground color and must be preceded by a I{,}. Any non-digit character is treated as invalid input and results in the state being set to "text". @param ch: The character being processed. rr rN) r*rTrr<rrJrrr+rrrrr,rrrstate_COLOR_BACKGROUND s z(_FormattingParser.state_COLOR_BACKGROUNDN)rrrrr+r rrrrr%rrrrr(r.r/rrrrr9 s "   $rcCs"t}|D]}||q|S)a  Parse text containing IRC formatting codes into structured information. Color codes are mapped from 0 to 15 and wrap around if greater than 15. @type text: C{str} @param text: Formatted text to parse. @return: Structured text and attributes. @since: 13.1 )rrr)rrr]rrrparseFormattedText s  r0cCst|tdS)aE Assemble formatted text from structured information. Currently handled formatting includes: bold, reverse, underline, mIRC color codes and the ability to remove all current formatting. It is worth noting that assembled text will always begin with the control code to disable other attributes for the sake of correctness. For example:: from twisted.words.protocols.irc import attributes as A assembleFormattedText( A.normal[A.bold['Time: '], A.fg.lightRed['Now!']]) Would produce "Time: " in bold formatting, followed by "Now!" with a foreground color of light red and without any additional formatting. Available attributes are: - bold - reverseVideo - underline Available colors are: 0. white 1. black 2. blue 3. green 4. light red 5. red 6. magenta 7. orange 8. yellow 9. light green 10. cyan 11. light cyan 12. light blue 13. light magenta 14. gray 15. light gray @see: U{http://www.mirc.co.uk/help/color.txt} @param formatted: Structured text and attributes. @rtype: C{str} @return: String containing mIRC control sequences that mimic those specified by I{formatted}. @since: 13.1 r )r flattenr) formattedrrrassembleFormattedText s4r3cCst|}t|tS)z Remove all formatting codes from C{text}, leaving only the text. @type text: C{str} @param text: Formatted text to parse. @rtype: C{str} @return: Plain text without any control sequences. @since: 13.1 )r0r r1DefaultFormattingState)rr2rrrstripFormatting5s r5r!c Csg}g}||d}|t}d}|r*|r||dn||d| }|sttd||dd<ttd||dd<ttt||dd<tt |D]!}||t d}|d}t |dkrj|d} nd} || f||<qQ|S)z Extract CTCP data from a string. @return: A C{dict} containing two keys: - C{'extended'}: A list of CTCP (tag, data) tuples. - C{'normal'}: A list of strings which were not inside a CTCP delimiter. )rrrNr!) r&rr(r)rur r ctcpDequoterrTSPC) rextended_messagesnormal_messagesretvalroddrrrrrrrrJs,    r0rrr%rcCs&ttttfD] }||t|}q|SrI)M_QUOTENULrrir mQuoteTabler*r rrrrsrcCtfdd}t||S)NcS4|d}z||}W|Sty|}Y|SwrgroupKeyError)matchobj mDequoteTabler*rrrsub   zlowDequote..sub)rH mEscape_rerIr*rIrrrri  rirrcCs"ttfD] }||t|}q|SrI)X_QUOTErr xQuoteTablerArrr ctcpQuotes rPcCrB)NcSrCrrD)rG xDequoteTabler*rrrrIrJzctcpDequote..sub)rQ xEscape_rerIrLrrrr6rMr6c Csg}|D]<\}}|r+t|ts#z dtt|}Wn ty"Ynw|d|}nt|}t|}t|t}||qd|}|S)z @type messages: a list of extended messages. An extended message is a (tag, data) tuple, where 'data' may be L{None}, a string, or a list of strings to be joined with whitespace. @returns: String r#r )rkr;rtrr=rPrr()rcoded_messagesrrrr4rrrrYs      rY001002003004005010302303301305306311312313317318319314369321322323325324331332341342346347348349351352315353366364365367368371374375372376381382383391392393394395200201202203204205206207208209210261262211212219242243221234235251252253254255256257258259263401402403404405406407408409411412413414415416421422423424431432433436437441442443444445446451461462463464465466467471472473474475476477478481482483484485491492501502 RPL_WELCOME RPL_YOURHOST RPL_CREATED RPL_MYINFO RPL_ISUPPORT RPL_BOUNCE RPL_USERHOSTRPL_ISONRPL_AWAY RPL_UNAWAY RPL_NOWAWAYrrrrrrRPL_WHOWASUSERRPL_ENDOFWHOWAS RPL_LISTSTARTRPL_LIST RPL_LISTEND RPL_UNIQOPISrrr RPL_INVITING RPL_SUMMONINGRPL_INVITELISTRPL_ENDOFINVITELISTRPL_EXCEPTLISTRPL_ENDOFEXCEPTLIST RPL_VERSIONrrrr RPL_LINKSRPL_ENDOFLINKS RPL_BANLISTRPL_ENDOFBANLISTRPL_INFO RPL_ENDOFINFO RPL_MOTDSTARTRPL_MOTD RPL_ENDOFMOTD RPL_YOUREOPER RPL_REHASHINGRPL_YOURESERVICERPL_TIMERPL_USERSSTART RPL_USERSRPL_ENDOFUSERS RPL_NOUSERS RPL_TRACELINKRPL_TRACECONNECTINGRPL_TRACEHANDSHAKERPL_TRACEUNKNOWNRPL_TRACEOPERATOR RPL_TRACEUSERRPL_TRACESERVERRPL_TRACESERVICERPL_TRACENEWTYPERPL_TRACECLASSRPL_TRACERECONNECT RPL_TRACELOG RPL_TRACEENDRPL_STATSLINKINFORPL_STATSCOMMANDSRPL_ENDOFSTATSRPL_STATSUPTIMERPL_STATSOLINE RPL_UMODEIS RPL_SERVLISTRPL_SERVLISTENDRPL_LUSERCLIENT RPL_LUSEROPRPL_LUSERUNKNOWNRPL_LUSERCHANNELS RPL_LUSERME RPL_ADMINME RPL_ADMINLOC1 RPL_ADMINLOC2RPL_ADMINEMAIL RPL_TRYAGAINERR_NOSUCHNICKERR_NOSUCHSERVERERR_NOSUCHCHANNELERR_CANNOTSENDTOCHANERR_TOOMANYCHANNELSERR_WASNOSUCHNICKERR_TOOMANYTARGETSERR_NOSUCHSERVICE ERR_NOORIGINERR_NORECIPIENTERR_NOTEXTTOSENDERR_NOTOPLEVELERR_WILDTOPLEVEL ERR_BADMASKERR_TOOMANYMATCHESERR_UNKNOWNCOMMAND ERR_NOMOTDERR_NOADMININFO ERR_FILEERRORERR_NONICKNAMEGIVENERR_ERRONEUSNICKNAMEERR_NICKNAMEINUSEERR_NICKCOLLISIONERR_UNAVAILRESOURCEERR_USERNOTINCHANNELERR_NOTONCHANNELERR_USERONCHANNEL ERR_NOLOGINERR_SUMMONDISABLEDERR_USERSDISABLEDERR_NOTREGISTEREDERR_NEEDMOREPARAMSERR_ALREADYREGISTREDERR_NOPERMFORHOSTERR_PASSWDMISMATCHERR_YOUREBANNEDCREEPERR_YOUWILLBEBANNED ERR_KEYSETERR_CHANNELISFULLERR_UNKNOWNMODEERR_INVITEONLYCHANERR_BANNEDFROMCHANERR_BADCHANNELKEYERR_BADCHANMASKERR_NOCHANMODESERR_BANLISTFULLERR_NOPRIVILEGESERR_CHANOPRIVSNEEDEDERR_CANTKILLSERVERERR_RESTRICTEDERR_UNIQOPPRIVSNEEDED)ERR_NOOPERHOSTERR_NOSERVICEHOSTERR_UMODEUNKNOWNFLAGERR_USERSDONTMATCH)r0rI)rS)rrr!rrrerFrdrrrrkr1rr_ functoolsrrtypingrtwisted.internetrrrtwisted.persistedrtwisted.protocolsr twisted.pythonr r r rr?rirrjr7rr Exceptionrrr>rr/r&rA RuntimeErrorrBrCr_Protocolr`rrGrArG Ephemeralr{rFactoryrrr ClientFactoryrrrr rrrrrrrrrr+CharacterAttributesMixinrr_FormattingStateMixinrrrr0r3r5rrr>r@rHrrcompileescapeDOTALLrKrrirNrOrQrRrPr6rYrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr r r r r rrrrrrrrrrrrrrrrrrr r!r"r#r$r%r&r'r(r)r*r+r,r-r.r/r0r1r2r3r4r5r6r7r8r9r:r;r<r=r>r?r@rArBrCrDrErFrGrHrIrJrKrLrMrNrOrPrQrRrSrTrUrVrWrXrYrZr[r\r]r^symbolic_to_numericrjrrrrsZ         (:"H1#I -7;?@A37*        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~