home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / cvview.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  14.9 KB  |  581 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* Please leave outside of ifdef for windows precompiled headers */
  20. #include "mkutils.h"
  21.  
  22. #ifdef MOZILLA_CLIENT
  23.  
  24. #include "mkstream.h"
  25. #include "mkgeturl.h"
  26. #include "xp.h"
  27. #include "mkparse.h"
  28. #include "cvview.h"
  29.  
  30. #include "libmime.h"
  31.  
  32.  
  33. /* for XP_GetString() */
  34. #include <xpgetstr.h>
  35. extern int XP_CONFIRM_EXEC_UNIXCMD_ARE;
  36. extern int XP_CONFIRM_EXEC_UNIXCMD_MAYBE;
  37. extern int XP_ALERT_UNABLE_INVOKEVIEWER;
  38. extern int MK_UNABLE_TO_OPEN_TMP_FILE;
  39.  
  40.  
  41. typedef struct _CV_DataObject {
  42.     FILE      * fp;
  43.     char      * filename;
  44.     char      * command;
  45.     char      * url;
  46.     unsigned int stream_block_size;
  47.     int32       cur_size;
  48.     int32       tot_size;
  49.     MWContext * context;
  50. } CV_DataObject;
  51.  
  52.  
  53. /*
  54. ** build_viewer_cmd
  55. **    Build up the command for forking the external viewer.
  56. **    Argument list is the template for the command and the a set of
  57. **    (char,char*) pairs of characters to be recognized as '%' escapes
  58. **    and what they should expand to, terminated with a 0.
  59. **
  60. **    Return value is a malloc'ed string, must be freed when command is done.
  61. **
  62. **    Example:
  63. **        char* s=build_viewer(line_from_mailcap, 's', tmpFile, 'u', url, 0);
  64. **
  65. **    I'm completely unsure what to do about security considerations and
  66. **    encodings.  Should the URL get % encoded.  What if it contains "bad"
  67. **    characters.  etc. etc. etc
  68. */
  69.  
  70. char*
  71. build_viewer_cmd(char *template, ...)
  72. {
  73.   va_list args;
  74.   char *ret, *from, *to;
  75.   int len;
  76.  
  77.   if (template == NULL)
  78.     return NULL;
  79.  
  80.   len = strlen(template);
  81.   ret = (char*) malloc(len+1);
  82.   if (ret == NULL)
  83.     return NULL;
  84.  
  85.   from = template, to = ret;
  86.  
  87.   while (*from) {
  88.     if (*from != '%' || *++from == '%') {
  89.       *to++ = *from++;
  90.     } else {
  91.  
  92.       /*
  93.       ** We have a % escape, now look through all the arguments for
  94.       ** a matching one.  When one is found, substitute in the
  95.       ** passed value.  If none is found, the % and following character
  96.       ** get swallowed.
  97.       */
  98.       char argc;
  99.       char* argv;
  100.  
  101.       va_start(args, template);
  102.       while ((argc = va_arg(args, int)) != 0) {
  103.     argv = va_arg(args, char*);
  104.     if (*from == argc) {
  105.       int off = to - ret;
  106.       int arglen = strlen(argv);
  107.  
  108.       len = len + arglen - 2;
  109.       ret = (char*) realloc(ret, len + 1);
  110.       if (ret == NULL)
  111.         return NULL;
  112.       XP_STRCPY(ret + off, argv);
  113.       to = ret + off + arglen;
  114.       break;
  115.     }
  116.       }
  117.       if (*from) from++;    /* skip char following % unless it was last */
  118.       va_end(args);
  119.     }
  120.   }
  121.   *to = '\0';
  122.   return ret;
  123. }
  124.  
  125. PRIVATE int net_ExtViewWrite (NET_StreamClass *stream, CONST char* s, int32 l)
  126. {
  127.     CV_DataObject *obj=stream->data_object;    
  128.     if(obj->tot_size)
  129.       {
  130.         obj->cur_size += l;
  131.  
  132.         obj->context->funcs->SetProgressBarPercent(obj->context, (obj->cur_size*100)/obj->tot_size);
  133.       }
  134.  
  135.     /* TRACEMSG(("Length of string passed to display: %d\n",l));
  136.      */
  137.     return(fwrite((char *) s, 1, l, obj->fp)); 
  138. }
  139.  
  140. PRIVATE int net_ExtViewWriteReady (NET_StreamClass * stream)
  141. {
  142.     CV_DataObject *obj=stream->data_object;
  143.     fd_set write_fds;
  144.     struct timeval timeout;
  145.     int ret;    
  146.  
  147.     if(obj->command)
  148.       {
  149.         return(MAX_WRITE_READY);  /* never wait for files */
  150.       }
  151.  
  152.     timeout.tv_sec = 0;
  153.     timeout.tv_usec = 1;  /* minimum hopefully */
  154.  
  155.     XP_MEMSET(&write_fds, 0, sizeof(fd_set));
  156.  
  157.     FD_SET(fileno(obj->fp), &write_fds);
  158.  
  159.     ret = select(fileno(obj->fp)+1, NULL, &write_fds, NULL, &timeout);
  160.  
  161.     if(ret)
  162.         return(obj->stream_block_size);  /* read in a max of 8000 bytes */
  163.     else
  164.         return(0);
  165. }
  166.  
  167.  
  168. PRIVATE void net_ExtViewComplete (NET_StreamClass *stream)
  169. {
  170.     CV_DataObject *obj=stream->data_object;
  171.     obj->context->funcs->SetProgressBarPercent(obj->context, 100);    
  172.  
  173.     if(obj->command)
  174.       {
  175.         char *p_tmp;
  176.         char *command;
  177.  
  178.         /* restrict to allowed url chars
  179.          *
  180.          */
  181.         for(p_tmp = obj->url; *p_tmp != '\0'; p_tmp++)
  182.                 if( (*p_tmp >= '0' && *p_tmp <= '9')
  183.                     || (*p_tmp >= 'A' && *p_tmp <= 'Z')
  184.                     || (*p_tmp >= 'a' && *p_tmp <= 'z')
  185.                     || (*p_tmp == '_')
  186.                     || (*p_tmp == '?')
  187.                     || (*p_tmp == '#')
  188.                     || (*p_tmp == '&')
  189.                     || (*p_tmp == '%')
  190.                     || (*p_tmp == '/')
  191.                     || (*p_tmp == ':')
  192.                     || (*p_tmp == '+')
  193.                     || (*p_tmp == '.')
  194.                     || (*p_tmp == '~')
  195.                     || (*p_tmp == '=')
  196.                     || (*p_tmp == '-'))
  197.           {
  198.             /* this is a good character.  Allow it.
  199.              */
  200.           }
  201.         else
  202.           {
  203.             *p_tmp = '\0';
  204.             break;
  205.           }
  206.  
  207.         command=build_viewer_cmd(obj->command, 
  208.                              's', obj->filename, 
  209.                              'u', obj->url, 0);
  210.  
  211.         fclose(obj->fp);
  212.         TRACEMSG(("Invoking: %s", command));
  213.  
  214.         system(command);
  215.         FREEIF(obj->command);
  216.       }
  217.     else
  218.       {
  219.         pclose(obj->fp);
  220.       }
  221.  
  222.     FREEIF(obj->filename);
  223.     FREEIF(obj->url);
  224.     FREE(obj);
  225.     return;
  226. }
  227.  
  228. PRIVATE void net_ExtViewAbort (NET_StreamClass *stream, int status)
  229. {
  230.     CV_DataObject *obj=stream->data_object;
  231.     obj->context->funcs->SetProgressBarPercent(obj->context, 100);    
  232.  
  233.     fclose(obj->fp);
  234.    
  235.     if(obj->filename)
  236.       {
  237.         remove(obj->filename);
  238.         FREE(obj->filename);
  239.       }
  240.  
  241.     FREEIF(obj->url);
  242.     FREEIF(obj->command);
  243.  
  244.     FREE(obj);
  245.     
  246.     return;
  247. }
  248.  
  249. #ifdef XP_UNIX
  250. extern char **fe_encoding_extensions; /* gag! */
  251. #endif
  252.  
  253.  
  254. PUBLIC NET_StreamClass * 
  255. NET_ExtViewerConverter   (int         format_out,
  256.                           void       *data_obj,
  257.                           URL_Struct *URL_s,
  258.                           MWContext  *window_id)
  259. {
  260.     CV_DataObject* obj;
  261.     NET_StreamClass* stream;
  262.     char *tmp_filename;
  263.     char *dot;
  264.     char *path;
  265.     CV_ExtViewStruct * view_struct = (CV_ExtViewStruct *)data_obj;
  266.     char small_buf[256];
  267.     int yes_stream=0;
  268.     
  269.     /* If this URL is a mail or news attachment, use the name of that
  270.        attachment as the URL -- this is so the temp file gets the right
  271.        extension on it (some helper apps are picky about that...)
  272.      */
  273.     path = MimeGuessURLContentName(window_id, URL_s->address);
  274.     if (!path)
  275.       path = NET_ParseURL(URL_s->address, GET_PATH_PART);
  276.     if (!path)
  277.       return 0;
  278.  
  279.  
  280.     TRACEMSG(("Setting up display stream. Have URL: %s\n", URL_s->address));
  281.  
  282.     stream = XP_NEW(NET_StreamClass);
  283.     if(stream == NULL) 
  284.             return(NULL);
  285.  
  286.     memset(stream, 0, sizeof(NET_StreamClass));
  287.  
  288.     obj = XP_NEW(CV_DataObject);
  289.     if (obj == NULL) 
  290.             return(NULL);
  291.     memset(obj, 0, sizeof(CV_DataObject));
  292.  
  293.     obj->context  = window_id;
  294.  
  295.     if(URL_s->content_length)
  296.       {
  297.         obj->tot_size = URL_s->content_length;
  298.       }
  299.     else
  300.       {
  301.         /* start the progress bar cyloning
  302.          */
  303.         obj->context->funcs->SetProgressBarPercent(window_id, -1);
  304.       }
  305.  
  306.     stream->name           = "Execute external viewer";
  307.     stream->complete       = (MKStreamCompleteFunc) net_ExtViewComplete;
  308.     stream->abort          = (MKStreamAbortFunc) net_ExtViewAbort;
  309.     stream->put_block      = (MKStreamWriteFunc) net_ExtViewWrite;
  310.     stream->is_write_ready = (MKStreamWriteReadyFunc) net_ExtViewWriteReady;
  311.     stream->data_object    = obj;  /* document info object */
  312.     stream->window_id      = window_id;
  313.  
  314. #ifdef XP_UNIX
  315.     /* Some naive people may have trustingly put
  316.  
  317.             application/x-sh; sh %s
  318.             application/x-csh; csh %s
  319.  
  320.        in their mailcap files without realizing how dangerous that is.
  321.        Worse, it might be there and they might not realize it.  So, if
  322.        we're about to execute a shell, pop up a dialog box first.
  323.      */
  324.     {
  325.       char *prog = XP_STRDUP (view_struct->system_command);
  326.       char *s, *start, *end;
  327.       int danger = 0;
  328.  
  329.       /* strip end space */
  330.       end = XP_StripLine(prog);
  331.  
  332.       /* Extract the leaf name of the program: " /bin/sh -foo" ==> "sh". */
  333.       for (; *end && !XP_IS_SPACE(*end); end++)
  334.         ;
  335.       *end = 0;
  336.  
  337.       if ((start = XP_STRRCHR (prog, '/')))
  338.         start++;
  339.       else
  340.         start = XP_StripLine(prog); /* start at first non-white space */
  341.  
  342.       /* Strip off everything after the first nonalphabetic.
  343.          This is so "perl-4.0" is compared as "perl" and
  344.          "emacs19" is compared as "emacs".
  345.        */
  346.       for (s = start; *s; s++)
  347.         if (!isalpha (*s))
  348.           *s = 0;
  349.  
  350.       /* These are things known to be shells - very bad. */
  351.       if (!XP_STRCMP (start, "ash") ||
  352.           !XP_STRCMP (start, "bash") ||
  353.           !XP_STRCMP (start, "csh") ||
  354.           !XP_STRCMP (start, "jsh") ||
  355.           !XP_STRCMP (start, "ksh") ||
  356.           !XP_STRCMP (start, "pdksh") ||
  357.           !XP_STRCMP (start, "sh") ||
  358.           !XP_STRCMP (start, "tclsh") ||
  359.           !XP_STRCMP (start, "tcsh") ||
  360.           !XP_STRCMP (start, "wish") ||        /* a tcl thing */
  361.           !XP_STRCMP (start, "wksh") ||
  362.           !XP_STRCMP (start, "zsh"))
  363.         danger = 2;
  364.  
  365.       /* Remote shells are potentially dangerous, in the case of
  366.          "rsh somehost some-dangerous-program", but it's hard to
  367.          parse that out, since rsh could take arbitrarily complicated
  368.          args, like "rsh somehost -u something -pass8 /bin/sh %s".
  369.          And we don't want to squawk about "rsh somehost playulaw -".
  370.          So... allow rsh to possibly be a security hole.
  371.        */
  372.       else if (!XP_STRCMP (start, "remsh") ||    /* remote shell */
  373.                !XP_STRCMP (start, "rksh") ||
  374.                !XP_STRCMP (start, "rsh")        /* remote- or restricted- */
  375.                )
  376.         danger = 0;
  377.  
  378.       /* These are things which aren't really shells, but can do the
  379.          same damage anyway since they can write files and/or execute
  380.          other programs. */
  381.       else if (!XP_STRCMP (start, "awk") ||
  382.                !XP_STRCMP (start, "e") ||
  383.                !XP_STRCMP (start, "ed") ||
  384.                !XP_STRCMP (start, "ex") ||
  385.                !XP_STRCMP (start, "gawk") ||
  386.                !XP_STRCMP (start, "m4") ||
  387.                !XP_STRCMP (start, "sed") ||
  388.                !XP_STRCMP (start, "vi") ||
  389.                !XP_STRCMP (start, "emacs") ||
  390.                !XP_STRCMP (start, "lemacs") ||
  391.                !XP_STRCMP (start, "xemacs") ||
  392.                !XP_STRCMP (start, "temacs") ||
  393.  
  394.                /* Other dangerous interpreters */
  395.                !XP_STRCMP (start, "basic") ||
  396.                !XP_STRCMP (start, "expect") ||
  397.                !XP_STRCMP (start, "expectk") ||
  398.                !XP_STRCMP (start, "perl") ||
  399.                !XP_STRCMP (start, "python") ||
  400.                !XP_STRCMP (start, "rexx")
  401.                )
  402.         danger = 1;
  403.  
  404.       /* Be suspicious of anything ending in "sh". */
  405.       else if (XP_STRLEN (start) > 2 &&
  406.                !XP_STRCMP (start + XP_STRLEN (start) - 2, "sh"))
  407.         danger = 1;
  408.  
  409.       if (danger)
  410.         {
  411.           char msg [2048];
  412.           PR_snprintf (msg,
  413.                    sizeof(msg),
  414.                    (danger > 1 ? XP_GetString(XP_CONFIRM_EXEC_UNIXCMD_ARE) : XP_GetString(XP_CONFIRM_EXEC_UNIXCMD_MAYBE)),
  415.                    start
  416.                    );
  417.           if (!FE_Confirm (window_id, msg))
  418.             {
  419.               FREE (stream);
  420.               FREE (obj);
  421.               FREE (path);
  422.               FREE (prog);
  423.               return(NULL);
  424.             }
  425.         }
  426.       FREE (prog);
  427.     }
  428. #endif /* XP_UNIX */
  429.  
  430.     if(view_struct->stream_block_size)
  431.       {
  432.         /* asks the user if they want to stream data.
  433.          * -1 cancel
  434.          * 0  No, don't stream data, play from the file
  435.          * 1  Yes, stream the data from the network
  436.          */
  437.         int XFE_AskStreamQuestion(MWContext * window_id); /* definition */
  438.  
  439.         if (NET_URL_Type (URL_s->address) == ABOUT_TYPE_URL)
  440.           yes_stream = 1;
  441.         else
  442.           yes_stream = XFE_AskStreamQuestion(window_id);
  443.  
  444.         if(yes_stream == -1)
  445.           {
  446.             FREE(stream);
  447.             FREE(obj);
  448.             FREE(path);
  449.             return(NULL);
  450.           }
  451.       }
  452.  
  453.     if(yes_stream && view_struct->stream_block_size)
  454.       {
  455.         /* use popen */
  456.         obj->fp = popen(view_struct->system_command, "w");
  457.  
  458.         if(!obj->fp)
  459.           {
  460.             FE_Alert(window_id, XP_GetString(XP_ALERT_UNABLE_INVOKEVIEWER));
  461.             return(NULL);
  462.           }
  463.  
  464.         obj->stream_block_size = view_struct->stream_block_size;
  465.  
  466.         signal(SIGPIPE, SIG_IGN);
  467.  
  468.       }
  469.     else
  470.       {
  471.         
  472.         dot = XP_STRRCHR(path, '.');
  473.  
  474. #ifdef XP_UNIX
  475.         /* Gag.  foo.ps.gz --> tmpXXXXX.ps, not tmpXXXXX.gz. */
  476.         if (dot && fe_encoding_extensions)
  477.           {
  478.             int i = 0;
  479.             while (fe_encoding_extensions [i])
  480.               {
  481.                 if (!XP_STRCMP (dot, fe_encoding_extensions [i]))
  482.                   {
  483.                     *dot = 0;
  484.                     dot--;
  485.                     while (dot > path && *dot != '.')
  486.                       dot--;
  487.                     if (*dot != '.')
  488.                       dot = 0;
  489.                     break;
  490.                   }
  491.                 i++;
  492.               }
  493.           }
  494. #endif /* XP_UNIX */
  495.  
  496.         tmp_filename = WH_TempName(xpTemporary, "MO");
  497.         if (!tmp_filename) {
  498.             FREEIF(stream);
  499.             FREEIF(obj);
  500.             return NULL;
  501.         }
  502.         if (dot)
  503.           {
  504.               char * p_tmp;
  505.  
  506.               StrAllocCopy(obj->filename, tmp_filename);
  507.  
  508.               /* restrict to ascii alphanumeric chars
  509.                *
  510.                * this fixes really bad security hole
  511.                */
  512.               for(p_tmp = dot+1; *p_tmp != '\0'; p_tmp++)
  513.                   if( (*p_tmp >= '0' && *p_tmp <= '9')
  514.                       || (*p_tmp >= 'A' && *p_tmp <= 'Z')
  515.                       || (*p_tmp >= 'a' && *p_tmp <= 'z')
  516.                       || (*p_tmp == '_')
  517.                       || (*p_tmp == '+')
  518.                       || (*p_tmp == '-'))
  519.                   {
  520.                       /* this is a good character.  Allow it.
  521.                        */
  522.                   }
  523.                   else
  524.                   {
  525.                       *p_tmp = '\0';
  526.                       break;
  527.                   }
  528.                   
  529.               StrAllocCat(obj->filename, dot);
  530.           }
  531.         else
  532.           {
  533.               StrAllocCopy(obj->filename, tmp_filename);
  534.           }
  535.         
  536.         FREE(path);
  537.         XP_FREE(tmp_filename);
  538.  
  539.         obj->fp = XP_FileOpen(obj->filename, xpTemporary, XP_FILE_WRITE);
  540.             
  541.         TRACEMSG(("Trying to open output file: %s\n", obj->filename));
  542.     
  543.         if(!obj->fp)
  544.           {
  545.             char *s = NET_ExplainErrorDetails (MK_UNABLE_TO_OPEN_TMP_FILE,
  546.                                                obj->filename);
  547.             if (s)
  548.               {
  549.                 FE_Alert (window_id, s);
  550.                 XP_FREE (s);
  551.               }
  552.             return(NULL);
  553.           }
  554.  
  555.         /* construct the command like this
  556.          *
  557.          * (( COMMAND ); rm %s )&
  558.          */
  559.         StrAllocCopy(obj->command, "((");
  560.  
  561.         /* this is a stream writable program that the user wants
  562.          * to use non streaming
  563.          */
  564.         if(view_struct->stream_block_size)
  565.             StrAllocCat(obj->command, "cat %s | ");
  566.  
  567.         StrAllocCat(obj->command, view_struct->system_command);
  568.  
  569.         PR_snprintf(small_buf, sizeof(small_buf), "); rm %.200s )&", obj->filename);
  570.         StrAllocCat(obj->command, small_buf);
  571.       }
  572.  
  573.     StrAllocCopy(obj->url, URL_s->address);
  574.     
  575.     TRACEMSG(("Returning stream from NET_ExtViewer\n"));
  576.  
  577.     return stream;
  578. }
  579.  
  580. #endif /* MOZILLA_CLIENT */
  581.