2007-08-30 Marcus Brinkmann <marcus@g10code.de>
[gpg4win.git] / src / g4wihelp.c
1 /* g4wihelp.c - NSIS Helper DLL used with gpg4win. -*- coding: latin-1; -*-
2  * Copyright (C) 2005 g10 Code GmbH
3  * Copyright (C) 2001 Justin Frankel
4  * 
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any
7  * damages arising from the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any
10  * purpose, including commercial applications, and to alter it and
11  * redistribute it freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must
14  *    not claim that you wrote the original software. If you use this
15  *    software in a product, an acknowledgment in the product
16  *    documentation would be appreciated but is not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must
19  *    not be misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source
22  *    distribution.
23  ************************************************************
24  * The code for the splash screen has been taken from the Splash
25  * plugin of the NSIS 2.04 distribution.  That code comes without
26  * explicit copyright notices in tyhe source files or author names, it
27  * seems that it has been written by Justin Frankel; not sure about
28  * the year, though. [wk 2005-11-28]
29  */
30
31 #include <windows.h>
32 #include "exdll.h"
33
34 static HINSTANCE g_hInstance; /* Our Instance. */
35 static HWND g_hwndParent;     /* Handle of parent window or NULL. */
36 static HBITMAP g_hbm;         /* Handle of the splash image. */ 
37 static int sleepint;          /* Milliseconds to show the spals image. */
38
39
40 /* Standard entry point for DLLs. */
41 int WINAPI
42 DllMain (HANDLE hinst, DWORD reason, LPVOID reserved)
43 {
44    if (reason == DLL_PROCESS_ATTACH)
45      g_hInstance = hinst;
46    return TRUE;
47 }
48
49
50
51 /* Dummy function for testing. */
52 void __declspec(dllexport) 
53 dummy (HWND hwndParent, int string_size, char *variables, 
54        stack_t **stacktop, extra_parameters_t *extra)
55 {
56   g_hwndParent = hwndParent;
57
58   EXDLL_INIT();
59
60   // note if you want parameters from the stack, pop them off in order.
61   // i.e. if you are called via exdll::myFunction file.dat poop.dat
62   // calling popstring() the first time would give you file.dat,
63   // and the second time would give you poop.dat. 
64   // you should empty the stack of your parameters, and ONLY your
65   // parameters.
66
67   // do your stuff here
68   {
69     char buf[1024];
70     sprintf(buf,"$R0=%s\r\n$R1=%s\r\n",
71             getuservariable(INST_R0),
72             getuservariable(INST_R1));
73     MessageBox(g_hwndParent,buf,0,MB_OK);
74
75     sprintf (buf,
76              "autoclose    =%d\r\n"
77              "all_user_var =%d\r\n"
78              "exec_error   =%d\r\n"
79              "abort        =%d\r\n"
80              "exec_reboot  =%d\r\n"
81              "reboot_called=%d\r\n"
82              "silent       =%d\r\n"
83              "instdir_error=%d\r\n"
84              "rtl          =%d\r\n"
85              "errlvl       =%d\r\n",
86              extra->exec_flags->autoclose,
87              extra->exec_flags->all_user_var,
88              extra->exec_flags->exec_error,
89              extra->exec_flags->abort,
90              extra->exec_flags->exec_reboot,
91              extra->exec_flags->reboot_called,
92              extra->exec_flags->silent,
93              extra->exec_flags->instdir_error,
94              extra->exec_flags->rtl,
95              extra->exec_flags->errlvl);      
96     MessageBox(g_hwndParent,buf,0,MB_OK);
97   }
98 }
99
100
101
102 void __declspec(dllexport) 
103 runonce (HWND hwndParent, int string_size, char *variables, 
104          stack_t **stacktop, extra_parameters_t *extra)
105 {
106   const char *result;
107
108   g_hwndParent = hwndParent;
109   EXDLL_INIT();
110
111   CreateMutexA (NULL, 0, getuservariable(INST_R0));
112   result = GetLastError ()? "1":"0";
113   setuservariable (INST_R0, result);
114 }
115
116
117 void __declspec(dllexport) 
118 playsound (HWND hwndParent, int string_size, char *variables, 
119            stack_t **stacktop, extra_parameters_t *extra)
120 {
121   char fname[MAX_PATH];
122
123   g_hwndParent = hwndParent;
124   EXDLL_INIT();
125
126   if (popstring(fname, sizeof fname))
127     return;
128   PlaySound (fname, NULL, SND_ASYNC|SND_FILENAME|SND_NODEFAULT);
129 }
130
131
132 void __declspec(dllexport) 
133 stopsound (HWND hwndParent, int string_size, char *variables, 
134            stack_t **stacktop, extra_parameters_t *extra)
135 {
136   g_hwndParent = hwndParent;
137   EXDLL_INIT();
138   PlaySound (NULL, NULL, 0);
139 }
140
141
142 /* Windows procedure to control the splashimage.  This one pauses the
143    execution until the sleep time is over or the user closes this
144    windows. */
145 static LRESULT CALLBACK 
146 splash_wndproc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
147 {
148   LRESULT result = 0;
149
150   switch (uMsg)
151     {
152     case WM_CREATE:
153       {
154         BITMAP bm;
155         RECT vp;
156
157         GetObject(g_hbm, sizeof(bm), (LPSTR)&bm);
158         SystemParametersInfo(SPI_GETWORKAREA, 0, &vp, 0);
159         SetWindowLong(hwnd,GWL_STYLE,0);
160         SetWindowPos(hwnd,NULL,
161                      vp.left+(vp.right-vp.left-bm.bmWidth)/2,
162                      vp.top+(vp.bottom-vp.top-bm.bmHeight)/2,
163                      bm.bmWidth,bm.bmHeight,
164                      SWP_NOZORDER);
165         ShowWindow(hwnd,SW_SHOW);
166         SetTimer(hwnd,1,sleepint,NULL);
167       }
168       break;
169   
170     case WM_PAINT:
171       {
172         PAINTSTRUCT ps;
173         RECT r;
174         HDC curdc=BeginPaint(hwnd,&ps);
175         HDC hdc=CreateCompatibleDC(curdc);
176         HBITMAP oldbm;
177         GetClientRect(hwnd,&r);
178         oldbm=(HBITMAP)SelectObject(hdc,g_hbm);
179         BitBlt(curdc,r.left,r.top,r.right-r.left,r.bottom-r.top,
180                hdc,0,0,SRCCOPY);
181         SelectObject(hdc,oldbm);
182         DeleteDC(hdc);
183         EndPaint(hwnd,&ps);
184       }
185       break;
186
187     case WM_CLOSE:
188       break;
189
190     case WM_TIMER:
191     case WM_LBUTTONDOWN:
192       DestroyWindow(hwnd);
193       /*(fall through)*/
194     default:
195       result =  DefWindowProc (hwnd, uMsg, wParam, lParam);
196     }
197
198   return result;
199 }
200
201
202 /* Display a splash screen.  Call as
203
204      g4wihelp::showsplash SLEEP FNAME
205
206    With SLEEP being the time in milliseconds to show the splashscreen
207    and FNAME the complete filename of the image.  As of now only BMP
208    is supported.
209 */
210 void __declspec(dllexport) 
211 showsplash (HWND hwndParent, int string_size, char *variables, 
212            stack_t **stacktop, extra_parameters_t *extra)
213 {
214   static WNDCLASS wc;
215   char sleepstr[30];
216   char fname[MAX_PATH];
217   int err = 0;
218   char *p;
219   char classname[] = "_sp";
220
221   g_hwndParent = hwndParent;
222   EXDLL_INIT();
223   if (popstring(sleepstr, sizeof sleepstr))
224     err = 1;
225   if (popstring(fname, sizeof fname))
226     err = 1;
227   if (err)
228     return;
229
230   if (!*fname)
231     return; /* Nothing to do. */
232
233   for (sleepint=0, p=sleepstr; *p >= '0' && *p <= '9'; p++)
234     {
235       sleepint *= 10;
236       sleepint += *p - '0';
237     }
238   if (sleepint <= 0)
239     return; /* Nothing to do. */
240
241   wc.lpfnWndProc = splash_wndproc;
242   wc.hInstance = g_hInstance;
243   wc.hCursor = LoadCursor(NULL,IDC_ARROW);
244   wc.lpszClassName = classname;
245   if (!RegisterClass(&wc)) 
246     return; /* Error. */
247
248   g_hbm = LoadImage (NULL, fname, IMAGE_BITMAP,
249                      0, 0 , LR_CREATEDIBSECTION|LR_LOADFROMFILE);
250   if (g_hbm) 
251     {
252       MSG msg;
253       HWND hwnd;
254
255       hwnd = CreateWindowEx (WS_EX_TOOLWINDOW, classname, classname,
256                              0, 0, 0, 0, 0, (HWND)hwndParent, NULL,
257                              g_hInstance, NULL);
258       
259       while (IsWindow(hwnd) && GetMessage ( &msg, hwnd, 0, 0))
260         {
261           DispatchMessage (&msg);
262         }
263
264       DeleteObject (g_hbm);
265       g_hbm = NULL;
266     }
267   UnregisterClass (classname, g_hInstance);
268 }
269
270 \f
271 /* Service Management.  */
272
273 /* Use this to report unexpected errors.  FIXME: This is really not
274    very descriptive.  */
275 void
276 service_error (const char *str)
277 {
278   char buf[1024];
279   snprintf (buf, sizeof (buf) - 1, "error: %s: ec=%d\r\n", str,
280             GetLastError ());
281   MessageBox(g_hwndParent, buf, 0, MB_OK);
282
283   setuservariable (INST_R0, "1");
284 }
285
286
287 void __declspec(dllexport) 
288 service_create (HWND hwndParent, int string_size, char *variables, 
289                  stack_t **stacktop, extra_parameters_t *extra)
290 {
291   SC_HANDLE sc;
292   SC_HANDLE service;
293   const char *result = NULL;
294   char service_name[256];
295   char display_name[256];
296   char program[256];
297   int err = 0;
298
299   g_hwndParent = hwndParent;
300   EXDLL_INIT();
301
302   /* The expected stack layout: service_name, display_name, program.  */
303   if (popstring (service_name, sizeof (service_name)))
304     err = 1;
305   if (!err && popstring (display_name, sizeof (display_name)))
306     err = 1;
307   if (!err && popstring (program, sizeof (program)))
308     err = 1;
309   if (err)
310     {
311       setuservariable (INST_R0, "1");
312       return;
313     }
314
315   sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
316   if (sc == NULL)
317     {
318       service_error ("OpenSCManager");
319       return;
320     }
321
322   service = CreateService (sc, service_name, display_name,
323                            SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
324                            /* Use SERVICE_DEMAND_START for testing.
325                               FIXME: Currently not configurable by caller.  */
326                            SERVICE_AUTO_START,
327                            SERVICE_ERROR_NORMAL, program,
328                            NULL, NULL, NULL,
329                            /* FIXME: Currently not configurable by caller.  */
330                            "NT AUTHORITY\\LocalService",
331                            NULL);
332   if (service == NULL)
333     {
334       service_error ("CreateService");
335       CloseServiceHandle (sc);
336       return;
337     }
338   CloseServiceHandle (service);
339
340   result = GetLastError () ? "1":"0";
341   setuservariable (INST_R0, result);
342   return;
343 }
344
345
346 /* Requires g_hwndParent to be set!  */
347 SC_HANDLE
348 service_lookup (char *service_name)
349 {
350   SC_HANDLE sc;
351   SC_HANDLE service;
352   
353   sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
354   if (sc == NULL)
355     {
356       service_error ("OpenSCManager");
357       return NULL;
358     }
359   service = OpenService (sc, service_name, SC_MANAGER_ALL_ACCESS);
360   if (service == NULL)
361     {
362       /* Fail silently here.  */
363       CloseServiceHandle (sc);
364       return NULL;
365     }
366   CloseServiceHandle (sc);
367   return service;
368 }
369
370
371 /* Returns status.  */
372 void __declspec(dllexport) 
373 service_query (HWND hwndParent, int string_size, char *variables, 
374                stack_t **stacktop, extra_parameters_t *extra)
375 {
376   SC_HANDLE service;
377   const char *result = NULL;
378   char service_name[256];
379   int err = 0;
380   SERVICE_STATUS status;
381
382   g_hwndParent = hwndParent;
383   EXDLL_INIT();
384
385   /* The expected stack layout: service_name argc [argv].  */
386   if (popstring (service_name, sizeof (service_name)))
387     err = 1;
388   if (err)
389     {
390       setuservariable (INST_R0, "ERROR");
391       return;
392     }
393
394   service = service_lookup (service_name);
395   if (service == NULL)
396   if (err == 0)
397     {
398       setuservariable (INST_R0, "MISSING");
399       return;
400     }
401
402   err = QueryServiceStatus (service, &status);
403   if (err == 0)
404     {
405       setuservariable (INST_R0, "ERROR");
406       CloseServiceHandle (service);
407       return;
408     }
409   CloseServiceHandle (service);
410
411   switch (status.dwCurrentState)
412     {
413     case SERVICE_START_PENDING:
414       result = "START_PENDING";
415       break;
416     case SERVICE_RUNNING:
417       result = "RUNNING";
418       break;
419     case SERVICE_PAUSE_PENDING:
420       result = "PAUSE_PENDING";
421       break;
422     case SERVICE_PAUSED:
423       result = "PAUSED";
424       break;
425     case SERVICE_CONTINUE_PENDING:
426       result = "CONTINUE_PENDING";
427       break;
428     case SERVICE_STOP_PENDING:
429       result = "STOP_PENDING";
430       break;
431     case SERVICE_STOPPED:
432       result = "STOPPED";
433       break;
434     default:
435       result = "UNKNOWN";
436     }
437   setuservariable (INST_R0, result);
438   return;
439 }
440
441
442 void __declspec(dllexport) 
443 service_start (HWND hwndParent, int string_size, char *variables, 
444                stack_t **stacktop, extra_parameters_t *extra)
445 {
446   SC_HANDLE service;
447   const char *result = NULL;
448   char service_name[256];
449   char argc_str[256];
450 #define NR_ARGS 10
451 #define ARG_MAX 256
452   char argv_str[NR_ARGS][ARG_MAX];
453   char *argv[NR_ARGS + 1];
454   int argc;
455   int i;
456   int err = 0;
457
458   g_hwndParent = hwndParent;
459   EXDLL_INIT();
460
461   /* The expected stack layout: service_name argc [argv].  */
462   if (popstring (service_name, sizeof (service_name)))
463     err = 1;
464   if (!err && popstring (argc_str, sizeof (argc_str)))
465     err = 1;
466   if (!err)
467     {
468       argc = atoi (argc_str);
469       for (i = 0; i < argc; i++)
470         {
471           if (popstring (argv_str[i], ARG_MAX))
472             {
473               err = 1;
474               break;
475             }
476           argv[i] = argv_str[i];
477         }
478       argv[i] = NULL;
479     }
480   if (err)
481     {
482       setuservariable (INST_R0, "1");
483       return;
484     }
485
486   service = service_lookup (service_name);
487   if (service == NULL)
488     return;
489
490   err = StartService (service, argc, argc == 0 ? NULL : argv);
491   if (err == 0)
492     {
493       service_error ("StartService");
494       CloseServiceHandle (service);
495       return;
496     }
497   CloseServiceHandle (service);
498
499   setuservariable (INST_R0, "0");
500   return;
501 }
502
503
504 void __declspec(dllexport) 
505 service_stop (HWND hwndParent, int string_size, char *variables, 
506               stack_t **stacktop, extra_parameters_t *extra)
507 {
508   SC_HANDLE service;
509   const char *result = NULL;
510   char service_name[256];
511   int err = 0;
512   SERVICE_STATUS status;
513   DWORD timeout = 10000;        /* 10 seconds.  */
514   DWORD start_time;
515
516   g_hwndParent = hwndParent;
517   EXDLL_INIT();
518
519   /* The expected stack layout: service_name argc [argv].  */
520   if (popstring (service_name, sizeof (service_name)))
521     err = 1;
522   if (err)
523     {
524       setuservariable (INST_R0, "1");
525       return;
526     }
527
528   service = service_lookup (service_name);
529   if (service == NULL)
530     return;
531
532   err = QueryServiceStatus (service, &status);
533   if (err == 0)
534     {
535       service_error ("QueryService");
536       CloseServiceHandle (service);
537       return;
538     }
539
540   if (status.dwCurrentState != SERVICE_STOPPED
541       && status.dwCurrentState != SERVICE_STOP_PENDING)
542     {
543       err = ControlService (service, SERVICE_CONTROL_STOP, &status);
544       if (err == 0)
545         {
546           service_error ("ControlService");
547           CloseServiceHandle (service);
548           return;
549         }
550     }
551
552   start_time = GetTickCount ();
553   while (status.dwCurrentState != SERVICE_STOPPED)
554     {
555       Sleep (1000);     /* One second.  */
556       if (!QueryServiceStatus (service, &status))
557         {
558           service_error ("QueryService");
559           CloseServiceHandle (service);
560           return;
561         }
562       if (status.dwCurrentState == SERVICE_STOPPED)
563         break;
564
565       if (GetTickCount () - start_time > timeout)
566         {
567           char buf[1024];
568           snprintf (buf, sizeof (buf) - 1,
569                     "time out waiting for service %s to stop\r\n",
570                     service_name);
571           MessageBox (g_hwndParent, buf, 0, MB_OK);
572           setuservariable (INST_R0, "1");
573           return;
574         }
575     }
576   CloseServiceHandle (service);
577   setuservariable (INST_R0, "0");
578   return;
579 }
580
581
582 void __declspec(dllexport) 
583 service_delete (HWND hwndParent, int string_size, char *variables, 
584                 stack_t **stacktop, extra_parameters_t *extra)
585 {
586   SC_HANDLE service;
587   const char *result = NULL;
588   char service_name[256];
589   int err = 0;
590
591   g_hwndParent = hwndParent;
592   EXDLL_INIT();
593
594   /* The expected stack layout: service_name argc [argv].  */
595   if (popstring (service_name, sizeof (service_name)))
596     err = 1;
597   if (err)
598     {
599       setuservariable (INST_R0, "1");
600       return;
601     }
602
603   service = service_lookup (service_name);
604   if (service == NULL)
605     return;
606
607   err = DeleteService (service);
608   if (err == 0)
609     {
610       service_error ("DeleteService");
611       CloseServiceHandle (service);
612       return;
613     }
614   CloseServiceHandle (service);
615
616   setuservariable (INST_R0, "0");
617   return;
618 }
619
620 \f
621 #include <stdio.h>
622
623 /* Extract config file parameters.  FIXME: Not particularly robust.
624    We expect some reasonable formatting.  The parser below is very
625    limited.  It expects a command line option /c=FILE or /C=FILE,
626    where FILE must be enclosed in double-quotes if it contains spaces.
627    That file should contain a single section [gpg4win] and KEY=VALUE
628    pairs for each additional configuration file to install.  Comments
629    are supported only on lines by themselves.  VALUE can be quoted in
630    double-quotes, but does not need to be, unless it has whitespace at
631    the beginning or end.  KEY can, for example, be "gpg.conf" (without
632    the quotes).  */
633 void
634 config_init (char **keys, char **values, int max)
635 {
636   /* First, parse the command line.  */
637   char *cmdline;
638   char *begin = NULL;
639   char *end = NULL;
640   char mark;
641   char *fname;
642   char *ptr;
643   FILE *conf;
644
645   *keys = NULL;
646   *values = NULL;
647
648   cmdline = getuservariable (INST_CMDLINE);
649
650   mark = (*cmdline == '"') ? (cmdline++, '"') : ' ';
651   while (*cmdline && *cmdline != mark)
652     cmdline++;
653   if (mark == '"' && *cmdline)
654     cmdline++;
655   while (*cmdline && *cmdline == ' ')
656     cmdline++;
657
658   while (*cmdline)
659     {
660       /* We are at the beginning of a new argument.  */
661       if (cmdline[0] == '/' && (cmdline[1] == 'C' || cmdline[1] == 'c')
662           && cmdline[2] == '=')
663         {
664           cmdline += 3;
665           begin = cmdline;
666         }
667
668       while (*cmdline && *cmdline != ' ')
669         {
670           /* Skip over quoted parts.  */
671           if (*cmdline == '"')
672             {
673               cmdline++;
674               while (*cmdline && *cmdline != '"')
675                 cmdline++;
676               if (*cmdline)
677                 cmdline++;
678             }
679           else
680             cmdline++;
681         }
682       if (begin && !end)
683         {
684           end = cmdline - 1;
685           break;
686         }
687       while (*cmdline && *cmdline == ' ')
688         cmdline++;
689     }
690
691   if (!begin || begin > end)
692     return;
693
694   /* Strip quotes.  */
695   if (*begin == '"' && *end == '"')
696     {
697       begin++;
698       end--;
699     }
700   if (begin > end)
701     return;
702
703   fname = malloc (end - begin + 2);
704   if (!fname)
705     return;
706
707   ptr = fname;
708   while (begin <= end)
709     *(ptr++) = *(begin++);
710   *ptr = '\0';
711
712   conf = fopen (fname, "r");
713   free (fname);
714   if (!conf)
715     return;
716
717   while (max - 1 > 0)
718     {
719       char line[256];
720       char *ptr2;
721
722       if (fgets (line, sizeof (line), conf) == NULL)
723         break;
724       ptr = &line[strlen (line)];
725       while (ptr > line && (ptr[-1] == '\n' || ptr[-1] == '\r'
726                             || ptr[-1] == ' ' || ptr[-1] == '\t'))
727         ptr--;
728       *ptr = '\0';
729
730       ptr = line;
731       while (*ptr && (*ptr == ' ' || *ptr == '\t'))
732         ptr++;
733       /* Ignore comment lines.  */
734       /* FIXME: Ignore section markers.  */
735       if (*ptr == '\0' || *ptr == ';' || *ptr == '[')
736         continue;
737       begin = ptr;
738       while (*ptr && *ptr != '=' && *ptr != ' ' && *ptr != '\t')
739         ptr++;
740       end = ptr - 1;
741       while (*ptr && (*ptr == ' ' || *ptr == '\t'))
742         ptr++;
743       if (*ptr != '=')
744         continue;
745       ptr++;
746
747       if (begin > end)
748         continue;
749
750       /* We found a key.  */
751       *keys = malloc (end - begin + 2);
752       if (!keys)
753         return;
754       ptr2 = *keys;
755       while (begin <= end)
756         *(ptr2++) = *(begin++);
757       *ptr2 = '\0';
758
759       *values = NULL;
760
761       while (*ptr && (*ptr == ' ' || *ptr == '\t'))
762         ptr++;
763       begin = ptr;
764       /* In this case, end points to the byte after the value, which
765          is OK because that is '\0'.  */
766       end = &line[strlen (line)];
767       if (begin > end)
768         begin = end;
769
770       /* Strip quotes.  */
771       if (*begin == '"' && end[-1] == '"')
772         {
773           begin++;
774           end--;
775           *end = '\0';
776         }
777       if (begin > end)
778         return;
779
780       *values = malloc (end - begin + 1);
781       ptr2 = *values;
782       while (begin <= end)
783         *(ptr2++) = *(begin++);
784
785       keys++;
786       values++;
787       max--;
788     }
789
790   fclose (conf);
791   *keys = NULL;
792   *values = NULL;
793 }
794
795
796 char *
797 config_lookup (char *key)
798 {
799 #define MAX_KEYS 128
800   static int initialised = 0;
801   static char *keys[MAX_KEYS];
802   static char *values[MAX_KEYS];
803   int i;
804
805   if (initialised == 0)
806     {
807       initialised = 1;
808       config_init (keys, values, MAX_KEYS);
809
810 #if 0
811       MessageBox(g_hwndParent, "Configuration File:", 0, MB_OK);
812       i = 0;
813       while (keys[i])
814         {
815           char buf[256];
816           sprintf (buf, "%s=%s\r\n", keys[i], values[i]);
817           MessageBox (g_hwndParent, buf, 0, MB_OK);
818           i++;
819         }
820 #endif
821     }
822
823   i = 0;
824   while (keys[i])
825     {
826       if (!strcmp (keys[i], key))
827         return values[i];
828       i++;
829     }
830   
831   return NULL;
832 }
833
834
835 void __declspec(dllexport) 
836 config_fetch (HWND hwndParent, int string_size, char *variables, 
837               stack_t **stacktop, extra_parameters_t *extra)
838 {
839   char key[256];
840   int err = 0;
841   char *value;
842
843   g_hwndParent = hwndParent;
844   EXDLL_INIT();
845
846   /* The expected stack layout: key.  */
847   if (popstring (key, sizeof (key)))
848     err = 1;
849   if (err)
850     {
851       setuservariable (INST_R0, "");
852       return;
853     }
854
855   value = config_lookup (key);
856
857   setuservariable (INST_R0, value == NULL ? "" : value);
858   return;
859 }
860
861
862 void __declspec(dllexport) 
863 config_fetch_bool (HWND hwndParent, int string_size, char *variables, 
864                    stack_t **stacktop, extra_parameters_t *extra)
865 {
866   char key[256];
867   int err = 0;
868   char *value;
869   int result;
870
871   g_hwndParent = hwndParent;
872   EXDLL_INIT();
873
874   /* The expected stack layout: key.  */
875   if (popstring (key, sizeof (key)))
876     err = 1;
877   if (err)
878     {
879       setuservariable (INST_R0, "");
880       return;
881     }
882
883   value = config_lookup (key);
884   if (value == NULL || *value == '\0')
885     {
886       setuservariable (INST_R0, "");
887       return;
888     }
889   
890   result = 0;
891   if (!strcasecmp (value, "true")
892       || !strcasecmp (value, "yes")
893       || atoi (value) != 0)
894     result = 1;
895
896   setuservariable (INST_R0, result == 0 ? "0" : "1");
897   return;
898 }