Renamed to olgpgmain and olgpgcore. Added fucntion to retrieve the
[gpgol.git] / src / config-dialog.c
1 /* config-dialog.c
2  *      Copyright (C) 2005 g10 Code GmbH
3  *      Copyright (C) 2003 Timo Schulz
4  *
5  * This file is part of GPGME Dialogs.
6  *
7  * GPGME Dialogs is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1 
10  * of the License, or (at your option) any later version.
11  *  
12  * GPGME Dialogs 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 GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with GPGME Dialogs; if not, write to the Free Software Foundation, 
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
20  */
21 #include <windows.h>
22 #include <shellapi.h>
23 #include <shlobj.h>
24 #include <time.h>
25 #include <sys/stat.h>
26 #include <gpgme.h>
27
28 #include "olgpgcoredlgs.h"
29 #include "keycache.h"
30 #include "intern.h"
31
32 #define REGPATH "Software\\GNU\\GnuPG"
33
34 static char*
35 get_open_file_name (const char *dir)
36 {
37     static char fname[MAX_PATH+1];
38     OPENFILENAME ofn;
39
40     memset (&ofn, 0, sizeof (ofn));
41     memset (fname, 0, sizeof (fname));
42     ofn.hwndOwner = GetDesktopWindow();
43     ofn.hInstance = glob_hinst;
44     ofn.lpstrTitle = "Select GnuPG binary";
45     ofn.lStructSize = sizeof (ofn);
46     ofn.lpstrInitialDir = dir;
47     ofn.lpstrFilter = "*.EXE";
48     ofn.lpstrFile = fname;
49     ofn.nMaxFile = sizeof(fname)-1;
50     if (GetOpenFileName(&ofn) == FALSE)
51         return NULL;
52     return fname;
53 }
54
55
56 static void 
57 SHFree (void *p) 
58 {         
59     IMalloc *pm;         
60     SHGetMalloc (&pm);
61     if (pm) {
62         pm->lpVtbl->Free(pm,p);
63         pm->lpVtbl->Release(pm);         
64     } 
65
66
67
68 /* Open the common dialog to select a folder. Caller has to free the string. */
69 static char*
70 get_folder (void)
71 {
72     char fname[MAX_PATH+1];
73     BROWSEINFO bi;
74     ITEMIDLIST * il;
75     char *path = NULL;
76
77     memset (&bi, 0, sizeof (bi));
78     memset (fname, 0, sizeof (fname));
79     bi.hwndOwner = GetDesktopWindow ();
80     bi.lpszTitle = "Select GnuPG home directory";
81     il = SHBrowseForFolder (&bi);
82     if (il != NULL) {
83         SHGetPathFromIDList (il, fname);
84         path = xstrdup (fname);
85         SHFree (il);
86     }
87     return path;
88 }
89
90
91 static int
92 load_config_value_ext (char **val)
93 {
94   static char buf[MAX_PATH+64];
95   
96   /* MSDN: This buffer must be at least MAX_PATH characters in size. */
97   memset (buf, 0, sizeof (buf));
98   if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, 
99                            NULL, 0, buf) < 0)
100     return -1;
101   strcat (buf, "\\gnupg");
102   if (GetFileAttributes (buf) == 0xFFFFFFFF)
103     return -1;
104   *val = buf;
105   return 0;
106 }
107
108
109 static char*
110 expand_path (const char *path)
111 {
112     DWORD len;
113     char *p;
114
115     len = ExpandEnvironmentStrings (path, NULL, 0);
116     if (!len)
117         return NULL;
118     len += 1;
119     p = xcalloc (1, len+1);
120     if (!p)
121         return NULL;
122     len = ExpandEnvironmentStrings (path, p, len);
123     if (!len) {
124         xfree (p);
125         return NULL;
126     }
127     return p; 
128 }
129
130 static int
131 load_config_value (HKEY hk, const char *path, const char *key, char **val)
132 {
133     HKEY h;
134     DWORD size=0, type;
135     int ec;
136
137     if (hk == NULL)
138         hk = HKEY_CURRENT_USER;
139     ec = RegOpenKeyEx (hk, path, 0, KEY_READ, &h);
140     if (ec != ERROR_SUCCESS)
141         return load_config_value_ext (val);
142
143     ec = RegQueryValueEx(h, key, NULL, &type, NULL, &size);
144     if (ec != ERROR_SUCCESS) {
145         RegCloseKey (h);
146         return -1;
147     }
148     if (type == REG_EXPAND_SZ) {
149         char tmp[256]; /* XXX: do not use a static buf */
150         RegQueryValueEx (h, key, NULL, NULL, (BYTE*)tmp, &size);
151         *val = expand_path (tmp);
152     }
153     else {
154         *val = xcalloc(1, size+1);
155         ec = RegQueryValueEx (h, key, NULL, &type, (BYTE*)*val, &size);
156         if (ec != ERROR_SUCCESS) {
157             xfree (*val);
158             *val = NULL;
159             RegCloseKey (h);
160             return -1;
161         }
162     }
163     RegCloseKey (h);
164     return 0;
165 }
166
167
168
169 static int
170 store_config_value (HKEY hk, const char *path, const char *key, const char *val)
171 {
172     HKEY h;
173     int type = REG_SZ;
174     int ec;
175
176     if (hk == NULL)
177         hk = HKEY_CURRENT_USER;
178     ec = RegOpenKeyEx (hk, path, 0, KEY_ALL_ACCESS, &h);
179     if (ec != ERROR_SUCCESS)
180         return -1;
181     if (strchr (val, '%'))
182         type = REG_EXPAND_SZ;
183     ec = RegSetValueEx (h, key, 0, type, (const BYTE*)val, strlen(val));
184     if (ec != ERROR_SUCCESS) {
185         RegCloseKey(h);
186         return -1;
187     }
188     RegCloseKey(h);
189     return 0;
190 }
191
192
193 static int
194 does_folder_exist (const char *path)
195 {
196     int attrs = GetFileAttributes (path);
197     int err = 0;
198
199     if (attrs == 0xFFFFFFFF)
200         err = -1;
201     else if (!(attrs & FILE_ATTRIBUTE_DIRECTORY))
202         err = -1;
203     if (err != 0) {
204         const char *fmt = "\"%s\" either does not exist or is not a directory";
205         char *p = xmalloc (strlen (fmt) + strlen (path) + 2 + 2);
206         sprintf (p, fmt, path);
207         MessageBox (NULL, p, "Config Error", MB_ICONERROR|MB_OK);
208         xfree (p);
209     }
210     return err;
211 }
212
213
214 static int
215 does_file_exist (const char *name, int is_file)
216 {
217     struct stat st;
218     const char *s;
219     char *p, *name2;
220     int err = 0;
221
222     /* check WinPT specific flags */
223     if ((p=strstr (name, "--keymanager"))) {
224         name2 = xcalloc (1, (p-name)+2);
225         strncpy (name2, name, (p-name)-1);
226     }
227     else
228         name2 = xstrdup (name);
229
230     if (stat (name2, &st) == -1) {
231         s = "\"%s\" does not exist.";
232         p = xmalloc (strlen (s) + strlen (name2) + 2);
233         sprintf (p, s, name2);
234         MessageBox (NULL, p, "Config Error", MB_ICONERROR|MB_OK);
235         err = -1;
236     }
237     else if (is_file && !(st.st_mode & _S_IFREG)) {
238         s = "\"%s\" is not a regular file.";
239         p = xmalloc (strlen (s) + strlen (name2) + 2);
240         sprintf (p, s, name2);
241         MessageBox (NULL, p, "Config Error", MB_ICONERROR|MB_OK);
242         err = -1;
243     }
244     xfree (name2);
245     xfree (p);
246     return err;
247 }
248
249
250 static void
251 error_box (const char *title)
252 {       
253     TCHAR buf[256];
254     DWORD last_err;
255
256     last_err = GetLastError ();
257     FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, last_err, 
258                    MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), 
259                    buf, sizeof (buf)-1, NULL);
260     MessageBox (NULL, buf, title, MB_OK);
261 }
262
263
264 static BOOL CALLBACK
265 config_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
266 {
267     char *buf = NULL;
268     char name[MAX_PATH+1];
269     int n;
270
271     switch (msg) {
272     case WM_INITDIALOG:
273         center_window (dlg, 0);
274         if (!load_config_value (NULL, REGPATH, "gpgProgram", &buf)) {
275             SetDlgItemText (dlg, IDC_OPT_GPGPRG, buf);
276             xfree (buf); 
277             buf=NULL;
278         }
279         if (!load_config_value (NULL, REGPATH, "HomeDir", &buf)) {
280             SetDlgItemText (dlg, IDC_OPT_HOMEDIR, buf);
281             xfree (buf); 
282             buf=NULL;
283         }
284         if (!load_config_value (NULL, REGPATH, "keyManager", &buf)) {
285             SetDlgItemText (dlg, IDC_OPT_KEYMAN, buf);
286             xfree (buf);
287             buf=NULL;
288         }
289         break;
290
291     case WM_COMMAND:
292         switch (LOWORD(wparam)) {
293         case IDC_OPT_SELPRG:
294             buf = get_open_file_name (NULL);
295             if (buf && *buf)
296                 SetDlgItemText(dlg, IDC_OPT_GPGPRG, buf);
297             break;
298
299         case IDC_OPT_SELHOMEDIR:
300             buf = get_folder ();
301             if (buf && *buf)
302                 SetDlgItemText(dlg, IDC_OPT_HOMEDIR, buf);
303             xfree (buf);
304             break;
305
306         case IDC_OPT_SELKEYMAN:
307             buf = get_open_file_name (NULL);
308             if (buf && *buf)
309                 SetDlgItemText (dlg, IDC_OPT_KEYMAN, buf);
310             break;
311
312         case IDOK:
313             n = GetDlgItemText (dlg, IDC_OPT_GPGPRG, name, MAX_PATH-1);
314             if (n > 0) {
315                 if (does_file_exist (name, 1))
316                     return FALSE;
317                 if (store_config_value (NULL, REGPATH, "gpgProgram", name))
318                     error_box ("GPG Config");
319             }
320             n = GetDlgItemText (dlg, IDC_OPT_KEYMAN, name, MAX_PATH-1);
321             if (n > 0) {
322                 if (does_file_exist (name, 1))
323                     return FALSE;
324                 if (store_config_value (NULL, REGPATH, "keyManager", name))
325                     error_box ("GPG Config");
326             }
327             n = GetDlgItemText (dlg, IDC_OPT_HOMEDIR, name, MAX_PATH-1);
328             if (n > 0) {
329                 if (does_folder_exist (name))
330                     return FALSE;
331                 if (store_config_value (NULL, REGPATH, "HomeDir", name))
332                     error_box ("GPG Config");
333             }
334             EndDialog (dlg, TRUE);
335             break;
336         }
337         break;
338     }
339
340     return FALSE;
341 }
342
343
344 /* Display GPG configuration dialog. */
345 void
346 config_dialog_box (HWND parent)
347 {
348     int resid=0;
349
350     switch (GetUserDefaultLangID ()) {
351     case 0x0407:    resid = IDD_OPT_DE;break;
352     default:        resid = IDD_OPT; break;
353     }
354
355     if (parent == NULL)
356         parent = GetDesktopWindow ();
357     DialogBoxParam (glob_hinst, (LPCTSTR)resid, parent,
358                     config_dlg_proc, 0);
359 }
360
361
362 /* Start the key manager specified by the registry entry 'keyManager'. */
363 int
364 start_key_manager (void)
365 {
366     PROCESS_INFORMATION pi;
367     STARTUPINFO si;
368     char *keyman = NULL;
369     
370     if (load_config_value (NULL, REGPATH, "keyManager", &keyman))
371         return -1;
372
373     /* create startup info for the gpg process */
374     memset (&si, 0, sizeof (si));
375     si.cb = sizeof (STARTUPINFO);
376     si.dwFlags = STARTF_USESHOWWINDOW;
377     si.wShowWindow = SW_SHOW;    
378
379     if (CreateProcess (NULL, keyman,
380                         NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
381                         NULL, NULL, &si, &pi) == TRUE) {
382         CloseHandle(pi.hProcess);
383         CloseHandle(pi.hThread);        
384     }
385
386     xfree (keyman);
387     return 0;
388 }
389
390
391 /* Store a key in the registry with the key given by @key and the 
392    value @value. */
393 int
394 store_extension_value (const char *key, const char *val)
395 {
396     return store_config_value (HKEY_LOCAL_MACHINE, 
397         "Software\\Microsoft\\Exchange\\Client\\Extensions\\OutlGPG", 
398         key, val);
399 }
400
401 /* Load a key from the registry with the key given by @key. The value is
402    returned in @val and needs to freed by the caller. */
403 int
404 load_extension_value (const char *key, char **val)
405 {
406     return load_config_value (HKEY_LOCAL_MACHINE, 
407         "Software\\Microsoft\\Exchange\\Client\\Extensions\\OutlGPG", 
408         key, val);
409 }