Fix left over use of jnlib on some platforms
[gnupg.git] / common / w32-reg.c
1 /* w32-reg.c -  MS-Windows Registry access
2  * Copyright (C) 1999, 2002, 2007 Free Software Foundation, Inc.
3  *
4  * This file is part of JNLIB, which is a subsystem of GnuPG.
5  *
6  * JNLIB is free software; you can redistribute it and/or modify it
7  * under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * JNLIB is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * General Public License for more details.
25  *
26  * You should have received a copies of the GNU General Public License
27  * and the GNU Lesser General Public License along with this program;
28  * if not, see <http://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32 #ifdef HAVE_W32_SYSTEM
33  /* This module is only used in this environment */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdarg.h>
39 #include <windows.h>
40
41 #include "libjnlib-config.h"
42 #include "utf8conv.h"
43 #include "w32help.h"
44
45
46 static HKEY
47 get_root_key(const char *root)
48 {
49   HKEY root_key;
50
51   if (!root)
52     root_key = HKEY_CURRENT_USER;
53   else if (!strcmp( root, "HKEY_CLASSES_ROOT" ) )
54     root_key = HKEY_CLASSES_ROOT;
55   else if (!strcmp( root, "HKEY_CURRENT_USER" ) )
56     root_key = HKEY_CURRENT_USER;
57   else if (!strcmp( root, "HKEY_LOCAL_MACHINE" ) )
58     root_key = HKEY_LOCAL_MACHINE;
59   else if (!strcmp( root, "HKEY_USERS" ) )
60     root_key = HKEY_USERS;
61   else if (!strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
62     root_key = HKEY_PERFORMANCE_DATA;
63   else if (!strcmp( root, "HKEY_CURRENT_CONFIG" ) )
64     root_key = HKEY_CURRENT_CONFIG;
65   else
66     return NULL;
67
68   return root_key;
69 }
70
71
72 /* Return a string from the Win32 Registry or NULL in case of error.
73    Caller must release the return value.  A NULL for root is an alias
74    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.  */
75 char *
76 read_w32_registry_string (const char *root, const char *dir, const char *name)
77 {
78 #ifdef HAVE_W32CE_SYSTEM
79   HKEY root_key, key_handle;
80   DWORD n1, nbytes, type;
81   char *result = NULL;
82   wchar_t *wdir, *wname;
83
84   if ( !(root_key = get_root_key(root) ) )
85     return NULL;
86
87   wdir = utf8_to_wchar (dir);
88   if (!wdir)
89     return NULL;
90
91   if (RegOpenKeyEx (root_key, wdir, 0, KEY_READ, &key_handle) )
92     {
93       if (root)
94         {
95           jnlib_free (wdir);
96           return NULL; /* No need for a RegClose, so return immediately. */
97         }
98       /* It seems to be common practise to fall back to HKLM. */
99       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, wdir, 0, KEY_READ, &key_handle) )
100         {
101           jnlib_free (wdir);
102           return NULL; /* Still no need for a RegClose. */
103         }
104     }
105   jnlib_free (wdir);
106
107   if (name)
108     {
109       wname = utf8_to_wchar (name);
110       if (!wname)
111         goto leave;
112     }
113   else
114     wname = NULL;
115
116   nbytes = 2;
117   if (RegQueryValueEx (key_handle, wname, 0, NULL, NULL, &nbytes))
118     goto leave;
119   result = jnlib_malloc ((n1=nbytes+2));
120   if (!result)
121     goto leave;
122   if (RegQueryValueEx (key_handle, wname, 0, &type, result, &n1))
123     {
124       jnlib_free (result);
125       result = NULL;
126       goto leave;
127     }
128   result[nbytes] = 0;   /* Make sure it is a string.  */
129   result[nbytes+1] = 0;
130   if (type == REG_SZ || type == REG_EXPAND_SZ)
131     {
132       wchar_t *tmp = (void*)result;
133       result = wchar_to_utf8 (tmp);
134       jnlib_free (tmp);
135     }
136
137  leave:
138   jnlib_free (wname);
139   RegCloseKey (key_handle);
140   return result;
141 #else /*!HAVE_W32CE_SYSTEM*/
142   HKEY root_key, key_handle;
143   DWORD n1, nbytes, type;
144   char *result = NULL;
145
146   if ( !(root_key = get_root_key(root) ) )
147     return NULL;
148
149   if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle) )
150     {
151       if (root)
152         return NULL; /* No need for a RegClose, so return immediately. */
153       /* It seems to be common practise to fall back to HKLM. */
154       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
155         return NULL; /* Still no need for a RegClose. */
156     }
157
158   nbytes = 1;
159   if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
160     goto leave;
161   result = jnlib_malloc ((n1=nbytes+1));
162   if (!result)
163     goto leave;
164   if (RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ))
165     {
166       jnlib_free (result);
167       result = NULL;
168       goto leave;
169     }
170   result[nbytes] = 0; /* Make sure it is a string.  */
171   if (type == REG_EXPAND_SZ && strchr (result, '%'))
172     {
173       char *tmp;
174
175       n1 += 1000;
176       tmp = jnlib_malloc (n1+1);
177       if (!tmp)
178         goto leave;
179       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
180       if (nbytes && nbytes > n1)
181         {
182           jnlib_free (tmp);
183           n1 = nbytes;
184           tmp = jnlib_malloc (n1 + 1);
185           if (!tmp)
186             goto leave;
187           nbytes = ExpandEnvironmentStrings (result, tmp, n1);
188           if (nbytes && nbytes > n1)
189             {
190               /* Oops - truncated, better don't expand at all.  */
191               jnlib_free (tmp);
192               goto leave;
193             }
194           tmp[nbytes] = 0;
195           jnlib_free (result);
196           result = tmp;
197         }
198       else if (nbytes)
199         {
200           /* Okay, reduce the length.  */
201           tmp[nbytes] = 0;
202           jnlib_free (result);
203           result = jnlib_malloc (strlen (tmp)+1);
204           if (!result)
205             result = tmp;
206             else
207               {
208                 strcpy (result, tmp);
209                 jnlib_free (tmp);
210               }
211         }
212       else
213         {
214           /* Error - don't expand.  */
215           jnlib_free (tmp);
216         }
217     }
218
219  leave:
220   RegCloseKey (key_handle);
221   return result;
222 #endif /*!HAVE_W32CE_SYSTEM*/
223 }
224
225
226 /* Note: This code is not well tested.  However, it is not used in
227    GnuPG.  */
228 int
229 write_w32_registry_string (const char *root, const char *dir,
230                            const char *name, const char *value)
231 {
232   HKEY root_key, reg_key;
233 #ifdef HAVE_W32CE_SYSTEM
234   wchar_t *wdir, *wname, *wvalue;
235   DWORD disp;
236
237   if ( !(root_key = get_root_key(root) ) )
238     return -1;
239
240   wdir = utf8_to_wchar (dir);
241   if (!wdir)
242     return -1;
243
244   if (RegOpenKeyEx (root_key, wdir, 0, 0, &reg_key))
245     {
246       jnlib_free (wdir);
247       return -1;
248     }
249   jnlib_free (wdir);
250
251   if (name)
252     {
253       wname = utf8_to_wchar (name);
254       if (!wname)
255         return -1;
256     }
257   else
258     wname = NULL;
259
260   wvalue = utf8_to_wchar (value);
261   if (wvalue)
262     {
263       jnlib_free (wname);
264       return -1;
265     }
266
267   if (RegSetValueEx (reg_key, wname, 0, REG_SZ,
268                      (BYTE *)wvalue, wcslen (wvalue)) != ERROR_SUCCESS )
269     {
270
271       if (RegCreateKeyEx (root_key, wname, 0, NULL, 0, 0, NULL,
272                           &reg_key, &disp) != ERROR_SUCCESS)
273         {
274           RegCloseKey(reg_key);
275           jnlib_free (wname);
276           jnlib_free (wvalue);
277           return -1;
278         }
279       if (RegSetValueEx (reg_key, wname, 0, REG_SZ,
280                          (BYTE *)wvalue, wcslen (wvalue)) != ERROR_SUCCESS )
281         {
282           RegCloseKey(reg_key);
283           jnlib_free (wname);
284           jnlib_free (wvalue);
285           return -1;
286         }
287     }
288
289   jnlib_free (wname);
290   jnlib_free (wvalue);
291   RegCloseKey (reg_key);
292   return 0;
293 #else /*!HAVE_W32CE_SYSTEM*/
294
295   if ( !(root_key = get_root_key(root) ) )
296     return -1;
297
298   if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, &reg_key )
299        != ERROR_SUCCESS )
300     return -1;
301
302   if ( RegSetValueEx (reg_key, name, 0, REG_SZ, (BYTE *)value,
303                       strlen( value ) ) != ERROR_SUCCESS )
304     {
305       if ( RegCreateKey( root_key, name, &reg_key ) != ERROR_SUCCESS )
306         {
307           RegCloseKey(reg_key);
308           return -1;
309         }
310       if ( RegSetValueEx (reg_key, name, 0, REG_SZ, (BYTE *)value,
311                           strlen( value ) ) != ERROR_SUCCESS )
312         {
313           RegCloseKey(reg_key);
314           return -1;
315         }
316     }
317
318   RegCloseKey (reg_key);
319   return 0;
320 #endif /*!HAVE_W32CE_SYSTEM*/
321 }
322
323 #endif /*HAVE_W32_SYSTEM*/