Imported Upstream version 2.1.11
[platform/upstream/gpg2.git] / agent / w32main.c
1 /* w32main.c - W32 main entry pint and taskbar support for the GnuPG Agent
2  * Copyright (C) 2007 Free Software Foundation, Inc.
3  * Copyright 1996, 1998 Alexandre Julliard
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #ifndef HAVE_W32_SYSTEM
23 #error This module is only useful for the W32 version of gpg-agent
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <windows.h>
30
31 #include "util.h"
32 #include "w32main.h"
33
34 /* The instance handle has received by WinMain.  */
35 static HINSTANCE glob_hinst;
36 static HWND glob_hwnd;
37
38
39 /* Build an argv array from the command in CMDLINE.  RESERVED is the
40    number of args to reserve before the first one.  This code is based
41    on Alexandre Julliard's LGPLed wine-0.9.34/dlls/kernel32/process.c
42    and modified to fit into our framework.  The function returns NULL
43    on error; on success an arry with the argiments is returned.  This
44    array has been allocaqted using a plain malloc (and not the usual
45    xtrymalloc). */
46 static char **
47 build_argv (char *cmdline_arg, int reserved)
48 {
49   int argc;
50   char **argv;
51   char *cmdline, *s, *arg, *d;
52   int in_quotes, bs_count;
53
54   cmdline = malloc (strlen (cmdline_arg) + 1);
55   if (!cmdline)
56     return NULL;
57   strcpy (cmdline, cmdline_arg);
58
59   /* First determine the required size of the array.  */
60   argc = reserved + 1;
61   bs_count = 0;
62   in_quotes = 0;
63   s = cmdline;
64   for (;;)
65     {
66       if ( !*s || ((*s==' ' || *s=='\t') && !in_quotes)) /* A space.  */
67         {
68           argc++;
69           /* Skip the remaining spaces.  */
70           while (*s==' ' || *s=='\t')
71             s++;
72           if (!*s)
73             break;
74           bs_count = 0;
75         }
76       else if (*s=='\\')
77         {
78           bs_count++;
79           s++;
80         }
81       else if ( (*s == '\"') && !(bs_count & 1))
82         {
83           /* Unescaped '\"' */
84           in_quotes = !in_quotes;
85           bs_count=0;
86           s++;
87         }
88       else /* A regular character. */
89         {
90           bs_count = 0;
91           s++;
92         }
93     }
94
95   argv = xtrymalloc (argc * sizeof *argv);
96   if (!argv)
97     {
98       xfree (cmdline);
99       return NULL;
100     }
101
102   /* Now actually parse the command line.  */
103   argc = reserved;
104   bs_count = 0;
105   in_quotes=0;
106   arg = d = s = cmdline;
107   while (*s)
108     {
109       if ((*s==' ' || *s=='\t') && !in_quotes)
110         {
111           /* Close the argument and copy it. */
112           *d = 0;
113           argv[argc++] = arg;
114
115           /* Skip the remaining spaces. */
116           do
117             s++;
118           while (*s==' ' || *s=='\t');
119
120           /* Start with a new argument */
121           arg = d = s;
122           bs_count = 0;
123         }
124       else if (*s=='\\')
125         {
126           *d++ = *s++;
127           bs_count++;
128         }
129       else if (*s=='\"')
130         {
131           if ( !(bs_count & 1) )
132             {
133               /* Preceded by an even number of backslashes, this is
134                  half that number of backslashes, plus a '\"' which we
135                  discard.  */
136               d -= bs_count/2;
137               s++;
138               in_quotes = !in_quotes;
139             }
140           else
141             {
142               /* Preceded by an odd number of backslashes, this is
143                  half that number of backslashes followed by a '\"'.  */
144               d = d - bs_count/2 - 1;
145               *d++ ='\"';
146               s++;
147             }
148           bs_count=0;
149         }
150       else /* A regular character. */
151         {
152           *d++ = *s++;
153           bs_count = 0;
154         }
155     }
156
157   if (*arg)
158     {
159       *d = 0;
160       argv[argc++] = arg;
161     }
162   argv[argc] = NULL;
163
164   return argv;
165 }
166
167
168
169 /* Our window message processing function.  */
170 static LRESULT CALLBACK
171 wndw_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
172 {
173
174   switch (msg)
175     {
176     case WM_USER:
177       fprintf (stderr,"%s: received WM_%s\n", __func__, "USER" );
178       break;
179
180     }
181
182   return DefWindowProc (hwnd, msg, wparam, lparam);
183 }
184
185
186 /* This function is called to do some fast event polling and
187    processing.  */
188 void
189 w32_poll_events (void)
190 {
191 /*   MSG msg; */
192
193 /*   fprintf (stderr,"%s: enter\n", __func__); */
194 /*   while (PeekMessage (&msg, glob_hwnd,  0, 0, PM_REMOVE))  */
195 /*     {  */
196 /*       DispatchMessage (&msg); */
197 /*     } */
198 /*   fprintf (stderr,"%s: leave\n", __func__); */
199 }
200
201
202
203 static void *
204 handle_taskbar (void *ctx)
205 {
206   WNDCLASS wndwclass = {0, wndw_proc, 0, 0, glob_hinst,
207                         0, 0, 0, 0, "gpg-agent"};
208   NOTIFYICONDATA nid;
209   HWND hwnd;
210   MSG msg;
211   int rc;
212
213   if (!RegisterClass (&wndwclass))
214     {
215       log_error ("error registering window class\n");
216       ExitThread (0);
217     }
218   hwnd = CreateWindow ("gpg-agent", "gpg-agent",
219                        0, 0, 0, 0, 0,
220                        NULL, NULL, glob_hinst, NULL);
221   if (!hwnd)
222     {
223       log_error ("error creating main window\n");
224       ExitThread (0);
225     }
226   glob_hwnd = hwnd;
227   UpdateWindow (hwnd);
228
229   memset (&nid, 0, sizeof nid);
230   nid.cbSize = sizeof (nid);
231   nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
232   nid.uCallbackMessage = WM_USER;
233   nid.hWnd = glob_hwnd;
234   nid.uID = 1;
235   nid.hIcon = LoadIcon (glob_hinst, MAKEINTRESOURCE (1));
236   mem2str (nid.szTip, GPG_AGENT_NAME " version "PACKAGE_VERSION,
237            sizeof nid.szTip);
238   Shell_NotifyIcon (NIM_ADD, &nid);
239   DestroyIcon (nid.hIcon);
240
241   fprintf (stderr, "%s: enter\n", __func__);
242   while ( (rc=GetMessage (&msg, hwnd,  0, 0)) )
243     {
244       if (rc == -1)
245         {
246           log_error ("getMessage failed: %s\n", w32_strerror (-1));
247           break;
248         }
249       TranslateMessage (&msg);
250       DispatchMessage (&msg);
251     }
252   fprintf (stderr,"%s: leave\n", __func__);
253   ExitThread (0);
254   return NULL;
255 }
256
257
258
259 /* This function initializes the Window system and sets up the taskbar
260    icon.  We only have very limited GUI support just to give the
261    taskbar icon a little bit of life.  This function is called once to
262    fire up the icon.  */
263 int
264 w32_setup_taskbar (void)
265 {
266   SECURITY_ATTRIBUTES sa;
267   DWORD tid;
268   HANDLE th;
269
270   memset (&sa, 0, sizeof sa);
271   sa.nLength = sizeof sa;
272   sa.bInheritHandle = FALSE;
273
274   fprintf (stderr,"creating thread for the taskbar_event_loop...\n");
275   th = CreateThread (&sa, 128*1024,
276                      (LPTHREAD_START_ROUTINE)handle_taskbar,
277                      NULL, 0, &tid);
278   fprintf (stderr,"created thread %p tid=%d\n", th, (int)tid);
279
280   CloseHandle (th);
281
282   return 0;
283 }
284
285
286 /* The main entry point for the Windows version.  We save away all GUI
287    related stuff, parse the command line and finally call the real
288    main.  */
289 int WINAPI
290 WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int showcmd)
291 {
292   char **argv;
293   int argc;
294
295   /* We use the GetCommandLine function because that also includes the
296      program name in contrast to the CMDLINE arg. */
297   argv = build_argv (GetCommandLineA (), 0);
298   if (!argv)
299     return 2; /* Can't do much about a malloc failure.  */
300   for (argc=0; argv[argc]; argc++)
301     ;
302
303   glob_hinst = hinst;
304
305   return w32_main (argc, argv);
306 }