/*static char *SCCSID = "@(#)openq.c	6.3 91/03/29";*/
/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1990                */
/*                 Copyright (c) Microsoft Corp.  1987, 1990                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

/*
 *      This code will implement DosOpenQueue
 */

#include        <dos.h>
#include        <doscalls.h>
#include        <error.h>
#include        <error2.h>
#include        <infoseg.h>
#include        <ipcqueue.h>

unsigned int Q_Find(char far *, int far *, struct Q_ENTRY far * far *);
unsigned int L_Tbl(struct Q_ENTRY far *);
unsigned far pascal w_DOSOPENQUEUE(unsigned far *, unsigned far *, char far *, unsigned short);

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SOURCE FILE NAME:   openq.c                                      */
/*                                                                  */
/* DESCRIPTIVE NAME:   DosOpenQueue                                 */
/*                                                                  */
/* STATUS: RELEASE 1 LEVEL 0                                        */
/*                                                                  */
/* FUNCTION:   Open a queue for the current process.                */
/*                                                                  */
/* NOTES:                                                           */
/*    DEPENDENCIES:                                                 */
/*    RESTRICTIONS:                                                 */
/*                                                                  */
/* ENTRY POINTS:       DosOpenQueue                                 */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             L_Tbl:NEAR                                           */
/*             Q_Find:NEAR                                          */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*             DosICanonicalize:FAR                                 */
/*             queues_sys_trace:NEAR                                */
/*             FindMem:NEAR                                         */
/*             FuncFree:NEAR                                        */
/*             FuncInit:NEAR                                        */
/*             ScanQname:NEAR                                       */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

#if defined(MMIOPH)
extern void queues_sys_trace(
unsigned,                                       /* que_major_code */
unsigned,                                       /* int que_data_len */
unsigned,                                       /* que_minor_code */
char far *);                                    /* que_data */
#endif

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    Q_Find                                       */
/*                                                                  */
/* DESCRIPTIVE NAME:   Q_Find                                       */
/*                                                                  */
/* FUNCTION:   Locate a specified queue within the queue segment    */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        Q_Find                                       */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*      DD     Queue Name                                           */
/*      DD     Queue Handle                                         */
/*      DD     Queue Entry Pointer Storage                          */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*             qu_entry        ;offset of desired queue             */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'QUEUE NAME DOES NOT EXIST'                          */
/*                                                                  */
/* EFFECTS:                                                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DosICanonicalize:FAR                                 */
/*             ScanQname:NEAR                                       */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      Q_Find:                                                     */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/*        Q_FIND attempts to locate a specified queue within the    */
/*   queue segment.                                                 */
/*        Q_FIND scans the q_entry chain for the desired queue. If  */
/*   the queue found, Q_FIND returns the address of the appropriate */
/*   queue.                                                         */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/*      call ScanQname                                              */
/*      if (ScanQname returns in error) then                        */
/*        return error          'QUEUE NAME DOES NOT EXIST'         */
/*      else                                                        */
/*        queue entry = offset qu_entry                             */
/*        return                'NO ERROR'                          */
/*      endif                                                       */

unsigned int
Q_Find(new_name,qhndl,qoff)
char    far     *new_name;
int     far     *qhndl;
struct  Q_ENTRY far * far *qoff;
{
        struct  Q_ENTRY far *q_off;
        struct  Q_ENTRY far *q_prev;

        if ((ScanQname((char far *) new_name,(struct  Q_ENTRY far * far *) &q_off,(struct  Q_ENTRY far * far *) &q_prev))
                != NO_ERROR)
                return(ERROR_QUE_NAME_NOT_EXIST);
        else
        {
                *qoff = q_off;
                return(NO_ERROR);
        }
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    L_Tbl                                        */
/*                                                                  */
/* DESCRIPTIVE NAME:   L_Tbl                                        */
/*                                                                  */
/* FUNCTION:   Links the requesting process to the desired queue    */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        L_Tbl                                        */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*      DD     qu_entry        ;offset of desired queue             */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'MEMORY ERROR'                                       */
/*                                                                  */
/* EFFECTS:                                                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             FindMem:NEAR                                         */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      L_Tbl:                                                      */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/*     L_TBL attempts to link the requesting process to the desired */
/*queue.                                                            */
/*     L_TBL scans the l_entry chain for the desired PID - queue    */
/*link. If found, L_TBL increments the count; if not found, L_TBL   */
/*attempts to create a link entry.                                  */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/*      if (queue pid == current pid)                               */
/*        increment q_l_cnt                                         */
/*        return with           'NO_ERROR'                          */
/*      endif                                                       */
/*      if (static.fst_link != NULL)                                */
/*        offset = static.fst_lnk                                   */
/*        while (offset.l_chain != 0 and                            */
/*              (offset.l_qhndl != qu_entry.q_hndl or               */
/*               offset.l_pid != static.st_pid))                    */
/*          offset = offset.l_chain                                 */
/*        endwhile                                                  */
/*        if ((offset.l_pid = static.st_pid) &&                     */
/*           (offset.l_qhndl = qu_entry.q_hndl))                    */
/*          increment l_cnt                                         */
/*          set q_linked on in qu_entry.q_flags                     */
/*          return with         'NO_ERROR'                          */
/*        endif                                                     */
/*      endif                                                       */
/*      call FindMem                                                */
/*      if (FindMem returns in error) then                          */
/*        return with           'INADEQUATE MEMORY'                 */
/*      else                                                        */
/*        initialize exitlist action variables                      */
/*        set exitlist action flag = ACT_ADD_LNK                    */
/*        initialize l_entry structure                              */
/*        update link chain                                         */
/*        set exitlist action flag off                              */
/*        return with           'NO_ERROR'                          */
/*      endif                                                       */

unsigned int
L_Tbl(q_addr)
struct  Q_ENTRY far *q_addr;
{
        extern  struct  STATDATA        statseg;
        extern  unsigned char   action;
        extern  struct  Q_ENTRY far     *que1;
        extern  struct  L_ENTRY far     *lnk1;

        struct  L_ENTRY far *l_off;


        if ((*q_addr).q_pid == statseg.st_pid)
        {
                (*q_addr).q_l_cnt++;
                return(NO_ERROR);
        }
        if (statseg.fst_link != NULL)
        {
                l_off = statseg.fst_link;
                while (((*l_off).l_chain != NULL) &&
                        (((*l_off).l_qhndl != (*q_addr).q_hndl) ||
                        ((*l_off).l_pid != statseg.st_pid)))
                {
                        l_off = (*l_off).l_chain;
                }
                if (((*l_off).l_qhndl == (*q_addr).q_hndl) && ((*l_off).l_pid == statseg.st_pid))
                {
                        (*l_off).l_cnt++;
                        (*q_addr).q_flags |= Q_LINKS;
                        return(NO_ERROR);
                }
        }
        if ((FindMem(sizeof(struct L_ENTRY),(unsigned char far * far *) &l_off)) != NO_ERROR)
        {
                return(ERROR_QUE_NO_MEMORY);
        }
        else
        {
                (*l_off).l_flags = NULL;
                (*l_off).l_cnt = 1;
                (*l_off).l_pid = statseg.st_pid;
                (*l_off).l_qhndl = (*q_addr).q_hndl;
                (*l_off).l_chain = statseg.fst_link;
                que1 = q_addr;
                lnk1 = l_off;
                action = ACT_ADD_LNK;
                statseg.fst_link = l_off;
                (*q_addr).q_flags |= Q_LINKS;
                action = 0;
                return(NO_ERROR);
        }
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    w_DosOpenQueue                               */
/*                                                                  */
/* DESCRIPTIVE NAME:   DosOpenQueue                                 */
/*                                                                  */
/* FUNCTION:   Main line control for DosOpenQueue                   */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        DosOpenQueue                                 */
/*    LINKAGE:         far at pl 2                                  */
/*                                                                  */
/* INPUT:                                                           */
/*             DD      owner pid       ;address for q owner pid     */
/*             DD      queue handle    ;address to store queue hnd  */
/*             DD      queue name      ;name of desired queue       */
/*             DW      callersize      ;32 or 16 bit flag           */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*             queue handle                                         */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'INSUFFICIENT MEMORY'                                */
/*             'QUEUE NAME DOES NOT EXIST'                          */
/*             'SYS ERROR'                                          */
/*                                                                  */
/* EFFECTS:    links the current process to the desired queue       */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             L_Tbl:NEAR                                           */
/*             Q_Find:NEAR                                          */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             queues_sys_trace:NEAR                                */
/*             FuncFree:NEAR                                        */
/*             FuncInit:NEAR                                        */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      DosOpenQueue:                                               */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/*   DosOpenQueue acts as the entry point and main line control for */
/*   DosOpenQueue.  It first checks for proper initialization, then */
/*   attempts to find the desired queue. If the queue is owned      */
/*   by the requesting process                                 along*/
/*   with the queue handle.  It will attempt to link the requesting */
/*   process to the desired queue.                                  */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/*      initialize error                'NO ERROR'                  */
/*      if (tracing active)                                         */
/*        call queues_sys_trace                                     */
/*      endif                                                       */
/*      call DosICanonicalize                                       */
/*      if (DosICanonicalize returns in error)                      */
/*        set error code        'QUEUE NAME DOES NOT EXIST'         */
/*      else                                                        */
/*        call FuncInit                                             */
/*        if (FuncInit returns in error) then                       */
/*          set error code        'SYS ERROR'                       */
/*        else                                                      */
/*          call Q_Find                                             */
/*          if (Q_Find returns in error) then                       */
/*            set error code      from Q_Find                       */
/*          else                                                    */
/*            if 32 bit open of 16 bit queue then                   */
/*              set error code    'PROC NO ACCESS'                  */
/*            else                                                  */
/*            call L_Tbl                                            */
/*              if (L_Tbl returns in error) then                    */
/*                set error code    from L_Tbl                      */
/*              else                                                */
/*                put queue owner pid in specified address          */
/*                put queue handle in specified address             */
/*                set error         'NO ERROR'                      */
/*              endif                                               */
/*            endif                                                 */
/*          endif                                                   */
/*          call FuncFree                                           */
/*          if (FuncFree returns in error and error not set)        */
/*            set error code        'SYS ERROR'                     */
/*          endif                                                   */
/*        endif                                                     */
/*      endif                                                       */
/*      if (tracing active)                                         */
/*        call queues_sys_trace                                     */
/*      endif                                                       */
/*      return                                                      */

extern unsigned far pascal DOSICANONICALIZE (char far *, char far *, char near *, char near *, unsigned);

unsigned far pascal w_DOSOPENQUEUE(OwnerPID,QHnd,QName,callersize)
unsigned far *OwnerPID;
unsigned far *QHnd;
char far *QName;
unsigned short   callersize;
{
        extern  struct  InfoSegGDT far  *globptr;
        extern  struct  STATDATA        statseg;
        extern  struct  Q_INST far *ISEG;
        struct  Q_ENTRY far *q_offset;
        register unsigned int    exitcode = 1;
        unsigned int len;
        register unsigned int rc;
        char    new_name[MAX_QUE_NAME_LENGTH];

#if defined(MMIOPH)
        struct RAS_PRE_OPEN {
                                        char rp_name[MAX_QUE_NAME_LENGTH];
        } ras_pre_open;
        struct RAS_POST_OPEN {
                unsigned long rp_rc;
                unsigned long rp_hnd;
                unsigned long rp_pid;
        } ras_post_open;
#endif

        PUSHALL_DS();
        rc = NO_ERROR;
        #if (cdbug)
        krnldbug();
        #endif

/***DT DosOpenQueue - Pre-Invocation Dynamic Trace
 *     TRACE MINOR =0x0003,
 *           TP=@
 *           TYPE  =(PRE,API),
 *           DESC  ="(OS) DosOpenQueue Pre-Invocation",
 *           FMT   ="Queue name=%ps",
 *           ASCIIZ=(.QName,i,260)
 */

#if defined(MMIOPH)
        if (((*globptr).mec_table[17] & 0x80) != NULL)
        {
                rascpy((char far *) ras_pre_open.rp_name,QName,(unsigned far *) &len);
                if (len > RASBUFLEN)
                        len = RASBUFLEN;
                queues_sys_trace(((unsigned) 0x88),len,((unsigned) 3),(char far *) &ras_pre_open);
        }
#endif

        if ((DOSICANONICALIZE(QName,(char far *) new_name,(char near *) new_name,(char near *) new_name+MAX_QUE_NAME_LENGTH, 2)) != NO_ERROR)
                rc = ERROR_QUE_NAME_NOT_EXIST;
        else
        {
           if ((FuncInit()) != NO_ERROR)
                   rc = ERROR_SYS_INTERNAL;
           else
           {
                   if ((rc = Q_Find((char far *)new_name,QHnd,(struct Q_ENTRY far * far *) &q_offset)) == NO_ERROR)
                   {
                           if (callersize && !((*q_offset).q_flags & Q_BIT32))
                                   rc = ERROR_QUE_PROC_NO_ACCESS;
                           else
                                   if ((rc = L_Tbl(q_offset)) == NO_ERROR)
                                   {
                                           *OwnerPID = (*q_offset).q_pid;
                                           *QHnd = (*q_offset).q_hndl;
                                   }
                   }
                   if ((FuncFree() != NO_ERROR) && (rc == NO_ERROR))
                           rc = ERROR_SYS_INTERNAL;
           }
        }

/***DT DosOpenQueue - Post-Invocation Dynamic Trace
 *     TRACE MINOR =0x8003,
 *           TP=@
 *           TYPE  =(POST,API),
 *           DESC  ="(OS) DosOpenQueue Post-Invocation",
 *           FMT   ="Return Code=%pw  Handle=%pw  Owner PID=%pw",
 *           MEM   =(.rc,d,2),
 *           MEM   =(.QHnd,i,2),
 *           MEM   =(.OwnerPID,i,2)
 */

#if defined(MMIOPH)
        if (((*globptr).mec_table[17] & 0x80) != NULL)
        {
                ras_post_open.rp_rc = (unsigned long)rc;
                ras_post_open.rp_hnd = (unsigned long)*QHnd;
                ras_post_open.rp_pid = (unsigned long)*OwnerPID;
                queues_sys_trace(((unsigned) 0x88),sizeof(struct RAS_POST_OPEN),((unsigned) 0x83),(char far *) &ras_post_open);
        }
#endif

        return(POPALL(rc));
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    DosOpenQueue                                 */
/*                                                                  */
/* DESCRIPTIVE NAME:   DosOpenQueue                                 */
/*                                                                  */
/* FUNCTION:   Parent routine for 16 bit DOSOPENQUEUE               */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        DosOpenQueue                                 */
/*    LINKAGE:         far at pl 2                                  */
/*                                                                  */
/* INPUT:                                                           */
/*             DD      owner pid       ;address for q owner pid     */
/*             DD      queue handle    ;address to store queue hnd  */
/*             DD      queue name      ;name of desired queue       */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*             queue handle                                         */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'INSUFFICIENT MEMORY'                                */
/*             'QUEUE NAME DOES NOT EXIST'                          */
/*             'SYS ERROR'                                          */
/*                                                                  */
/* EFFECTS:    links the current process to the desired queue       */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             L_Tbl:NEAR                                           */
/*             Q_Find:NEAR                                          */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             queues_sys_trace:NEAR                                */
/*             FuncFree:NEAR                                        */
/*             FuncInit:NEAR                                        */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      DosOpenQueue:                                               */
/********************************************************************/
/*                                                                  */
/*      call w_DOSOPENQUEUE                                         */
/*      return                                                      */

unsigned far pascal DOSOPENQUEUE(OwnerPID,QHnd,QName)
unsigned far *OwnerPID;
unsigned far *QHnd;
char far *QName;
{
        unsigned int rc;
        PUSHALL_DS();
        rc=w_DOSOPENQUEUE(OwnerPID,QHnd,QName,(unsigned int) 0);
        return(POPALL(rc));
}
