diff --git a/IRC.Mod b/IRC.Mod index 695238a..8f48ee1 100644 --- a/IRC.Mod +++ b/IRC.Mod @@ -5,7 +5,6 @@ CONST msgLen* = 512; (* message length not more than 512 characters *) cmdPing* = "PING"; cmdPong* = "PONG"; - zzo* = "001"; cmdMode* = "MODE"; cmdJoin* = "JOIN"; cmdUser* = "USER"; @@ -13,20 +12,30 @@ CONST CR* = 0DX; LF* = 0AX; + numRPLWELCOME = "001"; + numRPLYOURHOST = "002"; + numRPLCREATED = "003"; + numRPLMYINFO = "004"; + TYPE chn* = ARRAY 32 OF CHAR; chnlist* = POINTER TO ARRAY OF chn; + msg* = ARRAY msgLen OF CHAR; + callBack* = PROCEDURE(VAR in: ARRAY OF CHAR); + + + instance* = RECORD + owner*, user*, nick*, host*, port*: chn; + connection*: Internet.Socket; + channelList*: chnlist; + callback*: callBack; + END; VAR - connection : Internet.Socket; eol* : ARRAY 3 OF CHAR; - channelList: chnlist; -PROCEDURE setChannelList*(VAR chnl: chnlist); -BEGIN - channelList := chnl; -END setChannelList; +(* string operations *) (* cuts line, takes the part till the eol *) PROCEDURE cutLine(VAR src, dst: ARRAY OF CHAR); @@ -44,13 +53,26 @@ BEGIN REPEAT dst[i] := src[i]; INC(i); - UNTIL i = pos; + UNTIL (i = pos) OR (i = LEN(dst)-2); dst[i] := src[i]; - INC(i); - dst[i] := 0X; + dst[i+1] := 0X END; END cutLine; +PROCEDURE terminateLine(VAR str: ARRAY OF CHAR); +VAR + found: BOOLEAN; + pos : INTEGER; + pattern : ARRAY 1 OF CHAR; +BEGIN + pattern[0] := LF; + Strings.FindNext(pattern, str, 0, found, pos); + IF found THEN + IF (pos + 1) < LEN(str) THEN + str[pos + 1] := 0X + END + END; +END terminateLine; PROCEDURE formUserLine(VAR user, owner, result: ARRAY OF CHAR); BEGIN @@ -73,71 +95,22 @@ BEGIN Strings.Append(eol, result); END formNickLine; -PROCEDURE Auth*(user, owner, nick: ARRAY OF CHAR): BOOLEAN; -VAR - userRequest, nickRequest: ARRAY 255 OF CHAR; - b : BOOLEAN; +PROCEDURE formModeLine(VAR str, nick: ARRAY OF CHAR); BEGIN + COPY (cmdMode, str); + Strings.Append(" ", str); + Strings.Append(nick, str); + Strings.Append(" +B", str); + Strings.Append(eol, str); +END formModeLine; - formUserLine(user, owner, userRequest); - - Out.String("sending:"); Out.Ln; - Out.String(userRequest); Out.Ln; - - b := Internet.Write(connection, userRequest); - - IF b THEN Out.String("wrote!"); Out.Ln ELSE Out.String("write failed"); Out.Ln END; - - formNickLine(nick, nickRequest); - - Out.String("sending:"); Out.Ln; - Out.String(nickRequest); Out.Ln; - - IF b THEN Out.String("wrote!"); Out.Ln ELSE Out.String("write failed"); Out.Ln END; - - RETURN b -END Auth; - -PROCEDURE Receive*(VAR str: ARRAY OF CHAR): BOOLEAN; -VAR - b: BOOLEAN; +PROCEDURE formJoinLine(VAR ln, chan: ARRAY OF CHAR); BEGIN - b := Internet.Read(connection, str); - IF b THEN - Out.String("received:"); Out.Ln; - Out.String(str); Out.Ln; - ELSE - Out.String("receive failed"); Out.Ln; - END; - RETURN b -END Receive; - -PROCEDURE Send*(str: ARRAY OF CHAR): BOOLEAN; -VAR - b : BOOLEAN; -BEGIN - b := Internet.Write(connection, str); - IF b THEN - Out.String("sent:"); Out.Ln; - Out.String(str); Out.Ln; - ELSE - Out.String("sending failed"); Out.Ln; - END; - RETURN b -END Send; - -PROCEDURE Connect*(host, port: ARRAY OF CHAR): BOOLEAN; -VAR - res: BOOLEAN; -BEGIN - res := Internet.Connect(host, port, connection); - RETURN res -END Connect; - -PROCEDURE Disconnect*; -BEGIN - Internet.Disconnect(connection); -END Disconnect; + COPY(cmdJoin, ln); + Strings.Append(" ", ln); + Strings.Append(chan, ln); + Strings.Append(eol, ln); +END formJoinLine; PROCEDURE isPing(VAR line: ARRAY OF CHAR): BOOLEAN; VAR @@ -151,51 +124,139 @@ BEGIN END END isPing; -PROCEDURE Pong(VAR line: ARRAY OF CHAR); +PROCEDURE serverMsg(VAR line: ARRAY OF CHAR): BOOLEAN; +BEGIN + IF line[0] = ':' THEN RETURN TRUE ELSE RETURN FALSE END +END serverMsg; + +PROCEDURE rplWelcome(VAR line : ARRAY OF CHAR): BOOLEAN; +VAR + found: BOOLEAN; + pos : INTEGER; + i : INTEGER; +BEGIN + Strings.FindNext(numRPLWELCOME, line, 0, found, pos); + IF found THEN RETURN TRUE ELSE RETURN FALSE END +END rplWelcome; + + +(* instance functions *) + +PROCEDURE setChannelList*(VAR inst: instance; chnl: chnlist); +BEGIN + inst.channelList := chnl; +END setChannelList; + +PROCEDURE Receive*(VAR inst: instance; VAR str: ARRAY OF CHAR): BOOLEAN; +VAR + b: BOOLEAN; +BEGIN + b := Internet.Read(inst.connection, str); + IF b THEN + Out.String("received:"); Out.Ln; + Out.String(str); Out.Ln; + ELSE + Out.String("receive failed"); Out.Ln; + END; + RETURN b +END Receive; + +PROCEDURE Send*(VAR inst: instance; str: ARRAY OF CHAR): BOOLEAN; +VAR + b : BOOLEAN; +BEGIN + terminateLine(str); + b := Internet.Write(inst.connection, str); + IF b THEN + Out.String("sent:"); Out.Ln; + Out.String(str); Out.Ln; + ELSE + Out.String("sending failed"); Out.Ln; + END; + RETURN b +END Send; + +PROCEDURE Auth*(inst: instance): BOOLEAN; +VAR + userRequest, nickRequest: ARRAY 255 OF CHAR; + b : BOOLEAN; +BEGIN + + formUserLine(inst.user, inst.owner, userRequest); + + b := Send(inst, userRequest); + + IF b THEN + formNickLine(inst.nick, nickRequest); + + b := Send(inst, nickRequest); + END; + RETURN b +END Auth; + +PROCEDURE Connect*(VAR inst: instance): BOOLEAN; +VAR + res: BOOLEAN; +BEGIN + res := Internet.Connect(inst.host, inst.port, inst.connection); + RETURN res +END Connect; + +PROCEDURE Disconnect*(VAR inst: instance); +BEGIN + Internet.Disconnect(inst.connection); +END Disconnect; + +PROCEDURE Pong(VAR inst: instance; VAR line: ARRAY OF CHAR); VAR tmp: ARRAY msgLen OF CHAR; b : BOOLEAN; BEGIN cutLine(line, tmp); tmp[1] := 'O'; (* replace "PING" by "PONG" *) - b := Send(tmp); + b := Send(inst, tmp); END Pong; -PROCEDURE processResponse(VAR line: ARRAY OF CHAR); +PROCEDURE Mode(VAR inst: instance); +VAR + str : ARRAY msgLen OF CHAR; + b : BOOLEAN; BEGIN - IF isPing(line) THEN Pong(line) END; -(* - IF line[0] = ':' THEN - IF contains001(line) THEN - sendMode(line); - sendJoin; - END; - Strings.FindNext(IRC.zzo, str, 0, patternFound, patternPos); - IF patternFound THEN - Out.String("001 found"); Out.Ln; - COPY ("MODE ", str3); - Strings.Append(nick, str3); - Strings.Append(" +B", str3); - Strings.Append(eol, str3); - Strings.Append(0X, str3); - b2 := IRC.Send(str3); - COPY("JOIN ", str3); - Strings.Append("#oberon", str3); - Strings.Append(eol, str3); - Strings.Append(0X, str3); - b2 := IRC.Send(str3); - END; - END;*) + formModeLine(str, inst.nick); + b := Send(inst, str); +END Mode; + +PROCEDURE Join(VAR inst: instance); +VAR + str: ARRAY msgLen OF CHAR; + b: BOOLEAN; +BEGIN + formJoinLine(str, inst.channelList^[0]); + b := Send(inst, str); +END Join; + +PROCEDURE processResponse(VAR inst: instance; VAR line: ARRAY OF CHAR); +BEGIN + IF isPing(line) THEN Pong(inst, line) END; + + IF serverMsg(line) THEN + IF rplWelcome(line) THEN + Mode(inst); + Join(inst); + ELSE + inst.callback(line); + END; + END; END processResponse; -PROCEDURE Loop*; +PROCEDURE Loop*(VAR inst: instance); VAR b : BOOLEAN; str : ARRAY msgLen OF CHAR; BEGIN REPEAT - b := Receive(str); - processResponse(str); + b := Receive(inst, str); + processResponse(inst, str); UNTIL ~b; END Loop; diff --git a/test.Mod b/test.Mod index 434e75c..5745938 100644 --- a/test.Mod +++ b/test.Mod @@ -2,32 +2,41 @@ MODULE test; IMPORT IRC, Out, Strings := ooc2Strings; -VAR -owner, user, nick, host, port, channel: ARRAY 32 OF CHAR; +PROCEDURE clbk(VAR in: ARRAY OF CHAR); +BEGIN +Out.String("callback procedure is running, youhoo!"); Out.Ln; +Out.String("input:"); Out.Ln; +Out.String(in); Out.Ln; +Out.Ln; + + + +END clbk; PROCEDURE testBot; VAR - b: BOOLEAN; + inst: IRC.instance; channels : IRC.chnlist; + b: BOOLEAN; BEGIN + inst.owner := "norayr_shimamoto"; + inst.user := "nakata_san"; + inst.nick := "oshima"; + inst.host := "irc.freenode.net"; + inst.port := "6667"; + inst.callback := clbk; NEW(channels, 1); - channels[0] := channel; - IRC.setChannelList(channels); + channels[0] := "#oberon"; + IRC.setChannelList(inst, channels); - IF IRC.Connect(host, port) # FALSE THEN - b := IRC.Auth(user, nick, owner); - IRC.Loop; + IF IRC.Connect(inst) # FALSE THEN + b := IRC.Auth(inst); + IRC.Loop(inst); END; END testBot; BEGIN -owner := "norayr_tanakian"; -user := "norayr_tanakian"; -nick := "vocbot"; -host := "irc.freenode.net"; -port := "6667"; -channel := "#oberon"; testBot;