-- **************************************************************************** -- Handler for numeric replies and scripting commands -- Event method is the entry method for messages -- -- **************************************************************************** ::CLASS NumHandler ::METHOD Init expose client results use arg client results = .array~new ::METHOD Event use arg message do methodname over .local['IRC.EVENT.NUMRPL.'message~number] if self~hasmethod(methodname) then do .message~new(self,methodname,"I",message)~~send return end end ::METHOD RunMethod use arg name, mode, arguments self~start(name, mode, arguments) ::METHOD eventid PRIVATE expose results i = 1 do while results[i] \= .nil i = i + 1 end return i ::METHOD lastevent PRIVATE expose results i = 1 do until results[i] = .nil i = i + 1 end return i -- ================================= -- SCRIPTING METHODS -- ================================= ::METHOD Say expose client use arg target, text text=text~strip if text~length = 0 then return client~writeln("PRIVMSG" target~Makestring ':'text) -- make it possible for the client to track own PRIVMSG's -- client~event(.local['IRC.EVENT.SELFSAY'],.array~of(client~nick,target,text)) ::METHOD Notice expose client use arg target, text text=text~strip if text~length = 0 then return client~writeln("NOTICE" target~makestring ':'text) -- make it possible for the client to track own NOTICE's -- client~event(.local['IRC.EVENT.SELFNOTICE'],.array~of(client~nick,target,text)) ::METHOD CTCPReply expose client use arg target, type, text text=text~strip; type = type~strip if type~length = 0 then return marker = '1'~d2c client~writeln('NOTICE' target~makestring ':'marker||type||' '||text||marker) -- client~event(.local['IRC.EVENT.CTCPREPLY'],.array~of(target,type,text)) -- ================ WHOIS ================================= ::METHOD WhoIs expose results whois_done client parse arg nick, waittime client~writeln('WHOIS' nick) eventid = self~eventid whois_done = .false results[eventid] = .array~of("WHOIS",IRCUpper(nick~strip),.directory~new) if \datatype(waittime,'N') then waittime = .local['IRC.TIMEOUT.SCRIPTS'] timeoutalarm = .alarm~new(waittime, .message~new(self, 'WHOISCANCEL')) guard off when whois_done timeoutalarm~cancel ret = results[eventid][3] results~remove(eventid) return ret ::METHOD WhoIsCancel expose whois_done whois_done = .true ::METHOD RPL_WHOISUSER expose client users results use arg message parse value message~string with me nick username host '*' ':' description nick = IRCUpper(nick~strip) do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHOIS' & results[i][2] = nick then do results[i][3]['DESCRIPTION'] = description results[i][3]['USERNAME'] = username results[i][3]['HOST'] = HOST leave end end ::METHOD RPL_ENDOFWHOIS expose events results users whois_done use arg message parse value message~string with me nick ':' . nick = IRCUpper(nick~strip) do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHOIS' & results[i][2] = nick then do whois_done = .true leave end end ::METHOD RPL_WHOISCHANNELS expose users results use arg message parse value message~string with me nick ':'channels nick = IRCUpper(nick~strip) do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHOIS' & results[i][2] = nick then if results[i][3]['CHANNELS'] = .nil then results[i][3]['CHANNELS'] = channels else results[i][3]['CHANNELS'] = results[i][3]['CHANNELS'] channels end ::METHOD RPL_WHOISSERVER expose results use arg message parse value message~string with me nick server ':'info nick = IRCUpper(nick~strip) do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHOIS' & results[i][2] = nick then do results[i][3]['SERVER'] = server results[i][3]['SERVERINFO'] = info leave end -- WHOWAS also returns the whois server line else if results[i][1] = 'WHOWAS' then do results[i][2][results[i][2]~items][5] = server results[i][2][results[i][2]~items][6] = info leave end end -- IDLE of WHOIS reply ::METHOD RPL_WHOISIDLE expose results use arg message parse value message~string with me nick idle signon ':' . nick = IRCUpper(nick~strip) do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHOIS' & results[i][2] = nick then do results[i][3]['IDLE'] = idle -- singnon is permitted by some servers results[i][3]['SIGNON'] = signon leave end end -- ================ ISON ================================= ::METHOD IsOn expose results ison_done client parse arg nicks, waittime eventid = self~eventid ison_done = .false results[eventid] = .array~of("ISON","") if \datatype(waittime,'N') then waittime = .local['IRC.TIMEOUT.SCRIPTS'] timeoutalarm = .alarm~new(waittime, .message~new(self, 'IsOnCancel')) client~writeln('ISON' nicks) guard off when ison_done \= .false timeoutalarm~cancel ret = results[eventid][2] results~remove(eventid) return ret ::METHOD RPL_IsOn expose results ison_done use arg message parse value message~string with . ':' nicks do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'ISON' then do results[i][2] = nicks ison_done = nicks end end ::METHOD IsOnCancel expose ison_done ison_done = .true -- ================ JOIN ================================= -- Joins a channel, doesn't return anything. Look for the channel in the -- channel list to find out if it was successful ::METHOD Join expose client parse arg channel, key say channel if IRCIsChannel(channel) then client~writeln('JOIN' channel key) -- ================ TOPIC ================================= -- Returns the topic of a channel or a null string ::METHOD Topic expose results topic_done client parse arg channel, waittime channel = IRCUpper(channel~strip) eventid = self~eventid topic_done = .false results[eventid] = .array~of("TOPIC",channel,"") if \datatype(waittime,'N') then waittime = .local['IRC.TIMEOUT.SCRIPTS'] timeoutalarm = .alarm~new(waittime, .message~new(self, 'TopicCancel')) client~writeln('TOPIC' channel) guard off when topic_done \= .false timeoutalarm~cancel ret = results[eventid][3] results~remove(eventid) return ret ::METHOD RPL_Topic expose results topic_done use arg message parse value message~string with . channel':' topic channel = IRCUpper(channel~strip) do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'TOPIC' & results[i][2] = channel then do results[i][3] = topic topic_done = .true end end ::METHOD RPL_NoTopic expose results topic_done use arg message parse value message~string with . channel':' channel = IRCUpper(channel~strip) do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'TOPIC' & results[i][2] = channel then do topic_done = .true end end ::METHOD TopicCancel expose topic_done topic_done = .true -- ================ LIST ================================= -- returns a 2 dimensional array. array[n]=[channel,users,topic] ::METHOD List expose results list_done client parse arg channels, waittime channels = IRCUpper(channels~space~translate(' ',',')) eventid = self~eventid list_done = .false results[eventid] = .array~of("LIST",.array~new) if \datatype(waittime,'N') then waittime = .local['IRC.TIMEOUT.SCRIPTS'] timeoutalarm = .alarm~new(waittime, .message~new(self, 'ListCancel')) client~writeln('LIST' channels) guard off when list_done \= .false timeoutalarm~cancel ret = results[eventid][2] results~remove(eventid) return ret -- this reply is used by some servers but it's discarded here ::METHOD RPL_ListStart ::METHOD RPL_LIST expose results use arg message parse value message~string with . channel users ':' topic do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'LIST' then do results[i][2][results[i][2]~items+1] = .array~of(channel~strip,users~strip,topic~strip) end end ::METHOD RPL_ListEnd expose results list_done do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'LIST' then do list_done = .true end end ::METHOD ListCancel expose list_done list_done = .true -- ================ TIME ================================= ::METHOD Time expose results time_done client parse arg server, waittime eventid = self~eventid time_done = .false results[eventid] = .array~of("TIME",.array~of('','')) if \datatype(waittime,'N') then waittime = .local['IRC.TIMEOUT.SCRIPTS'] timeoutalarm = .alarm~new(waittime, .message~new(self, 'TimeCancel')) client~writeln('TIME' server) guard off when Time_done \= .false timeoutalarm~cancel ret = results[eventid][2] results~remove(eventid) return ret ::METHOD RPL_Time expose results Time_done use arg message parse value message~string with . server ':' time do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'TIME' then do results[i][2]~~put(server~strip,1)~~put(time~strip,2) time_done = .true end end ::METHOD TimeCancel expose time_done time_done = .true -- ================ WHOWAS ================================= -- Returns a 2 dimensional array, array one contains n arrays with 4 or 6 strings each. -- array[n] = [nick, user, host, realname] -- - or - -- array[n] = [nick, user, host, realname,server,serverinfo] -- Call: self~WhoWas(nick[,limit, target, waittime]) -- Example: -- list = self~whowas("can",5) -- if list = .nil then say "There was no such nick!" -- else do i = 1 to list~items -- do string over list[i] -- call charout ,string' ' -- end -- Say -- end ::METHOD WhoWas expose results whowas_done client parse arg nick, limit, target, waittime eventid = self~eventid whowas_done = .false if \ datatype(limit,'N') then results[eventid] = .array~of("WHOWAS", .array~new) else results[eventid] = .array~of("WHOWAS", .array~new(limit)) if \datatype(waittime,'N') then waittime = .local['IRC.TIMEOUT.SCRIPTS'] timeoutalarm = .alarm~new(waittime, .message~new(self, 'whowasCancel')) client~writeln('WHOWAS' nick limit target) guard off when whowas_done \= .false timeoutalarm~cancel if results[eventid][2]~items = 0 then ret = .nil else ret = results[eventid][2] results~remove(eventid) return ret ::METHOD RPL_WhoWasUser expose results use arg message parse value message~string with . nick user host '*' ':' realname do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHOWAS' then do results[i][2][results[i][2]~items+1] = .array~of(nick~strip, user~strip,host~strip,realname~strip) end end -- Don't think we need this method, see the if ... after -- the timoutalarm~cancel in the whowas method -- ::METHOD Err_WasNoSuchNick -- expose results -- parse arg . nick . ':' . -- do i = 1 to results~items -- if results[i] = .nil then iterate -- if results[i][1] = 'WHOWAS' then do -- results[i][2] = .nil -- end -- end ::METHOD RPL_EndOfWhoWas expose results whowas_done do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHOWAS' then do whowas_done = .true end end ::METHOD WhoWasCancel expose WhoWas_done WhoWas_done = .true -- ================ WHO ================================= -- Returns a single-dimensional array with lines of the following structure: -- " -- ( "H" / "G" > ["*"] [ ( "@" / "+" ) ] : " -- h: here, G: Away, *: IRCOp, @: Op in one channel we're in as well, +: Voiced in one channel ::METHOD Who expose results Who_done client parse arg string, waittime eventid = self~eventid Who_done = .false results[eventid] = .array~of("WHO",.array~new) if \datatype(waittime,'N') then waittime = .local['IRC.TIMEOUT.SCRIPTS'] timeoutalarm = .alarm~new(waittime, .message~new(self, 'WhoCancel')) client~writeln('WHO' string) guard off when Who_done \= .false timeoutalarm~cancel ret = results[eventid][2] results~remove(eventid) return ret ::METHOD RPL_WhoReply expose results use arg message parse value message~string with . line do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHO' then do results[i][2][results[i][2]~items+1] = line end end ::METHOD RPL_EndOfWho expose results Who_done -- parse arg ??? do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'WHO' then do Who_done = .true end end ::METHOD WhoCancel expose Who_done Who_done = .true /* --- Construct for active scripts --- /* ================ =================================*/ ::METHOD xxx expose results xxx_done client parse arg string, waittime eventid = self~eventid xxx_done = .false results[eventid] = .array~of("XXX") if \datatype(waittime,'N') then waittime = .local['IRC.TIMEOUT.SCRIPTS'] timeoutalarm = .alarm~new(waittime, .message~new(self, 'xxxCancel')) client~writeln('xxx' server) guard off when xxx_done \= .false timeoutalarm~cancel ret = results[eventid][2] results~remove(eventid) return ret ::METHOD RPL_xxx expose results xxx_done parse arg ??? do i = 1 to results~items if results[i] = .nil then iterate if results[i][1] = 'xxx' then do results[i][2] = ??? xxx_done = .true end end ::METHOD xxxCancel expose xxx_done xxx_done = .true */ -- ================================= -- DEFAULT NUMERIC REPLY METHODS -- ================================= ::Method OnRPL_001 expose client client~ClientEvent('IRC.EVENT.CONNECT',client) -- If we get the 001 reply we can be sure that we're connected to the server sucessfully -- message that tells us what our host is ::METHOD RPL_YourHost expose client use arg message parse value message~string with ":" . . . host client~Settings~SetEntry("Host",host) -- message that contains the time the server was started ::METHOD RPL_Created expose client use arg message parse value message~string with ":" time client~Settings~SetEntry("Created",time) -- mesage including host, verion of the server and a lot of strange info... ::METHOD RPL_MyInfo expose client use arg message parse value message~string with . host version client~Settings~SetEntry("Version",version) -- Method parses an ISupport reply, number 005 ::METHOD RPL_Isupport expose client return parse value message~string with . modifiers ":" do i = 1 to modifiers~words -- each word has the form PARAMETER[=VALUE] or -PARAMETER -- an empty value means that the service PARAMETER is available on the server parse value modifier~word(i) with token"="parameter if token~left(1) = "-" then do -- Reset setting to default value client~Settings~IsSupported~Revert(token~right(token~lenght-1)) iterate end else client~Settings~IsSupported~SetEntry(token,parameter) end ::Method OnRPL_UserHost expose users client use arg message parse value message~string with . ':' userinfostring do i = 1 to userinfostring~words parse value userinfostring~word(i) with nick'='host if nick~right(1) = '*' then do -- Nick is an IRCop mode = '+O' nick = nick~translate('','*') end else mode = '' awaystate = host~left(1) host = host~right(host~length-1) SELECT WHEN awaystate = '+' then mode = mode'-a' WHEN awaystate = '-' then mode = mode'+a' OTHERWISE Say 'Wrong 302 RPL_USERHOST from server!' END -- nicko=users~getnick(nick) -- if nicko = .nil then do -- nicko = .nick~new(self~client,nick'!'host,users,self~client~channels) -- nicko~mode(.msgmode~new(.nil,nicko,mode)) -- users~AddNick(nicko) -- SAy "new user created why?" nick -- end -- else -- nicko~mode(.msgmode~new(.nil,nicko,mode)) -- Say '***' nick 'is' host', mode:' mode end ::Method OnRPL_353 expose client use arg message parse value message~string with . mode channel ':' nicks channelname = channel~strip -- channel = .channel~new(client,channelname) channel = client~GetReceiverObject(channelname) if channel = .nil then channel = .channel~new(client,channelname) client~event(.msgjoin~new(client~users[1],channel)) do i = 1 to nicks~words nick = nicks~word(i) mode = "" if nick~pos("@")>0 then mode = "@" if nick~pos("+")>0 then mode = mode"+" nick = nick~translate("",mode)~strip user = client~GetReceiverObject(nick) if user = .NIL then user = .User~new(client,nick) call debug "[NumHandler: OnRPL_353: Created new msgjoin for" nick "joining" channel "with mode" mode,8 client~event(.msgjoin~new(user,channel,mode)) end ::Method OnRPL_433 expose client use arg message parse value message~string with target nick . -- not registered yet if target = '*' then do call debug "[NumHandler: 433: initally proposed nick is in use already.",8 client~event(.msgnick~new(client~users[1],nick~copies(2)~substr(2,nick~length))) client~writeln('NICK' client~users[1]~makestring) end -- The Supported class is a subclass of the directory class. -- It implements the default values of basically the 005 numrpl ::CLASS IsSupported SUBCLASS directory ::METHOD Init expose default -- The default values here may not be accurate. Thus experience from users is highly recommended! default = .directory~new default["CASEMAPPING"] = "rfc1459" default["CHANNELLEN"] = 200 default["CHANTYPES"] = "#&" default["NICKLEN"] = 9 default["PREFIX"] = "(ov)@+" default["CHANTYPES"] = "#&" default["MODES"] = 3 default["MAXBANS"] = 25 default["TOPICLEN"] = 80 default["KICKLEN"] = 80 default["MAXTARGETS"] = 4 -- at the time of the initialization the default values are copied to the current values. They -- are expected to be overwritten by the IRC server in the progress of establishing the connection. do name over default self~SetEntry(name,default[name]) end -- This method resets a value to its default value -- It is only called in case the client receives a message saying to drop the value received earlier for -- this particular setting. ::METHOD Revert expose default use arg name self~SetEntry(name,default[name])