home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / url.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-16  |  10.7 KB  |  446 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. /* Author: Josh MacDonald. */
  20.  
  21. #include "config.h"
  22.  
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <sys/param.h>
  26. #include <sys/wait.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <errno.h>
  30.  
  31. #ifdef __EMX__
  32. #include <process.h>
  33. #endif
  34.  
  35. #include <libgimp/gimp.h>
  36.  
  37. #include "libgimp/stdplugins-intl.h"
  38.  
  39.  
  40. #define TIMEOUT "300"
  41. #define BUFSIZE 1024
  42.  
  43. static void   query (void);
  44. static void   run   (gchar      *name,
  45.              gint        nparams,
  46.              GimpParam  *param,
  47.              gint       *nreturn_vals,
  48.              GimpParam **return_vals);
  49.  
  50. static gint32   load_image (gchar             *filename,
  51.                 GimpRunModeType    run_mode,
  52.                 GimpPDBStatusType *status /* return value */);
  53.  
  54. GimpPlugInInfo PLUG_IN_INFO =
  55. {
  56.   NULL,  /* init_proc  */
  57.   NULL,  /* quit_proc  */
  58.   query, /* query_proc */
  59.   run,   /* run_proc   */
  60. };
  61.  
  62. MAIN ()
  63.  
  64. static void
  65. query (void)
  66. {
  67.   static GimpParamDef load_args[] =
  68.   {
  69.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  70.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  71.     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
  72.   };
  73.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  74.  
  75.   static GimpParamDef load_return_vals[] =
  76.   {
  77.     { GIMP_PDB_IMAGE, "image", "Output image" }
  78.   };
  79.   static gint nload_return_vals = (sizeof (load_return_vals) /
  80.                    sizeof (load_return_vals[0]));
  81.  
  82.   gimp_install_procedure ("file_url_load",
  83.                           "loads files given a URL",
  84.                           "You need to have GNU Wget installed.",
  85.                           "Spencer Kimball & Peter Mattis",
  86.                           "Spencer Kimball & Peter Mattis",
  87.                           "1995-1997",
  88.                           "<Load>/URL",
  89.               NULL,
  90.                           GIMP_PLUGIN,
  91.                           nload_args, nload_return_vals,
  92.                           load_args, load_return_vals);
  93.  
  94.   gimp_register_load_handler ("file_url_load",
  95.                   "",
  96.                   "http:,ftp:");
  97. }
  98.  
  99. static void
  100. run (gchar      *name,
  101.      gint        nparams,
  102.      GimpParam  *param,
  103.      gint       *nreturn_vals,
  104.      GimpParam **return_vals)
  105. {
  106.   static GimpParam  values[2];
  107.   GimpRunModeType   run_mode;
  108.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  109.   gint32            image_ID;
  110.  
  111.   run_mode = param[0].data.d_int32;
  112.  
  113.   *nreturn_vals = 1;
  114.   *return_vals  = values;
  115.   values[0].type          = GIMP_PDB_STATUS;
  116.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  117.  
  118.   if (strcmp (name, "file_url_load") == 0)
  119.     {
  120.       image_ID = load_image (param[2].data.d_string,
  121.                  run_mode,
  122.                  &status);
  123.  
  124.       if (image_ID != -1 &&
  125.       status == GIMP_PDB_SUCCESS)
  126.     {
  127.       *nreturn_vals = 2;
  128.       values[1].type         = GIMP_PDB_IMAGE;
  129.       values[1].data.d_image = image_ID;
  130.     }
  131.     }
  132.   else
  133.     {
  134.       status = GIMP_PDB_CALLING_ERROR;
  135.     }
  136.  
  137.   values[0].data.d_status = status;
  138. }
  139.  
  140. static gint32
  141. load_image (gchar             *filename,
  142.         GimpRunModeType    run_mode,
  143.         GimpPDBStatusType *status)
  144. {
  145.   gint32  image_ID;
  146.   gchar  *ext = strrchr (filename, '.');
  147.   gchar  *tmpname;
  148.   gint    pid;
  149.   gint    wpid;
  150.   gint    process_status;
  151.   gint    p[2];
  152.  
  153.   if (!ext || ext[1] == 0 || strchr(ext, '/'))
  154.     {
  155.       g_message ("url: can't open URL without an extension");
  156.       *status = GIMP_PDB_CALLING_ERROR;
  157.       return -1;
  158.     }
  159.  
  160.   tmpname = gimp_temp_name (ext + 1);
  161.  
  162. #ifndef __EMX__
  163.   if (pipe (p) != 0)
  164.     {
  165.       g_message ("url: pipe() failed: %s", g_strerror (errno));
  166.       g_free (tmpname);
  167.       *status = GIMP_PDB_EXECUTION_ERROR;
  168.       return -1;
  169.     }
  170.  
  171.   if ((pid = fork()) < 0)
  172.     {
  173.       g_message ("url: fork() failed: %s", g_strerror (errno));
  174.       g_free (tmpname);
  175.       *status = GIMP_PDB_EXECUTION_ERROR;
  176.       return -1;
  177.     }
  178.   else if (pid == 0)
  179.     {
  180.       close (p[0]);
  181.       close (2);
  182.       dup (p[1]);
  183.       close (p[1]);
  184.  
  185. #ifdef HAVE_PUTENV
  186.       /* produce deterministic output */
  187.       putenv ("LANGUAGE=C");
  188.       putenv ("LC_ALL=C");
  189.       putenv ("LANG=C");
  190. #endif
  191.  
  192.       execlp ("wget", "wget", "-T", TIMEOUT, filename, "-O", tmpname, NULL);
  193.       g_message ("url: exec() failed: wget: %s", g_strerror (errno));
  194.       g_free (tmpname);
  195.       _exit (127);
  196.     }
  197.   else
  198.     {
  199.       if (run_mode == GIMP_RUN_NONINTERACTIVE)
  200.     {
  201.       wpid = waitpid (pid, &process_status, 0);
  202.  
  203.       if ((wpid < 0)
  204.           || !WIFEXITED (process_status)
  205.           || (WEXITSTATUS (process_status) != 0))
  206.         {
  207.           g_message ("url: wget exited abnormally on URL %s", filename);
  208.           g_free (tmpname);
  209.           *status = GIMP_PDB_EXECUTION_ERROR;
  210.           return -1;
  211.         }
  212.     }
  213.       else
  214.     {
  215.       FILE     *input;
  216.       gchar     buf[BUFSIZE];
  217.       gboolean  connected = FALSE;
  218.       gboolean  file_found = FALSE;
  219.       gchar     sizestr[32];
  220.       gint      size = 0;
  221.       gchar    *message;
  222.       gint      i, j;
  223.       gchar     dot;
  224.       gint      kilobytes = 0;
  225.       gboolean  finished = FALSE;
  226.  
  227.       gboolean  debug = FALSE;
  228.  
  229. #define DEBUG(x) if (debug) fprintf (stderr, (x))
  230.  
  231.       close (p[1]);
  232.  
  233.       input = fdopen (p[0], "r");
  234.  
  235.       /*  hardcoded and not-really-foolproof scanning of wget putput  */
  236.  
  237.       if (fgets (buf, BUFSIZE, input) == NULL)
  238.         {
  239.           /*  no message here because failing on the first line means
  240.            *  that wget was not found
  241.            */
  242.           g_free (tmpname);
  243.           *status = GIMP_PDB_EXECUTION_ERROR;
  244.           return -1;
  245.         }
  246.  
  247.       DEBUG (buf);
  248.  
  249.       /*  The second line is the local copy of the file  */
  250.       if (fgets (buf, BUFSIZE, input) == NULL)
  251.         {
  252.           g_message ("url: wget exited abnormally on URL\n%s", filename);
  253.           g_free (tmpname);
  254.           *status = GIMP_PDB_EXECUTION_ERROR;
  255.           return -1;
  256.         }
  257.  
  258.       DEBUG (buf);
  259.  
  260.       /*  The third line is "Connecting to..."  */
  261.       gimp_progress_init ("Connecting to server... "
  262.                   "(timeout is "TIMEOUT" seconds)");
  263.  
  264.       if (fgets (buf, BUFSIZE, input) == NULL)
  265.         {
  266.           g_message ("url: wget exited abnormally on URL\n%s", filename);
  267.           g_free (tmpname);
  268.           *status = GIMP_PDB_EXECUTION_ERROR;
  269.           return -1;
  270.         }
  271.       else if (strstr (buf, "connected"))
  272.         {
  273.           connected = TRUE;
  274.         }
  275.  
  276.       DEBUG (buf);
  277.  
  278.       /*  The fourth line is either the network request or an error  */
  279.       gimp_progress_init ("Opening URL... "
  280.                   "(timeout is "TIMEOUT" seconds)");
  281.  
  282.       if (fgets (buf, BUFSIZE, input) == NULL)
  283.         {
  284.           g_message ("url: wget exited abnormally on URL\n%s", filename);
  285.           g_free (tmpname);
  286.           *status = GIMP_PDB_EXECUTION_ERROR;
  287.           return -1;
  288.         }
  289.       else if (! connected)
  290.         {
  291.           g_message ("url: a network error occured: %s", buf);
  292.  
  293.           DEBUG (buf);
  294.  
  295.           g_free (tmpname);
  296.           *status = GIMP_PDB_EXECUTION_ERROR;
  297.           return -1;
  298.         }
  299.  
  300.       DEBUG (buf);
  301.  
  302.       /*  The fifth line is either the length of the file or an error  */
  303.       if (fgets (buf, BUFSIZE, input) == NULL)
  304.         {
  305.           g_message ("url: wget exited abnormally on URL\n%s", filename);
  306.           g_free (tmpname);
  307.           *status = GIMP_PDB_EXECUTION_ERROR;
  308.           return -1;
  309.         }
  310.       else if (strstr (buf, "Length"))
  311.         {
  312.           file_found = TRUE;
  313.         }
  314.       else
  315.         {
  316.           g_message ("url: a network error occured: %s", buf);
  317.  
  318.           DEBUG (buf);
  319.  
  320.           g_free (tmpname);
  321.           *status = GIMP_PDB_EXECUTION_ERROR;
  322.           return -1;
  323.         }
  324.  
  325.       DEBUG (buf);
  326.  
  327.       if (sscanf (buf, "Length: %31s", sizestr) != 1)
  328.         {
  329.           g_message ("url: could not parse wget's file length message");
  330.           g_free (tmpname);
  331.           *status = GIMP_PDB_EXECUTION_ERROR;
  332.           return -1;
  333.         }
  334.  
  335.       /*  strip away commas  */
  336.       for (i = 0, j = 0; i < sizeof (sizestr); i++, j++)
  337.         {
  338.           if (sizestr[i] == ',')
  339.         i++;
  340.  
  341.           sizestr[j] = sizestr[i];
  342.  
  343.           if (sizestr[j] == '\0')
  344.         break;
  345.         }
  346.  
  347.       size = atoi (sizestr);
  348.  
  349.       /*  Start the actual download...  */
  350.       message = g_strdup_printf ("Downloading %d bytes of image data... "
  351.                      "(timeout is "TIMEOUT" seconds)", size);
  352.       gimp_progress_init (message);
  353.       g_free (message);
  354.  
  355.       /*  Switch to byte parsing wget's output...  */
  356.  
  357.       while (1)
  358.         {
  359.           dot = fgetc (input);
  360.  
  361.           if (dot == EOF)
  362.         break;
  363.  
  364.           if (debug)
  365.         {
  366.           fputc (dot, stderr);
  367.           fflush (stderr);
  368.         }
  369.  
  370.           if (dot == '.')  /* one kilobyte */
  371.         {
  372.           kilobytes++;
  373.           gimp_progress_update ((gdouble) (kilobytes * 1024) /
  374.                     (gdouble) size);
  375.         }
  376.           else if (dot == ':')  /* the time string contains a ':' */
  377.         {
  378.           fgets (buf, BUFSIZE, input);
  379.  
  380.           DEBUG (buf);
  381.  
  382.           if (! strstr (buf, "error"))
  383.             {
  384.               finished = TRUE;
  385.               gimp_progress_update (1.0);
  386.             }
  387.  
  388.           break;
  389.         }
  390.         }
  391.  
  392.       if (! finished)
  393.         {
  394.           g_message ("url: wget exited before finishing downloading URL\n%s",
  395.              filename);
  396.           unlink (tmpname);
  397.           g_free (tmpname);
  398.           *status = GIMP_PDB_EXECUTION_ERROR;
  399.           return -1;
  400.         }
  401.     }
  402.     }
  403. #else /* __EMX__ */
  404.   {
  405.     pid = spawnlp (P_NOWAIT,
  406.            "wget",
  407.            "wget", "-T", TIMEOUT, filename, "-O", tmpname, NULL);
  408.  
  409.     if (pid == -1)
  410.       {
  411.     g_message ("url: spawn failed: %s", g_strerror (errno));
  412.     g_free (tmpname);
  413.     *status = GIMP_PDB_EXECUTION_ERROR;
  414.     return -1;
  415.       }
  416.  
  417.     wpid = waitpid (pid, &process_status, 0);
  418.  
  419.     if ((wpid < 0)
  420.     || !WIFEXITED (process_status)
  421.     || (WEXITSTATUS (process_status) != 0))
  422.       {
  423.     g_message ("url: wget exited abnormally on URL %s", filename);
  424.     g_free (tmpname);
  425.     *status = GIMP_PDB_EXECUTION_ERROR;
  426.     return -1;
  427.       }
  428.   }
  429. #endif
  430.  
  431.   image_ID = gimp_file_load (GIMP_RUN_INTERACTIVE, tmpname, tmpname);
  432.  
  433.   unlink (tmpname);
  434.   g_free (tmpname);
  435.  
  436.   if (image_ID != -1)
  437.     {
  438.       *status = GIMP_PDB_SUCCESS;
  439.       gimp_image_set_filename (image_ID, filename);
  440.     }
  441.   else
  442.     *status = GIMP_PDB_EXECUTION_ERROR;
  443.  
  444.   return image_ID;
  445. }
  446.