Oberon/A2/Unix.Oberon.NetSystem.Mod
Appearance
(* ETH Oberon, Copyright 2000 ETH Zürich Institut für Computersysteme, ETH Zentrum, CH-8092 Zürich.
Refer to the general ETH Oberon System license contract available at: http://www.oberon.ethz.ch/ *)
MODULE NetSystem IN Oberon;
IMPORT S := SYSTEM, IP IN A2, DNS := DNS IN A2, TCP := TCP IN A2, UDP := UDP IN A2,
Texts, Oberon, Input, Fonts, Strings, Out;
CONST
CR = 0DX; LF = 0AX;
(* res values *)
done* = 0; (*everything went ok*)
error* = 1; (*failure occured*)
timeout* = 2; (*opening a connection is timed out*)
(* return values of procedure State *)
closed* = 0; (*connection is closed (neither sending nor receiving)*)
listening* = 1; (*passive connection is listening for a request*)
in* = 2; (*receiving only*)
out* = 3; (*sending only*)
inout* = 4; (*sending and receiving is possible*)
waitCon* = 5; (** still waiting for connection *)
errorCon* = 6; (** connecting failed *)
undef = -1; (** unknown state *)
IPAdrLen = 4;
(* any port value *)
anyport* = 0;
TYPE
IPAdr* = IP.Adr;
Connection* = TCP.Connection; (* TCP-Connection *)
HostInfo* = POINTER TO HostInfoDesc; (** handle for asynchronous GetIP and GetName *)
HostInfoDesc* = RECORD
next: HostInfo;
ip-: IPAdr; (** the ip-number of host name *)
name-: ARRAY 64 OF CHAR; (** the host name for ip-number *)
done-, err-, getip: BOOLEAN (** indicating success or failure *)
END;
Socket*= UDP.Socket; (* UDP-Connection *)
Access = POINTER TO AccessDesc;
AccessDesc = RECORD
service, user, host, passwd: ARRAY 64 OF CHAR;
next: Access
END;
Bytes = ARRAY MAX( SIGNED32 ) OF CHAR;
VAR
hostIP* : IPAdr; (** the ip-number of host name *)
anyIP*, allIP*: IPAdr;
hostName*: ARRAY 65 OF CHAR; (** own machine name *)
hostInfos: HostInfo;
W: Texts.Writer;
accessList: Access;
verbose: BOOLEAN;
PROCEDURE Start*;
VAR res: INTEGER;
BEGIN
DNS.GetHostName( hostName, res );
IF res = DNS.Ok THEN
DNS.HostByName( hostName, hostIP, res );
END
END Start;
PROCEDURE Stop*;
BEGIN
END Stop;
PROCEDURE ToHost* ( CONST num: ARRAY OF CHAR; VAR adr: IPAdr; VAR done: BOOLEAN );
BEGIN
adr := IP.StrToAdr(num);
done := ~(IP.IsNilAdr(adr))
END ToHost;
PROCEDURE ToNum*( adr: IPAdr; VAR num: ARRAY OF CHAR );
BEGIN
IP.AdrToStr(adr, num)
END ToNum;
PROCEDURE AsyncGetIP*( VAR hostInfo: HostInfo; name: ARRAY OF CHAR );
VAR res: INTEGER;
BEGIN
NEW( hostInfo ); Strings.Lower( name, name );
hostInfo.next := NIL; COPY( name, hostInfo.name );
hostInfo.done := FALSE; hostInfo.err := FALSE;
IF (name[0] >= "0") & (name[0] <= "9") THEN
DNS.HostByNumber( hostInfo.ip, name, res );
hostInfo.err := res # DNS.Ok; hostInfo.done := TRUE
ELSE
DNS.HostByName( name, hostInfo.ip, res ); (* human comprehensible name *)
IF res = DNS.Ok THEN
hostInfo.err := FALSE; hostInfo.done := TRUE;
hostInfo.next := hostInfos; hostInfos := hostInfo
ELSE
hostInfo.err := TRUE
END
END;
END AsyncGetIP;
PROCEDURE GetIP* ( CONST name: ARRAY OF CHAR; VAR IP: IPAdr );
VAR hostInfo: HostInfo;
BEGIN
IP := anyIP;
AsyncGetIP( hostInfo, name );
IF ~hostInfo.err THEN
IP := hostInfo.ip
END
END GetIP;
PROCEDURE AsyncGetName*( VAR hostInfo: HostInfo; IP: IPAdr );
VAR res: INTEGER;
BEGIN
NEW( hostInfo );
hostInfo.getip := FALSE; hostInfo.next := NIL;
S.MOVE( ADDRESSOF( IP ), ADDRESSOF( hostInfo.ip ), IPAdrLen );
hostInfo.done := FALSE; hostInfo.err := FALSE;
DNS.HostByNumber( hostInfo.ip, hostInfo.name, res );
IF res = DNS.Ok THEN
hostInfo.err := FALSE; hostInfo.done := TRUE;
hostInfo.next := hostInfos; hostInfos := hostInfo
ELSE
hostInfo.err := TRUE; hostInfo.name[0]:= 0X
END
END AsyncGetName;
PROCEDURE GetName* ( IP: IPAdr; VAR name: ARRAY OF CHAR );
VAR hostInfo: HostInfo;
BEGIN
COPY("", name);
AsyncGetName( hostInfo, IP );
IF ~hostInfo.err THEN
COPY( hostInfo.name, name )
END
END GetName;
(** Passwords *)
PROCEDURE WriteURL( CONST service, user, host: ARRAY OF CHAR );
BEGIN
Out.String("NetSystem.SetUser "); Out.String(service);
Out.Char(":"); Out.String(user); Out.Char("@");
Out.String(host); Out.String(" ~"); Out.Ln
END WriteURL;
(** Retrieve the password for user using service on host. Parameters service, host and user can be specified.
Parameter user is in/out. If user is empty, the first (user,password) pair for host is returned. Otherwise the
password of the user is returned. *)
PROCEDURE GetPassword*(service, host: ARRAY OF CHAR; VAR user, password: ARRAY OF CHAR);
VAR access: Access; r: Texts.Reader; ch: CHAR;
BEGIN
Strings.Lower(service, service); Strings.Lower(host, host);
access := accessList;
WHILE (access # NIL) & ~((access.service = service) & (access.host = host) & ((user = "") OR (access.user = user))) DO
access := access.next
END;
IF access # NIL THEN
COPY(access.user, user); COPY(access.passwd, password)
ELSE
IF (service # "") & (user # "") THEN
IF Oberon.Log.len > 0 THEN
Texts.OpenReader(r, Oberon.Log, Oberon.Log.len-1);
Texts.Read(r, ch);
IF ch # CHR(13) THEN Out.Ln END
END;
WriteURL(service, user, host);
END;
COPY("", user); COPY("", password)
END
END GetPassword;
(** Remove access for user using service on host. *)
PROCEDURE DelPassword*( CONST pservice, user, phost: ARRAY OF CHAR);
VAR paccess, access: Access;
service, host: ARRAY 64 OF CHAR;
BEGIN
Strings.Lower( pservice, service ); Strings.Lower( phost, host );
paccess := NIL; access := accessList;
WHILE (access # NIL) & ((access.service # service) & (access.host # host) & (access.user # user)) DO
paccess := access; access := access.next
END;
IF access # NIL THEN
IF paccess # NIL THEN
paccess.next := access.next
ELSE
accessList := access.next
END
END
END DelPassword;
(* An accessString is delimited by whitespace or "~" or a non-font entity. *)
PROCEDURE ReadAccessString(VAR R: Texts.Reader; VAR accessString: ARRAY OF CHAR; VAR at: SIGNED32): BOOLEAN;
VAR i: SIGNED32;
BEGIN
i := 0; at := -1;
REPEAT Texts.Read(R, accessString[i]) (* Skip leading whitespace. *)
UNTIL R.eot OR ((R.lib IS Fonts.Font) & (" " < accessString[i]));
WHILE ~R.eot & (R.lib IS Fonts.Font) & (" " < accessString[i]) & (accessString[i] # "~") DO
IF accessString[i] = "@" THEN at := i END;
INC(i);
Texts.Read(R, accessString[i])
END;
accessString[i] := 0X;
RETURN 0 < i
END ReadAccessString;
(* Extract next component from an accessString. *)
PROCEDURE Next(VAR accessString, str: ARRAY OF CHAR; VAR a, at: SIGNED32): BOOLEAN;
VAR i: SIGNED32;
BEGIN
i := 0;
WHILE (accessString[a] # 0X) & (a # at) & (accessString[a] # ":") & (accessString[a] > " ")
& (accessString[a] # "/") & (accessString[a] # "~") (* & (R.lib IS Fonts.Font)*) DO
str[i] := accessString[a];
INC(i); INC(a)
END;
str[i] := 0X;
RETURN 0 < i
END Next;
(* Accept a password from the user via the keyboard. *)
PROCEDURE ReadPwd(VAR access: Access; VAR pwd: ARRAY OF CHAR; VAR ch: CHAR);
VAR i: SIGNED32;
BEGIN
Texts.SetColor(W, 1);
Texts.WriteString(W, "Mouse left click in Oberon to focus input.");Texts.WriteLn(W);
Texts.WriteString(W, "Enter password for ");
Texts.WriteString(W, access.service); Texts.WriteString(W, "://");
Texts.WriteString(W, access.user); Texts.Write(W, "@");
Texts.WriteString(W, access.host); Texts.WriteString(W, ": ");
Texts.SetColor(W, 15);
Texts.Append(Oberon.Log, W.buf);
Input.Read(ch); i := 0;
WHILE ch > " " DO
IF ch = 7FX (* Delete *) THEN
IF i > 0 THEN
Texts.Delete(Oberon.Log, Oberon.Log.len-1, Oberon.Log.len);
DEC(i)
END
ELSE
Texts.Write(W, "*"); Texts.Append(Oberon.Log, W.buf);
pwd[i] := ch; INC(i)
END;
Input.Read(ch)
END;
pwd[i] := 0X;
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
END ReadPwd;
(* access points to a tetrad. If a match to the (service, user, host) of access is found
in accessList, the password is replaced. Otherwise access is prepended to accessList. *)
PROCEDURE Update(access: Access);
VAR a: Access;
BEGIN
IF verbose THEN
Texts.WriteString(W, "Update of access list requested with ");
Texts.WriteString(W, access.service);
Texts.Write(W, ":"); Texts.WriteString(W, access.user);
Texts.Write(W, ":");
IF access.passwd # "" THEN Texts.WriteString(W, "<password>") END;
Texts.Write(W, "@"); Texts.WriteString(W, access.host); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END;
a := accessList;
WHILE (a # NIL) & ~((a.service = access.service) & (a.host = access.host) & (a.user = access.user)) DO
a := a.next
END;
IF a = NIL THEN
IF verbose THEN
Texts.WriteString(W, "Matching access not found. Prepend access for ");
Texts.WriteString(W, access.service); Texts.WriteString(W, " to accessList.");Texts.WriteLn(W)
END;
access.next := accessList; accessList := access
ELSE
IF verbose THEN
Texts.WriteString(W, "Matching access found. Copy password in."); Texts.WriteLn(W)
END;
COPY(access.passwd, a.passwd)
END;
Texts.Append(Oberon.Log, W.buf)
END Update;
(** NetSystem.SetUser {"\v" | access } "~".
access = service ":" ["//"] user [":" password] "@" host [ "/" ].
If password is not specified in-line, submit interactively.
"@" can occur anywhere in an accessString and host begins after the last @.
The (service, host, user, password) tetrad is stored in memory for retrieval with GetPassword. *)
PROCEDURE SetUser*;
VAR
R: Texts.Reader;
service, usr, host, pwd: ARRAY 64 OF CHAR; (* Components of an accessDesc. *)
accessString: ARRAY 256 OF CHAR;
c: SIGNED32; (* Index in accessString. *)
at: SIGNED32; (* Index of the last "@" in the accessString. *)
acc: Access;
tempAccess: Access; (* Temporary list of accesses for which passwords are pending. *)
ch: CHAR;
BEGIN
(* Accesses where the password is included in parameters. *)
Texts.OpenReader(R, Oberon.Par.text, Oberon.Par.pos);
tempAccess := NIL;
WHILE ReadAccessString(R, accessString, at) DO
IF accessString = "\v" THEN
verbose := TRUE
ELSE
c := 0;
WHILE Next(accessString, service, c, at) DO
Strings.Lower(service, service);
IF verbose THEN
Texts.WriteLn(W);
Texts.WriteString(W, "service = "); Texts.WriteString(W, service); Texts.WriteLn(W)
END;
IF accessString[c] = ":" THEN
INC(c);
IF ~Next(accessString, usr, c, at) THEN
Texts.WriteString(W, "For service = "); Texts.WriteString(W, service);
Texts.WriteString(W, ", Next() failed to retrieve usr."); Texts.WriteLn(W)
ELSE (* Found usr. Look fo password. *)
IF accessString[c] = "@" THEN
IF verbose THEN
Texts.WriteString(W, "Password omitted. Prompt for it later."); Texts.WriteLn(W);
END;
ASSERT(c = at);
INC(c);
IF ~Next(accessString, host, c, at) THEN
Texts.WriteString(W, "For service = "); Texts.WriteString(W, service);
Texts.WriteString(W, ", Next() failed to retrieve host."); Texts.WriteLn(W)
ELSE
Strings.Lower(host, host);
NEW(acc); acc.next := tempAccess; tempAccess := acc; (* prepend to temp list *)
COPY(service, acc.service); COPY(host, acc.host); COPY(usr, acc.user)
END
ELSIF accessString[c] = ":" THEN
IF verbose THEN
Texts.WriteString(W, ": separator provided for password."); Texts.WriteLn(W);
END;
INC(c);
IF ~Next(accessString, pwd, c, at) THEN
Texts.WriteString(W, "For service = "); Texts.WriteString(W, service);
Texts.WriteString(W, ", Next() failed to retrieve password."); Texts.WriteLn(W)
ELSE
IF verbose THEN
IF pwd # "" THEN
Texts.WriteString(W, "Password supplied in SetUser command."); Texts.WriteLn(W)
ELSE
Texts.WriteString(W, ": separator present but password not in parameter of SetUser().");
Texts.WriteLn(W)
END
END;
IF accessString[c] = "@" THEN
ASSERT(c = at);
INC(c);
IF ~Next(accessString, host, c, at) THEN
Texts.WriteString(W, "For service = "); Texts.WriteString(W, service);
Texts.WriteString(W, ", Next() failed to retrieve host."); Texts.WriteLn(W)
ELSE
IF verbose THEN
Texts.WriteString(W, "host = "); Texts.WriteString(W, host); Texts.WriteLn(W)
END;
IF host # "" THEN
NEW(acc); COPY(service, acc.service); COPY(host, acc.host);
COPY(usr, acc.user); COPY(pwd, acc.passwd);
Update(acc)
END (* IF host # "" *)
END (* ~Next(accessString, host, c, at) *)
END (* IF accessString[c] = "@" *)
END (* IF ~Next(accessString(accessString, pwd, c, at) *)
END (* IF accessString[c] = "@" *)
END (* ~Next(accessString, usr, c, at) *)
END (* IF accessString = ":" *)
END (* WHILE Next(accessString, service, c, at) *)
END (* IF accessString = "\v" *)
END; (* WHILE ReadAccessString *)
(* Accesses where the password is requested interactively. *)
WHILE tempAccess # NIL DO (* Fill password in each access of "temporary" list. *)
ReadPwd(tempAccess, pwd, ch);
IF ch = CR THEN (* password was entered *)
acc := tempAccess;
tempAccess := tempAccess.next;
COPY(pwd, acc.passwd);
Update(acc)
END
END;
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
END SetUser;
(** clears accessList from memory *)
PROCEDURE ClearUser*;
BEGIN
accessList := NIL
END ClearUser;
(************************************** TCP ****************************************)
PROCEDURE Available* (conn: Connection): SIGNED32;
BEGIN
RETURN conn.Available()
END Available;
PROCEDURE OpenConnection* ( VAR conn: Connection; locPort: UNSIGNED16; remIP: IPAdr; remPort: UNSIGNED16;
VAR res: SIGNED16 );
VAR r: SIGNED32;
BEGIN
IF remPort = anyport THEN remIP := anyIP END;
NEW( conn );
conn.Open( locPort, remIP, remPort MOD 10000H, r );
IF r = TCP.Ok THEN res := done ELSE res := error END
END OpenConnection;
PROCEDURE AsyncOpenConnection* ( VAR conn: Connection; locPort: UNSIGNED16; remIP: IPAdr; remPort: UNSIGNED16;
VAR res: SIGNED16 );
BEGIN
OpenConnection( conn, locPort, remIP, remPort, res )
END AsyncOpenConnection;
PROCEDURE CloseConnection* ( conn: Connection );
BEGIN
IF conn # NIL THEN conn.Close() END
END CloseConnection;
PROCEDURE Requested* ( conn: Connection ): BOOLEAN;
BEGIN
RETURN (conn.state = listening) & conn.Requested()
END Requested;
PROCEDURE Accept* ( conn: Connection; VAR newC: Connection; VAR res: SIGNED16 );
VAR r: SIGNED32;
BEGIN
conn.Accept( newC, r );
IF r = TCP.Ok THEN res := done ELSE res := error END
END Accept;
PROCEDURE State* (conn: Connection): SIGNED16;
VAR res: SIGNED16;
BEGIN
CASE conn.state OF
| TCP.Closed: res := closed
| TCP.Listen: res := listening
| TCP.Established: res := inout
ELSE
res := undef
END;
RETURN res
END State;
PROCEDURE GetPartner* (conn:Connection; VAR remIP: IPAdr; VAR remPort: UNSIGNED16);
BEGIN
remIP := conn.fip;
remPort := SHORT( conn.fport )
END GetPartner;
(*----- Read -----*)
PROCEDURE Read* (conn: Connection; VAR ch: CHAR);
VAR l: SIZE; r: INTEGER; bytes: ARRAY 1 OF CHAR;
BEGIN
conn.Receive( bytes, 0, 1, 1, l, r );
ch := bytes[0]
END Read;
PROCEDURE ReadBytes* ( conn: Connection; pos, len: SIGNED32; VAR buf: ARRAY OF S.BYTE );
VAR l: SIZE; r: INTEGER;
BEGIN
conn.Receive( S.VAL( Bytes, buf ), pos, len, len, l, r );
END ReadBytes;
PROCEDURE ReadBool* (conn: Connection; VAR b: BOOLEAN);
VAR l: SIZE; r: INTEGER; bytes: ARRAY 1 OF CHAR;
BEGIN
conn.Receive(bytes, 0, 1, 1, l, r );
b := ODD(ORD(bytes[0]));
END ReadBool;
PROCEDURE ReadInt* ( conn: Connection; VAR x: SIGNED16 );
VAR buf: ARRAY 4 OF CHAR; len: SIZE; res: INTEGER;
BEGIN
conn.Receive( buf, 0, 2, 2, len, res );
IF (res = 0) & (len = 2) THEN
x := ORD(buf[0])*100H + ORD(buf[1])
ELSE
x := 0
END
END ReadInt;
PROCEDURE ReadLInt* (conn: Connection; VAR x: SIGNED32);
VAR buf: ARRAY 4 OF CHAR; len: SIZE; res: INTEGER;
BEGIN
conn.Receive( buf, 0, 4, 4, len, res );
IF (res = 0) & (len = 4) THEN
x := ORD(buf[0])*1000000H + ORD(buf[1])*10000H + ORD(buf[2])*100H + ORD(buf[3])
ELSE
x := 0
END
END ReadLInt;
(** Blocking read a string terminated by ( [CR]LF | 0X ). *)
PROCEDURE ReadString* (conn: Connection; VAR s: ARRAY OF CHAR);
VAR
ch, ch0: CHAR;
i, l: SIZE; r: INTEGER;
bytes: ARRAY 1 OF CHAR;
BEGIN
i := -1; ch := 0X;
REPEAT
INC( i );
ch0 := ch;
conn.Receive( bytes, 0, 1, 1, l, r );
ch := bytes[0];
s[i] := ch;
UNTIL ( r # TCP.Ok) OR (ch = 0X) OR (ch = LF);
IF (ch = LF) & (ch0 = CR) THEN
s[i - 1] := 0X
ELSE s
[i] := 0X
END
END ReadString;
(*----- Write -----*)
PROCEDURE Write* (conn: Connection; ch: CHAR);
VAR r: SIGNED32; bytes: ARRAY 1 OF CHAR;
BEGIN
bytes[0] := ch;
conn.Send( bytes, 0, 1, TRUE, r )
END Write;
PROCEDURE WriteBytes* (conn: Connection; pos, len: SIGNED32; CONST buf: ARRAY OF S.BYTE );
VAR r: SIGNED32;
BEGIN
conn.Send( S.VAL( Bytes, buf ), pos, len, TRUE, r)
END WriteBytes;
PROCEDURE WriteBool* (conn: Connection; b: BOOLEAN);
VAR r: SIGNED32; bytes: ARRAY 1 OF CHAR;
BEGIN
IF b THEN bytes[0] := 1X ELSE bytes[0] := 0X END;
conn.Send( bytes, 0, 1, TRUE, r )
END WriteBool;
PROCEDURE WriteInt* (conn: Connection; x: SIGNED16);
VAR buf: ARRAY 2 OF CHAR; r: SIGNED32;
BEGIN
buf[0] := CHR(x DIV 100H MOD 100H);
buf[1] := CHR(x MOD 100H);
conn.Send( buf, 0, 2, TRUE, r )
END WriteInt;
PROCEDURE WriteLInt* (conn: Connection; x: SIGNED32);
VAR buf: ARRAY 4 OF CHAR; r: SIGNED32;
BEGIN
buf[0] := CHR(x DIV 1000000H MOD 100H);
buf[1] := CHR(x DIV 10000H MOD 100H);
buf[2] := CHR(x DIV 100H MOD 100H);
buf[3] := CHR(x MOD 100H);
conn.Send( buf, 0, 4, TRUE, r )
END WriteLInt;
PROCEDURE WriteString* (conn: Connection; CONST s: ARRAY OF CHAR);
VAR
cs: ARRAY 2 OF CHAR;
i, r: SIGNED32;
BEGIN i := 0;
WHILE s[i] # 0X DO INC( i ) END;
conn.Send( s, 0, i, FALSE, r);
cs[0] := CR; cs[1] := LF;
conn.Send( cs, 0, 2, TRUE, r )
END WriteString;
(******************************** UDP **************************************)
PROCEDURE OpenSocket* ( VAR soc: Socket; locPort: UNSIGNED16; VAR res: SIGNED16 );
VAR r: SIGNED32;
BEGIN
NEW( soc, locPort MOD 10000H, r );
IF r = UDP.Ok THEN res := done ELSE res := error END
END OpenSocket;
PROCEDURE CloseSocket* (S: Socket);
BEGIN
S.Close();
END CloseSocket;
PROCEDURE AvailableDG* (soc: Socket): SIGNED32;
BEGIN
RETURN 0
END AvailableDG;
PROCEDURE SendDG* ( soc: Socket; remIP: IPAdr; remport: UNSIGNED16; pos, len: SIGNED32; CONST buf: ARRAY OF S.BYTE );
VAR res: INTEGER;
BEGIN
soc.Send( remIP, remport MOD 10000H, S.VAL( Bytes, buf ), pos, len, res )
END SendDG;
PROCEDURE ReceiveDG* ( soc: Socket; VAR remIP: IPAdr; VAR remport: UNSIGNED16;
pos: SIGNED32; VAR len: SIGNED32; VAR buf: ARRAY OF S.BYTE );
VAR res: SIGNED32; port: SIGNED32; length: SIZE;
BEGIN
soc.Receive( S.VAL( Bytes, buf ), pos, len, 0, remIP, port, length, res );
len := length(SIGNED32);
remport := SHORT( port)
END ReceiveDG;
(** Write 2 bytes in network byte ordering to buf[pos]. *)
PROCEDURE PutInt* (VAR buf: ARRAY OF S.BYTE; pos: SIGNED16; x: SIGNED16);
BEGIN
buf[pos] := CHR(x DIV 100H MOD 100H);
buf[pos+1] := CHR(x MOD 100H)
END PutInt;
(** Write 4 bytes in network byte ordering to buf[pos]. *)
PROCEDURE PutLInt* (VAR buf: ARRAY OF S.BYTE; pos: SIGNED16; x: SIGNED32);
BEGIN
buf[pos] := CHR(x DIV 1000000H MOD 100H);
buf[pos+1] := CHR(x DIV 10000H MOD 100H);
buf[pos+2] := CHR(x DIV 100H MOD 100H);
buf[pos+3] := CHR(x MOD 100H)
END PutLInt;
(** Read 2 bytes in network byte ordering from buf[pos]. *)
PROCEDURE GetInt* (CONST buf: ARRAY OF S.BYTE; pos: SIGNED16; VAR x: SIGNED16);
BEGIN
x := ORD(buf[pos])*100H +
ORD(buf[pos+1])
END GetInt;
(** Read 4 bytes in network byte ordering from buf[pos]. *)
PROCEDURE GetLInt* (CONST buf: ARRAY OF S.BYTE; pos: SIGNED16; VAR x: SIGNED32);
BEGIN
x := ORD( buf[pos] )*1000000H +
ORD( buf[pos+1] )*10000H +
ORD( buf[pos+2] )*100H +
ORD( buf[pos+3] )
END GetLInt;
PROCEDURE WriteAccess (service, user, password, host: ARRAY OF CHAR);
BEGIN
Texts.WriteString(W, service);
Texts.Write(W, ":"); Texts.WriteString(W, user);
Texts.Write(W, ":"); Texts.WriteString(W, password);
Texts.Write(W, "@"); Texts.WriteString(W, host); Texts.WriteLn(W) (* ;
Texts.Append(Oberon.Log, W.buf) *)
END WriteAccess;
PROCEDURE Show*;
VAR p: Access;
BEGIN
p := accessList;
Texts.WriteLn(W); Texts.WriteString(W, "NetSystem.Show"); Texts.WriteLn(W);
WHILE p # NIL DO
WriteAccess(p.service, p.user, "hidden password", p.host);
p := p.next
END;
Texts.Append(Oberon.Log, W.buf)
END Show;
BEGIN
verbose := FALSE;
anyIP := IP.NilAdr;
allIP := IP.NilAdr;
allIP.usedProtocol := IP.IPv4;
allIP.ipv4Adr := SIGNED32( 0FFFFFFFFH );
Texts.OpenWriter(W);
accessList := NIL;
Start
END NetSystem.