Imported Upstream version 0.18.3.2
[platform/upstream/gettext.git] / gettext-tools / src / urlget.c
1 /* Get the contents of an URL.
2    Copyright (C) 2001-2003, 2005-2010, 2012 Free Software Foundation, Inc.
3    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <getopt.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <locale.h>
30 #include <unistd.h>
31
32 #include "closeout.h"
33 #include "error.h"
34 #include "error-progname.h"
35 #include "progname.h"
36 #include "relocatable.h"
37 #include "basename.h"
38 #include "full-write.h"
39 #include "execute.h"
40 #include "javaexec.h"
41 #include "binary-io.h"
42 #include "propername.h"
43 #include "gettext.h"
44
45 #define _(str) gettext (str)
46
47 #ifndef STDOUT_FILENO
48 # define STDOUT_FILENO 1
49 #endif
50
51
52 /* Only high-level toolkits, written in languages with exception handling,
53    have an URL datatype and operations to fetch an URL's contents.  Such
54    toolkits are Java (class java.net.URL), Qt (classes QUrl and QUrlOperator).
55    We use the Java toolkit.
56    Note that this program doesn't handle redirection pages; programs which
57    wish to process HTML redirection tags need to include a HTML parser,
58    and only full-fledged browsers like w3m, lynx, links have have both
59    an URL fetcher (which covers at least the protocols "http", "ftp", "file")
60    and a HTML parser.  [Well, this is not true: libxml2 and Java (see
61    <http://java.sun.com/products/jfc/tsc/articles/bookmarks/>) also contain
62    HTML parsers.]  */
63
64
65 /* Whether to output something on standard error.
66    This is true by default, because the user should know why we are trying to
67    establish an internet connection.  Also, users get confused if a program
68    produces no output for more than 10 seconds for no apparent reason.  */
69 static bool verbose = true;
70
71 /* Long options.  */
72 static const struct option long_options[] =
73 {
74   { "help", no_argument, NULL, 'h' },
75   { "quiet", no_argument, NULL, 'q' },
76   { "silent", no_argument, NULL, 'q' },
77   { "version", no_argument, NULL, 'V' },
78   { NULL, 0, NULL, 0 }
79 };
80
81
82 /* Forward declaration of local functions.  */
83 static void usage (int status)
84 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
85      __attribute__ ((noreturn))
86 #endif
87 ;
88 static void fetch (const char *url, const char *file);
89
90
91 int
92 main (int argc, char *argv[])
93 {
94   int optchar;
95   bool do_help;
96   bool do_version;
97
98   /* Set program name for messages.  */
99   set_program_name (argv[0]);
100   error_print_progname = maybe_print_progname;
101
102 #ifdef HAVE_SETLOCALE
103   /* Set locale via LC_ALL.  */
104   setlocale (LC_ALL, "");
105 #endif
106
107   /* Set the text message domain.  */
108   bindtextdomain (PACKAGE, relocate (LOCALEDIR));
109   textdomain (PACKAGE);
110
111   /* Ensure that write errors on stdout are detected.  */
112   atexit (close_stdout);
113
114   /* Set default values for variables.  */
115   do_help = false;
116   do_version = false;
117
118   /* Parse command line options.  */
119   while ((optchar = getopt_long (argc, argv, "hqV", long_options, NULL)) != EOF)
120     switch (optchar)
121     {
122     case '\0':          /* Long option.  */
123       break;
124     case 'h':           /* --help */
125       do_help = true;
126       break;
127     case 'q':           /* --quiet / --silent */
128       verbose = false;
129       break;
130     case 'V':           /* --version */
131       do_version = true;
132       break;
133     default:
134       usage (EXIT_FAILURE);
135       /* NOTREACHED */
136     }
137
138   /* Version information requested.  */
139   if (do_version)
140     {
141       printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
142       /* xgettext: no-wrap */
143       printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
144 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
145 This is free software: you are free to change and redistribute it.\n\
146 There is NO WARRANTY, to the extent permitted by law.\n\
147 "),
148               "2001-2003, 2005-2009");
149       printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
150       exit (EXIT_SUCCESS);
151     }
152
153   /* Help is requested.  */
154   if (do_help)
155     usage (EXIT_SUCCESS);
156
157   /* Test argument count.  */
158   if (optind + 2 != argc)
159     error (EXIT_FAILURE, 0, _("expected two arguments"));
160
161   /* Fetch the contents.  */
162   fetch (argv[optind], argv[optind + 1]);
163
164   exit (EXIT_SUCCESS);
165 }
166
167 /* Display usage information and exit.  */
168 static void
169 usage (int status)
170 {
171   if (status != EXIT_SUCCESS)
172     fprintf (stderr, _("Try '%s --help' for more information.\n"),
173              program_name);
174   else
175     {
176       printf (_("\
177 Usage: %s [OPTION] URL FILE\n\
178 "), program_name);
179       printf ("\n");
180       /* xgettext: no-wrap */
181       printf (_("\
182 Fetches and outputs the contents of an URL.  If the URL cannot be accessed,\n\
183 the locally accessible FILE is used instead.\n\
184 "));
185       printf ("\n");
186       printf (_("\
187 Informative output:\n"));
188       printf (_("\
189   -h, --help                  display this help and exit\n"));
190       printf (_("\
191   -V, --version               output version information and exit\n"));
192       printf (_("\
193   -q, --quiet, --silent       suppress progress indicators\n"));
194       printf ("\n");
195       /* TRANSLATORS: The placeholder indicates the bug-reporting address
196          for this package.  Please add _another line_ saying
197          "Report translation bugs to <...>\n" with the address for translation
198          bugs (typically your translation team's web or email address).  */
199       fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
200              stdout);
201     }
202
203   exit (status);
204 }
205
206 /* Copy a file's contents to stdout.  */
207 static void
208 cat_file (const char *src_filename)
209 {
210   int src_fd;
211   char buf[4096];
212   const int buf_size = sizeof (buf);
213
214   src_fd = open (src_filename, O_RDONLY | O_BINARY);
215   if (src_fd < 0)
216     error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"),
217            src_filename);
218
219   for (;;)
220     {
221       ssize_t n_read = read (src_fd, buf, buf_size);
222       if (n_read < 0)
223         {
224 #ifdef EINTR
225           if (errno == EINTR)
226             continue;
227 #endif
228           error (EXIT_FAILURE, errno, _("error reading \"%s\""), src_filename);
229         }
230       if (n_read == 0)
231         break;
232
233       if (full_write (STDOUT_FILENO, buf, n_read) < n_read)
234         error (EXIT_FAILURE, errno, _("error writing stdout"));
235     }
236
237   if (close (src_fd) < 0)
238     error (EXIT_FAILURE, errno, _("error after reading \"%s\""), src_filename);
239 }
240
241 /* Exit code of the Java program.  */
242 static int java_exitcode;
243
244 static bool
245 execute_it (const char *progname,
246             const char *prog_path, char **prog_argv,
247             void *private_data)
248 {
249   (void) private_data;
250
251   java_exitcode =
252     execute (progname, prog_path, prog_argv, true, true, false, false, true,
253              false, NULL);
254   /* Exit code 0 means success, 2 means timed out.  */
255   return !(java_exitcode == 0 || java_exitcode == 2);
256 }
257
258 /* Fetch the URL.  Upon error, use the FILE as fallback.  */
259 static void
260 fetch (const char *url, const char *file)
261 {
262   if (verbose)
263     {
264       fprintf (stderr, _("Retrieving %s..."), url);
265       fflush (stderr);
266     }
267
268 #if USEJAVA
269   /* First try: using Java.  */
270   {
271     const char *class_name = "gnu.gettext.GetURL";
272     const char *gettextjexedir;
273     const char *gettextjar;
274     const char *args[2];
275
276 # if USEJEXE
277     /* Make it possible to override the executable's location.  This is
278        necessary for running the testsuite before "make install".  */
279     gettextjexedir = getenv ("GETTEXTJEXEDIR");
280     if (gettextjexedir == NULL || gettextjexedir[0] == '\0')
281       gettextjexedir = relocate (GETTEXTJEXEDIR);
282 # else
283     gettextjexedir = NULL;
284 # endif
285
286     /* Make it possible to override the gettext.jar location.  This is
287        necessary for running the testsuite before "make install".  */
288     gettextjar = getenv ("GETTEXTJAR");
289     if (gettextjar == NULL || gettextjar[0] == '\0')
290       gettextjar = relocate (GETTEXTJAR);
291
292     /* Prepare arguments.  */
293     args[0] = url;
294     args[1] = NULL;
295
296     /* Fetch the URL's contents.  */
297     java_exitcode = 127;
298     if (!execute_java_class (class_name, &gettextjar, 1, true, gettextjexedir,
299                              args,
300                              false, true,
301                              execute_it, NULL))
302       {
303         if (verbose)
304           {
305             if (java_exitcode == 0)
306               fprintf (stderr, _(" done.\n"));
307             else if (java_exitcode == 2)
308               fprintf (stderr, _(" timed out.\n"));
309           }
310         return;
311       }
312   }
313 #endif
314
315   /* Second try: using "wget -q -O - -T 30 url".  */
316   {
317     static bool wget_tested;
318     static bool wget_present;
319
320     if (!wget_tested)
321       {
322         /* Test for presence of wget: "wget --version > /dev/null"  */
323         char *argv[3];
324         int exitstatus;
325
326         argv[0] = "wget";
327         argv[1] = "--version";
328         argv[2] = NULL;
329         exitstatus = execute ("wget", "wget", argv, false, false, true, true,
330                               true, false, NULL);
331         wget_present = (exitstatus == 0);
332         wget_tested = true;
333       }
334
335     if (wget_present)
336       {
337         char *argv[8];
338         int exitstatus;
339
340         argv[0] = "wget";
341         argv[1] = "-q";
342         argv[2] = "-O"; argv[3] = "-";
343         argv[4] = "-T"; argv[5] = "30";
344         argv[6] = (char *) url;
345         argv[7] = NULL;
346         exitstatus = execute ("wget", "wget", argv, true, false, false, false,
347                               true, false, NULL);
348         if (exitstatus != 127)
349           {
350             if (exitstatus != 0)
351               goto failed;
352             if (verbose)
353               fprintf (stderr, _(" done.\n"));
354             return;
355           }
356       }
357   }
358
359   /* Third try: using "lynx -source url".  */
360   {
361     static bool lynx_tested;
362     static bool lynx_present;
363
364     if (!lynx_tested)
365       {
366         /* Test for presence of lynx: "lynx --version > /dev/null"  */
367         char *argv[3];
368         int exitstatus;
369
370         argv[0] = "lynx";
371         argv[1] = "--version";
372         argv[2] = NULL;
373         exitstatus = execute ("lynx", "lynx", argv, false, false, true, true,
374                               true, false, NULL);
375         lynx_present = (exitstatus == 0);
376         lynx_tested = true;
377       }
378
379     if (lynx_present)
380       {
381         char *argv[4];
382         int exitstatus;
383
384         argv[0] = "lynx";
385         argv[1] = "-source";
386         argv[2] = (char *) url;
387         argv[3] = NULL;
388         exitstatus = execute ("lynx", "lynx", argv, true, false, false, false,
389                               true, false, NULL);
390         if (exitstatus != 127)
391           {
392             if (exitstatus != 0)
393               goto failed;
394             if (verbose)
395               fprintf (stderr, _(" done.\n"));
396             return;
397           }
398       }
399   }
400
401   /* Fourth try: using "curl --silent url".  */
402   {
403     static bool curl_tested;
404     static bool curl_present;
405
406     if (!curl_tested)
407       {
408         /* Test for presence of curl: "curl --version > /dev/null"  */
409         char *argv[3];
410         int exitstatus;
411
412         argv[0] = "curl";
413         argv[1] = "--version";
414         argv[2] = NULL;
415         exitstatus = execute ("curl", "curl", argv, false, false, true, true,
416                               true, false, NULL);
417         curl_present = (exitstatus == 0 || exitstatus == 2);
418         curl_tested = true;
419       }
420
421     if (curl_present)
422       {
423         char *argv[4];
424         int exitstatus;
425
426         argv[0] = "curl";
427         argv[1] = "--silent";
428         argv[2] = (char *) url;
429         argv[3] = NULL;
430         exitstatus = execute ("curl", "curl", argv, true, false, false, false,
431                               true, false, NULL);
432         if (exitstatus != 127)
433           {
434             if (exitstatus != 0)
435               goto failed;
436             if (verbose)
437               fprintf (stderr, _(" done.\n"));
438             return;
439           }
440       }
441   }
442
443  failed:
444   if (verbose)
445     fprintf (stderr, _(" failed.\n"));
446   /* Use the file as fallback.  */
447   cat_file (file);
448 }