{$X+,B-,V-} {essential compiler directives}

UNIT nwQMS;

{ nwQMS unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R. Spronk }
{ Based in part on a unit containing queue services routines, written by
  Erik van Heyningen in April 1994. }

INTERFACE

Uses nwMisc;

{ Function:                             Interrupt:  Comments:

  Queue Server Functions:

. AbortServicingQueueJob                (F217/73)   (S)
. AttachQueueServerToQueue              (F217/6F)   (S)
. ChangeToClientRights                  (F217/74)   (S)
. DetachQueueServerFromQueue            (F217/70)   (S)
. FinishServicingQueueJob               (F217/72)   (S)
. RestoreQueueServerRights              (F217/75)   (S)
. ServiceQueueJob                       (F217/71)   (S)
. SetQueueServerStatus                  (F217/77)   (S)

  Queue Operator Functions:

. ChangeQueueJobPosition                (F217/6E)   (O)
* CreateQueue                           (F217/64)   (SUP)
* DestroyQueue                          (F217/65)   (SUP)
. SetQueueStatus                        (F217/67)   (O)

  Queue User Functions:

. CreateQueueJob                        (F217/68)   (C)
. StartQueueJob                         (F217/69)   (C)        (1)

  Miscellaneous Queue Functions:

. ChangeQueueJobEntry                   (F217/6D)   (C-O)
* GetQueueJobList                       (F217/6B)   (C-O)
* GetQueueJobsFileSize                  (F217/78)   (C-O-S)
* ReadQueueStatus                       (F217/66)   (C-O)
* ReadQueueJobEntry                     (F217/6C)   (C-O-S)
. ReadQueueServerStatus                 (F217/76)   (C-O)
* RemoveJobFromQueue                    (F217/6A)   (C-O)


Notes: C  : Function available to Clients (Queue Users);
       S  : Function available to Servers (Queue Servers);
       O  : Functions availaible to Operators (Queue Operators);
       SUP: Functions available to Supervisors/Workgroup managers.

       (1): StartQueueJob is a.k.a. CloseFileAndStartQueueJob
}

CONST { Queue status flag }
      QS_ALL_OK              = $00;
      QS_CANT_ADD_JOBS       = $01; { possibility to add jobs disabled by operator }
      QS_SERVERS_CANT_ATTACH = $02; { attachment of servers to queue disabled by operator }
      QS_CANT_SERVICE_JOBS   = $04; { queue halted by operator }
       { QS_XXXX constants can be ORed to form a QstatusFlag }

      QF_NONE                = $00;
      QF_AUTO_START          = $08;
      QF_SERVICE_RESTART     = $10;
      QF_ENTRY_OPEN          = $20;
      QF_USER_HOLD           = $40;
      QF_OPERATOR_HOLD       = $80;

CONST MaxQueueJobs = 250;

Type TQueueStatus= RECORD
                   ObjectId               : Longint; { Object id of queue                         }
                   Status                 : Byte;    { status of queue QS_XXX }
                   NbrOfJobs              : Byte;    { Number of jobs in queue                   }
                   NbrOfServers           : Byte;    { Number of servers attached to queue       }
                   ServerObjectIds        : array[1..25] of Longint;
                     { List of Objects-ids of attached servers            }
                   ServerConnNbrs         : array[1..25] of Byte;
                     { List of attached server stations                   }
                   MaxNbrOfServers        : Byte; { ??? }
                   end;

     TQueueServerStatus= Array[1..64] of Byte;
                         { undefined structure -as far as QMS is concerned-}

Type TJobNumberList = Array[1..MaxQueueJobs] OF Word;
     TQueueJobList  = record
                      JobCount   : Word;
                      JobNbrs    : TJobNumberList; { List of jobs numbers by position in queue }
                      MaxJobs    : Word;    {????}    { Maximum job numbers              }
                      end;

     TJobFileHandle=Array[1..6] of Byte;
     TQueueJobEntry =Record  { Unit external Type }
                     ClientConnNbr          : Byte;
                     ClientTaskNbr          : Byte;
                     ClientObjectID         : Longint;
                     JobEntryTime           : TnovTime;
                     JobNumber              : Word;
                     JobFileName            : String[14];
                     JobFileHandle          : TjobFileHandle;

                     TargetServerIDnumber   : Longint;     {2}
                     TargetExecutionTime    : TnovTime;    {2}
                     JobType                : Word;        {2}
                     JobControlFlags        : Byte;        {2}
                     JobDescription         : String[50];  {2}
                     ClientRecordArea       : Array[1..152] OF Byte; {2}

                     JobPosition            : Byte;        {2/operators only}

                     ServerConnNbr,                        {1}
                     ServerTaskNbr          : Byte;        {1}
                     ServerObjectID         : Longint;     {1}
                     End;
       { 1: Filled by Queue server. As long as ServerTaskNbr=0,
            queue entry is not being serviced.
         2: Can be changed by queue operators and/or the 'owner' of
            the job after job has been placed in queue
       }

Var result:Word;

{F217/64 {2.1x+}
Function CreateQueue(Qname     :string; QobjectType:Word;
                     dirHandle :Byte;   pathName   :string;
                     VAR QobjID:Longint                      ):Boolean;
{ Creates an object of an object_queue_type in the bindery, checks that
  all settings are valid before creating. Returns the object_id of the
  created queue if creation was successfull. }

{F217/65 [2.1x+]}
Function DestroyQueue(QobjID:Longint):Boolean;
{ Destroys the specified Queue; aborts all jobs in the queue;
  associated files/directories are deleted;
  queue object is removed from the bindery. }


{F217/76 [2.1x/3.x]}
Function ReadQueueStatus(QobjID:Longint;
                         Var Qstatus:TQueueStatus):Boolean;
{ Read the status of a queue. This information is changed by queueservers.}

{F217/67 [2.1x+]}
Function SetQueueStatus(QobjId:Longint; NewQstatusFlag:Byte):Boolean;
{ Change the queue status flag. Use the QS_XXXX constants }

{F217/6B}
FUNCTION GetQueueJobList( QueueObjId: Longint;
                          Var QJobList:TQueueJobList): Boolean;
{ You need to be either a Q_USER or a Q_OPERATOR }

{F217/6C}
FUNCTION ReadQueueJobEntry( QObjId: Longint;JobNbr: Word;
                            VAR QJob: TQueueJobEntry): Boolean;
{ You need to be either a Q_USER, Q_OPERATOR or a Q_SERVER }

{F217/6A}
FUNCTION RemoveJobFromQueue( QObjId: Longint; JobNbr: Word): Boolean;
{ You need to be Q_OPERATOR or the Q_USER who queued the job }

{F217/69 [2.1x+]}
Function StartQueueJob(QobjId:Longint;JobNbr:Word):Boolean;


{F217/6E [2.1x+]}
Function ChangeQueueJobPosition(QobjId:Longint; JobNbr:Word;
                                NewJobPos:Byte              ):Boolean;
{ Q_OPERATOR only }


{F217/6F [2.1x+]}
Function AttachQueueServerToQueue(QobjId:Longint):Boolean;
{ Q_SERVERs only }


{F217/70 [2.1x+]}
Function DetachQueueServerFromQueue(QobjId:Longint):Boolean;
{ Q_SERVERs only }


{F217/71 [2.1x+]}
Function ServiceQueueJob(QobjID:Longint; JobType:Word;
                                    Var QjobEntry:TQueueJobEntry):Boolean;
{ Q_SERVERs only }

{F217/72 [2.1x+]}
Function FinishServicingQueueJob(QobjId:Longint;JobNbr:Word;
                                 Charge:Longint             ):Boolean;
{ Q_SERVERs only }

{F217/73 [2.1x+]}
Function AbortServicingQueueJob(QobjId:Longint; JobNbr:Word):Boolean;

{F217/74 [2.1x+]}
Function ChangeToClientRights(QobjId:Longint;JobNbr:Word):Boolean;
{ Q_SERVERs servicing job only }

{F217/75 [2.1x+]}
Function RestoreQueueServerRights:Boolean;
{ Q_SERVERs, servicing job and having previously called
  ChangeToClientRights only }

{F217/76 [2.1x+]}
Function ReadQueueServerStatus(QobjId        :Longint;
                               QserverObjId  :Longint;
                               QserverConnNbr:Byte;
                           Var Qstatus:TQueueServerStatus):Boolean;


{F217/77 [2.1x+]}
Function SetQueueServerStatus(QobjId:Longint; Qstatus:TqueueServerStatus):Boolean;

{F217/78 [2.1x+]}
Function GetQueueJobsFileSize(QobjId:Longint; JobNbr:Word;
                             Var JobSize:Longint          ):Boolean;

{F217/68 [2.1x+]}
Function CreateQueueJob(QobjId:Longint;
              {i/o} Var Qjob:TqueueJobEntry):Boolean;

{F217/6D [2.1x+]}
Function ChangeQueueJobEntry(QobjId:Longint;Qjob:TQueueJobEntry):Boolean;

IMPLEMENTATION {============================================================}

Uses nwIntr;

Type TIntJobStruct =Record  { Unit internal Type }
                 _ClientConnNbr,
                 _ClientTaskNbr           : Byte;
                 _ClientObjectID,            {hi-lo}
                 _TargetServerIDnumber : Longint;      {hi-lo}
                 _TargetExecutionTime,
                 _JobEntryTime         : Array[1..6] OF Byte; { YMDHMS }
                 _JobNumber,                           {hi-lo}
                 _JobType              : Word;         {hi-lo}
                 _JobPosition,
                 _JobControlFlags      : Byte;
                 _JobFileName          : Array[1..14] OF CHAR; { ASCIIZ }
                 _JobFileHandle        : TJobFileHandle;
                 _ServerConnNbr,
                 _ServerTaskNbr        : Byte;
                 _ServerObjectID       : Longint;       {hi-lo}
                 _JobDescription       : Array[1..50] OF CHAR; { ASCIIZ }
                 _ClientRecordArea     : Array[1..152] OF Byte
                 End;

Procedure ConvertQJE2ext(qje:TintJobStruct;VAR ext:TQueueJobEntry;
                         Unrestricted:Boolean);
{convert the internal QueueJobEntry type into the equivalent
 unit external type }
begin
With qje,ext
 do begin
    ClientConnNbr:=_ClientConnNbr;
    ClientTaskNbr:=_ClientTaskNbr;
    ClientObjectId:=Lswap(_ClientObjectId);
    Move(_JobEntryTime,JobEntryTime,6); JobEntryTime.DayOfWeek:=0;
    { # fix year for year 2000+ ? }
    JobNumber:=swap(_JobNumber);
    ZstrCopy(JobFileName,_JobFileName,14);
    JobFileHandle:=_JobFileHandle;
    TargetServerIdNumber:=Lswap(_TargetServerIdNumber);
    Move(_TargetExecutionTime,TargetExecutionTime,6); TargetExecutionTime.DayOfWeek:=0;
    { # fix year for year 2000+ ? }
    JobType:=swap(_JobType);
    JobControlFlags:=_JobControlFlags;
    IF UnRestricted
     then begin
          ZstrCopy(JobDescription,_JobDescription,50);
          Move(_ClientRecordArea,ClientRecordArea,152);
          end;
    JobPosition:=_JobPosition;
    ServerConnNbr:=_ServerConnNbr;
    ServerTaskNbr:=_ServerTaskNbr;
    ServerObjectId:=Lswap(_ServerObjectId);
    end;
end;

Procedure ConvertQJE2int(qje:TQueueJobEntry;VAR int:TintJobStruct);
{convert the external QueueJobEntry type into the equivalent
 unit internal type }
Var s:string[50];
begin
With qje,int
 do begin
    _ClientConnNbr:=ClientConnNbr;
    _ClientTaskNbr:=ClientTaskNbr;
    _ClientObjectId:=Lswap(ClientObjectId);
    _TargetServerIdNumber:=Lswap(TargetServerIdNumber);
    Move(TargetExecutionTime,_TargetExecutionTime,6);
    { # fix year for year 2000+ ? }
    Move(JobEntryTime,_JobEntryTime,6);
    { # fix year for year 2000+ ? }
    _JobNumber:=swap(JobNumber);
    _JobType:=swap(JobType);
    _JobPosition:=JobPosition;
    _JobControlFlags:=JobControlFlags;
    PStrCopy(s,JobFilename,14);Move(s[1],_JobFileName,14);
    _JobFileHandle:=JobFileHandle;
    _ServerConnNbr:=ServerConnNbr;
    _ServerTaskNbr:=ServerTaskNbr;
    _ServerObjectId:=Lswap(ServerObjectId);
    PstrCopy(s,JobDescription,50);Move(s[1],_JobDescription,50);
    Move(ClientRecordArea,_ClientRecordArea,152);
    end;
end;


{--- Initial Functions, create and destroy Job Queue --------------------}

{F217/64 {2.1x+}
Function CreateQueue(Qname     :string; QobjectType:Word;
                     dirHandle :Byte;   pathName   :string;
                     VAR QobjID:Longint                      ):Boolean;
{ Creates an object of an object_queue_type in the bindery, checks that
  all settings are valid before creating. Returns the object_id of the
  created queue if creation was successfull. }
{ QobjectType= OT_PRINT_QUEUE, OT_JOB_QUEUE,
               OT_ARCHIVE_QUEUE, own obj.type >$8000 }
{ You need supervisor-equivalent or workgroup-manager rights to perform
  this action. }
{ To add (remove) Queue operators or
  (dis-)allow Queue servers to attach to a queue or
  (dis-)allow objects (users/groups) to use a queue,
  use the AddBinderyObjectToSet and DeleteBinderyObjectFromSet functions
  in the nwBindry unit with the property names Q_OPERATORS, Q_SERVERS
  and Q_USERS respectively. }
Type Treq=record
          len       :Word;
          subFunc   :Byte;
          _Qtype    :Word; { hi-lo}
          _QdivData :array[1..168] of Byte;
          end;
     Trep=record
          _Qid:Longint; {hi-lo}
          end;
     TPreq=^Treq;
     TPrep=^Trep;
Var i:Byte;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$64;
    _Qtype:=swap(QobjectType); { force hi-lo }
    i:=ord(Qname[0])+1;
    UpString(Qname);Move(Qname[0],_QdivData[1],i);

    inc(i);
    _QdivData[i]:=DirHandle;

    inc(i);
    UpString(PathName);
    Move(PathName[0],_QDivData[i],ord(PathName[0])+1);

    len:=3+i+ord(PathName[0]);
    F2SystemCall($17,len+2,SizeOf(Trep),result);
    end;
With TPrep(GlobalReplyBuf)^
 do begin
    QobjID:=Lswap(_Qid); { force lo-hi }
    end;
CreateQueue:=(result=0)
{ resultcodes: $00 Success ; $96 Server Out Of Memory; $99 Drectory Full;
               $9B Bad Directory Handle; $9C Invalid Path; $ED Property Already Exists;
               $EE Object Already Exists; $EF Invalid Name; $F0 Wildcard Not Allowed;
               $F1 Invalid Bindery Security; $F5 No Object Create Privilege;
               $F7 No Property Create Privilege; $FC No Such Object;
               $FE Server Bindery Locked; $FF Bindery Failure. }
end;

{F217/65 [2.1x+]}
Function DestroyQueue(QobjID:Longint):Boolean;
{ Destroys the specified Queue; aborts all jobs in the queue;
  associated files/directories are deleted;
  queue object is removed from the bindery. }
Type Treq=record
          len:Word;
          subFunc:Byte;
          _QobjID:Longint; {hi-lo}
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    len:=SizeOf(Treq)-2;
    subFunc:=$65;
    _QobjID:=Lswap(QobjID); { force hi-lo }
    end;
F2SystemCall($17,Sizeof(Treq),0,result);
DestroyQueue:=(result=0);
{ resultcodes: $00 Success ; $96 Server Out Of Memory; $9C Invalid Path;
               $D0 Queue Error; $D1 No Queue; $FF Hardware Failure. }
end;

{----------------Client or Diagnostic Functions-----------------------------}

{F217/76 [2.1x/3.x]}
Function ReadQueueStatus(QobjID:Longint;
                         Var Qstatus:TQueueStatus):Boolean;
{ Read the status of a queue. This information is changed by queueservers.}
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjID:Longint; {hi-lo}
          end;
     Trep=record
          _QobjID:Longint; {hi-lo}
          _Qstatus:Byte;
          _NbrOfJobs:Byte;
          _NbrOfServers:Byte;    {max.25}
          _serverIDlist:array[1..25] of Longint; {hi-lo}
          _ServerConnNbrs:array[1..25] of Byte;
          _MaxNumberOfServers:Byte;
          end;
     TPreq=^Treq;
     TPrep=^Trep;
Var t:Byte;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    len:=SizeOf(Treq)-2;
    subFunc:=$66;
    _QobjID:=Lswap(QobjID); {force hi-lo}
    end;
F2SystemCall($17,Sizeof(Treq),SizeOf(Trep),result);
With Qstatus, TPrep(GlobalReplyBuf)^
 do begin
    ObjectId:=Lswap(_QobjId);
    status:=_Qstatus;
    NbrOfJobs:=_NbrOfJobs;
    NbrOfServers:=_NbrOfServers;

    for t:=1 to NbrOfServers
     do ServerObjectIDs[t]:=Lswap(_ServerIDlist[t]);
    Move(_ServerConnNbrs,ServerConnNbrs,25);
    MaxNbrOfServers:=_MaxNumberOfServers;
    end;
ReadQueueStatus:=(result=0)
end;

{F217/67 [2.1x+]}
Function SetQueueStatus(QobjId:Longint; NewQstatusFlag:Byte):Boolean;
{ Change the queue status flag. Use the QS_XXXX constants }
Type Treq=record
          len:Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          _Qstatus:Byte;
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$67;
    _QobjId:=Lswap(QobjId);
    _Qstatus:=NewQStatusFlag;
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
SetQueueStatus:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $D3 No Queue Rights;
  $FE Server Bindery Locked;
  $FF Bindery Failure.
}
end;



{F217/6B}
FUNCTION GetQueueJobList( QueueObjId: Longint;
                          Var QJobList:TQueueJobList): Boolean;
{ You need to be either a Q_USER or a Q_OPERATOR }
Type TReq=Record
          BufLen     : Word;
          func       : Byte;
          _QueueObjId: Longint; {hi-lo}
          end;
     TRep=Record
          _JobCount:Word; {max 250, hi-lo}
          _JobBuf  :TJobNumberList; {array, entries hi-lo}
          _MaxJobs :Word; {hi-lo}
          End;
     TPrep=^Trep;
     TPreq=^Treq;
Var i:Word;
Begin
With TPReq(GlobalReqBuf)^
 do Begin
    func:= $6B;
    _QueueObjId:= LSwap(QueueObjId);
    BufLen:=5;
    End;
F2SystemCall($17,Sizeof(Treq),SizeOf(Trep),result);
IF result = 0
 Then with QJobList, TPrep(GlobalReplyBuf)^
       do Begin
          JobCount:= Swap(_JobCount);
          IF (JobCount > MaxQueueJobs)
           Then JobCount:= MaxQueueJobs;
          FOR i:= 1 TO JobCount
           DO JobNbrs[i]:= Swap(_JobBuf[i]);
          MaxJobs:=swap(_MaxJobs);
          End;
GetQueueJobList:= (result = 0);
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $D2 No Queue Server;
  $D3 No Queue Rights;
  $FC No Such Object;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
End;

{F217/6C}
FUNCTION ReadQueueJobEntry( QObjId: Longint;JobNbr: Word;
                            VAR QJob: TQueueJobEntry): Boolean;
{ You need to be either a Q_USER, Q_OPERATOR or a Q_SERVER }
Type TReq=Record
          BufLen     : Word;
          func       : Byte;
          _QueueObjId: Longint;  {hi-lo}
          _JobNumber : Word      {hi-lo}
          End;
     TRep=Record
          buf   : TintJobStruct; { Unit INTERNAL type. To be converted }
          End;
     TPreq=^Treq;
     TPrep=^Trep;
Begin
With TPReq(GlobalReqBuf)^
 do Begin
    Buflen:= 7;
    func:= $6C;
    _QueueObjId:= LSwap(QObjId);
    _JobNumber:= Swap(JobNbr);
    End;
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
IF result= 0
 Then with TPrep(GlobalReplyBuf)^
       do Begin
          ConvertQJE2ext(buf,QJob,True);
          End;
ReadQueueJobEntry:= result = 0;
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $D0 Queue Error;
  $D1 No Queue;
  $D2 No Queue Server;
  $D3 No Queue Rights;
  $D5 No Queue Job;
  $FC No Such Object;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
End;

{F217/6A}
FUNCTION RemoveJobFromQueue( QObjId: Longint; JobNbr: Word): Boolean;
{ You need to be Q_OPERATOR or the Q_USER who queued the job }
Type TReq=Record
          BufLen:   Word;
          func:     Byte;
          _QueueObjId: Longint; {hi-lo}
          _JobNumber:Word    {hi-lo}
          End;
     TPreq=^Treq;
Begin
With TPReq(GlobalReqBuf)^
 do Begin
    Buflen:= 7;
    func:= $6A;
    _QueueObjId:= LSwap(QObjId);
    _JobNumber:= Swap(JobNbr);
    End;
F2SystemCall($17,SizeOf(Treq),0,result);
RemoveJobFromQueue:= result = 0;
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $D0 Queue Error;
  $D1 No Queue;
  $D3 No Queue Rights;
  $D5 No Queue Job;
  $D6 No Job Rights;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
End;


{F217/69 [2.1x+]}
Function StartQueueJob(QobjId:Longint;JobNbr:Word):Boolean;
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          _JobNbr:Word;    {hi-lo}
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$69;
    _QobjId:=Lswap(QobjID);
    _JobNbr:=swap(JobNbr);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
StartQueueJob:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $D0 Queue Error;
  $D1 No Queue;
  $D3 No Queue Rights;
  $D5 No Queue Job;
  $D6 No Job Rights;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;


{F217/6E [2.1x+]}
Function ChangeQueueJobPosition(QobjId:Longint; JobNbr:Word;
                                NewJobPos:Byte              ):Boolean;
{ Q_OPERATOR only }
Type Treq=record
          len       :Word;
          subFunc   :Byte;
          _QobjId   :Longint; {hi-lo}
          _JobNbr   :Word;    {hi-lo}
          _NewJobPos:Byte;
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$6E;
    _QobjId:=Lswap(QobjId);
    _JobNbr:=swap(JobNbr);
    _NewJobPos:=NewJobPos;
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
ChangeQueueJobPosition:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $D0 Queue Error;
  $D1 No Queue;
  $D5 No Queue Job;
  $D6 No Job Rights;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;

{F217/6F [2.1x+]}
Function AttachQueueServerToQueue(QobjId:Longint):Boolean;
{ Q_SERVERs only }
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$6F;
    _QobjId:=Lswap(QobjId);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
AttachQueueServerToQueue:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $D2 No Queue Server;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;


{F217/70 [2.1x+]}
Function DetachQueueServerFromQueue(QobjId:Longint):Boolean;
{ Q_SERVERs only }
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$70;
    _QobjId:=Lswap(QobjId);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
DetachQueueServerFromQueue:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $D2 No Queue Server;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;


{F217/71 [2.1x+]}
Function ServiceQueueJob(QobjID:Longint; JobType:Word;
                                    Var QjobEntry:TQueueJobEntry):Boolean;
{ Q_SERVERs only }
Type Treq=record
          len     :Word;
          subFunc :Byte;
          _QobjId :Longint; {hi-lo}
          _JobType:Word; {hi-lo}
          end;
     Trep=Record
          _qje:TintJobStruct; { EXCEPT last two fields }
          end;
     TPreq=^Treq;
     TPrep=^Trep;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$71;
    _QobjId:=Lswap(QobjId);
    _JobType:=swap(JobType);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep)-50-152,result);
With TPrep(GlobalReplyBuf)^
 do begin
    ConvertQJE2Ext(_qje,QjobEntry,false);
    FillChar(QjobEntry.JobDescription,50,#$0);
    FillChar(QjobEntry.ClientRecordArea,152,#$0);
    { Use the ReadQueueJobEntry function to get job's
      descriptionstring and clientRecordArea. }
    end;
ServiceQueueJob:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $D3 No Queue Rights;
  $D5 No Queue Job;
  $D9 Connection not Queue Server;
  $DA Queue Halted;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;

{F217/72 [2.1x+]}
Function FinishServicingQueueJob(QobjId:Longint;JobNbr:Word;
                                 Charge:Longint             ):Boolean;
{ Q_SERVERs only }
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          _JobNbr:Word;    {hi-lo}
          _Charge:Longint; {hi-lo}
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$72;
    _QobjId:=Lswap(QobjId);
    _JobNbr:=swap(JobNbr);
    _Charge:=Lswap(Charge);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
FinishServicingQueueJob:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $D0 Queue Error;
  $D1 No Queue;
  $D6 No Job Rights; }
end;

{F217/73 [2.1x+]}
Function AbortServicingQueueJob(QobjId:Longint; JobNbr:Word):Boolean;
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          _JobNbr:Word;    {hi-lo}
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$73;
    _QobjId:=Lswap(QobjId);
    _JobNbr:=swap(JobNbr);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
AbortServicingQueueJob:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $D0 Queue Error;
  $D1 No Queue;
  $D6 No Job Rights;
  $D9 Connection not Queue Server; }
end;

{F217/74 [2.1x+]}
Function ChangeToClientRights(QobjId:Longint;JobNbr:Word):Boolean;
{ Q_SERVERs servicing job only }
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          _JobNbr:Word;    {hi-lo}
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$74;
    _QobjId:=Lswap(QobjId);
    _JobNbr:=swap(JobNbr);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
ChangeToClientRights:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $D0 Queue Error;
  $D1 No Queue;
  $D6 No Job Rights;
  $D9 Connection not Queue Server; }
end;

{F217/75 [2.1x+]}
Function RestoreQueueServerRights:Boolean;
{ Q_SERVERs, servicing job and having previously called
  ChangeToClientRights only }
Type Treq=record
          len    :Word;
          subFunc:Byte;
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$75;
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
RestoreQueueServerRights:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $D3 No Queue Rights;
  $D5 No Queue Job;
  $D9 Connection not Queue Server;
  $DA Queue Halted;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;

{F217/76 [2.1x+]}
Function ReadQueueServerStatus(QobjId        :Longint;
                               QserverObjId  :Longint;
                               QserverConnNbr:Byte;
                           Var Qstatus:TQueueServerStatus):Boolean;
Type Treq=record
          len       :Word;
          subFunc   :Byte;
          _QobjId   :Longint; {hi-lo}
          _QSobjId  :Longint; {hi-lo}
          _QSconnNbr:Byte;
          end;
     Trep=record
          _Qstatus:TqueueServerStatus;
          end;
     TPreq=^Treq;
     TPrep=^Trep;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$76;
    _QobjId:=Lswap(QobjId);
    _QSobjId:=Lswap(QserverObjId);
    _QSconnNbr:=QserverConnNbr;
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
With TPrep(GlobalReplyBuf)^
 do begin
    Move(_Qstatus,Qstatus,SizeOf(TQueueServerStatus));
    end;
ReadQueueServerStatus:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $D1 No Queue;
  $D2 No Queue Server;
  $D3 No Queue Rights;
  $F1 Invalid Bindery Security;
  $FC No Such Object;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;

{F217/77 [2.1x+]}
Function SetQueueServerStatus(QobjId:Longint; Qstatus:TqueueServerStatus):Boolean;
Type Treq=record
          len     :Word;
          subFunc :Byte;
          _QobjId :Longint; {hi-lo}
          _Qstatus:TQueueServerStatus;
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$77;
    _QobjId:=Lswap(QobjId);
    Move(Qstatus,_Qstatus,Sizeof(TQueueServerStatus));
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
SetQueueServerStatus:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;

{F217/78 [2.1x+]}
Function GetQueueJobsFileSize(QobjId:Longint; JobNbr:Word;
                             Var JobSize:Longint          ):Boolean;
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          _JobNbr:Word;    {hi-lo}
          end;
     Trep=record
          _QobjId :Longint; {hi-lo}
          _JobNbr :Word;    {hi-lo}
          _JobSize:Longint; {hi-lo}
          end;
     TPreq=^Treq;
     TPrep=^Trep;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$78;
    _QobjId:=Lswap(QobjId);
    _JobNbr:=swap(JobNbr);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
With TPrep(GlobalReplyBuf)^
 do begin
    JobSize:=Lswap(_JobSize);
    end;
GetQueueJobsFileSize:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $9C Invalid Path;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;


{F217/68 [2.1x+]}
Function CreateQueueJob(QobjId:Longint;
              {i/o} Var Qjob:TqueueJobEntry):Boolean;
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint; {hi-lo}
          _Qjob  :TintJobStruct;
          end;
     Trep=record
          _QjobR:TintJobStruct; { Except the last two fields ! }
          end;
     TPreq=^Treq;
     TPrep=^Trep;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$68;
    _QobjId:=Lswap(QobjId);
    ConvertQJE2Int(Qjob,_Qjob);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep)-152-50,result);
With TPrep(GlobalReplyBuf)^
 do begin
    ConvertQJE2Ext(_QjobR,Qjob,False);
    { False => Last 2 fields remain unchanged }
    end;
CreateQueueJob:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $99 Directory Full;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $D2 No Queue Server;
  $D3 No Queue Rights;
  $D4 Queue Full;
  $DA Queue Halted;
  $ED Property Already Exists;
  $EF Invalid Name;
  $F0 Wildcard Not Allowed;
  $F1 Invalid Bindery Security;
  $F7 No Property Create Privilege;
  $FC No Such Object;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;

{F217/6D [2.1x+]}
Function ChangeQueueJobEntry(QobjId:Longint;Qjob:TQueueJobEntry):Boolean;
Type Treq=record
          len    :Word;
          subFunc:Byte;
          _QobjId:Longint;      {hi-lo}
          _Qjob  :TintJobStruct;
          end;
     TPreq=^Treq;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$6D;
    _QobjId:=Lswap(QobjId);
    ConvertQJE2Int(Qjob,_Qjob);
    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),0,result);
ChangeQueueJobEntry:=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $D0 Queue Error;
  $D1 No Queue;
  $D5 No Queue Job;
  $D7 Queue Servicing;
  $FE Server Bindery Locked;
  $FF Bindery Failure. }
end;


{$IFDEF Template} {--------------- Q unit function template ---------------}

{F217/ [2.1x+]}
Function (   ):Boolean;
Type Treq=record
          len:Word;
          subFunc:Byte;

          end;
     Trep=record

          end;
     TPreq=^Treq;
     TPrep=^Trep;
Begin
WITH TPreq(GlobalReqBuf)^
 do begin
    subFunc:=$

    len:=SizeOf(Treq)-2;
    end;
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
With TPrep(GlobalReplyBuf)^
 do begin

    end;
  :=(result=0)
{ Valid completion codes:
  $00 Success
  $96 Server Out Of Memory;
  $99 Drectory Full;
  $9B Bad Directory Handle;
  $9C Invalid Path;
  $D0 Queue Error;
  $D1 No Queue;
  $D2 No Queue Server;
  $D3 No Queue Rights;
  $D4 Queue Full;
  $D5 No Queue Job;
  $D6 No Job Rights;
  $D7 Queue Servicing;
  $D9 Connection not Queue Server;
  $DA Queue Halted;
  $DB Max Queue Servers;
  $ED Property Already Exists;
  $EE Object Already Exists;
  $EF Invalid Name;
  $F0 Wildcard Not Allowed;
  $F1 Invalid Bindery Security;
  $F5 No Object Create Privilege;
  $F7 No Property Create Privilege;
  $FC No Such Object;
  $FE Server Bindery Locked;
  $FF Bindery Failure.
}
end;

{$ENDIF}

end.
