Update kleopatra
[gpg4win.git] / src / gpgwrap.c
1 /* gpgwrap.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, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* The operation mode of this wrapper can be controlled by the
21    GPGWRAP_VARIANT macro.  The following variants are defined:
22
23      0 = Standard.
24      2 = Also insert a "2" right before the .exe.
25
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <process.h>
35 #include <windows.h>
36
37
38 #if GPGWRAP_VARIANT == 2
39 # define PGM_SUFFIX "-2"
40 #else
41 # define PGM_SUFFIX ""
42 #endif
43
44
45 /* Return a copy of ARGV, but with proper quoting.  To release the
46    copy, you have to free argv_quoted[0] and argv_quoted.  */
47 static char **
48 build_commandline (const char * const *argv)
49 {
50   int i;
51   int j;
52   int n = 0;
53   char *buf;
54   char *p;
55   char **argv_quoted;
56
57   /* We have to quote some things because under Windows the program
58      parses the commandline and does some unquoting.  We enclose the
59      whole argument in double-quotes, and escape literal double-quotes
60      as well as backslashes with a backslash.  We end up with a
61      trailing space at the end of the line, but that is harmless.  */
62   for (i = 0; argv[i]; i++)
63     {
64       p = (char *) argv[i];
65       /* The leading double-quote.  */
66       n++;
67       while (*p)
68         {
69           /* An extra one for each literal that must be escaped.  */
70           if (*p == '\\' || *p == '"')
71             n++;
72           n++;
73           p++;
74         }
75       /* The trailing double-quote and the delimiter.  */
76       n += 2;
77     }
78   /* And a trailing zero.  */
79   n++;
80
81   /* Allocate a new vector.  */
82   argv_quoted = malloc (sizeof (char *) * (i + 1));
83   if (!argv_quoted)
84     return NULL;
85
86   buf = p = malloc (n);
87   if (!buf)
88     {
89       free (argv_quoted);
90       return NULL;
91     }
92
93   for (i = 0; argv[i]; i++)
94     {
95       const char *argvp = argv[i];
96
97       argv_quoted[i] = p;
98
99       *(p++) = '"';
100       while (*argvp)
101         {
102           if (*argvp == '\\' || *argvp == '"')
103             *(p++) = '\\';
104           *(p++) = *(argvp++);
105         }
106       *(p++) = '"';
107       *(p++) = 0;
108     }
109   *(p++) = 0;
110   argv_quoted[i] = NULL;
111
112   return argv_quoted;
113 }
114
115
116 int
117 main (int argc, const char * const *argv)
118 {
119   int rc;
120   char pgm[MAX_PATH+100];
121   char *p, *p0;
122   char **argv_quoted;
123
124   /* Note: We decrement by one to allow inserting one character.  */
125   if (!GetModuleFileNameA (NULL, pgm, sizeof (pgm) - 1 - 1))
126     {
127       fprintf (stderr, "gpgwrap: error getting my own name: rc=%d\n",
128                GetLastError());
129       return 2;
130     }
131
132   /* Remove one directory part of the file name.  */
133   p = strrchr (pgm, '\\');
134   if (!p)
135     goto leave;
136   *p = 0;
137   p0 = strrchr (pgm, '\\');
138   *p = '\\';
139   if (!p0)
140     goto leave;
141   while (*p)
142     *p0++ = *p++;
143   *p0 = 0;
144
145 #if GPGWRAP_VARIANT == 2
146   p = strrchr (pgm, '.');
147   if (p)
148     {
149       memmove (p+1, p, strlen (p)+1);
150       *p = '2';
151     }
152 #endif /* GPGWRAP_VARIANT == 2 */
153
154
155   /* Hack to output our own version along with the real file name
156      before the actual, we require that the --version option is given
157      twice. */
158   if (argc > 2
159       && !strcmp(argv[1], "--version")
160       && !strcmp(argv[2], "--version"))
161     {
162       fputs ("gpgwrap" PGM_SUFFIX " (Gpg4win) " PACKAGE_VERSION " ;", stdout);
163       fputs (pgm, stdout);
164       fputc ('\n', stdout);
165       fflush (stdout);
166     }
167
168   argv_quoted = build_commandline (argv);
169   if (!argv_quoted)
170     goto leave;
171
172   /* Using execv does not replace the existing program image, but
173      spawns a new one and daemonizes it, confusing the command line
174      interpreter.  So we have to use spawnv.  */
175   rc = _spawnv (_P_WAIT, pgm, (const char **) argv_quoted);
176   if (rc < 0)
177     {
178       fprintf (stderr, "gpgwrap: executing `%s' failed: %s\n",
179                pgm, strerror (errno));
180       return 2;
181     }
182
183   return rc;
184
185  leave:
186   fprintf (stderr, "gpgwrap: internal error parsing my own name `%s'\n",
187            pgm);
188   return 2;
189 }