2006-03-17 Timo Schulz <ts@g10code.com>
[gpgol.git] / src / common.c
1 /* common.c 
2  *      Copyright (C) 2005 g10 Code GmbH
3  *
4  * This file is part of GPGol.
5  *
6  * GPGol is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 
9  * of the License, or (at your option) any later version.
10  *  
11  * GPGol 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 GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with GPGol; if not, write to the Free Software Foundation, 
18  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
19  */
20 #include <windows.h>
21 #include <time.h>
22
23 #include "gpgme.h"
24 #include "intern.h"
25 #include "util.h"
26
27 HINSTANCE glob_hinst = NULL;
28
29 void
30 set_global_hinstance (HINSTANCE hinst)
31 {
32     glob_hinst = hinst;
33 }
34
35 /* Center the given window with the desktop window as the
36    parent window. */
37 void
38 center_window (HWND childwnd, HWND style) 
39 {     
40     HWND parwnd;
41     RECT rchild, rparent;    
42     HDC hdc;
43     int wchild, hchild, wparent, hparent;
44     int wscreen, hscreen, xnew, ynew;
45     int flags = SWP_NOSIZE | SWP_NOZORDER;
46
47     parwnd = GetDesktopWindow ();
48     GetWindowRect (childwnd, &rchild);     
49     wchild = rchild.right - rchild.left;     
50     hchild = rchild.bottom - rchild.top;
51
52     GetWindowRect (parwnd, &rparent);     
53     wparent = rparent.right - rparent.left;     
54     hparent = rparent.bottom - rparent.top;      
55     
56     hdc = GetDC (childwnd);     
57     wscreen = GetDeviceCaps (hdc, HORZRES);     
58     hscreen = GetDeviceCaps (hdc, VERTRES);     
59     ReleaseDC (childwnd, hdc);      
60     xnew = rparent.left + ((wparent - wchild) / 2);     
61     if (xnew < 0)
62         xnew = 0;
63     else if ((xnew+wchild) > wscreen) 
64         xnew = wscreen - wchild;
65     ynew = rparent.top  + ((hparent - hchild) / 2);
66     if (ynew < 0)
67         ynew = 0;
68     else if ((ynew+hchild) > hscreen)
69         ynew = hscreen - hchild;
70     if (style == HWND_TOPMOST || style == HWND_NOTOPMOST)
71         flags = SWP_NOMOVE | SWP_NOSIZE;
72     SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags);
73 }
74
75
76
77 /* Return a filename to be used for saving an attachment. Returns a
78    malloced string on success. HWND is the current Window and SRCNAME
79    the filename to be used as suggestion.  On error (i.e. cancel) NULL
80    is returned. */
81 char *
82 get_save_filename (HWND root, const char *srcname)
83 {
84   char filter[] = "All Files (*.*)\0*.*\0\0";
85   char fname[MAX_PATH+1];
86   OPENFILENAME ofn;
87
88   memset (fname, 0, sizeof (fname));
89   strncpy (fname, srcname, MAX_PATH-1);
90   fname[MAX_PATH] = 0;  
91   
92
93   memset (&ofn, 0, sizeof (ofn));
94   ofn.lStructSize = sizeof (ofn);
95   ofn.hwndOwner = root;
96   ofn.lpstrFile = fname;
97   ofn.nMaxFile = MAX_PATH;
98   ofn.lpstrFileTitle = NULL;
99   ofn.nMaxFileTitle = 0;
100   ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
101   ofn.lpstrTitle = _("GPG - Save decrypted attachment");
102   ofn.lpstrFilter = filter;
103
104   if (GetSaveFileName (&ofn))
105     return xstrdup (fname);
106   return NULL;
107 }
108
109
110 void
111 out_of_core (void)
112 {
113     MessageBox (NULL, "Out of core!", "Fatal Error", MB_OK);
114     abort ();
115 }
116
117 void*
118 xmalloc (size_t n)
119 {
120     void *p = malloc (n);
121     if (!p)
122         out_of_core ();
123     return p;
124 }
125
126 void*
127 xcalloc (size_t m, size_t n)
128 {
129     void *p = calloc (m, n);
130     if (!p)
131         out_of_core ();
132     return p;
133 }
134
135 char*
136 xstrdup (const char *s)
137 {
138     char *p = xmalloc (strlen (s)+1);
139     strcpy (p, s);
140     return p;
141 }
142
143 void
144 xfree (void *p)
145 {
146     if (p)
147         free (p);
148 }
149
150
151 /* This is a helper function to load a Windows function from either of
152    one DLLs. */
153 HRESULT
154 w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
155 {
156   static int initialized;
157   static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
158
159   if (!initialized)
160     {
161       static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
162       void *handle;
163       int i;
164
165       initialized = 1;
166
167       for (i=0, handle = NULL; !handle && dllnames[i]; i++)
168         {
169           handle = LoadLibrary (dllnames[i]);
170           if (handle)
171             {
172               func = (HRESULT (WINAPI *)(HWND,int,HANDLE,DWORD,LPSTR))
173                      GetProcAddress (handle, "SHGetFolderPathA");
174               if (!func)
175                 {
176                   FreeLibrary (handle);
177                   handle = NULL;
178                 }
179             }
180         }
181     }
182
183   if (func)
184     return func (a,b,c,d,e);
185   else
186     return -1;
187 }
188
189
190 /* Return a malloced string encoded in UTF-8 from the wide char input
191    string STRING.  Caller must xfree this value. On failure returns
192    NULL; caller may use GetLastError to get the actual error number.
193    The result of calling this function with STRING set to NULL is not
194    defined. */
195 char *
196 wchar_to_utf8 (const wchar_t *string)
197 {
198   int n;
199   char *result;
200
201   /* Note, that CP_UTF8 is not defined in Windows versions earlier
202      than NT.*/
203   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
204   if (n < 0)
205     return NULL;
206
207   result = xmalloc (n+1);
208   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
209   if (n < 0)
210     {
211       xfree (result);
212       return NULL;
213     }
214   return result;
215 }
216
217
218 /* Same as above, but only convert the first LEN wchars.  */
219 char *
220 wchar_to_utf8_2 (const wchar_t *string, size_t len)
221 {
222   int n;
223   char *result;
224
225   /* Note, that CP_UTF8 is not defined in Windows versions earlier
226      than NT.*/
227   n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL);
228   if (n < 0)
229     return NULL;
230
231   result = xmalloc (n+1);
232   n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL);
233   if (n < 0)
234     {
235       xfree (result);
236       return NULL;
237     }
238   return result;
239 }
240
241 /* Return a malloced wide char string from an UTF-8 encoded input
242    string STRING.  Caller must xfree this value. On failure returns
243    NULL; caller may use GetLastError to get the actual error number.
244    The result of calling this function with STRING set to NULL is not
245    defined. */
246 wchar_t *
247 utf8_to_wchar (const char *string)
248 {
249   int n;
250   wchar_t *result;
251
252   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
253   if (n < 0)
254     return NULL;
255
256   result = xmalloc ((n+1) * sizeof *result);
257   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
258   if (n < 0)
259     {
260       xfree (result);
261       return NULL;
262     }
263   return result;
264 }
265
266
267 /* Same as above but convert only the first LEN characters.  STRING
268    must be at least LEN characters long. */
269 wchar_t *
270 utf8_to_wchar2 (const char *string, size_t len)
271 {
272   int n;
273   wchar_t *result;
274
275   n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0);
276   if (n < 0)
277     return NULL;
278
279   result = xmalloc ((n+1) * sizeof *result);
280   n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n);
281   if (n < 0)
282     {
283       xfree (result);
284       return NULL;
285     }
286   result[n] = 0;
287   return result;
288 }
289
290
291 /* CP850 -> CP1251 charset table. */
292 static unsigned char cp850_to_cp1251[] = 
293 {
294   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
295   0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
296   0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
297   0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
298   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
299   0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
300   0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
301   0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
302   0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
303   0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0xc7, 0xfc,
304   0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7, 0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4,
305   0xc5, 0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9, 0xff, 0xd6, 0xdc, 0xf8,
306   0xa3, 0xd8, 0xd7, 0x00, 0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba, 0xbf,
307   0xae, 0xac, 0xbd, 0xbc, 0xa1, 0xab, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1,
308   0xc2, 0xc0, 0xa9, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xa5, 0x00, 0x00, 0x00, 0x00,
309   0x00, 0x00, 0x00, 0xe3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4,
310   0xf0, 0xd0, 0xca, 0xcb, 0xc8, 0x00, 0xcd, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00,
311   0xa6, 0xcc, 0x00, 0xd3, 0xdf, 0xd4, 0xd2, 0xf5, 0xd5, 0xb5, 0xfe, 0xde, 0xda,
312   0xdb, 0xd9, 0xfd, 0xdd, 0xaf, 0xb4, 0xad, 0xb1, 0x00, 0xbe, 0xb6, 0xa7, 0xf7,
313   0xb8, 0xb0, 0xa8, 0xb7, 0xb9, 0xb3, 0xb2, 0x00, 0xa0,
314 };
315
316 char *utf8_to_native (const char *string);
317     
318 /* Convert the console (CP850) encoded UTF8 data from STRING into
319    the current window charset and return it.
320    Caller must free string. */
321 char *
322 utf8_to_wincp (const char *string)
323 {
324   char *res;
325   unsigned char *res_8;
326   size_t i;
327
328   res_8 = res = utf8_to_native (string);
329   
330   /* XXX: currently only CP850->CP1251 is supported. */
331   for (i=0; i < strlen (res); i++)
332     {
333       unsigned char ch = cp850_to_cp1251[res_8[i]];
334       if (ch != 0x00)
335         res_8[i] = ch;
336     }
337   
338   return res;
339 }
340
341   
342 /* Assume STRING is a Latin-1 encoded and convert it to utf-8.
343    Returns a newly malloced UTF-8 string. */
344 char *
345 latin1_to_utf8 (const char *string)
346 {
347   const char *s;
348   char *buffer, *p;
349   size_t n;
350
351   for (s=string, n=0; *s; s++) 
352     {
353       n++;
354       if (*s & 0x80)
355         n++;
356     }
357   buffer = xmalloc (n + 1);
358   for (s=string, p=buffer; *s; s++)
359     {
360       if (*s & 0x80)
361         {
362           *p++ = 0xc0 | ((*s >> 6) & 3);
363           *p++ = 0x80 | (*s & 0x3f);
364         }
365       else
366         *p++ = *s;
367     }
368   *p = 0;
369   return buffer;
370 }
371
372
373 /* Strip off trailing white spaces from STRING.  Returns STRING. */
374 char *
375 trim_trailing_spaces (char *string)
376 {
377   char *p, *mark;
378
379   for (mark=NULL, p=string; *p; p++)
380     {
381       if (strchr (" \t\r\n", *p ))
382         {
383           if (!mark)
384             mark = p;
385         }
386         else
387           mark = NULL;
388     }
389
390   if (mark)
391     *mark = 0;
392   return string;
393 }
394
395
396 /* Helper for read_w32_registry_string(). */
397 static HKEY
398 get_root_key(const char *root)
399 {
400   HKEY root_key;
401
402   if( !root )
403     root_key = HKEY_CURRENT_USER;
404   else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
405     root_key = HKEY_CLASSES_ROOT;
406   else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
407     root_key = HKEY_CURRENT_USER;
408   else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
409     root_key = HKEY_LOCAL_MACHINE;
410   else if( !strcmp( root, "HKEY_USERS" ) )
411     root_key = HKEY_USERS;
412   else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
413     root_key = HKEY_PERFORMANCE_DATA;
414   else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
415     root_key = HKEY_CURRENT_CONFIG;
416   else
417     return NULL;
418   return root_key;
419 }
420
421 /* Return a string from the Win32 Registry or NULL in case of error.
422    Caller must release the return value.  A NULL for root is an alias
423    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.  NOTE: The value
424    is allocated with a plain malloc() - use free() and not the usual
425    xfree(). */
426 char *
427 read_w32_registry_string (const char *root, const char *dir, const char *name)
428 {
429   HKEY root_key, key_handle;
430   DWORD n1, nbytes, type;
431   char *result = NULL;
432
433   if ( !(root_key = get_root_key(root) ) )
434     return NULL;
435
436   if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
437     {
438       if (root)
439         return NULL; /* no need for a RegClose, so return direct */
440       /* It seems to be common practise to fall back to HKLM. */
441       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
442         return NULL; /* still no need for a RegClose, so return direct */
443     }
444
445   nbytes = 1;
446   if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) {
447     if (root)
448       goto leave;
449     /* Try to fallback to HKLM also vor a missing value.  */
450     RegCloseKey (key_handle);
451     if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
452       return NULL; /* Nope.  */
453     if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes))
454       goto leave;
455   }
456   result = malloc( (n1=nbytes+1) );
457   if( !result )
458     goto leave;
459   if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
460     free(result); result = NULL;
461     goto leave;
462   }
463   result[nbytes] = 0; /* make sure it is really a string  */
464   if (type == REG_EXPAND_SZ && strchr (result, '%')) {
465     char *tmp;
466
467     n1 += 1000;
468     tmp = malloc (n1+1);
469     if (!tmp)
470       goto leave;
471     nbytes = ExpandEnvironmentStrings (result, tmp, n1);
472     if (nbytes && nbytes > n1) {
473       free (tmp);
474       n1 = nbytes;
475       tmp = malloc (n1 + 1);
476       if (!tmp)
477         goto leave;
478       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
479       if (nbytes && nbytes > n1) {
480         free (tmp); /* oops - truncated, better don't expand at all */
481         goto leave;
482       }
483       tmp[nbytes] = 0;
484       free (result);
485       result = tmp;
486     }
487     else if (nbytes) { /* okay, reduce the length */
488       tmp[nbytes] = 0;
489       free (result);
490       result = malloc (strlen (tmp)+1);
491       if (!result)
492         result = tmp;
493       else {
494         strcpy (result, tmp);
495         free (tmp);
496       }
497     }
498     else {  /* error - don't expand */
499       free (tmp);
500     }
501   }
502
503  leave:
504   RegCloseKey( key_handle );
505   return result;
506 }
507