uri-backend-wget.c 8.85 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18

Michael Natterer's avatar
Michael Natterer committed
19
20
/* Author: Josh MacDonald. */

21
22
#include "config.h"

Elliot Lee's avatar
Elliot Lee committed
23
24
#include <stdlib.h>
#include <stdio.h>
Sven Neumann's avatar
Sven Neumann committed
25
26
#include <string.h>
#include <errno.h>
Elliot Lee's avatar
Elliot Lee committed
27
28
#include <sys/param.h>
#include <sys/wait.h>
Sven Neumann's avatar
Sven Neumann committed
29
30

#ifdef HAVE_UNISTD_H
Elliot Lee's avatar
Elliot Lee committed
31
#include <unistd.h>
Sven Neumann's avatar
Sven Neumann committed
32
#endif
33
34

#include <libgimp/gimp.h>
35
#include <libgimp/gimpui.h>
36
37
38

#include "libgimp/stdplugins-intl.h"

Elliot Lee's avatar
Elliot Lee committed
39

Michael Natterer's avatar
Michael Natterer committed
40
#define TIMEOUT "300"
41
#define BUFSIZE 1024
Michael Natterer's avatar
Michael Natterer committed
42

Elliot Lee's avatar
Elliot Lee committed
43

44
45
46
47
48
49
50
51
52
53
54
gboolean
uri_backend_init (GError **error)
{
  return TRUE;
}

void
uri_backend_shutdown (void)
{
}

Michael Natterer's avatar
Michael Natterer committed
55
56
const gchar *
uri_backend_get_load_protocols (void)
Elliot Lee's avatar
Elliot Lee committed
57
{
Michael Natterer's avatar
Michael Natterer committed
58
  return "http:,https:,ftp:";
Elliot Lee's avatar
Elliot Lee committed
59
60
}

61
62
63
64
65
66
const gchar *
uri_backend_get_save_protocols (void)
{
  return NULL;
}

Michael Natterer's avatar
Michael Natterer committed
67
68
69
70
71
gboolean
uri_backend_load_image (const gchar  *uri,
                        const gchar  *tmpname,
                        GimpRunMode   run_mode,
                        GError      **error)
Elliot Lee's avatar
Elliot Lee committed
72
{
Michael Natterer's avatar
Michael Natterer committed
73
74
  gint pid;
  gint p[2];
Elliot Lee's avatar
Elliot Lee committed
75

Michael Natterer's avatar
Michael Natterer committed
76
  if (pipe (p) != 0)
Elliot Lee's avatar
Elliot Lee committed
77
    {
Michael Natterer's avatar
Michael Natterer committed
78
79
      g_set_error (error, 0, 0, "pipe() failed: %s", g_strerror (errno));
      return FALSE;
Elliot Lee's avatar
Elliot Lee committed
80
    }
Michael Natterer's avatar
Michael Natterer committed
81
82

  if ((pid = fork()) < 0)
Elliot Lee's avatar
Elliot Lee committed
83
    {
Michael Natterer's avatar
Michael Natterer committed
84
85
      g_set_error (error, 0, 0, "fork() failed: %s", g_strerror (errno));
      return FALSE;
Elliot Lee's avatar
Elliot Lee committed
86
    }
Michael Natterer's avatar
Michael Natterer committed
87
  else if (pid == 0)
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
88
    {
Michael Natterer's avatar
Michael Natterer committed
89
90
91
92
      close (p[0]);
      close (2);
      dup (p[1]);
      close (p[1]);
93
94
95
96
97
98
99
100

#ifdef HAVE_PUTENV
      /* produce deterministic output */
      putenv ("LANGUAGE=C");
      putenv ("LC_ALL=C");
      putenv ("LANG=C");
#endif

101
102
      execlp ("wget", "wget", "e", "server-response=off", "-T", TIMEOUT,
              uri, "-O", tmpname, NULL);
Michael Natterer's avatar
Michael Natterer committed
103
      g_set_error (error, 0, 0, "exec() failed: wget: %s", g_strerror (errno));
Michael Natterer's avatar
Michael Natterer committed
104
      _exit (127);
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
105
    }
Michael Natterer's avatar
Michael Natterer committed
106
  else
Elliot Lee's avatar
Elliot Lee committed
107
    {
108
109
110
      FILE     *input;
      gchar     buf[BUFSIZE];
      gboolean  seen_resolve = FALSE;
Michael Natterer's avatar
Michael Natterer committed
111
      gboolean  connected    = FALSE;
112
      gboolean  redirect     = FALSE;
Michael Natterer's avatar
Michael Natterer committed
113
      gboolean  file_found   = FALSE;
114
115
116
      gchar     sizestr[37];
      gchar    *endptr;
      guint64   size         = 0;
117
118
      gint      i, j;
      gchar     dot;
119
      guint64   kilobytes    = 0;
Michael Natterer's avatar
Michael Natterer committed
120
121
      gboolean  finished     = FALSE;
      gboolean  debug        = FALSE;
122
      gchar    *memsize;
Sven Neumann's avatar
Sven Neumann committed
123
124
      gchar    *message;
      gchar    *timeout_msg;
Michael Natterer's avatar
Michael Natterer committed
125

Sven Neumann's avatar
Sven Neumann committed
126
#define DEBUG(x) if (debug) g_printerr (x)
Michael Natterer's avatar
Michael Natterer committed
127

128
129
130
131
132
133
      close (p[1]);

      input = fdopen (p[0], "r");

      /*  hardcoded and not-really-foolproof scanning of wget putput  */

134
135
136
137
138
139
140
141
142
143
144
    wget_begin:
      /* Eat any Location lines */
      if (redirect && fgets (buf, sizeof (buf), input) == NULL)
        {
          g_set_error (error, 0, 0,
                       _("wget exited abnormally on URI '%s'"), uri);
          return FALSE;
        }

      redirect = FALSE;

145
      if (fgets (buf, sizeof (buf), input) == NULL)
146
147
148
149
        {
          /*  no message here because failing on the first line means
           *  that wget was not found
           */
Michael Natterer's avatar
Michael Natterer committed
150
          return FALSE;
151
152
153
154
155
        }

      DEBUG (buf);

      /*  The second line is the local copy of the file  */
156
      if (fgets (buf, sizeof (buf), input) == NULL)
157
        {
Sven Neumann's avatar
Sven Neumann committed
158
159
          g_set_error (error, 0, 0,
                       _("wget exited abnormally on URI '%s'"), uri);
Michael Natterer's avatar
Michael Natterer committed
160
          return FALSE;
161
162
163
164
165
        }

      DEBUG (buf);

      /*  The third line is "Connecting to..."  */
Sven Neumann's avatar
Sven Neumann committed
166
167
168

      timeout_msg = g_strdup_printf (_("(timeout is %s seconds)"), TIMEOUT);

Sven Neumann's avatar
Sven Neumann committed
169
170
171
      gimp_progress_init (NULL);
      gimp_progress_set_text ("%s %s",
                              _("Connecting to server..."), timeout_msg);
172
173

    read_connect:
174
      if (fgets (buf, sizeof (buf), input) == NULL)
175
        {
Sven Neumann's avatar
Sven Neumann committed
176
177
          g_set_error (error, 0, 0,
                       _("wget exited abnormally on URI '%s'"), uri);
Michael Natterer's avatar
Michael Natterer committed
178
          return FALSE;
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
        }
      else if (strstr (buf, "connected"))
        {
          connected = TRUE;
        }
      /* newer wgets have a "Resolving foo" line, so eat it */
      else if (!seen_resolve && strstr (buf, "Resolving"))
        {
          seen_resolve = TRUE;
          goto read_connect;
        }

      DEBUG (buf);

      /*  The fourth line is either the network request or an error  */
Sven Neumann's avatar
Sven Neumann committed
194
195

      gimp_progress_set_text ("%s %s", _("Opening URI..."), timeout_msg);
196

197
      if (fgets (buf, sizeof (buf), input) == NULL)
198
        {
Sven Neumann's avatar
Sven Neumann committed
199
200
          g_set_error (error, 0, 0,
                       _("wget exited abnormally on URI '%s'"), uri);
Michael Natterer's avatar
Michael Natterer committed
201
          return FALSE;
202
203
204
        }
      else if (! connected)
        {
Sven Neumann's avatar
Sven Neumann committed
205
206
          g_set_error (error, 0, 0,
                       _("A network error occured: %s"), buf);
207
208
209

          DEBUG (buf);

Michael Natterer's avatar
Michael Natterer committed
210
          return FALSE;
211
        }
212
213
214
215
216
217
218
219
220
221
      else if (strstr (buf, "302 Found"))
        {
          DEBUG (buf);

          connected = FALSE;
          seen_resolve = FALSE;

          redirect = TRUE;
          goto wget_begin;
        }
222
223
224
225

      DEBUG (buf);

      /*  The fifth line is either the length of the file or an error  */
226
      if (fgets (buf, sizeof (buf), input) == NULL)
227
        {
Sven Neumann's avatar
Sven Neumann committed
228
229
          g_set_error (error, 0, 0,
                       _("wget exited abnormally on URI '%s'"), uri);
Michael Natterer's avatar
Michael Natterer committed
230
          return FALSE;
231
232
233
234
235
236
237
        }
      else if (strstr (buf, "Length"))
        {
          file_found = TRUE;
        }
      else
        {
Sven Neumann's avatar
Sven Neumann committed
238
239
          g_set_error (error, 0, 0,
                       _("A network error occured: %s"), buf);
240
241
242

          DEBUG (buf);

Michael Natterer's avatar
Michael Natterer committed
243
          return FALSE;
244
245
246
247
        }

      DEBUG (buf);

248
      if (sscanf (buf, "Length: %37s", sizestr) != 1)
249
        {
Michael Natterer's avatar
Michael Natterer committed
250
251
252
          g_set_error (error, 0, 0,
                       "Could not parse wget's file length message");
          return FALSE;
253
254
255
256
257
258
259
260
261
262
263
264
265
266
        }

      /*  strip away commas  */
      for (i = 0, j = 0; i < sizeof (sizestr); i++, j++)
        {
          if (sizestr[i] == ',')
            i++;

          sizestr[j] = sizestr[i];

          if (sizestr[j] == '\0')
            break;
        }

267
268
269
270
271
272
273
      if (*sizestr != '\0')
        {
          size = g_ascii_strtoull (sizestr, &endptr, 10);

          if (*endptr != '\0' || size == G_MAXUINT64)
            size = 0;
        }
274
275

      /*  Start the actual download...  */
276
277
278
279
280
281
282
283
284
285
286
      if (size > 0)
        {
          memsize = gimp_memsize_to_string (size);
          message = g_strdup_printf (_("Downloading %s of image data..."),
                                     memsize);
        }
      else
        {
          message = g_strdup (_("Downloading unknown amount of image data..."));
          memsize = NULL;
        }
Sven Neumann's avatar
Sven Neumann committed
287

Sven Neumann's avatar
Sven Neumann committed
288
      gimp_progress_set_text ("%s %s", message, timeout_msg);
Sven Neumann's avatar
Sven Neumann committed
289

290
      g_free (message);
291
      g_free (memsize);
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

      /*  Switch to byte parsing wget's output...  */

      while (1)
        {
          dot = fgetc (input);

          if (feof (input))
            break;

          if (debug)
            {
              fputc (dot, stderr);
              fflush (stderr);
            }

          if (dot == '.')  /* one kilobyte */
            {
              kilobytes++;
311
312

              if (size > 0)
313
314
315
316
                {
                  gimp_progress_update ((gdouble) (kilobytes * 1024) /
                                        (gdouble) size);
                }
317
              else
318
319
320
321
322
323
324
325
326
327
328
                {
                  memsize = gimp_memsize_to_string (kilobytes * 1024);
                  message = g_strdup_printf (_("Downloaded %s of image data"),
                                             memsize);
                  g_free (memsize);

                  gimp_progress_set_text (message);
                  gimp_progress_pulse ();

                  g_free (message);
                }
329
330
331
            }
          else if (dot == ':')  /* the time string contains a ':' */
            {
332
              fgets (buf, sizeof (buf), input);
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

              DEBUG (buf);

              if (! strstr (buf, "error"))
                {
                  finished = TRUE;
                  gimp_progress_update (1.0);
                }

              break;
            }
        }

      if (! finished)
        {
Michael Natterer's avatar
Michael Natterer committed
348
349
350
351
          g_set_error (error, 0, 0,
                       "wget exited before finishing downloading URI\n'%s'",
                       uri);
          return FALSE;
352
        }
Elliot Lee's avatar
Elliot Lee committed
353
354
    }

Michael Natterer's avatar
Michael Natterer committed
355
  return TRUE;
Elliot Lee's avatar
Elliot Lee committed
356
}
357
358
359
360
361
362
363
364
365
366
367

gboolean
uri_backend_save_image (const gchar  *uri,
                        const gchar  *tmpname,
                        GimpRunMode   run_mode,
                        GError      **error)
{
  g_set_error (error, 0, 0, "EEK");

  return FALSE;
}