-- PrintStatus.mesa; edited by Johnsson, 17-Apr-81  9:16:01
-- edited by Paul Rovner, 6-Jan-82 19:13:18
-- edited by Warren Teitelman,  8-Mar-82 13:11:53

DIRECTORY
  Ascii USING [CR, SP],
  IO USING [char, rope, string, Put, PutRope, PutChar],
  LongString USING [AppendString],
  LongStorage USING [CopyString, FreeString],
  PrintOps USING [printerName, out],
  PupDefs USING [
    GetFreePupBuffer, GetPupAddress, GetPupContentsBytes, PupAddress, PupBuffer,
    PupNameTrouble, PupPackageMake, PupSocket, PupSocketID, PupSocketMake,
    ReturnFreePupBuffer, SecondsToTocks, SetPupContentsBytes],
  PupTypes USING [fillInSocketID, PupSocketID, PupType],
  String USING [AppendChar, EqualStrings]
  ;

PrintStatus: PROGRAM
  IMPORTS LongString, LongStorage, PrintOps, PupDefs, String, IO 
  EXPORTS PrintOps =
  BEGIN OPEN IO;
  
  printerStatusSocket: CARDINAL = 21B;
  printerStatusRequest: PupTypes.PupType = LOOPHOLE[200B];
  printerStatusReply: PupTypes.PupType = LOOPHOLE[201B];
  printerCapabilityRequest: PupTypes.PupType = LOOPHOLE[202B];
  printerCapabilityReply: PupTypes.PupType = LOOPHOLE[203B];
  printerJobStatusRequest: PupTypes.PupType = LOOPHOLE[204B];
  printerJobStatusReply: PupTypes.PupType = LOOPHOLE[205B];
  
  statusSocket: PupDefs.PupSocketID = [0, printerStatusSocket];
  
  havePrinter: BOOLEAN ← FALSE;
  
  Ask: PROCEDURE [
    printer: PupDefs.PupSocket, q: PupDefs.PupBuffer, atype: PupTypes.PupType]
    RETURNS [a: PupDefs.PupBuffer] =
    BEGIN
    THROUGH [0..2) DO
      printer.put[q];
      DO
        a ← printer.get[];
        IF a = NIL THEN EXIT;
        IF a.pupType = atype AND a.pupID = q.pupID THEN RETURN;
        PupDefs.ReturnFreePupBuffer[a];
        ENDLOOP;
      ENDLOOP;
    END;
    
  GetStatus: PUBLIC PROCEDURE RETURNS [BOOLEAN] =
    BEGIN OPEN PupDefs;
    a, b: PupBuffer;
    available: BOOLEAN ← TRUE;
    socket: PupSocket;
    remote: PupAddress;
    printerName: STRING = [40];
    remote.socket ← statusSocket;
    IF PrintOps.printerName = NIL OR PrintOps.printerName.length = 0 THEN
      {PrintOps.out.PutRope["No printer host name!"]; GOTO Fail};
    PupPackageMake[];
    LongString.AppendString[printerName, PrintOps.printerName];
    GetPupAddress[
      @remote, printerName !
      PupNameTrouble => {PrintOps.out.Put[string[e], char['\n]];
			 GOTO Fail}];
    socket ← PupSocketMake[PupTypes.fillInSocketID, remote, SecondsToTocks[1]];
    b ← GetFreePupBuffer[];
    b.requeueProcedure ← NullRequeue;
    b.pupType ← printerStatusRequest;
    SetPupContentsBytes[b, 0];
    a ← Ask[socket, b, printerStatusReply];
    IF a = NIL THEN PrintOps.out.Put[rope["No response from "], string[printerName], char['\n]]
    ELSE {
      c: CHARACTER;
      available ← a.pupWords[0] # 1;
      FOR i: CARDINAL IN [2..GetPupContentsBytes[a]) DO
	PrintOps.out.PutChar[c ← a.pupChars[i]]; ENDLOOP;
      IF c # Ascii.CR THEN PrintOps.out.PutChar[Ascii.CR];
      ReturnFreePupBuffer[a];
      IF available THEN {
	b.pupType ← printerCapabilityRequest;
	a ← Ask[socket, b, printerCapabilityReply];
	IF a # NIL THEN
	  {ParseProperties[@a.pupChars]; ReturnFreePupBuffer[a]}}};
    ReturnFreePupBuffer[b];
    RETURN[available];
    EXITS Fail => RETURN[FALSE];
    END;
    
  Capability: TYPE = {id, instance, duplex, color, mailbox};
  
  printerCapabilities: ARRAY Capability OF BOOLEAN ← ALL[FALSE];
  jobID: LONG STRING ← NIL;
  
  ParseProperties: PROCEDURE [p: LONG POINTER TO PACKED ARRAY [0..0) OF CHARACTER] =
    BEGIN OPEN String;
    capabilityStrings: ARRAY Capability OF STRING =
      ["ID"L, "PRINT-INSTANCE"L, "DUPLEX"L, "COLOR"L, "MAILBOX"L];
    property: STRING = [40];
    value: STRING = [40];
    i: CARDINAL ← 1;
    DO
      IF p[i] = '( THEN i ← i + 1 ELSE EXIT;
      property.length ← value.length ← 0;
      WHILE p[i] # Ascii.SP DO AppendChar[property, p[i]]; i ← i + 1 ENDLOOP;
      i ← i + 1;
      WHILE p[i] # ') DO AppendChar[value, p[i]]; i ← i + 1 ENDLOOP;
      i ← i + 1;
      FOR j: Capability IN Capability DO
	IF EqualStrings[property, capabilityStrings[j]] THEN{
	  IF j = id THEN {LongStorage.FreeString[jobID]; jobID ← LongStorage.CopyString[value]}
	  ELSE printerCapabilities[j] ← value[0] = 'T;
	  EXIT};
	ENDLOOP;
      ENDLOOP;
    END;
    
  NullRequeue: PROCEDURE [LONG POINTER] = {};
    
  
  END...