home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 19 Printer / 19-Printer.zip / RESPOOL.ZIP / RESPOOL.C < prev    next >
C/C++ Source or Header  |  1991-07-08  |  18KB  |  524 lines

  1. /* Network Respooler v 1.0
  2.  
  3.    by Phillip G. Austin
  4.  
  5.    The following is a Lan Manager service designed to allow redirection of
  6.    print jobs to network printers from any system that does not support
  7.    network connection but that will print to a serial device.  The service
  8.    can run on either a server or an OS/2 workstation, and the number of
  9.    redirected print devices is limited only by the machine/network capacity
  10.    through the use of multiple threads.  See the file "respool.txt" for
  11.    installation instructions.
  12.  
  13.    Version 1.0 of this software is released as shareware and may be freely
  14.    used and distributed, however commercial sale of this software or
  15.    distribution where fees are charged is prohibited unless consent of the
  16.    author is first obtained.  This software has no warranty of any kind,
  17.    is distributed as-is, and usage is at the risk of the user.
  18.  
  19.    This program requires Microsoft C 6.0 and the Lan Manager PTK in order
  20.    to compile.    The file "makeit.bat" illustrates the required compiler
  21.    and linker command lines.
  22.  
  23. */
  24.  
  25.  
  26. #define     INCL_KBD
  27. #define     INCL_VIO
  28. #define     INCL_DOSSIGNALS
  29. #define     INCL_DOSPROCESS
  30. #define     INCL_DOSSEMAPHORES
  31. #define     INCL_DOSFILEMGR
  32. #define     INCL_DOSERRORS
  33. #define     INCL_DOSDEVIOCTL
  34. #include    <os2.h>        // MS OS/2 header files
  35.  
  36. #define     INCL_NETSERVICE
  37. #define     INCL_NETALERT
  38. #define     INCL_NETERRORS
  39. #define     INCL_NETERRORLOG
  40. #include    <lan.h>        // LAN Manager header files
  41.                      
  42. #include    <stdio.h>
  43. #include    <process.h>
  44. #include    <stdlib.h>
  45. #include    <string.h>
  46.  
  47. #define DEFAULT_STACK_SIZE    (8152+512) // 8K thread stack size
  48.  
  49. #define MYSERVICENAME        "RESPOOLER"
  50. #define DEFAULTCOMPONENTNAME    "RESPOOLER"
  51.  
  52. #define MSGERRCNTRLCSIGNAL  "Error in Setting CTL-C Handler %d"
  53. #define MSGERRCNTRLBSIGNAL  "Error in Setting CTL-BREAK Handler %d"
  54. #define MSGERRKILLPSIGNAL   "Error in Setting KILLPROCESS Handler %d"
  55. #define MSGERRFLAGASIGNAL   "Error in Setting Flag A Handler %d"
  56. #define MSGERRFLAGBSIGNAL   "Error in Setting Flag B Handler %d"
  57. #define MSGERRFLAGCSIGNAL   "Error in Setting Flag C Handler %d"
  58. #define MSGERRSRVSSIGNAL    "Error in Setting Service Handler %d"
  59. #define MSGERRDOSSEMSET     "Error in DosSemSet %d"
  60. #define MSGERRDOSSEMWAIT    "Error in DosSemWait %d"
  61. #define MSGERRBEGINTHREAD   "Error in Spawning Thread tid: %d"
  62. #define MSGERRSEMWAIT       "Error in DosSemWait %d"
  63. #define MSGERRGETPID        "Error in DosGetPID %d"
  64. #define MSGERRDOSOPEN        "Error in DosOpen %d"
  65. #define MSGERRCREATESEM     "Error Creating System Semaphore %d"
  66.  
  67. PFNSIGHANDLER pnPrevHandler;       // Previous handle address
  68. unsigned short pfPrevAction;       // Previous action flag
  69. int  fSigStarted;                  // Flag: TRUE if signal handler started
  70. struct service_status ssStatus;    // Service status structure
  71.  
  72. PBYTE  pbStack;                    // Address of top of stack
  73. TID tThreadTid;                    // TID of Alert handler thread
  74.  
  75. // Application Semaphores
  76. unsigned long hSemThreadInit;       // RAM semaphore to pause main during thread init
  77. unsigned long hSemPause = 0;       // RAM semaphore for pausing respooler
  78. HSEM hSemThreadBlock;           // System Semaphore to block main until threads complete
  79.  
  80. char  szErrBuffer[80];           // Buffer used to report errors
  81. int   Shutdown = FALSE;        // Service shutdown flag
  82.  
  83.  
  84. // Function declarations
  85. void far Respool(char *arg);
  86. void ErrOut(unsigned short, char far *);
  87. void far pascal SignalHandler(unsigned short, unsigned short);
  88. void far PopOneUp(char far *);
  89.  
  90. unsigned extern far pascal DosDevIOCtl(void far *, void far *, unsigned, unsigned, unsigned);
  91.  
  92.  
  93. void main(int argc, char *argv[])
  94. {
  95.    int iCount;                    // Index for parsing argv
  96.    unsigned uReturnCode;          // Return code
  97.    char  szErrBuffer[80];         // Buffer used to report errors
  98.    unsigned short usAction;      // Action taken by DosOpen
  99.    PIDINFO pidInfo;               // Get PID of main process
  100.    HFILE   hFileNul;          // Handle for NUL device
  101.    HFILE   hNewHandle;            // Temporary handle
  102.    fSigStarted  = FALSE;          // Signal handler not started
  103.                                   // Set up service status for param error
  104.    ssStatus.svcs_status = SERVICE_UNINSTALLED |
  105.                           SERVICE_UNINSTALLABLE;
  106.    ssStatus.svcs_code = SERVICE_UIC_M_ERRLOG;    // Look at error log
  107.  
  108.    /* 
  109.     * Get the process ID of the main process to be
  110.     * used in subsequest NetServiceStatus calls.
  111.     */
  112.  
  113.    uReturnCode = DosGetPID( &pidInfo);
  114.  
  115.    if (uReturnCode != NERR_Success)
  116.    {
  117.       sprintf(szErrBuffer, MSGERRGETPID, uReturnCode);
  118.       ErrOut(uReturnCode, szErrBuffer);
  119.    }
  120.    ssStatus.svcs_pid = pidInfo.pid;
  121.  
  122.    /* 
  123.     * Notify LAN Manager that the service is installing. At this time, 
  124.     * the service cannot be paused or uninstalled because signal handler 
  125.     * has not been installed.
  126.     */
  127.  
  128.    ssStatus.svcs_status = SERVICE_INSTALL_PENDING |
  129.                           SERVICE_NOT_UNINSTALLABLE |
  130.                           SERVICE_NOT_PAUSABLE;
  131.    ssStatus.svcs_code = SERVICE_UIC_NORMAL;
  132.  
  133.    uReturnCode = NetServiceStatus((char far *) &ssStatus, sizeof(ssStatus));
  134.  
  135.    /* 
  136.     * Install the signal handler. Ignore CTRL-C, BREAK, and KILL 
  137.     * signals and let LAN Manager take care of them. The signal 
  138.     * handler will be raised when SERVICE_RCV_SIG_FLAG is raised
  139.     * (SERVICE_RCV_SIG_FLAG is the same as SIG_PFLG_A).
  140.     */
  141.  
  142.    uReturnCode = DosSetSigHandler(SignalHandler,
  143.                                   &pnPrevHandler,
  144.                                   &pfPrevAction,
  145.                                   SIGA_ACCEPT,
  146.                                   SERVICE_RCV_SIG_FLAG);
  147.  
  148.    if (uReturnCode != NERR_Success)
  149.    {
  150.       sprintf(szErrBuffer, MSGERRCNTRLCSIGNAL, uReturnCode);
  151.       ErrOut(uReturnCode, szErrBuffer);
  152.    }
  153.  
  154.    // PopOneUp("Signal Handler Installed");
  155.  
  156.    /* 
  157.     * Signal handler has been installed. Service can now be
  158.     * paused or uninstalled.
  159.     */
  160.  
  161.    fSigStarted = TRUE;
  162.    ssStatus.svcs_status = SERVICE_INSTALL_PENDING |
  163.                           SERVICE_UNINSTALLABLE |
  164.                           SERVICE_PAUSABLE;
  165.    ssStatus.svcs_code = SERVICE_UIC_NORMAL;
  166.  
  167.    uReturnCode = NetServiceStatus((char far *)&ssStatus, sizeof(ssStatus));
  168.  
  169.    uReturnCode = DosSetSigHandler(NULL,      // Ignore CTRL-C
  170.                                   &pnPrevHandler,
  171.                                   &pfPrevAction,
  172.                                   SIGA_IGNORE,
  173.                                   SIG_CTRLC);
  174.  
  175.    if (uReturnCode != NERR_Success)
  176.    {
  177.       sprintf(szErrBuffer, MSGERRCNTRLCSIGNAL, uReturnCode);
  178.       ErrOut(uReturnCode, szErrBuffer);
  179.    }
  180.  
  181.    uReturnCode = DosSetSigHandler(NULL,      // Ignore BREAK signal
  182.                                   &pnPrevHandler,
  183.                                   &pfPrevAction,
  184.                                   SIGA_IGNORE,
  185.                                   SIG_CTRLBREAK);
  186.  
  187.    if (uReturnCode != NERR_Success)
  188.    {
  189.       sprintf(szErrBuffer, MSGERRCNTRLBSIGNAL, uReturnCode);
  190.       ErrOut(uReturnCode, szErrBuffer);
  191.    }
  192.  
  193.    uReturnCode = DosSetSigHandler(NULL,      // Ignore KILL signal
  194.                                   &pnPrevHandler,
  195.                                   &pfPrevAction,
  196.                                   SIGA_IGNORE,
  197.                                   SIG_KILLPROCESS);
  198.  
  199.    if (uReturnCode != NERR_Success)
  200.    {
  201.       sprintf(szErrBuffer, MSGERRKILLPSIGNAL, uReturnCode);
  202.       ErrOut(uReturnCode, szErrBuffer);
  203.    }
  204.  
  205.    uReturnCode = DosSetSigHandler(NULL, // Flag B should cause error
  206.                                   &pnPrevHandler,
  207.                                   &pfPrevAction,
  208.                                   SIGA_ERROR,
  209.                                   SIG_PFLG_B);
  210.  
  211.    if (uReturnCode != NERR_Success)
  212.    {
  213.       sprintf(szErrBuffer, MSGERRFLAGBSIGNAL, uReturnCode);
  214.       ErrOut(uReturnCode, szErrBuffer);
  215.    }
  216.  
  217.    uReturnCode = DosSetSigHandler(NULL, // Flag C should cause error
  218.                                   &pnPrevHandler,
  219.                                   &pfPrevAction,
  220.                                   SIGA_ERROR,
  221.                                   SIG_PFLG_C);
  222.  
  223.    if (uReturnCode != NERR_Success)
  224.    {
  225.       sprintf(szErrBuffer, MSGERRFLAGCSIGNAL, uReturnCode);
  226.       ErrOut(uReturnCode, szErrBuffer);
  227.    }
  228.  
  229.    /* 
  230.     * Close stdin, stdout, and stderr handles so that
  231.     * they cannot be used from this service. Redirect stdin, stdout,
  232.     * stderr to NULL device.
  233.     */
  234.  
  235.     // Open the null device
  236.     uReturnCode = DosOpen("NUL",        // Name of device
  237.                            &hFileNul,      // Handle
  238.                            &usAction,   // Action taken
  239.                            0L,          // File size
  240.                            FILE_NORMAL, // File attribute
  241.                            FILE_OPEN,   // Open action
  242.                                         // Open mode
  243.                            OPEN_ACCESS_READWRITE|OPEN_SHARE_DENYNONE,
  244.                            0L);         // Reserved
  245.     if (uReturnCode != NERR_Success)
  246.     {
  247.       sprintf(szErrBuffer, MSGERRDOSOPEN, uReturnCode);
  248.       ErrOut(uReturnCode, szErrBuffer);
  249.     }
  250.  
  251.     // Reroute stdin, stderr, and stderr to NUL
  252.     for (hNewHandle=0; hNewHandle < 3; hNewHandle++)
  253.     {
  254.         // Skip the duplicating operation if the
  255.         // handle already points to NUL
  256.         if (hFileNul != hNewHandle)
  257.             DosDupHandle(hFileNul, &hNewHandle);
  258.     }
  259.  
  260.     // Extra handle to NUL not needed anymore
  261.     if (hFileNul > 2)
  262.     DosClose(hFileNul);
  263.  
  264.    /* Create ThreadBlock system semaphore which is recursively owned by
  265.     * each thread.
  266.     */
  267.  
  268.    uReturnCode = DosCreateSem(0,&hSemThreadBlock,"\\SEM\\RESPOOL\\TBLOCK.SEM");
  269.    if (uReturnCode != 0)
  270.     {
  271.     sprintf(szErrBuffer, MSGERRCREATESEM, uReturnCode);
  272.     ErrOut(0, szErrBuffer);
  273.     }
  274.  
  275.    // Notify LAN Manager that the service is installed and active.
  276.    ssStatus.svcs_status = SERVICE_INSTALLED |
  277.                           SERVICE_ACTIVE |
  278.                           SERVICE_UNINSTALLABLE|
  279.                           SERVICE_PAUSABLE;
  280.    ssStatus.svcs_code = SERVICE_UIC_NORMAL;
  281.  
  282.    uReturnCode = NetServiceStatus((char far *) &ssStatus, sizeof(ssStatus));
  283.  
  284.    /*
  285.     * Parse the service parameters passed by LAN Manager.
  286.     * The parameters passed in argv are from the LANMAN.INI
  287.     * [Respooler] section and follow the convention:
  288.     *
  289.     *    Input Port=Printer Name,Timeout (seconds)
  290.     *
  291.     * Start a thread to service each port listed.
  292.     */
  293.  
  294.    for (iCount = 1; iCount < argc; iCount++)
  295.    {
  296.       DosSemSet(&hSemThreadInit);
  297.       tThreadTid = _beginthread(Respool,
  298.                 NULL,
  299.                 DEFAULT_STACK_SIZE,
  300.                 argv[iCount]);
  301.       if(tThreadTid == -1)
  302.       {
  303.      sprintf(szErrBuffer, MSGERRBEGINTHREAD,tThreadTid);
  304.      PopOneUp(szErrBuffer);
  305.      ErrOut(0, szErrBuffer);
  306.       }
  307.       else
  308.       {
  309.      DosSemWait(&hSemThreadInit,SEM_INDEFINITE_WAIT);
  310.       }
  311.    }
  312.  
  313.    /*
  314.     * The main thread waits on the system semaphore, but it is
  315.     * interrupted whenever a signal comes. Loop over DosSemWait 
  316.     * if interrupted by a signal.
  317.     */
  318.  
  319.    do {
  320.       uReturnCode = DosSemWait(hSemThreadBlock, SEM_INDEFINITE_WAIT);
  321.  
  322.    } while (uReturnCode == ERROR_INTERRUPT);
  323.  
  324.    DosCloseSem(hSemThreadBlock);
  325.  
  326.    //Notify LAN Manager that the service will uninstall.
  327.    ssStatus.svcs_status = SERVICE_UNINSTALL_PENDING |
  328.                           SERVICE_UNINSTALLABLE |
  329.                           SERVICE_NOT_PAUSABLE;
  330.    ssStatus.svcs_code = SERVICE_UIC_NORMAL;
  331.  
  332.    uReturnCode = NetServiceStatus((char far *) &ssStatus, sizeof(ssStatus));
  333.  
  334.    // Notify LAN Manager that the service is uninstalled.
  335.    ssStatus.svcs_status = SERVICE_UNINSTALLED |
  336.                           SERVICE_UNINSTALLABLE |
  337.                           SERVICE_NOT_PAUSABLE;
  338.    ssStatus.svcs_code = SERVICE_UIC_NORMAL;
  339.  
  340.    NetServiceStatus((char far *) &ssStatus, sizeof(ssStatus));
  341.    return;
  342. }
  343.  
  344. //=======================================================================
  345. //  ErrOut
  346. // 
  347. //  This routine is called whenever an error that needs to
  348. //  be reported occurs. It writes a text message in the error log
  349. //  and then calls the ExitHandler routine to stop the service.
  350. //=======================================================================
  351.  
  352. void ErrOut(unsigned short usErrCode, char far * psErrStr)
  353. {
  354.    NetErrorLogWrite(NULL,                // Reserved; must be NULL
  355.                     usErrCode,           // Error code
  356.                     MYSERVICENAME,       // Component name
  357.                     NULL,                // Pointer to raw data buffer
  358.                     0,                   // Length of raw data buffer
  359.                     psErrStr,            // String data
  360.                     1,                   // Number of error strings
  361.                     NULL);               // Reserved; Must be NULL
  362.  
  363.    /*
  364.     * If signal handler IS installed, notify LAN Manager 
  365.     * that the service is exiting.
  366.     */
  367.  
  368.    DosExit(EXIT_PROCESS, 0);
  369. }
  370.  
  371. //=======================================================================
  372. //  SignalHandler
  373. // 
  374. //  The signal handling routine gets control when the system sends a
  375. //  status-changing request to the service. The routine should always 
  376. //  expect these arguments:
  377. //     usSigArg = Opcode that describes the request 
  378. //     usSigNum = Number that identifies the process flag
  379. //                the signal was raised on
  380. //=======================================================================
  381.  
  382. void far pascal SignalHandler(unsigned short usSigArg,
  383.                               unsigned short usSigNum)
  384. {
  385.    unsigned uReturnCode;
  386.    unsigned char fOpCode;
  387.                                            // Compute the function code
  388.    fOpCode = (unsigned char) (usSigArg & 0xFF);
  389.                    
  390.    switch (fOpCode)                        // Do the function
  391.    {
  392.       case SERVICE_CTRL_UNINSTALL:       // Uninstall; end the service
  393.      Shutdown = TRUE;
  394.      return;
  395.          break;
  396.       case SERVICE_CTRL_PAUSE:             // Pause service
  397.          DosSemSet(&hSemPause);            // Pause AlertHandler
  398.          ssStatus.svcs_status = SERVICE_INSTALLED |
  399.                                 SERVICE_PAUSED |
  400.                                 SERVICE_UNINSTALLABLE|
  401.                                 SERVICE_PAUSABLE;
  402.          ssStatus.svcs_code = SERVICE_UIC_NORMAL;
  403.          uReturnCode = NetServiceStatus((char far *) &ssStatus,
  404.                                         sizeof(ssStatus));
  405.          break;
  406.       case SERVICE_CTRL_CONTINUE:          // Continue service
  407.          DosSemClear(&hSemPause);          // Continue AlertHandler
  408.          ssStatus.svcs_status = SERVICE_INSTALLED |
  409.                                 SERVICE_ACTIVE |
  410.                                 SERVICE_UNINSTALLABLE|
  411.                                 SERVICE_PAUSABLE;
  412.          ssStatus.svcs_code = SERVICE_UIC_NORMAL;
  413.          uReturnCode = NetServiceStatus((char far *) &ssStatus,
  414.                                         sizeof(ssStatus));
  415.          break;
  416.       case SERVICE_CTRL_INTERROGATE:       // Give service status
  417.       default:
  418.          uReturnCode = NetServiceStatus((char far *) &ssStatus,
  419.                                         sizeof(ssStatus));
  420.          break;
  421.    }
  422.  
  423.    /*
  424.     * Reenable signal handling. This signal handler accepts the next 
  425.     * signal raised on usSigNum.
  426.     */
  427.    uReturnCode = DosSetSigHandler(0,
  428.                           0,
  429.                           0,
  430.                           SIGA_ACKNOWLEDGE,
  431.                           usSigNum);
  432.    return;
  433. }
  434.  
  435. void far Respool(char *Parms)
  436. {
  437.    char CommBuffer[1024];
  438.    USHORT BytesIn;
  439.    USHORT BytesOut;
  440.    char Port[6];
  441.    char PrintDev[30];
  442.    char cReadTimeout[20];
  443.    unsigned hCommPort;
  444.    unsigned hPrinterPort;
  445.    unsigned Action;
  446.    int PrinterOpen = FALSE;
  447.    DCBINFO PortDCB;
  448.  
  449.    // Set ThreadBlock Semaphore
  450.    DosSemRequest( hSemThreadBlock, 0);
  451.  
  452.    // Parse Parms
  453.    _fstrcpy(Port,_fstrtok(Parms,"="));
  454.    _fstrcpy(PrintDev,_fstrtok(NULL,","));
  455.    _fstrcpy(cReadTimeout,_fstrtok(NULL,","));
  456.  
  457.    // Open and initialize ports
  458.    if(DosOpen(Port,&hCommPort,&Action,0L,0,0x01,0x12, 0L))
  459.       PopOneUp("Can't Open Port");
  460.  
  461.    DosDevIOCtl(&PortDCB,NULL,0x73,1,hCommPort);
  462.    PortDCB.usReadTimeout = (USHORT) atoi(cReadTimeout)*100;
  463.    DosDevIOCtl(NULL,&PortDCB,0x53,1,hCommPort);
  464.  
  465.    // Clear ThreadInit Semaphore
  466.    DosSemClear( &hSemThreadInit );
  467.  
  468.    // loop until Shutdown = TRUE
  469.    while ( Shutdown == FALSE )
  470.    {
  471.       DosSemWait( &hSemPause, -1 );
  472.       DosRead(hCommPort, CommBuffer,1024,&BytesIn);
  473.       if (BytesIn > 0)
  474.       {
  475.      if ( PrinterOpen != TRUE )
  476.      {
  477.         DosOpen(PrintDev,&hPrinterPort,&Action,0L,0,0x01,0x41,0);
  478.         PrinterOpen = TRUE;
  479.      }
  480.      DosWrite(hPrinterPort,CommBuffer,BytesIn,&BytesOut);
  481.       }
  482.       else
  483.       {
  484.      if (PrinterOpen == TRUE)
  485.      {
  486.         DosClose(hPrinterPort);
  487.         PrinterOpen = FALSE;
  488.      }
  489.       }
  490.  
  491.  
  492.       // DosSleep(10000);
  493.       // DosSemWait( &hSemPause, -1 );
  494.       // PopOneUp(PopBuffer);
  495.    }
  496.  
  497.  
  498.    // Close ports and clean up
  499.    DosClose(hCommPort);
  500.    if (PrinterOpen == TRUE)
  501.       DosClose(hPrinterPort);
  502.  
  503.    // Clear ThreadBlock Semaphore
  504.    DosSemClear( hSemThreadBlock );
  505.  
  506.    return;
  507. }
  508.  
  509. void far PopOneUp(char *message)
  510. {
  511.     unsigned short fPopUp = VP_WAIT | VP_OPAQUE;
  512.     unsigned char bAttr = 0x17;
  513.     char sVioString[80];
  514.     KBDKEYINFO kbci;
  515.  
  516.     VioPopUp(&fPopUp, 0);
  517.     VioWrtNAttr(&bAttr, 25 *80,0,0,0);
  518.     sprintf(sVioString,"%s", message);
  519.     VioWrtCharStrAtt(sVioString, strlen(sVioString),5,5,&bAttr,0);
  520.     KbdCharIn(&kbci, IO_WAIT,0);
  521.     VioEndPopUp(0);
  522.     return;
  523. }
  524.