home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / xgopher.1.3 / sc_extend.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-25  |  11.7 KB  |  513 lines

  1. /* sc_extend.c
  2.    gopher item subclass procedures for extended type */
  3.  
  4.      /*---------------------------------------------------------------*/
  5.      /* Xgopher        version 1.3     08 April 1993                  */
  6.      /*                version 1.2     20 November 1992               */
  7.      /*                version 1.1     20 April 1992                  */
  8.      /*                version 1.0     04 March 1992                  */
  9.      /* X window system client for the University of Minnesota        */
  10.      /*                                Internet Gopher System.        */
  11.      /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
  12.      /*                Computing and Communications Services Office   */
  13.      /* Copyright 1992, 1993 by                                       */
  14.      /*           the Board of Trustees of the University of Illinois */
  15.      /* Permission is granted to freely copy and redistribute this    */
  16.      /* software with the copyright notice intact.                    */
  17.      /*---------------------------------------------------------------*/
  18.  
  19. #include "osdep.h"
  20. #include "conf.h"
  21. #include "globals.h"
  22. #include "gopher.h"
  23. #include "appres.h"
  24. #include "typeres.h"
  25. #include "util.h"
  26. #include "status.h"
  27. #include "subst.h"
  28. #include "misc.h"
  29. #include "jobs.h"
  30. #include "sc_extend.h"
  31. #include "sc_extendP.h"
  32.  
  33. #include <stdio.h>
  34. extern     errno;
  35.  
  36. static extTypeValue    *etvList = NULL;
  37.  
  38.  
  39. #define    PIPE_CHAR    '|'
  40.  
  41.  
  42. /* forkAndExec
  43.    fork off another process which will call system to execute a command */
  44.  
  45. static PID_TYPE
  46. forkAndExec(cmd, tempName, forkErrno)
  47. char    *cmd;
  48. char    *tempName;
  49. int    *forkErrno;
  50. {
  51.     PID_TYPE    pid;
  52.  
  53.  
  54.     /* fprintf (stderr, "forkAndExec: %s\n", cmd); */
  55.  
  56.     *forkErrno = 0;
  57.     if ((pid = fork()) == (PID_TYPE) 0) {
  58.  
  59.         /* we should immediately do a 
  60.            close (ConnectionNumber(XtDisplay(widget)));
  61.            here.  */
  62.            
  63.         system(cmd);
  64.         if (tempName != (char *) NULL) {
  65.             unlink (tempName);
  66.         }
  67.  
  68.         /* the child's useful life is over */
  69.  
  70.         exit(0);
  71.  
  72.     } else if (pid < 0) {
  73.         *forkErrno = errno;
  74.         if (tempName != (char *) NULL) {
  75.             unlink (tempName);
  76.         }
  77.         pid = ((PID_TYPE) 0);
  78.     }
  79.  
  80.     return pid;
  81. }
  82.  
  83.  
  84. /* forkAndPipe
  85.    fork off another process which will pipe stdin to another command */
  86.  
  87. static PID_TYPE
  88. forkAndPipe(cmd, gi, forkErrno)
  89. char        *cmd;
  90. gopherItemP    gi;
  91. int        *forkErrno;
  92. {
  93.     char        message[MESSAGE_STRING_LEN];
  94.     FILE        *cmdFile;
  95.     int        s;
  96.     PID_TYPE    pid;
  97.  
  98.     *forkErrno = 0;
  99.     if ((pid = fork()) == (PID_TYPE) 0) {
  100.  
  101.         /* we should immediately do a 
  102.               close (ConnectionNumber(XtDisplay(widget)));
  103.            here.
  104.         */
  105.  
  106.         s = connectToSocket(gi->host, gi->port);
  107.         if (s < 0) {
  108.             networkError(s, gi->host, gi->port);
  109.             return FALSE;
  110.         }
  111.  
  112.         writeString(s, vStringValue(&(gi->selector)));
  113.         writeString(s, EOL_STRING);
  114.  
  115.         cmdFile = popen(cmd, "w");
  116.  
  117.         if (cmdFile == (FILE *) NULL) {
  118.             sprintf(message,
  119.             "Unable to start the command (\'%s\')\n",
  120.                 cmd);
  121.             fprintf(stderr, "%s\n", message);
  122.             close (s);
  123.             /* this is the child process */
  124.             exit(-1);
  125.         }
  126.  
  127.         GI_copyNetUntilEOF(s, cmdFile);
  128.  
  129.         close(s);
  130.         pclose(cmdFile);
  131.  
  132.         /* the child's useful life is over */
  133.  
  134.         exit(0);
  135.  
  136.  
  137.     } else if (pid < 0) {
  138.         *forkErrno = errno;
  139.         pid = ((PID_TYPE) 0);
  140.     }
  141.  
  142.     return pid;
  143. }
  144.  
  145.  
  146. BOOLEAN
  147. issueCommand(gi, etv)
  148. gopherItemP    gi;
  149. extTypeValue    *etv;
  150. {
  151.     scInfo    *sc = gi->sc;
  152.     char    *cmd;
  153.     char    errorString[MESSAGE_STRING_LEN];
  154.     char    tempName[PATH_NAME_LEN];
  155.     char    message[MESSAGE_STRING_LEN];
  156.     int    tempFD;
  157.     int    s;
  158.     char    *path, *suffix = (char *) NULL;
  159.  
  160.  
  161.     /* Three cases: 1) no data to be copied (e.g. a telnet session);
  162.             2) data copied to temp file first (e.g. text)
  163.             3) data piped from network to program (e.g. sound)
  164.     */
  165.  
  166.  
  167.     if (sc->copyProc == GI_noCopyItem) {
  168.         
  169.         /* ===== No Data needed ===== */
  170.  
  171.         int    forkError;
  172.  
  173.         cmd = editCommand(gi, etv->execCommand, "", (char *) NULL);
  174.         /* fprintf (stderr, "\tExecute the command\n\t%s\n\n", cmd); */
  175.  
  176.         sprintf(message, "Working on %s, please stand by",
  177.                 gi->sc->typeName);
  178.         showStatus(message, STAT_TEMP_MESSAGE, (char *) NULL, 0);
  179.  
  180.         if ((etv->pid =
  181.             forkAndExec(tildePath(cmd), (char *)NULL, &forkError))
  182.             == 0) {
  183.         etv->failed = TRUE;
  184.         sprintf(message,
  185.             "Error trying to start command for \'%s\' (error %d)\n\'%s\'\n",
  186.             sc->typeName, errno, cmd);
  187.         showError(message);
  188.         }
  189.  
  190.         if (etv->pid != (PID_TYPE) 0) {
  191.         addJob(gi->type, etv->pid);
  192.         }
  193.  
  194.         if (etv->wait) {
  195.         waitForJob(etv->pid);
  196.         }
  197.  
  198.         free(cmd);
  199.  
  200.     } else if (*(etv->execCommand) != PIPE_CHAR) { 
  201.  
  202.         /* ===== Data copied to temp file ===== */
  203.  
  204.         int    forkError;
  205.         BOOLEAN okSoFar;
  206.  
  207.         getTempFile(tempName);
  208.  
  209.         /* find the file name suffix which may provide additional
  210.            info on file type to the implementor -- if possible */
  211.  
  212.         path = vStringValue(&(gi->selector));
  213.         suffix = rindex(path, '.');
  214.         if (suffix != NULL) {
  215.  
  216.         /* find length of ".xxx".  If it's 4 or fewer characters
  217.            after the dot, assume that it's a meaningful suffix
  218.            and copy it to the end of the temp file name. */
  219.  
  220.         int    nch = strlen(suffix);
  221.  
  222.         if (nch <= 4) {
  223.             strcat (tempName, suffix);
  224.         }
  225.         }
  226.  
  227.         if ((tempFD = open(tempName, O_WRONLY | O_CREAT, TMP_FILE_MODE))
  228.                                     < 0) {
  229.         perror("issueCommand");
  230.         (void) removeStatusPanel();
  231.  
  232.         sprintf(errorString,
  233.             "Cannot open the temporary file %s", tempName);
  234.         showError(errorString);
  235.         fprintf (stderr, "%s\n", errorString);
  236.         return FALSE;
  237.         }
  238.     
  239.         okSoFar = GI_copyFromNet(tempFD, gi, (char *) NULL);
  240.  
  241.         close(tempFD);
  242.  
  243.         if (! okSoFar) {
  244.             unlink (tempName);
  245.             return FALSE;
  246.         }
  247.  
  248.         cmd = editCommand(gi, etv->execCommand, tempName, tempName);
  249.         /* fprintf (stderr, "\tExecute the command\n\t%s\n\n", cmd); */
  250.  
  251.         sprintf(message, "Working on %s, please stand by",
  252.                 gi->sc->typeName);
  253.         showStatus(message, STAT_TEMP_MESSAGE, (char *) NULL, 0);
  254.  
  255.         if ((etv->pid =
  256.             forkAndExec(tildePath(cmd), tempName, &forkError))
  257.             == 0) {
  258.         etv->failed = TRUE;
  259.         sprintf(message,
  260.             "Error trying to start command for \'%s\' (error %d)\n\'%s\'\n",
  261.             sc->typeName, errno, cmd);
  262.         showError(message);
  263.         }
  264.  
  265.         if (etv->pid != (PID_TYPE) 0) {
  266.         addJob(gi->type, etv->pid);
  267.         }
  268.  
  269.         if (etv->wait) {
  270.         waitForJob(etv->pid);
  271.         }
  272.  
  273.         free(cmd);
  274.  
  275.     } else {                /* pipe data to command */
  276.         
  277.         /* ===== Data comes from a pipe ===== */
  278.  
  279.         int    *forkError;
  280.  
  281.         cmd = editCommand(gi, etv->execCommand, "", (char *) NULL);
  282.         /* fprintf (stderr, "\tExecute the command\n\t%s\n\n", cmd); */
  283.  
  284.         sprintf(message, "Working on %s, please stand by",
  285.                 gi->sc->typeName);
  286.         showStatus(message, STAT_TEMP_MESSAGE, (char *) NULL, 0);
  287.  
  288.         if ((etv->pid =
  289.             forkAndPipe(tildePath(cmd+1), gi, &forkError))
  290.             == 0) {
  291.         etv->failed = TRUE;
  292.         sprintf(message,
  293.             "Error trying to start command for \'%s\' (error %d)\n\'%s\'\n",
  294.             sc->typeName, errno, cmd);
  295.         showError(message);
  296.         }
  297.  
  298.         if (etv->pid != (PID_TYPE) 0) {
  299.         addJob(gi->type, etv->pid);
  300.         }
  301.  
  302.         if (etv->wait) {
  303.         waitForJob(etv->pid);
  304.         }
  305.  
  306.         free(cmd);
  307.     }
  308.  
  309.     return TRUE;
  310. }
  311.  
  312.  
  313. /* getExtTypeValue
  314.    return the extended type value record for a given type letter, or
  315.    NULL if it does not exist. */
  316.  
  317. static extTypeValue *
  318. getExtTypeValue(wanted)
  319. char    wanted;
  320. {
  321.     extTypeValue    *etv;
  322.  
  323.     for (etv=etvList;
  324.         (etv != (extTypeValue *) NULL  &&  etv->type != wanted);
  325.         etv=etv->next) ;
  326.  
  327.     return etv;
  328. }
  329.  
  330.  
  331. /* GIExtend_init
  332.    initialize extend type class - host access list and prefix. */
  333.  
  334. void
  335. GIExtend_init()
  336. {
  337.     char        *s = appResources->extendedTypes;
  338.     char        extType[6];
  339.     typeResources    *typeRes;
  340.     scInfo        *scRec;
  341.     char        message[MESSAGE_STRING_LEN];
  342.  
  343.     if (s == (char *) NULL  ||  *s == NULLC) {    
  344.         return;
  345.     }
  346.  
  347.     GU_makePrefix(prefixExtend,  appResources->prefixUnknown);
  348.  
  349.     strcpy(extType, "type ");
  350.     while (*s != NULLC) {
  351.         if (*s == ' '  ||  *s == '\t') {s++; continue;}
  352.  
  353.         /* process new type; receive back a static struct */
  354.  
  355.         extType[4] = *s;
  356.         typeRes = getTypeResources(extType, EXT_CLASS);
  357.  
  358.         /* look for "sameAs" - if NOT present, copy EXTEND subclass */
  359.  
  360.         if (typeRes->sameAs == (String) NULL  ||
  361.             *(typeRes->sameAs) == NULLC) {
  362.             extTypeValue    *etv;
  363.             scRec = GU_copySubclassRecord(A_EXTENDED);
  364.  
  365.         /* copy execCommand, useTempFile, wait, singleThread
  366.            to a new record. */
  367.  
  368.         etv = (extTypeValue *) malloc (sizeof(extTypeValue));
  369.         etv->type         = *s;
  370.         if (typeRes->execCommand != (char *) NULL) {
  371.             etv->execCommand  =
  372.                 (char *) malloc (strlen(typeRes->execCommand) + 1);
  373.             strcpy(etv->execCommand, typeRes->execCommand);
  374.             } else {
  375.                 etv->execCommand = (char *) NULL;
  376.             }
  377.         etv->wait      = typeRes->wait;
  378.         etv->failed      = FALSE;
  379.         etv->pid      = (PID_TYPE) 0;
  380.         etv->next      = etvList;
  381.  
  382.         etvList = etv;
  383.  
  384.         /* "sameAs" given - use internal or extended type */
  385.  
  386.         } else if (*(typeRes->sameAs + 1) != NULLC) {
  387.                 sprintf (message,
  388.             "Extended type \'%c\' - \'sameAs\' %s (not \'%s\')",
  389.                 *s, "resource must be a single character",
  390.             typeRes->sameAs);
  391.                 fprintf (stderr, "%s\n", message);
  392.         } else {
  393.         extTypeValue    *oldEtv = getExtTypeValue(*(typeRes->sameAs));
  394.  
  395.         scRec = GU_copySubclassRecord(*(typeRes->sameAs));
  396.  
  397.         if (oldEtv != (extTypeValue *) NULL) {
  398.             extTypeValue    *etv;
  399.  
  400.             /* copy extTypeValue to complete the "sameAs" processing */
  401.  
  402.             etv = (extTypeValue *) malloc (sizeof(extTypeValue));
  403.             bcopy((char *) oldEtv, (char *) etv, sizeof(extTypeValue));
  404.  
  405.             /* then, replace the type and execCommand
  406.                in the new record. */
  407.  
  408.             etv->type         = *s;
  409.             if (typeRes->execCommand != (char *) NULL) {
  410.                 etv->execCommand  =
  411.                     (char *) malloc (strlen(typeRes->execCommand) + 1);
  412.                 strcpy(etv->execCommand, typeRes->execCommand);
  413.                 }
  414.  
  415.             etv->failed      = FALSE;
  416.             etv->pid      = (PID_TYPE) 0;
  417.             etv->next      = etvList;
  418.  
  419.             etvList = etv;
  420.             }
  421.         }
  422.  
  423.         if (typeRes->description != (String) NULL) {
  424.             scRec->typeName = malloc(strlen(typeRes->description) + 1);
  425.             strcpy(scRec->typeName, typeRes->description);
  426.         }
  427.         if (typeRes->prefix != (String) NULL) {
  428.             scRec->typePrefix = (char *) malloc(PREFIX_LEN);
  429.         GU_makePrefix(scRec->typePrefix, typeRes->prefix);
  430.         }
  431.         if (typeRes->servers != (String) NULL) {
  432.             scRec->hostList    = (accessList *) malloc(sizeof(accessList));
  433.             *(scRec->hostList) = GU_createAccessList(typeRes->servers);
  434.         }
  435.  
  436.         if (typeRes->dataType != copyTypeUnspec) {
  437.             scRec->copyDataType = typeRes->dataType;
  438.             if (scRec->copyDataType == copyTypeNone) {
  439.             scRec->copyProc = GI_noCopyItem;
  440.             } else {
  441.             scRec->copyProc = GI_copyToFile;
  442.             }
  443.         }
  444.  
  445.         GU_registerNewType(*s, scRec);
  446.  
  447.         s++;
  448.     }
  449.  
  450.     return;
  451. }
  452.  
  453.  
  454. /* GIExtend_access
  455.    check the accessability of an extended type file selection */
  456.  
  457. BOOLEAN
  458. GIExtend_access(gi)
  459. gopherItemP    gi;
  460. {
  461.     BOOLEAN    result;
  462.  
  463.     if (gi->sc->hostList == NULL  ||  *(gi->sc->hostList) == NULL  ||
  464.         GU_checkAccess(gi->host, *(gi->sc->hostList))) {
  465.         result = TRUE;
  466.     }else {
  467.         result = FALSE;
  468.     }
  469.  
  470.     return result;
  471. }
  472.  
  473.  
  474. /* GIExtend_process
  475.    process an extended type file selection */
  476.  
  477. BOOLEAN
  478. GIExtend_process(gi)
  479. gopherItemP    gi;
  480. {
  481.     BOOLEAN        result;
  482.     extTypeValue    *etv = getExtTypeValue(gi->type);
  483.     char        message[MESSAGE_STRING_LEN];
  484.  
  485.  
  486.     /* fprintf (stderr, "Process a type %c.\n", gi->type); */
  487.  
  488.     if (etv == (extTypeValue *) NULL) {
  489.          return FALSE;
  490.     }
  491.  
  492.     if (etv->execCommand == (char *) NULL  ||
  493.         strlen(etv->execCommand) == 0) {
  494.         fprintf (stderr,
  495.              "Type %c item (%s) - nothing to do\n",
  496.             gi->type, gi->sc->typeName);
  497.         return FALSE;
  498.     }
  499.  
  500.     /* fprintf (stderr, "Process a type %c.\n\tRaw command:\t%s\n",
  501.             gi->type, etv->execCommand); */
  502.  
  503.     sprintf (message, "Trying to start %s %s",
  504.         (GU_isVowel(gi->sc->typeName) ? "an" : "a"), gi->sc->typeName);
  505.  
  506.     showStatus(message, STAT_TEMP_MESSAGE, gi->host, gi->port);
  507.  
  508.  
  509.     result = issueCommand(gi, etv); 
  510.     
  511.     return result;
  512. }
  513.