Ϫf 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'Gdde(Z)Gdde(Z*Gdde+Z,dZ-dfdZ.dgdZ/Gdde0Z1GddZ2dhdZ3GddejhZ5Gdd e2Z6Gd!d"ejnZ8d#Z9Gd$d%ejhejtZ;Gd&d'ejhejtZ<Gd(d)ejzZ>d*Z?Gd+d,ejnejtZ@Gd-d.ejZBd/ZCGd0d1e;ZDd2ZEd3ZFd4ZGd5ZHd6ZIeJeKgd7eLd8ZMeMjDcic]\}}|| c}}ZOGd9d:ejZQeQZRGd;dd?e2ZVd@ZWdAZXdBZYe dCZZdDZ[e d8Z\e!e\dEze#e\dFze"e\dGze\e\e\ziZ]iZ^e]jD] \Z_Z`e_e^e`dH<[_[`ejeje\dIejZddJZedKZfdLZgeZegdMzegegegziZhiZiehjD] \Z_Z`e_eie`dH<ejejegdIejZjdNZkdOZldPZmdQZndRZodSZpdTZqdUZrdVZsdWZtdXZudYZvdZZwd[Zxd\Zyd]Zzd^Z{d_Z|d`Z}daZ~dbZdcZddZdeZdfZdgZdhZdiZdjZdkZdlZdmZdnZdoZdpZdqZdrZdsZdtZduZdvZdwZdxZdyZdzZd{Zd|Zd}Zd~ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZiddQddRddSddTddUddVddWddXddYddZdd[dd\dd]dd^dd_dd`ddaiddbddcdddddeddfddgddhddiddjddkddlddmddnddoddpddqddriddsddtdduddvddwddxddyddzdd{dd|d d}d d~d dd dd dddddiddddddddddddddddddddddddddddddddd did!dd"dd#dd$dd%dd&dd'dd(dd)dd*dd+dd,dd-dd.dd/dd0dd1did2dd3dd4dd5dd6dd7dd8dd9dd:dd;dddd?dd@ddAddBdidCddDddEddFddGddHddIddJddKddLddMddNd“dOdÓdPdēdQdœdRdƓdSdǓidTdȓdUdɓdVdʓdWd˓dXd̓dYd͓dZdΓd[dϓd\dГd]dѓd^dғd_dӓd`dԓdadՓdbd֓dcdדdddؓddddܐdeZiZejD] \Z_Z`e_ee`< ycc}}w(ia* 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 eZdZy) IRCBadMessageN__name__ __module__ __qualname__=/usr/lib/python3/dist-packages/twisted/words/protocols/irc.pyrrHrrc eZdZy)IRCPasswordMismatchNrrrrrrLrrrceZdZdZy) IRCBadModeszS A malformed mode was encountered while attempting to parse a mode string. Nrrr__doc__rrrrrPrrcFd}g}|s td|dddk(r|ddjdd\}}|jdd k7r7|jdd\}}|j}|j|n|j}|j 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)sprefixtrailingargscommands rparsemsgr3VsFH M**1v}abEKKQ' vvd|rggdA& 8wwy HwwyhhqkG 7D  rc|jdDcgc]}tj||D]}|!c}}Scc}}w)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}  )r*textwrapwrap)strlengthlinechunks rr*r*qs7 "iio Wd8==v;V W%E WE WW Ws$=cN|r t|S|S#ttf$rY|SwxYw)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)valuedefaults r _intOrDefaultrBs;  u:  N:&   N s $$ceZdZdZy)UnhandledCommandzO A command dispatcher could not locate an appropriate command handler. Nr rrrrDrDr"rrDc,eZdZUdZdZeeed<dZy)_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/cfdfd}||}|||S|d}|td|d||g|S)z2 Perform actual command dispatch. c&jd|S)N_)r/)r2selfs r_getMethodNamez8_CommandDispatcherMixin.dispatch.._getMethodNameskk]!G9- -rc*t|dSN)getattr)namerKrJs r _getMethodz4_CommandDispatcherMixin.dispatch.._getMethods4!5t< "!."=!@P k)D))r) rrrr!r/rr8__annotations__rTrrrrFrFs !FHSM *rrFct|dk(r td|ddvrtd|ggf}d}d}|D]c}|dvr'|dk(rtd|dj|}d}.d}|||vr |jd}||j ||f|d z }et|dkDrtd |d ||dk(rtd||S#t$rtd|wxYw) 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 directioncountchparams r parseModesrbsA. 5zQ-.. Qxt4UI>??2hGI E :z!$9%"CDD 2IEEZ **H"JJqME I  % %r5k 2 QJE  6{Q1%!F:FGG z1%;<< N"H%(?v&FGGHs 1CC+ceZdZUdZdZdZdZeee d<dZ dZ dZ ddZ d Zd Zd Zd Zd ZdZdZdZdZddZdZdZdZdZdZddZdZy)IRCz. Internet Relay Chat server protocol. r$Nencodingc^g|_|jtj|_yyrM)channelshostnamesocketgetfqdnrJs rconnectionMadezIRC.connectionMades& == "NN,DM !rc|tztz}t|tr+|jr |jnd}|j |}|j j|yNutf-8)CRLF isinstancer8reencode transportwrite)rJr: useEncodings rsendLinez IRC.sendLine sJby2~ dC +/==$--gK;;{+D T"rcF|s tdd|vs|ddk(rtd|zdj|gt|z}d|vrdj|d|}|j |t |dkDr$t jd t ||fzy y ) 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?joinlistformatrwrWr msg)rJr2parameter_listr/r:s r sendMessagezIRC.sendMessages>? ? '>WQZ3.13:;  xx D$889 v ??6(#3T:D d ~  # GG@~&-.  $rch|s tdd|vs|ddk(rtd|d|i}dj|gt|z}|rd|d|}|r|j|}d|d|}|j |t |d kDr$t jd t ||fzyy) 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} ryr'rr&zInvalid command: ""N@rzr{)r?r|r} _stringTagsrwrWr r)rJr2 parametersr/tagsr:tagStrs r sendCommandzIRC.sendCommand4s,>? ? '>WQZ3.1'!<= = <Dxx D$445 vhav&D %%d+Fvhav&D d z?R  GG@z?D)*  rc|j|g}|jD]>\}}|r&|j|d|j|.|j|@dj |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,_escapeTagValuer|)rJr tagStringstagr@s rrzIRC._stringTagscsw 4  **, 'JC!!SE4+?+?+F*G"HI!!#&  ' xx ##rc|jD]9\}}|s td|D]"}|jr|dvstd;y)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)rJrrr@chars rrzIRC._validateTagsus[**, IJC !:;; I||~$o*E$%GHH I Irc|jddjddjddjddjd 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\rr5z\n)replace)rJr@s rrzIRC._escapeTagValuesG MM$ ' WS% WS% WT5 ! WT5 !  rcft|tr|jd}|j|zj t }|j |_|D]T}t|dkr|dtk(r|dd}t|\}}}|j}|j|||Vy)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.) ror)N) rrbytesdecodebufferr*rqr-rWrpr3upper handleCommand)rJdatalinesr:r/r2r[s r dataReceivedzIRC.dataReceiveds dE ";;w'Dt#**2.iik  8D4yA~Bx2~CRy&.tn #FGVmmoG   w 7 8rct|d|zd} | |||y|j|||y#t$rtjYywxYwa 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_%sNrN irc_unknown BaseExceptionr deferrrJr2r/r[rSs rrzIRC.handleCommandVx'148 !vv&  &9  JJL  22AAct|||)z Called by L{handleCommand} on a command that doesn't have a defined handler. Subclasses should override this method. NotImplementedErrorrJr/r2r[s rrzIRC.irc_unknowns "'66::rcF|jd|dt|f|y)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)rlowQuoterJsenderrecipmessages rprivmsgz IRC.privmsgs( Ua0A/B,C$DfMrc4|jd|d|f|y)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)rrs rnoticez IRC.notices!& EQwi=#96Brc8|jd|d|d|y)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(Nrwrs ractionz IRC.actions# &%7)<=rc |i|/|jd|jdtd|d|dd y|jd|jdtd|d|dt | y|jd|d|dt |y)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. Nr&r'r(zNo topic is set.z TOPIC )rwrh RPL_NOTOPIC RPL_TOPICr)rJuserchanneltopicauthors rrz IRC.topics}$ >} }}k4BTV  }}iwQ MMAfXWWIR7HI Jrc L|jd|jd||||fzy)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 %diMNrwrh)rJrrrdates r topicAuthorzIRC.topicAuthor's), DMM3gvt#T T rc2t|t|zdz}d|z }g}d}|D]}|t|zdz|kDrL|jd|jdtd|d|ddj | |g}t|}c|j ||t|dzz }|r=|jd|jdtd|d|ddj | |jd|jdt d|d|d y ) 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%r&r'z = r(z :End of /NAMES listN)rWrwrh RPL_NAMREPLYr|r,RPL_ENDOFNAMES) rJrrnames prefixLength namesLengthLr_ns rrz IRC.namesAs7|c$i/"4 L(  $As1v~!K/ }}lD'388A;PCA Q!# $ MM==,gsxx{L  }}ndG = rc|D]?}|\}}}}} } } | dvsJ|jd|jt||||||| | | f zA|jd|jdtd|d|d y)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 %sr&r'z :End of /WHO list.N)rwrh RPL_WHOREPLY RPL_ENDOFWHO) rJrr memberInfoinfousernamehostmaskservernicknameflaghopsrealNames rwhozIRC.whojs$ DKO HXx4x:% %% MM4MM     ( }}lD' ; rc L|jd|jdtd|d|d|d|d||jd|jdtd|d|d|d| |r,|jd|jdtd|d|d |jd|jt ||| | fz|jd|jdt d|d|ddj|  |jd|jdtd|d|d y) 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 r&r'z * :r(z :is an IRC operatorz-:%s %s %s %s %d %d :seconds idle, signon timez :End of WHOIS list.N) rwrh RPL_WHOISUSERRPL_WHOISSERVERRPL_WHOISOPERATOR RPL_WHOISIDLERPL_WHOISCHANNELSr|RPL_ENDOFWHOIS) rJrnickrrhrr serverInfooperidlesignOnrgs rwhoisz IRC.whoissh }}mT48X W  }}otT6: O   MM=="3T4A  ;}}mT4vF G  }}/tSXXh=O Q  }}ndD : rc2|jd|d|y)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)rJrwheres rr|zIRC.joins #fUG,-rcl|r|jd|d|d|y|jd|d|y)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)rJrrreasons rpartzIRC.parts?  MMAcU&r&: ; MMAcU&0 1rc|jd|jdtd|d|d|ddj| y)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. r&r'N)rwrhRPL_CHANNELMODEISr|)rJrrmoder1s r channelModezIRC.channelModes0 }}/wchhtn V r)NNrM)rrrr!rrhrerr8rUrlrwrrrrrrrrrrrrrrrrr|rrrrrrdrdsFH"Hhsm"- # D-^$$ I &840;N"C*>"K@ 4' R) VL \ .2( rrdceZdZdZdZdZeddZedZedZ edZ ed Z dd Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ y) ServerSupportedFeaturesz Handle ISUPPORT messages. Feature names match those in the ISUPPORT RFC draft identically. Information regarding the specifics of ISUPPORT was gleaned from . isupportc rdtddd|jd|jgdd|_y)Nz#& z(ovh)@+%)br$lkr$) CHANNELLEN CHANTYPESMODESNICKLENPREFIX CHANMODES)tuple_parsePrefixParam_parseChanModesParam _featuresrks r__init__z ServerSupportedFeatures.__init__&s:t,,Z8 223FG  rNc<dfd}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)} c|SrMr)xs rz9ServerSupportedFeatures._splitParamArgs..Jsqrc3pKD],}d|vr|dz }|jdd\}}||f.yw)Nr&r%)r*)raarr[valueProcessors r_parsez7ServerSupportedFeatures._splitParamArgs.._parseLsK +e#SLE{{3*1***  +s36)r})clsr[rrs `` r_splitParamArgsz'ServerSupportedFeatures._splitParamArgs4s#*  !(N +FH~rcFfd}dvrSdj|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} c3Kjd}|jd|D])}|dd|dd}} t|d}t ||z+y#t$rtd|wxYww)N\xrrzInvalid hex octet: )r*r-r=r?chr)partsr.octetrestr@s r _unescapez>ServerSupportedFeatures._unescapeParamValue.._unescape`sKK&E))A,  (eQqrUtFrNE%j4''  ("F$':5)%DEEFs4A2 AA2A//A2rr$)r|)rr@rs ` r_unescapeParamValuez+ServerSupportedFeatures._unescapeParamValueUs( (  Lwwy{##rcd|vr|dz }|jdd\}}||jdDcgc]}|j|c}fScc}w)z Split an ISUPPORT parameter. @type param: C{str} @rtype: C{(str, list)} @return: C{(key, arguments)} rr%,)r*r )rrakeyr@vs r _splitParamz#ServerSupportedFeatures._splitParampsV e  SLE[[a( US9IJAS,,Q/JJJJsAc|sy|ddk7rd|vr td|jdd\}}t|tt |}|dd}t t||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*ziprangerWdict)rr/rZsymbolss rr z)ServerSupportedFeatures._parsePrefixParamso !9 6 19: :c1-wguS\23ab Cw'((rcd}t|t|kDr"tdt|t|fztd||}t|S)z Parse the ISUPPORT "CHANMODES" parameter. See L{isupport_CHANMODES} for a detailed explanation of this parameter. ) addressModesrasetParamnoParamz9Expecting a maximum of %d channel mode parameters, got %dc||xsdfS)Nr$r)r#r@s rrz>ServerSupportedFeatures._parseChanModesParam..sU[b'9r)rWr?mapr+)rJr[rrs rr z,ServerSupportedFeatures._parseChanModesParamsZA v;U #Ku:s6{+, 95&IE{rc:|jj||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 )r get)rJfeaturerAs r getFeaturez"ServerSupportedFeatures.getFeatures ~~!!'733rc(|j|duS)z[ Determine whether a feature is supported or not. @rtype: C{bool} N)r6)rJr5s r hasFeaturez"ServerSupportedFeatures.hasFeatures w't33rc|D]f}|j|\}}|jdr |jj|dddH|j |||j|<hy)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% startswithr r-rT)rJr[rar#r@s rparsezServerSupportedFeatures.parsesh @E))%0JC~~c"""3qr7D1&*mmC&?s#  @rct|S)z- Unknown ISUPPORT parameter. r)rJr2r[s risupport_unknownz(ServerSupportedFeatures.isupport_unknownsV}rc.|j|tS)zJ The maximum number of each channel type a user may join. rrBrJr[s risupport_CHANLIMITz*ServerSupportedFeatures.isupport_CHANLIMITs##FM::rcf |j|S#t$r|jdcYSwxYw)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)r r?r6rAs risupport_CHANMODESz*ServerSupportedFeatures.isupport_CHANMODESs6$ 0,,V4 4 0??;/ / 0s 00c>t|d|jdS)zG Maximum length of a channel name a client may create. rrrBr6rAs risupport_CHANNELLENz+ServerSupportedFeatures.isupport_CHANNELLENsVAY (EFFrct|dS)z) Valid channel prefixes. rr=rAs risupport_CHANTYPESz*ServerSupportedFeatures.isupport_CHANTYPESsVAYrc|dxsdS)z Mode character for "ban exceptions". The presence of this parameter indicates that the server supports this functionality. rerrAs risupport_EXCEPTSz(ServerSupportedFeatures.isupport_EXCEPTSayCrc$|j|S)z Safe channel identifiers. The presence of this parameter indicates that the server supports this functionality. )rrAs risupport_IDCHANz'ServerSupportedFeatures.isupport_IDCHANs##F++rc|dxsdS)z Mode character for "invite exceptions". The presence of this parameter indicates that the server supports this functionality. rIrrAs risupport_INVEXz&ServerSupportedFeatures.isupport_INVEXrMrct|dS)zH Maximum length of a kick message a client may provide. rrBrAs risupport_KICKLENz(ServerSupportedFeatures.isupport_KICKLENVAY''rc.|j|tS)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@rAs risupport_MAXLISTz(ServerSupportedFeatures.isupport_MAXLIST s ##FM::rct|dS)z Maximum number of modes accepting parameters that may be sent, by a client, in a single MODE command. rrTrAs risupport_MODESz&ServerSupportedFeatures.isupport_MODES(s VAY''rc |dS)z# IRC network name. rrrAs risupport_NETWORKz(ServerSupportedFeatures.isupport_NETWORK/sayrc>t|d|jdS)zB Maximum length of a nickname the client may use. rrrFrAs risupport_NICKLENz(ServerSupportedFeatures.isupport_NICKLEN5sVAY (BCCrcl |j|dS#t$r|jdcYSwxYw)zQ Mapping of channel modes that clients may have to status flags. rr)r r?r6rAs risupport_PREFIXz'ServerSupportedFeatures.isupport_PREFIX;s: -))&)4 4 -??8, , -s 33cy)z Flag indicating that a client may request a LIST without being disconnected due to the large amount of data generated. TrrAs risupport_SAFELISTz)ServerSupportedFeatures.isupport_SAFELISTDs rc |dS)zv The server supports sending messages to only to clients on a channel with a specific status. rrrAs risupport_STATUSMSGz*ServerSupportedFeatures.isupport_STATUSMSGKs ayrc@t|j|tS)zh Maximum number of targets allowable for commands that accept multiple targets. )r+rrBrAs risupport_TARGMAXz(ServerSupportedFeatures.isupport_TARGMAXRs D((?@@rct|dS)z< Maximum length of a topic that may be set. rrTrAs risupport_TOPICLENz)ServerSupportedFeatures.isupport_TOPICLENYrVrrM)!rrrr!r/r  classmethodrr r%r r r6r8r;r>rBrDrGrIrLrOrRrUrXrZr\r^r`rbrdrfrhrrrrrsF  @$$4 K K))*  4$4@" ; 0.G   , ( ;( D -A(rrcleZdZdZdZdZdZdZdZdZ dZ dZ dZ dZ dZdZdZdZdZdZdZdZdZdZd Zd Zd ZdZd Zd ZdZdZdZ dZ!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.dZ/d Z0d!Z1d"Z2d#Z3d$Z4d%Z5d&Z6d'Z7d(Z8d)Z9d*Z:d+Z;d,Zdd/Z?dd0Z@dd1ZAe@ZBd2ZCdd3ZDdd4ZEdd5ZFd6ZGdd7ZHdd8ZIdd9ZJdd:ZKd;ZLdd<ZMdd=ZNd>ZOdd?ZPd@ZQdZRdAZSddBZTdCZUdDZVdEZWdFZXdGZYdHZZdIZ[dJZ\dKZ]dLZ^dMZ_dNZ`dOZadPZbdQZcdRZddSZedTZfdUZgdVZhdWZidXZjdYZkdZZld[Zmd\Znd]Zod^Zpd_Zqd`ZrdaZsdbZtdcZuddZvdeZwdfZxdgZydhZzdiZ{djZ|dkZ}dlZ~dmZdnZdoZdpZdqZdrZdsZdtZduZdvZdwZdxZdyZdzZd{Zd|Zd}Zd~ZdZdZdZdZdZdZdZy) 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$ defaultnickxct|}t|tr|jd}|dz }tj j ||S)Nro )rrrr8rsr LineReceiverrw)rJr: quoteLines r_reallySendLinezIRCClient._reallySendLinesHTN i %!((1IU !!**4;;rc|j|j|y|jj||js|j yyrM)lineRatert_queuer,_queueEmptying _sendLinerJr:s rrwzIRCClient.sendLinesD ==   & KK  t $&& 'rc|jrZ|j|jjdtj|j |j |_yd|_y)Nr)rwrtr-r callLaterrvryrxrks rryzIRCClient._sendLinesI ;;  !3 4")"3"3DMM4>>"RD "&D rcdtjj|||jyrM)r rrconnectionLost stopHeartbeatrJrs rr~zIRCClient.connectionLosts$ ))$7 rc@tj|jS)z6 Create the heartbeat L{LoopingCall}. )r LoopingCall_sendHeartbeatrks r_createHeartbeatzIRCClient._createHeartbeats 3 344rc@|jd|jzy)zR Send a I{PING} message to the IRC server as a form of keepalive. zPING Nrrks rrzIRCClient._sendHeartbeats g -.rc`|j"|jjd|_yy)zy Stop sending I{PING} messages to keep the connection to the server alive. @since: 11.1 N) _heartbeatstoprks rrzIRCClient.stopHeartbeats* ?? & OO ""DO 'rc|j|jy|j|_|jj |jdy)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)rheartbeatIntervalrrstartrks rstartHeartbeatzIRCClient.startHeartbeat sL   ! ! ) //1 d44%@rcy)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)rJwhens rcreatedzIRCClient.createdrcy)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. NrrJrs ryourHostzIRCClient.yourHost&rrcy)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)rJ servernameversionumodescmodess rmyInfozIRCClient.myInfo.rrcy)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. Nrrs r luserClientzIRCClient.luserClient?rrcy)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. Nrrs rbouncezIRCClient.bounceHrrcy)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)rJoptionss rrzIRCClient.isupportQrrcy)zl Called with the number of channels existent on the server. @type channels: C{int} Nr)rJrgs r luserChannelszIRCClient.luserChannelsZrrcy)zc Called with the number of ops logged on to the server. @type ops: C{int} Nr)rJopss rluserOpzIRCClient.luserOparrcy)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. Nrrs rluserMezIRCClient.luserMehrrcy)zN Called when I have a message from a user to me or a channel. NrrJrrrs rrzIRCClient.privmsgs rcy)z Called when I finish joining a channel. channel has the starting character (C{'#'}, C{'&'}, C{'!'}, or C{'+'}) intact. NrrJrs rjoinedzIRCClient.joinedyrrcy)z Called when I have left a channel. channel has the starting character (C{'#'}, C{'&'}, C{'!'}, or C{'+'}) intact. Nrrs rleftzIRCClient.leftrrcy)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. Nrrs rnoticedzIRCClient.noticedrrcy)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)rJrrsetrZr1s r modeChangedzIRCClient.modeChangedrrcy)z? Called with the results of a CTCP PING query. Nr)rJrsecss rpongzIRCClient.pongrrcy)zE Called after successfully signing on to the server. Nrrks rsignedOnzIRCClient.signedOnrrcy)z9 Called when I am kicked from a channel. Nr)rJrkickerrs r kickedFromzIRCClient.kickedFromrrc||_y)z7 Called when my nick has been changed. N)r)rJrs r nickChangedzIRCClient.nickChangeds  rcy)zC Called when I see another user joining a channel. NrrJrrs r userJoinedzIRCClient.userJoinedrrcy)zC Called when I see another user leaving a channel. Nrrs ruserLeftzIRCClient.userLeftrrcy)zM Called when I see another user disconnect from the network. Nr)rJr quitMessages ruserQuitzIRCClient.userQuitrrcy)zQ Called when I observe someone else being kicked from a channel. Nr)rJkickeerrrs r userKickedzIRCClient.userKickedrrcy)zJ Called when I see a user perform an ACTION on a channel. NrrJrrrs rrzIRCClient.actionrrcy)zt In channel, user changed the topic to newTopic. Also called when first joining a channel. Nr)rJrrnewTopics r topicUpdatedzIRCClient.topicUpdateds rcy)zD A user changed their name from oldname to newname. Nr)rJoldnamenewnames r userRenamedzIRCClient.userRenamedrrcy)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)rJmotds r receivedMOTDzIRCClient.receivedMOTDs rc|dtvrd|z}|r|jd|d|y|jd|y)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_PREFIXESrw)rJrr#s rr|zIRCClient.join sI 1:- -GmG  MME'!C51 2 MME'+ ,rc|dtvrd|z}|r|jd|d|y|jd|y)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)rJrrs rleavezIRCClient.leavesI 1:- -GmG  MME'"VH5 6 MME'+ ,rc|dtvrd|z}|r|jd|d|d|y|jd|d|y)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)rJrrrs rkickzIRCClient.kick,sU 1:- -GmG  MME'!D6F8< = MME'!D62 3rcR|dtvrd|z}|jd|d|y)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'Nrrs rinvitezIRCClient.inviteAs3 1:- -GmG vQwi01rc|dtvrd|z}|dk7r|jd|d|y|jd|y)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)rJrrs rrzIRCClient.topicPsM 1:- -GmG D= MMF7)2eW5 6 MMF7), -rc|r d|d|}nd|d|}|d||fz}n||d|}n ||d|}|j|y)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)rJchanrrZlimitrmaskr:s rrzIRCClient.modefsw, 4&5'*D4&5'*D  dE]*D  V1TF#D  V1TF#D drcJ|dtvrd|z}|j|||y)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)rr)rJrrr9s rsayz IRCClient.says*" 1:- -GmG '6*rcdjd|jjdzdd|}d}tt |z |z 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)r~ supportedr6MAX_COMMAND_LENGTHrW)rJr2 theoreticalfudges r_safeMaximumLineLengthz IRCClient._safeMaximumLineLengthsP%++ $..++I6 6     !C $44u<005FC1 ] "($/0 '6M#9: &D MM#* % &rc,|jd|||y)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} rNrrJrrr9s rrz IRCClient.msgs, )T7F;rc,|jd|||y)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. @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} rNrrs rrzIRCClient.notices& (D'6:rc,|jd|zy)z Mark this client as away. @type message: C{str} @param message: If specified, the away message. zAWAY :%sNrrJrs rawayzIRCClient.away s j7*+rc$|jy)z( Clear the away status. N)rrks rbackzIRCClient.backs rc`||jd|zy|jd|d|y)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)rJrrs rrzIRCClient.whoiss3 > MM(X- . MMF6(!H:6 7rc|j|jd|jz|j||j||_|jdj |j|||j y)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 {} {} {} :{})passwordrwsetNickrr~realname)rJrrhrs rregisterzIRCClient.register'sk == $ MM)dmm3 4 X == $DM  & & xT]]  rc:||_|jd|zy)z Set this client's nickname. @type nickname: C{str} @param nickname: The nickname to change to. zNICK %sN)_attemptedNickrwrJrs rrzIRCClient.setNick=s' i(*+rc,|jd|zy)z Disconnect from the server @type message: C{str} @param message: If specified, the message to give when quitting the server. zQUIT :%sNrrs rquitzIRCClient.quitGs j7*+rc.|j|d|fgy)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)rJrrs rdescribezIRCClient.describeTs 7h%7$89r c|ji|_|ntjtjztjz}dj t dDcgc]}tj|c}}n t|}tj|j||f<|j|d|fgt|j|jkDr|jjDcgc] \}}||f }}}|jt|j|jz } t | D]}|j||d=yycc}wcc}}w)zA Measure round-trip delay to another IRC client. Nr$r PINGr%)_pingsstring ascii_lettersdigits punctuationr|r*randomchoicer8timer rW _MAX_PINGRINGrsort) rJrtextcharsir#kr$byValueexcesss rpingzIRCClient.pingds/ ;; DK <((6==86;M;MME''rCA6==/CDCd)C#'99; T3K  463-1 t{{ d00 0,0KK,=,=,?@&1a1v@G@ LLN%(:(::F6] /KK 1 . / 1 DAs E.E3ctd)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)rJrfiles rdccSendzIRCClient.dccSend{s" H  rc6|j|dd|||gfgy)z< Send a DCC RESUME request to another user. DCCRESUMENr rJrfileNameport resumePoss r dccResumezIRCClient.dccResume% 458XtY*O"P!QRrc6|j|dd|||gfgy)zT Send a DCC ACCEPT response to clients who have requested a resume. r%ACCEPTNr r's rdccAcceptResumezIRCClient.dccAcceptResumer,rcz|j|j|_|j|jy)zg Called when we try to register or change to a nickname that is already taken. N)alterCollidedNickrrrJr/r[s rirc_ERR_NICKNAMEINUSEzIRCClient.irc_ERR_NICKNAMEINUSEs/ #44T5H5HI T(()rc |dzS)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} rIrrs rr1zIRCClient.alterCollidedNicks#~rcT|js|j|jyy)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) _registeredrerroneousNickFallbackr2s rirc_ERR_ERRONEUSNICKNAMEz"IRCClient.irc_ERR_ERRONEUSNICKNAMEs$ LL33 4 rctd)z6 Called when the login was incorrect. zPassword Incorrect.)rr2s rirc_ERR_PASSWDMISMATCHz IRCClient.irc_ERR_PASSWDMISMATCHs""788rc||_d|_|j|_|j |j y)zK Called when we have received the welcome from the server. TN)rhr6rrrrr2s rirc_RPL_WELCOMEzIRCClient.irc_RPL_WELCOMEs5 ++   rc|jdd}|d}||jk(r|j|y|j||y)z5 Called when a user joins a channel. !rr)N)r*rrrrJr/r[rrs rirc_JOINzIRCClient.irc_JOINsF||C #* 4== KK OOD' *rc|jdd}|d}||jk(r|j|y|j||y)z6 Called when a user leaves a channel. r>rN)r*rrrr?s rirc_PARTzIRCClient.irc_PARTsF||C #) 4== IIg  MM$ (rcV|jdd}|j||dy)z. Called when a user has quit. r>rN)r*rrJr/r[rs rirc_QUITzIRCClient.irc_QUITs)||C # dF1I&rc|d|d|dd}}}|ddvrd|z}||jk(r|j}n|j} t|||\}}|r/t |\}}|j ||ddj |||r0t |\}}|j ||d dj ||yy#t$r+tjdd d j |YywxYw) z5 Parse a server mode change message. rr%rNz-++Tr$FzAAn error occurred while parsing the following MODE message: MODE r') rgetUserModeParamsgetChannelModeParamsrbr)rr|rr err) rJrr[rrZr1r\addedremoveds rirc_MODEzIRCClient.irc_MODEs  &ay&)VABZ 84 %KE dmm #//1J224J O'tZ@NE7 #U v  wbggenfM #W v  wrwwu~vN  GG+.88F+;>  s C1C54C5c2|jd|dzy)z1 Called when some has pinged us. zPONG %sr)Nrr2s rirc_PINGzIRCClient.irc_PING s i&*,-rc|}|d}|d}|sy|dtk(r@t|}|dr|j|||d|dsydj|d}|j |||y)z/ Called when we get a message. rr)Nextendednormalr')X_DELIM ctcpExtract ctcpQueryr|rrJr/r[rrrms r irc_PRIVMSGzIRCClient.irc_PRIVMSGs~)*  1: G$A}tWa m<X;hhq{+G T7G,rc|}|d}|d}|dtk(r@t|}|dr|j|||d|dsydj|d}|j |||y)z3 Called when a user gets a notice. rr)rQrRNr')rSrT ctcpReplyr|rrVs r irc_NOTICEzIRCClient.irc_NOTICE(sx)* 1: G$A}tWa m<X;hhq{+G T7G,rc|jddd}||jk(r|j|dy|j||dy)z< Called when a user changes their nickname. r>r%rN)r*rrrrDs rirc_NICKzIRCClient.irc_NICK<sK||C#A& 4==   VAY '   T6!9 -rc|jdd}|d}|d}|d}|j|jjk(r|j|||y|j ||||y)z> Called when a user is kicked from a channel. r>rr%r)N)r*lowerrrr)rJr/r[rrkickedrs rirc_KICKzIRCClient.irc_KICKFsoc"1%)* <<>T]]002 2 OOGVW 5 OOFGVW =rcf|jdd}|d}|d}|j|||y)z7 Someone in the channel set the topic. r>rr%Nr*rrJr/r[rrnewtopics r irc_TOPICzIRCClient.irc_TOPICTs;||C #)!9 $2rcf|jdd}|d}|d}|j|||y)zt Called when the topic for a channel is initially reported or when it subsequently changes. r>rr%rNrcrds r irc_RPL_TOPICzIRCClient.irc_RPL_TOPIC]s; ||C #)!9 $2rc`|jdd}|d}d}|j|||y)Nr>rr%r$rcrds rirc_RPL_NOTOPICzIRCClient.irc_RPL_NOTOPICgs5||C #) $2rcX|djdr |ddd|d<|dg|_yNr)z- r)r:rr2s rirc_RPL_MOTDSTARTzIRCClient.irc_RPL_MOTDSTARTms4 ":  &ABF2JBZL rc|djdr |ddd|d<|jg|_|jj|dyrl)r:rr,r2s r irc_RPL_MOTDzIRCClient.irc_RPL_MOTDrsN ":  &ABF2J 99 DI $rcL|j}d|_|j|y)z I{RPL_ENDOFMOTD} indicates the end of the message of the day messages. Deliver the accumulated lines to C{receivedMOTD}. N)rr)rJr/r[rs rirc_RPL_ENDOFMOTDzIRCClient.irc_RPL_ENDOFMOTDys" yy  $rc,|j|dyNr%)rr2s rirc_RPL_CREATEDzIRCClient.irc_RPL_CREATED VAYrc,|j|dyrs)rr2s rirc_RPL_YOURHOSTzIRCClient.irc_RPL_YOURHOSTs fQi rc|djdd}t|dkr |jdt|dkr |j|y)Nr%r)r*rWr,r)rJr/r[rs rirc_RPL_MYINFOzIRCClient.irc_RPL_MYINFOsHaytQ'$i!m KK $i!m Trc,|j|dyrs)rr2s rirc_RPL_BOUNCEzIRCClient.irc_RPL_BOUNCEs F1Ircf|dd}|jj||j|y)Nr%r))rr;r)rJr/r[r1s rirc_RPL_ISUPPORTzIRCClient.irc_RPL_ISUPPORTs-a| T" drc,|j|dyrs)rr2s rirc_RPL_LUSERCLIENTzIRCClient.irc_RPL_LUSERCLIENTs #rc^ |jt|dy#t$rYywxYwrs)rr=r?r2s rirc_RPL_LUSEROPzIRCClient.irc_RPL_LUSEROPs-  LLVAY (     ,,c^ |jt|dy#t$rYywxYwrs)rr=r?r2s rirc_RPL_LUSERCHANNELSzIRCClient.irc_RPL_LUSERCHANNELSs/    s6!9~ .   rc,|j|dyrs)rr2s rirc_RPL_LUSERMEzIRCClient.irc_RPL_LUSERMErurcyrMrrs rrzIRCClient.irc_unknown rct}|D]K\}}t|d|zd}||vr!| ||||n|j|||||j|My)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)rrNctcpUnknownQueryadd)rJrrmessagesseenrrrSs rrUzIRCClient.ctcpQuerysiu! ICT>C#7>F$%4$/))$dC HHSM rc@tjd|d|d|y)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 rrJrrrrs rrzIRCClient.ctcpUnknownQuerys$ *4("SG1THEFrc*|j|||yrM)rrs rctcpQuery_ACTIONzIRCClient.ctcpQuery_ACTIONs D'4(rcV|jdd}|j|d|fgy)Nr>rrr* ctcpMakeReplyrJrrrrs rctcpQuery_PINGzIRCClient.ctcpQuery_PINGs+zz#q! 464.!12rc||jd|d|d|jsyt|jr|j}nt|j}|j dd}|j |d|fgy)NWhy did  send 'z' with a FINGER query?r>rFINGER) quirkyMessage fingerReplycallabler8r*r)rJrrrreplyrs rctcpQuery_FINGERzIRCClient.ctcpQuery_FINGERs     $wtfrVERSIONr&r$)r versionNamer*r versionNum versionEnvrs rctcpQuery_VERSIONzIRCClient.ctcpQuery_VERSIONs     $wtfrSOURCE)rN)r sourceURLr*rrs rctcpQuery_SOURCEzIRCClient.ctcpQuery_SOURCEse     $wtf>::c?1%D   tx&@BR%S T rc||jd|d|d|jr4|jdd}|j|d|jfgyy)Nrrz' with a USERINFO query?r>rUSERINFO)ruserinfor*rrs rctcpQuery_USERINFOzIRCClient.ctcpQuery_USERINFO s`     $wtfr ctcpQuery_ CLIENTINFOr'NERRMSGz CLIENTINFO z :Unknown query ''r!r$)r*sortedr prefixedMethodNames __class__rr|rN) rJrrrrrr1rSdocs rctcpQuery_CLIENTINFOzIRCClient.ctcpQuery_CLIENTINFO szz#q!766t~~|TUE   t|SXXe_&E%F G::rrz%s :No error has occurred.rrs rctcpQuery_ERRMSGzIRCClient.ctcpQuery_ERRMSG* s4zz#q! 48-ID-P"Q!RSrc ||jd|d|d|jdd}|j|ddtjtj tjzfgy)Nrrz' with a TIME query?r>rTIMEz:%s)rr*rrasctime localtimers rctcpQuery_TIMEzIRCClient.ctcpQuery_TIME0 sp     $wtfrzDCC z :Unknown DCC type 'rz offered unknown DCC type )r*rrN dcc_sessionsrWrr)rJrrrdcctypehandlerrs r ctcpQuery_DCCzIRCClient.ctcpQuery_DCC8 s **T1%a(..0$ 0$7   ($&!G q(*+D D'4 (::c?1%D   d4&(th GH H$(!H!7D!'* At9D t9> 47| tWdHdDA A"6th ?@ @ A  s B#B#B # B/.B/ctj|}t|dkrtd||dd\}}} t |}t |}|j ||||y#t $rYywxYw)Nrz#malformed DCC SEND ACCEPT request: )rr*rWrr=r?dccDoAcceptResumerJrrrrr)r*s r dcc_ACCEPTzIRCClient.dcc_ACCEPTo s{{4  t9q="EdX NO O&*2Ah#4 t9DII tXtY?   A'' A32A3ctj|}t|dkrtd||dd\}}} t |}t |}|j ||||y#t $rYywxYw)Nrz#malformed DCC SEND RESUME request: )rr*rWrr=r? dccDoResumers r dcc_RESUMEzIRCClient.dcc_RESUME| s{{4  t9q="EdX NO O&*2Ah#4 t9DII xy9   rctj|}t|dkrtd||dd\}}}t |} t |}|j|||||y#t $rtd|wxYw)Nrzmalformed DCC CHAT request: r)rr*rWrrr=r? dccDoChat)rJrrrrrr)s rdcc_CHATzIRCClient.dcc_CHAT s{{4  t9q=">th GH H$(!H!7D!'* At9D tWgtT: A"6th ?@ @ As  A((Bcy)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)rJrrr)r(rrs rrzIRCClient.dccDoSend rrcy)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} NrrJrr"r)r*s rrzIRCClient.dccDoResume & rcy)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} Nrrs rrzIRCClient.dccDoAcceptResume rrcyrMr)rJrrrr)rs rrzIRCClient.dccDoChat rrc:|j|t|y)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 ctcpStringifyrJrrs rrzIRCClient.ctcpMakeReply s D-12rc:|j|t|y)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)rrrs rr zIRCClient.ctcpMakeQuery s }X./rc|D]?}t|d|dzd}|r||||d&|j|||d|dAy)z@ Dispatch method for any CTCP replies received. z ctcpReply_%srNr%)rNctcpUnknownReply)rJrrrrWrSs rrZzIRCClient.ctcpReply s[ AAT>AaD#8$?FtWad+%%dGQqT1Q4@  Arc|jddd}|jr||f|jvrtd|d||j||f}|j|t j|z y)Nr>r%rzBogus PING response from r)r*rrrr)rJrrrrt0s rctcpReply_PINGzIRCClient.ctcpReply_PING sqzz#q!!$ $T[[!@";D6D6 JK K [[$ & $ b()rc Btjd|d|d|dy)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'r5Nrrs rrzIRCClient.ctcpUnknownReply s&( *4&3%qbABrc tj|tjdjtj|||y)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 rr| tracebackformat_exception)rJr:excTypeexcValuetbs r badMessagezIRCClient.badMessage/ s3$    227HbIJKrc4tj|dzy)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} r5NrrJr.s rrzIRCClient.quirkyMessageD s Drct|_g|_|jr|j |j yyrM)rrrw performLoginrrrks rrlzIRCClient.connectionMadeP s102    MM$-- ( rct|tr|jd}|jdd}tj j ||y)Nrorqr)rrr8rsrr rrrrJrs rrzIRCClient.dataReceivedV s@ dC ;;w'D||E3' ''d3rcFttk7r!t|tr|jd}t |} t |\}}}|t vr t |}|j|||y#t$r(|j|gtjYywxYwrn) rr8rrr lowDequoter3numeric_to_symbolicrrrsysexc_info)rJr:r/r2r[s r lineReceivedzIRCClient.lineReceived\ s C 2 3s3A//.B B c ddgS)z Get user modes that require parameters for correct parsing. @rtype: C{[str, str]} @return: C{[add, remove]} r$rrks rrHzIRCClient.getUserModeParamsj s Bxrcddg}|jjdi}dj|jx|d<|d<|jjd}|_|dxx|j ddz cc<|dxx|j ddz cc<|d|d<|dxx|j ddz cc<|S) z Get channel modes that require parameters for correct parsing. @rtype: C{[str, str]} @return: C{[add, remove]} r$rrr%rr.rar/)rr6r|keysr4)rJr[prefixes chanmodess rrIzIRCClient.getChannelModeParamss sb>>,,Xr: "  88q F1INN--k:  1I~r: :I 1Iw3 3Iq F1I 1Iz26 6I rct|d|zd} | |||y|j|||y#t$rtjYywxYwrrrs rrzIRCClient.handleCommand rrcN|jj}d|d<d|d<|S)Nrr)__dict__copy)rJdcts r __getstate__zIRCClient.__getstate__ s,mm  ""NH  rrM)NNN)r$)foobar)rrrr!rhrrrrrrrrrrr dcc_destdirrrrvrwrx delimiter __pychecker__r6rr7rrrtrwryr~rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr|rrrrrrrrrrrrrrrrrr rrr r#r+r/r3r1r8r:r<r@rBrErMrOrXr[r]rarfrhrjrmrorqrtrwrzr|r~rrrrrrUrrrrrrrrrrrrrrrrrrrrr rZrrrrrlrrrHrIrr rrrrkrk`s ObH DHHHHHKKJJ5IKLLH FNI7MKN)J<!'5 / # A(   "            6            -"-"4& D 2., D+*=.&&P<0;*, 8 ,, , :FM/.  S S*  59  + )'OB. -0-(. >333 ! %  ! $    "G)3 6* UD B0 @ : ;$ 4 * * 30 A*C2L*) 4 3*0rrkcd|vr |S t|}|dz dz|dz dz|dz dz|dzf}djtt|}|S#t$rt d|wxYw)NrrzIndecipherable address )r=r|r2r8r?r)rs rrr s g~  N 2'lG B$&B$&A%$ G hhs301G N G"9' EF F Gs AA(c"eZdZdZdZddZdZy)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} rc&||_|dk7|_y)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)rJ resumeOffsets rr zDccFileReceiveBasic.__init__ s *"a' rc|jt|z|_|jjt j d|jy)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)rrWrtrustructpackrs rrz DccFileReceiveBasic.dataReceived s>"//#d); V[[t/A/ABCrN)r)rrrr!rr rrrrrr s M( DrrcBeZdZdZdZdZdZdZdZdZ dZ dZ dZ d Z y) 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} iNrcHt|turt||_yyrM)typer8openr"rJr"s rr zDccSendProtocol.__init__ s : T DI rc2d|_|jyrs) connected sendBlockrks rrlzDccSendProtocol.connectionMade s rctjd|}||jkry||jkDr|jj y|j y)Nz!I)runpack bytesSentrtloseConnectionr$)rJr bytesShesGots rrzDccSendProtocol.dataReceived sP}}T40 $.. (  DNN * NN ) ) +  rc|jj|j}|r9|jj ||j t |z|_y|jjd|_yrs) r"read blocksizertrur'rWr( completed)rJblocks rr$zDccSendProtocol.sendBlock sZ t~~.  NN  '!^^c%j8DN NN ) ) +DNrctd|_t|jdr|jjyy)Nrclose)r#hasattrr"r0rs rr~zDccSendProtocol.connectionLost s* 499g & IIOO  'r)rrrr!r,r"r'r-r#r rlrr$r~rrrrr s;.I DIII#&rrceZdZeZdZdZy)DccSendFactoryc||_yrM)r"r!s rr zDccSendFactory.__init__) s  rcJ|j|j}||_|SrM)rr"factory)rJ connectionps r buildProtocolzDccSendFactory.buildProtocol, s MM$)) $ rN)rrrrrr r9rrrr3r3& sHrr3c\d}t|dr;|j} tj|}|tj }|St|drAtj|jr" tj|j}|St|drDt|dr8 |jdd|j}|jdd|S|S#t $rYwxYw#t $rYlwxYw#|jddwxYw#t $rY|SwxYw)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}. NfilenorOseektellrr) r1r;osfstatstatST_SIZErrexistsrOgetsizer<r=)r"rr;stat_s rfileSizerE2 s DtX HHV$E&DKtVTYY!7 << *DKtVv!6   !Qyy{ !QK K3       !Q   K  sG(C)6C81"DD) C54C58 DDDD D+*D+czeZdZdZdZej dej dzZdZ dZ dZ ddZ dZ dZy) 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. NasciircN||_|r||_|jd|_yy)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 remotePartyrJrJrKs rr zDccChat.__init__t s+ &DN#~~a0D  rc|j|z|_|jjt}|j|_|D]$}|dtk(r|dd}|j |&y)Nr))rr*rqr-rpr)rJrrr:s rrzDccChat.dataReceived shkkD(  !!"%iik  $DBx2~CRy   d # $rctjd|jd||jj |j|jj |y)Nz DCC CHAT )r rrLrJrrrzs rrzDccChat.lineReceived sH )D,,-Rv67 D,,dkk.B.BDIrrM)rrrr!rKrprsNLr rJrLrr rrrrrrGrG_ sI I '"RYYw%77I FK F1" $JrrGc,eZdZeZdZdZdZdZdZ y)DccChatFactoryFc ||_||_yrMrJrKrMs rr zDccChatFactory.__init__ s "rcb|j|j|j}||_|S)NrT)rrJrKr6)rJaddrr8s rr9zDccChatFactory.buildProtocol s( MMM G rcN|jjj|yrMrJrremoverJunused_connector unused_reasons rclientConnectionFailedz%DccChatFactory.clientConnectionFailed    ''-rcN|jjj|yrMrXrZs rclientConnectionLostz#DccChatFactory.clientConnectionLost r^rN) rrrrGrnoisyr r9r]r`rrrrRrR s H E# ..rrRc|}|j}t|dkr|S|dd\}}}}d|vrnF t|}|dz dz|dz dz|dz dz|dzf}djt t |}|dk(r=|}d }t|d k\r t|d}d |fz}d j||||} | S|d k(r d|d|} | S|} | S#t $rY`wxYw#t $rYCwxYw)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. ryNrrrrrSENDr$z of size %d bytesz(SEND for file '{}'{} at host {}, port {}CHATzCHAT for host z, port )r*rWr=r|r2r8r?r~) r orig_datarargrr)rsize_txtrdcc_texts r dccDescriberj sSI :: 47|.$8>DD       O F #G9GD6: O OC   &  s# C C CC C('C(ceZdZUdZdZdZdZdZdZe e e d<dZ ddZ d Zd Zd Zd Zd ZdZdefdZdefdZy)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)rrNfromUserctj||||_||_||_||_|r||_|j d|_yy)N)rr)rr rdestDirrE _resumeOffsetrKrn)rJrrErKrprs rr zDccFileReceive.__init__ sS $$T $E     ) &DN NN1-DM rcrtj|sttjd|tj |sttj d|tj|tjtjzsttjd|||_ y)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) rrBOSErrorerrnoENOENTisdirENOTDIRr>accessX_OKW_OKEACCESrp)rJ directorys r set_directoryzDccFileReceive.set_directory s{{9%%,,(EyQ Qzz)$ S  yyBGGbgg$56 JI ! rc||_y)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)r)rJrs r set_filenamezDccFileReceive.set_filename7 s ! rc||_y)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)rJbooleans r set_overwritezDccFileReceive.set_overwriteB s !rctjtj|j|j}tj |}|j r|rt|d|_|jj|j|jjtjd|j|jjfzy|j r|stt j"d||j$s|st|d|_ytt j&d|)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.)rabspathr|rprrBrr r"r<rqtruncater rr=rsrtrurEEXIST)rJdstrBs rrlzDccFileReceive.connectionMadeN sll499T\\4==ABS! ;;6S%(DI IINN4-- . II   GGB99diinn./0 [[ M  ^^6S$DI W rcf|jj|tj||yrM)r"rurrrs rrzDccFileReceive.dataReceivedj s" ((t4rcd|_|d}|jdkDrtd||j|jfz}|j|jk(rnO|j|jkrd||j|jz fz}n|d}nd||jfz}t|drN|d|jj d }t|jd r|jj y y y ) 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 receivedr"z and written to z. r0N)r#rErr1r"rOr0)rJrlogmsgs rr~zDccFileReceive.connectionLostp s6" ==1 /"" 3F !!T]]2##dmm37MMD$6$66; #8#?@,8J8J/KKF 4 x/ /?sCFtyy'* !+ !rreturnc|jsdt|ddS|j}|Jt|j }|j |j d|d}d|j d|}|S)Nz&z (r(zDCC transfer of 'z' from )r#idrtr8getPeerrnr)rJrtfrom_r.s r__str__zDccFileReceive.__str__ s~~;BtHQ> LL $    LL ( ?? &$//*EA*Vt000*W111 LL! $bggc#uo...r)FFFFNN)rrrr!compareAttributesr rrrrrr s-   % /rrc6tfdt||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}. c||SrMr)ryfs rrz_foldr..X s qAwr)rreversed)rzxss` r_foldrrJ s & a 88rc VeZdZdZdZedededede diZ dZ d Z d Z d Zd Zd ZdZy)_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. staterrcolorrrchd|_d|_t|_d|_d|_d|_y)NTEXTr$)r_bufferr_attrs_resultrrrks rr z_FormattingParser.__init__ s.  e  rc<|j|j|y)zs Handle input. @type ch: C{str} @param ch: A single character of input to process N)rTr)rJr`s rprocessz_FormattingParser.process s djj"%rc||j|jtj|_|jS)z Flush the current buffer and return the final parsed result. @return: Structured text and attributes. )emitr attributesrRrks rcompletez_FormattingParser.complete s. << %,,DL||rc|jr|jDcgc]}tt|}}|j t d|j |jg|s|jtj|j|jttj|j|}|j||_n|j|d|_yycc}w)z? Add the currently parsed input to the result. Nr$)rrrNrextendfilterrrr,rRroperatorgetitemr-r)rJrOrattrs rrz_FormattingParser.emit s <<;?;;G4WZ.GEG LLt&HI J Z../ LL &(**EIIK?D||##  T"DL GsC6cB|jj|}|dk(r|jd|_y||xj|z c_y|j|dk(rt |_dx|_|_y|j j|gy)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) _formatCodesr4rrrrrrrsymmetric_difference_update)rJr` formatNames r state_TEXTz_FormattingParser.state_TEXT s&&**2.  IIK+DJ! "  &"%%DK8<> rc@tj|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) formatteds rassembleFormattedTextr sh  " "9.>.@BV WWrcht|}tj|tjS)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 )rr rDefaultFormattingState)rrs rstripFormattingrWs*#4(I  " "9o.T.T.V WWrr%cg}g}||d}|jt}d}|rI|r!|j|jdn |j|jd| }|rIt t d||ddt t d||ddt t t||ddtt|D]=}||jtd}|d}t|dkDr|d} nd} || f||<?|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. )rQrRrNr%) r*rSr,r-r}rr2 ctcpDequoter*rWSPC) rextended_messagesnormal_messagesretvalroddrrWrrs rrTrTlsO+ GF}}W%H C    $ $X\\!_ 5  " "8<<? 3g  t-> ?@afT?;.subD NN Q  a A A   ++)r mEscape_rerr.rs rrr$1 >>#q !!rrrcZttfD]}|j|t|}|SrM)X_QUOTErSr xQuoteTabler s r ctcpQuoters/w ) IIaQ () Hrc@tfd}tj||S)Nc\|jd} ||}|S#t$r|}Y|SwxYwrsr )r xDequoteTabler.s rrzctcpDequote..subrr)r xEscape_rerrs rrrrrc@g}|D]v\}}|r8t|ts djtt|}|d|}n t|}t |}t |t }|j|xdj|}|S#t$rY_wxYw)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$)rrr8r|r2r>rrSr,)rcoded_messagesrrrWr:s rrrsN! T dC(88CTN3D%qACA aLis7) $a ! 77> "D K!sB BB001002003004005010302303301305306311312313317318319314369321322323325324331332341342346347348349351352315353366364365367368371374375372376381382383391392393394395200201202203204205206207208209210261262211212219242243221234235251252253254255256257258259263401402403404405406407408409411412413414415416421422423424431432433436437441442443444445446451461462463464465466467471472473474475476477478481482483484485491492501502 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)PrM))r$r$)r!rtrr>rrerrir@rrrr6rr functoolsrrtypingrtwisted.internetrrrtwisted.persistedr twisted.protocolsr twisted.pythonr r r rrrprPrqrrr Exceptionrrr?rr3r*rB RuntimeErrorrDrFrbProtocolrdrrrrkr EphemeralrrFactoryr3rErG ClientFactoryrRrjrlrrrrrr+r)r*rrrCharacterAttributesMixinrr_FormattingStateMixinrrrrrrrSrTrr rrr$compileescapeDOTALLrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr r r r r rrrrrrrrrrrrrrrrrrr r!r"r#r$r%r&r'r(r)r*r+r,symbolic_to_numericr)rOcodes00rrBs @   44$#88 !fYY $i I  ) * !6X&  | %*%*P7t[ (  [ |C(5C(L D""DN2& D(++V-=-= DFFh'')9)9FR X%% *Z4Je  &"2"24Jn.X++.(8v{({|    $ b ' 22=1B1B1DE:4D$JE=U?CC=U@" # >/<<>/B9"o/od&4Xn X$ d)%T d)3# #  Ww       DAqM!B%q RZZ9299W-.a0")) <  " # w'0AB     DAqM!B%RZZ9299W-.a0")) <  "<                                                         M5MEM5M% M E M % MEMMM%M5MUMuMMUM e!M"#M$e%M&u'M(U)M*+M,5-M.E/M01M253M45M6E7M8U9M:e;M<5=M>e?M@5AMB5CMDEEMFEGMHEIMJeKMLMMNeOMP5QMRSMTUMVUWMXUYMZ[M\U]M^U_M`UaMbcMdeMfegMhiMjekMl5mMnUoMp5qMr%sMtuMvwMxUyMzu{M|}M~M@eAMB%CMDEEMFEGMHIMJKMLeMMNuOMPeQMR5SMTEUMVuWMXuYMZ5[M\]M^_M`5aMb5cMdUeMfUgMheiMjEkMlemMnoMpqMrEsMt5uMvwMx%yMz{M|E}M~uM@AMBeCMDEMF5GMH%IMJ%KML%MMNuOMPUQMR5SMTEUMVWMXYMZ5[M\E]M^_M`aMb5cMd%eMfgMhiMj%kMlEmMnoMp%qMrEsMt5uMv%wMxyMzu{M|%}M~%M@AMBuCMDuEMFuGMHIMJEKML%MMNeOMPUQMR!YM^  % % 'DAqeFs" Y4