5e01801e287c3cf32957aedd0533e128c7251d9b
[gpg4win.git] / src / kleowrap.c
1 /* kleopatrawrap.c - Wrapper to call gpg udner Windows.
2  * Copyright (C) 2007 g10 Code GmbH
3  *
4  * This file is part of Gpg4win.
5  *
6  * Gpg4win is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Gpg4win is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <process.h>
29 #include <windows.h>
30
31
32 /* Return a copy of ARGV, but with proper quoting.  To release the
33    copy, you have to free argv_quoted[0] and argv_quoted.  */
34 static char **
35 build_commandline (const char * const *argv)
36 {
37   int i;
38   int j;
39   int n = 0;
40   char *buf;
41   char *p;
42   char **argv_quoted;
43
44   /* We have to quote some things because under Windows the program
45      parses the commandline and does some unquoting.  We enclose the
46      whole argument in double-quotes, and escape literal double-quotes
47      as well as backslashes with a backslash.  We end up with a
48      trailing space at the end of the line, but that is harmless.  */
49   for (i = 0; argv[i]; i++)
50     {
51       p = (char *) argv[i];
52       /* The leading double-quote.  */
53       n++;
54       while (*p)
55         {
56           /* An extra one for each literal that must be escaped.  */
57           if (*p == '\\' || *p == '"')
58             n++;
59           n++;
60           p++;
61         }
62       /* The trailing double-quote and the delimiter.  */
63       n += 2;
64     }
65   /* And a trailing zero.  */
66   n++;
67
68   /* Allocate a new vector.  */
69   argv_quoted = malloc (sizeof (char *) * (i + 1));
70   if (!argv_quoted)
71     return NULL;
72
73   buf = p = malloc (n);
74   if (!buf)
75     {
76       free (argv_quoted);
77       return NULL;
78     }
79
80   for (i = 0; argv[i]; i++)
81     {
82       const char *argvp = argv[i];
83
84       argv_quoted[i] = p;
85
86       *(p++) = '"';
87       while (*argvp)
88         {
89           if (*argvp == '\\' || *argvp == '"')
90             *(p++) = '\\';
91           *(p++) = *(argvp++);
92         }
93       *(p++) = '"';
94       *(p++) = 0;
95     }
96   *(p++) = 0;
97   argv_quoted[i] = NULL;
98
99   return argv_quoted;
100 }
101
102
103 int
104 main (int argc, const char * const *argv)
105 {
106   int rc;
107   char pgm[MAX_PATH+100];
108   char *p, *p0;
109   char **argv_quoted;
110
111   if (!GetModuleFileNameA (NULL, pgm, sizeof (pgm) - 1))
112     {
113       fprintf (stderr, "kleopatrawrap: error getting my own name: rc=%d\n",
114                GetLastError());
115       return 2;
116     }
117
118   /* Insert bin directory.  */
119   p = strrchr (pgm, '\\');
120   if (!p)
121     goto leave;
122   p++;
123   memmove (p + 4, p, strlen (p) + 1);
124   strncpy (p, "bin\\", 4);
125
126   /* Hack to output our own version along with the real file name
127      before the actual, we require that the --version option is given
128      twice. */
129   if (argc > 2
130       && !strcmp(argv[1], "--version")
131       && !strcmp(argv[2], "--version"))
132     {
133       fputs ("kleopatrawrap (Gpg4win) " PACKAGE_VERSION " ;", stdout);
134       fputs (pgm, stdout);
135       fputc ('\n', stdout);
136       fflush (stdout);
137     }
138
139   argv_quoted = build_commandline (argv);
140   if (!argv_quoted)
141     goto leave;
142
143   /* Using execv does not replace the existing program image, but
144      spawns a new one and daemonizes it, confusing the command line
145      interpreter.  So we have to use spawnv.  */
146   rc = _spawnv (_P_WAIT, pgm, (const char **) argv_quoted);
147   if (rc < 0)
148     {
149       fprintf (stderr, "kleopatrawrap: executing `%s' failed: %s\n",
150                pgm, strerror (errno));
151       return 2;
152     }
153
154   return rc;
155
156  leave:
157   fprintf (stderr, "kleopatrawrap: internal error parsing my own name `%s'\n",
158            pgm);
159   return 2;
160 }