Umlaut bug fixes
[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
21 #include <config.h>
22 #include <windows.h>
23 #include <time.h>
24
25 #include "gpgme.h"
26 #include "intern.h"
27 #include "util.h"
28
29 HINSTANCE glob_hinst = NULL;
30
31 void
32 set_global_hinstance (HINSTANCE hinst)
33 {
34     glob_hinst = hinst;
35 }
36
37 /* Center the given window with the desktop window as the
38    parent window. */
39 void
40 center_window (HWND childwnd, HWND style) 
41 {     
42     HWND parwnd;
43     RECT rchild, rparent;    
44     HDC hdc;
45     int wchild, hchild, wparent, hparent;
46     int wscreen, hscreen, xnew, ynew;
47     int flags = SWP_NOSIZE | SWP_NOZORDER;
48
49     parwnd = GetDesktopWindow ();
50     GetWindowRect (childwnd, &rchild);     
51     wchild = rchild.right - rchild.left;     
52     hchild = rchild.bottom - rchild.top;
53
54     GetWindowRect (parwnd, &rparent);     
55     wparent = rparent.right - rparent.left;     
56     hparent = rparent.bottom - rparent.top;      
57     
58     hdc = GetDC (childwnd);     
59     wscreen = GetDeviceCaps (hdc, HORZRES);     
60     hscreen = GetDeviceCaps (hdc, VERTRES);     
61     ReleaseDC (childwnd, hdc);      
62     xnew = rparent.left + ((wparent - wchild) / 2);     
63     if (xnew < 0)
64         xnew = 0;
65     else if ((xnew+wchild) > wscreen) 
66         xnew = wscreen - wchild;
67     ynew = rparent.top  + ((hparent - hchild) / 2);
68     if (ynew < 0)
69         ynew = 0;
70     else if ((ynew+hchild) > hscreen)
71         ynew = hscreen - hchild;
72     if (style == HWND_TOPMOST || style == HWND_NOTOPMOST)
73         flags = SWP_NOMOVE | SWP_NOSIZE;
74     SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags);
75 }
76
77
78
79 /* Return a filename to be used for saving an attachment. Returns a
80    malloced string on success. HWND is the current Window and SRCNAME
81    the filename to be used as suggestion.  On error (i.e. cancel) NULL
82    is returned. */
83 char *
84 get_save_filename (HWND root, const char *srcname)
85 {
86   char filter[] = "All Files (*.*)\0*.*\0\0";
87   char fname[MAX_PATH+1];
88   OPENFILENAME ofn;
89
90   memset (fname, 0, sizeof (fname));
91   strncpy (fname, srcname, MAX_PATH-1);
92   fname[MAX_PATH] = 0;  
93   
94
95   memset (&ofn, 0, sizeof (ofn));
96   ofn.lStructSize = sizeof (ofn);
97   ofn.hwndOwner = root;
98   ofn.lpstrFile = fname;
99   ofn.nMaxFile = MAX_PATH;
100   ofn.lpstrFileTitle = NULL;
101   ofn.nMaxFileTitle = 0;
102   ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
103   ofn.lpstrTitle = _("GPG - Save decrypted attachment");
104   ofn.lpstrFilter = filter;
105
106   if (GetSaveFileName (&ofn))
107     return xstrdup (fname);
108   return NULL;
109 }
110
111
112 void
113 out_of_core (void)
114 {
115     MessageBox (NULL, "Out of core!", "Fatal Error", MB_OK);
116     abort ();
117 }
118
119 void*
120 xmalloc (size_t n)
121 {
122     void *p = malloc (n);
123     if (!p)
124         out_of_core ();
125     return p;
126 }
127
128 void*
129 xcalloc (size_t m, size_t n)
130 {
131     void *p = calloc (m, n);
132     if (!p)
133         out_of_core ();
134     return p;
135 }
136
137 char*
138 xstrdup (const char *s)
139 {
140     char *p = xmalloc (strlen (s)+1);
141     strcpy (p, s);
142     return p;
143 }
144
145 void
146 xfree (void *p)
147 {
148     if (p)
149         free (p);
150 }
151
152
153 /* This is a helper function to load a Windows function from either of
154    one DLLs. */
155 HRESULT
156 w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
157 {
158   static int initialized;
159   static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
160
161   if (!initialized)
162     {
163       static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
164       void *handle;
165       int i;
166
167       initialized = 1;
168
169       for (i=0, handle = NULL; !handle && dllnames[i]; i++)
170         {
171           handle = LoadLibrary (dllnames[i]);
172           if (handle)
173             {
174               func = (HRESULT (WINAPI *)(HWND,int,HANDLE,DWORD,LPSTR))
175                      GetProcAddress (handle, "SHGetFolderPathA");
176               if (!func)
177                 {
178                   FreeLibrary (handle);
179                   handle = NULL;
180                 }
181             }
182         }
183     }
184
185   if (func)
186     return func (a,b,c,d,e);
187   else
188     return -1;
189 }
190
191
192
193 /* Same as above, but only convert the first LEN wchars.  */
194 char *
195 wchar_to_utf8_2 (const wchar_t *string, size_t len)
196 {
197   int n;
198   char *result;
199
200   /* Note, that CP_UTF8 is not defined in Windows versions earlier
201      than NT.*/
202   n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL);
203   if (n < 0)
204     return NULL;
205
206   result = xmalloc (n+1);
207   n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL);
208   if (n < 0)
209     {
210       xfree (result);
211       return NULL;
212     }
213   return result;
214 }
215
216
217 /* Same as above but convert only the first LEN characters.  STRING
218    must be at least LEN characters long. */
219 wchar_t *
220 utf8_to_wchar2 (const char *string, size_t len)
221 {
222   int n;
223   wchar_t *result;
224
225   n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0);
226   if (n < 0)
227     return NULL;
228
229   result = xmalloc ((n+1) * sizeof *result);
230   n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n);
231   if (n < 0)
232     {
233       xfree (result);
234       return NULL;
235     }
236   result[n] = 0;
237   return result;
238 }
239
240
241 /* Assume STRING is a Latin-1 encoded and convert it to utf-8.
242    Returns a newly malloced UTF-8 string. */
243 char *
244 latin1_to_utf8 (const char *string)
245 {
246   const char *s;
247   char *buffer, *p;
248   size_t n;
249
250   for (s=string, n=0; *s; s++) 
251     {
252       n++;
253       if (*s & 0x80)
254         n++;
255     }
256   buffer = xmalloc (n + 1);
257   for (s=string, p=buffer; *s; s++)
258     {
259       if (*s & 0x80)
260         {
261           *p++ = 0xc0 | ((*s >> 6) & 3);
262           *p++ = 0x80 | (*s & 0x3f);
263         }
264       else
265         *p++ = *s;
266     }
267   *p = 0;
268   return buffer;
269 }
270
271
272 /* Strip off trailing white spaces from STRING.  Returns STRING. */
273 char *
274 trim_trailing_spaces (char *string)
275 {
276   char *p, *mark;
277
278   for (mark=NULL, p=string; *p; p++)
279     {
280       if (strchr (" \t\r\n", *p ))
281         {
282           if (!mark)
283             mark = p;
284         }
285         else
286           mark = NULL;
287     }
288
289   if (mark)
290     *mark = 0;
291   return string;
292 }
293
294
295 /* Helper for read_w32_registry_string(). */
296 static HKEY
297 get_root_key(const char *root)
298 {
299   HKEY root_key;
300
301   if( !root )
302     root_key = HKEY_CURRENT_USER;
303   else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
304     root_key = HKEY_CLASSES_ROOT;
305   else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
306     root_key = HKEY_CURRENT_USER;
307   else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
308     root_key = HKEY_LOCAL_MACHINE;
309   else if( !strcmp( root, "HKEY_USERS" ) )
310     root_key = HKEY_USERS;
311   else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
312     root_key = HKEY_PERFORMANCE_DATA;
313   else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
314     root_key = HKEY_CURRENT_CONFIG;
315   else
316     return NULL;
317   return root_key;
318 }
319
320 /* Return a string from the Win32 Registry or NULL in case of error.
321    Caller must release the return value.  A NULL for root is an alias
322    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.  NOTE: The value
323    is allocated with a plain malloc() - use free() and not the usual
324    xfree(). */
325 char *
326 read_w32_registry_string (const char *root, const char *dir, const char *name)
327 {
328   HKEY root_key, key_handle;
329   DWORD n1, nbytes, type;
330   char *result = NULL;
331
332   if ( !(root_key = get_root_key(root) ) )
333     return NULL;
334
335   if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
336     {
337       if (root)
338         return NULL; /* no need for a RegClose, so return direct */
339       /* It seems to be common practise to fall back to HKLM. */
340       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
341         return NULL; /* still no need for a RegClose, so return direct */
342     }
343
344   nbytes = 1;
345   if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) {
346     if (root)
347       goto leave;
348     /* Try to fallback to HKLM also vor a missing value.  */
349     RegCloseKey (key_handle);
350     if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
351       return NULL; /* Nope.  */
352     if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes))
353       goto leave;
354   }
355   result = malloc( (n1=nbytes+1) );
356   if( !result )
357     goto leave;
358   if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
359     free(result); result = NULL;
360     goto leave;
361   }
362   result[nbytes] = 0; /* make sure it is really a string  */
363   if (type == REG_EXPAND_SZ && strchr (result, '%')) {
364     char *tmp;
365
366     n1 += 1000;
367     tmp = malloc (n1+1);
368     if (!tmp)
369       goto leave;
370     nbytes = ExpandEnvironmentStrings (result, tmp, n1);
371     if (nbytes && nbytes > n1) {
372       free (tmp);
373       n1 = nbytes;
374       tmp = malloc (n1 + 1);
375       if (!tmp)
376         goto leave;
377       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
378       if (nbytes && nbytes > n1) {
379         free (tmp); /* oops - truncated, better don't expand at all */
380         goto leave;
381       }
382       tmp[nbytes] = 0;
383       free (result);
384       result = tmp;
385     }
386     else if (nbytes) { /* okay, reduce the length */
387       tmp[nbytes] = 0;
388       free (result);
389       result = malloc (strlen (tmp)+1);
390       if (!result)
391         result = tmp;
392       else {
393         strcpy (result, tmp);
394         free (tmp);
395       }
396     }
397     else {  /* error - don't expand */
398       free (tmp);
399     }
400   }
401
402  leave:
403   RegCloseKey( key_handle );
404   return result;
405 }
406