New code to install forms so that appropriate icons are shown in the Viewer.
[gpgol.git] / src / common.c
1 /* common.c - Common routines used by GpgOL
2  *      Copyright (C) 2005, 2007, 2008 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 this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <windows.h>
22 #include <shlobj.h>
23 #ifndef CSIDL_APPDATA
24 #define CSIDL_APPDATA 0x001a
25 #endif
26 #ifndef CSIDL_LOCAL_APPDATA
27 #define CSIDL_LOCAL_APPDATA 0x001c
28 #endif
29 #ifndef CSIDL_FLAG_CREATE
30 #define CSIDL_FLAG_CREATE 0x8000
31 #endif
32 #include <time.h>
33 #include <fcntl.h>
34 #include <ctype.h>
35
36 #include "common.h"
37
38 HINSTANCE glob_hinst = NULL;
39
40
41 /* The base-64 list used for base64 encoding. */
42 static unsigned char bintoasc[64+1] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
43                                        "abcdefghijklmnopqrstuvwxyz"
44                                        "0123456789+/");
45
46 /* The reverse base-64 list used for base-64 decoding. */
47 static unsigned char const asctobin[256] = {
48   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
52   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
53   0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
54   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
55   0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
56   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
57   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
58   0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
61   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
62   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
63   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
64   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
68   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
69   0xff, 0xff, 0xff, 0xff
70 };
71
72
73
74 void
75 set_global_hinstance (HINSTANCE hinst)
76 {
77     glob_hinst = hinst;
78 }
79
80 /* Center the given window with the desktop window as the
81    parent window. */
82 void
83 center_window (HWND childwnd, HWND style)
84 {
85     HWND parwnd;
86     RECT rchild, rparent;
87     HDC hdc;
88     int wchild, hchild, wparent, hparent;
89     int wscreen, hscreen, xnew, ynew;
90     int flags = SWP_NOSIZE | SWP_NOZORDER;
91
92     parwnd = GetDesktopWindow ();
93     GetWindowRect (childwnd, &rchild);
94     wchild = rchild.right - rchild.left;
95     hchild = rchild.bottom - rchild.top;
96
97     GetWindowRect (parwnd, &rparent);
98     wparent = rparent.right - rparent.left;
99     hparent = rparent.bottom - rparent.top;
100
101     hdc = GetDC (childwnd);
102     wscreen = GetDeviceCaps (hdc, HORZRES);
103     hscreen = GetDeviceCaps (hdc, VERTRES);
104     ReleaseDC (childwnd, hdc);
105     xnew = rparent.left + ((wparent - wchild) / 2);
106     if (xnew < 0)
107         xnew = 0;
108     else if ((xnew+wchild) > wscreen)
109         xnew = wscreen - wchild;
110     ynew = rparent.top  + ((hparent - hchild) / 2);
111     if (ynew < 0)
112         ynew = 0;
113     else if ((ynew+hchild) > hscreen)
114         ynew = hscreen - hchild;
115     if (style == HWND_TOPMOST || style == HWND_NOTOPMOST)
116         flags = SWP_NOMOVE | SWP_NOSIZE;
117     SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags);
118 }
119
120
121 /* Return the system's bitmap of the check bar used which check boxes.
122    If CHECKED is set, this check mark is returned; if it is not set,
123    the one used for not-checked is returned.  May return NULL on
124    error.  Taken from an example in the platform reference. 
125
126    Not used as of now. */
127 HBITMAP
128 get_system_check_bitmap (int checked)
129 {
130   COLORREF bg_color;
131   HBRUSH bg_brush, saved_dst_brush;
132   HDC src_dc, dst_dc;
133   WORD xsize, ysize;
134   HBITMAP result, saved_dst_bitmap, saved_src_bitmap, checkboxes;
135   BITMAP bitmap;
136   RECT rect;
137
138   bg_color = GetSysColor (COLOR_MENU);
139   bg_brush = CreateSolidBrush (bg_color);
140
141   src_dc = CreateCompatibleDC (NULL);
142   dst_dc = CreateCompatibleDC (src_dc);
143
144   xsize = GetSystemMetrics (SM_CXMENUCHECK);
145   ysize = GetSystemMetrics (SM_CYMENUCHECK);
146   result = CreateCompatibleBitmap(src_dc, xsize, ysize);
147
148   saved_dst_brush  = SelectObject (dst_dc, bg_brush);
149   saved_dst_bitmap = SelectObject (dst_dc, result);
150
151   PatBlt (dst_dc, 0, 0, xsize, ysize, PATCOPY);
152
153   checkboxes = LoadBitmap (NULL, (LPTSTR)OBM_CHECKBOXES);
154
155   saved_src_bitmap = SelectObject (src_dc, checkboxes);
156
157   GetObject (checkboxes, sizeof (BITMAP), &bitmap);
158   rect.top = 0;
159   rect.bottom = (bitmap.bmHeight / 3);
160   if (checked)
161     {
162       /* Select row 1, column 1.  */
163       rect.left  = 0;
164       rect.right = (bitmap.bmWidth / 4);
165     }
166   else
167     {
168       /* Select row 1, column 2. */ 
169       rect.left  = (bitmap.bmWidth / 4);
170       rect.right = (bitmap.bmWidth / 4) * 2;
171     }
172
173   if ( ((rect.right - rect.left) > (int)xsize)
174        || ((rect.bottom - rect.top) > (int)ysize) )
175     StretchBlt (dst_dc, 0, 0, xsize, ysize, src_dc, rect.left, rect.top,
176                 rect.right - rect.left, rect.bottom - rect.top, SRCCOPY);
177   else
178     BitBlt (dst_dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
179             src_dc, rect.left, rect.top, SRCCOPY);
180
181   SelectObject (src_dc, saved_src_bitmap);
182   SelectObject (dst_dc, saved_dst_brush);
183   result = SelectObject (dst_dc, saved_dst_bitmap);
184
185   DeleteObject (bg_brush);
186   DeleteObject (src_dc);
187   DeleteObject (dst_dc);
188   return result;
189 }
190
191
192 /* Return a filename to be used for saving an attachment. Returns a
193    malloced string on success. HWND is the current Window and SRCNAME
194    the filename to be used as suggestion.  On error (i.e. cancel) NULL
195    is returned. */
196 char *
197 get_save_filename (HWND root, const char *srcname)
198 {
199   char filter[] = "All Files (*.*)\0*.*\0\0";
200   char fname[MAX_PATH+1];
201   OPENFILENAME ofn;
202
203   memset (fname, 0, sizeof (fname));
204   strncpy (fname, srcname, MAX_PATH-1);
205   fname[MAX_PATH] = 0;
206
207
208   memset (&ofn, 0, sizeof (ofn));
209   ofn.lStructSize = sizeof (ofn);
210   ofn.hwndOwner = root;
211   ofn.lpstrFile = fname;
212   ofn.nMaxFile = MAX_PATH;
213   ofn.lpstrFileTitle = NULL;
214   ofn.nMaxFileTitle = 0;
215   ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
216   ofn.lpstrTitle = _("GpgOL - Save decrypted attachment");
217   ofn.lpstrFilter = filter;
218
219   if (GetSaveFileName (&ofn))
220     return xstrdup (fname);
221   return NULL;
222 }
223
224
225 void
226 out_of_core (void)
227 {
228     MessageBox (NULL, "Out of core!", "Fatal Error", MB_OK);
229     abort ();
230 }
231
232 void*
233 xmalloc (size_t n)
234 {
235     void *p = malloc (n);
236     if (!p)
237         out_of_core ();
238     return p;
239 }
240
241 void*
242 xcalloc (size_t m, size_t n)
243 {
244     void *p = calloc (m, n);
245     if (!p)
246         out_of_core ();
247     return p;
248 }
249
250 void *
251 xrealloc (void *a, size_t n)
252 {
253   void *p = realloc (a, n);
254   if (!p)
255     out_of_core ();
256   return p;
257 }
258
259 char*
260 xstrdup (const char *s)
261 {
262     char *p = xmalloc (strlen (s)+1);
263     strcpy (p, s);
264     return p;
265 }
266
267 void
268 xfree (void *p)
269 {
270     if (p)
271         free (p);
272 }
273
274
275 /* This is a helper function to load a Windows function from either of
276    one DLLs. */
277 static HRESULT
278 w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
279 {
280   static int initialized;
281   static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
282
283   if (!initialized)
284     {
285       static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
286       void *handle;
287       int i;
288
289       initialized = 1;
290
291       for (i=0, handle = NULL; !handle && dllnames[i]; i++)
292         {
293           handle = LoadLibrary (dllnames[i]);
294           if (handle)
295             {
296               func = (HRESULT (WINAPI *)(HWND,int,HANDLE,DWORD,LPSTR))
297                      GetProcAddress (handle, "SHGetFolderPathA");
298               if (!func)
299                 {
300                   FreeLibrary (handle);
301                   handle = NULL;
302                 }
303             }
304         }
305     }
306
307   if (func)
308     return func (a,b,c,d,e);
309   else
310     return -1;
311 }
312
313
314
315 /* Same as above, but only convert the first LEN wchars.  */
316 char *
317 wchar_to_utf8_2 (const wchar_t *string, size_t len)
318 {
319   int n;
320   char *result;
321
322   /* Note, that CP_UTF8 is not defined in Windows versions earlier
323      than NT.*/
324   n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL);
325   if (n < 0)
326     return NULL;
327
328   result = xmalloc (n+1);
329   n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL);
330   if (n < 0)
331     {
332       xfree (result);
333       return NULL;
334     }
335   return result;
336 }
337
338
339 /* Same as above but convert only the first LEN characters.  STRING
340    must be at least LEN characters long. */
341 wchar_t *
342 utf8_to_wchar2 (const char *string, size_t len)
343 {
344   int n;
345   wchar_t *result;
346
347   n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0);
348   if (n < 0)
349     return NULL;
350
351   result = xmalloc ((n+1) * sizeof *result);
352   n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n);
353   if (n < 0)
354     {
355       xfree (result);
356       return NULL;
357     }
358   result[n] = 0;
359   return result;
360 }
361
362
363 /* Assume STRING is a Latin-1 encoded and convert it to utf-8.
364    Returns a newly malloced UTF-8 string. */
365 char *
366 latin1_to_utf8 (const char *string)
367 {
368   const char *s;
369   char *buffer, *p;
370   size_t n;
371
372   for (s=string, n=0; *s; s++)
373     {
374       n++;
375       if (*s & 0x80)
376         n++;
377     }
378   buffer = xmalloc (n + 1);
379   for (s=string, p=buffer; *s; s++)
380     {
381       if (*s & 0x80)
382         {
383           *p++ = 0xc0 | ((*s >> 6) & 3);
384           *p++ = 0x80 | (*s & 0x3f);
385         }
386       else
387         *p++ = *s;
388     }
389   *p = 0;
390   return buffer;
391 }
392
393
394 /* Strip off trailing white spaces from STRING.  Returns STRING. */
395 char *
396 trim_trailing_spaces (char *string)
397 {
398   char *p, *mark;
399
400   for (mark=NULL, p=string; *p; p++)
401     {
402       if (strchr (" \t\r\n", *p ))
403         {
404           if (!mark)
405             mark = p;
406         }
407         else
408           mark = NULL;
409     }
410
411   if (mark)
412     *mark = 0;
413   return string;
414 }
415
416
417 /* Strip off leading and trailing white spaces from STRING.  Returns
418    STRING. */
419 char *
420 trim_spaces (char *arg_string)
421 {
422   char *string = arg_string;
423   char *p, *mark;
424
425   /* Find first non space character. */
426   for (p = string; *p && isascii (*p) && isspace (*p) ; p++ )
427     ;
428   /* Move characters. */
429   for (mark = NULL; (*string = *p); string++, p++ )
430     {
431       if (isascii (*p) && isspace (*p))
432         {
433           if (!mark)
434           mark = string;
435         }
436       else
437         mark = NULL ;
438     }
439   if (mark)
440     *mark = 0;
441   
442   return arg_string;
443 }
444
445
446
447 /* Helper for read_w32_registry_string(). */
448 static HKEY
449 get_root_key(const char *root)
450 {
451   HKEY root_key;
452
453   if( !root )
454     root_key = HKEY_CURRENT_USER;
455   else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
456     root_key = HKEY_CLASSES_ROOT;
457   else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
458     root_key = HKEY_CURRENT_USER;
459   else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
460     root_key = HKEY_LOCAL_MACHINE;
461   else if( !strcmp( root, "HKEY_USERS" ) )
462     root_key = HKEY_USERS;
463   else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
464     root_key = HKEY_PERFORMANCE_DATA;
465   else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
466     root_key = HKEY_CURRENT_CONFIG;
467   else
468     return NULL;
469   return root_key;
470 }
471
472 /* Return a string from the Win32 Registry or NULL in case of error.
473    Caller must release the return value.  A NULL for root is an alias
474    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.  NOTE: The value
475    is allocated with a plain malloc() - use free() and not the usual
476    xfree(). */
477 char *
478 read_w32_registry_string (const char *root, const char *dir, const char *name)
479 {
480   HKEY root_key, key_handle;
481   DWORD n1, nbytes, type;
482   char *result = NULL;
483
484   if ( !(root_key = get_root_key(root) ) )
485     return NULL;
486
487   if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
488     {
489       if (root)
490         return NULL; /* no need for a RegClose, so return direct */
491       /* It seems to be common practise to fall back to HKLM. */
492       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
493         return NULL; /* still no need for a RegClose, so return direct */
494     }
495
496   nbytes = 1;
497   if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) {
498     if (root)
499       goto leave;
500     /* Try to fallback to HKLM also vor a missing value.  */
501     RegCloseKey (key_handle);
502     if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
503       return NULL; /* Nope.  */
504     if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes))
505       goto leave;
506   }
507   result = malloc( (n1=nbytes+1) );
508   if( !result )
509     goto leave;
510   if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
511     free(result); result = NULL;
512     goto leave;
513   }
514   result[nbytes] = 0; /* make sure it is really a string  */
515   if (type == REG_EXPAND_SZ && strchr (result, '%')) {
516     char *tmp;
517
518     n1 += 1000;
519     tmp = malloc (n1+1);
520     if (!tmp)
521       goto leave;
522     nbytes = ExpandEnvironmentStrings (result, tmp, n1);
523     if (nbytes && nbytes > n1) {
524       free (tmp);
525       n1 = nbytes;
526       tmp = malloc (n1 + 1);
527       if (!tmp)
528         goto leave;
529       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
530       if (nbytes && nbytes > n1) {
531         free (tmp); /* oops - truncated, better don't expand at all */
532         goto leave;
533       }
534       tmp[nbytes] = 0;
535       free (result);
536       result = tmp;
537     }
538     else if (nbytes) { /* okay, reduce the length */
539       tmp[nbytes] = 0;
540       free (result);
541       result = malloc (strlen (tmp)+1);
542       if (!result)
543         result = tmp;
544       else {
545         strcpy (result, tmp);
546         free (tmp);
547       }
548     }
549     else {  /* error - don't expand */
550       free (tmp);
551     }
552   }
553
554  leave:
555   RegCloseKey( key_handle );
556   return result;
557 }
558
559
560 /* Get the standard home directory.  In general this function should
561    not be used as it does not consider a registry value or the
562    GNUPGHOME environment variable.  Please use default_homedir(). */
563 static const char *
564 standard_homedir (void)
565 {
566   static char *dir;
567
568   if (!dir)
569     {
570       char path[MAX_PATH];
571
572       /* It might be better to use LOCAL_APPDATA because this is
573          defined as "non roaming" and thus more likely to be kept
574          locally.  For private keys this is desired.  However, given
575          that many users copy private keys anyway forth and back,
576          using a system roaming services might be better than to let
577          them do it manually.  A security conscious user will anyway
578          use the registry entry to have better control.  */
579       if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE,
580                                NULL, 0, path) >= 0)
581         {
582           char *tmp = malloc (strlen (path) + 6 + 1);
583
584           strcpy (tmp, path);
585           strcat (tmp, "\\gnupg");
586
587           dir = tmp;
588
589           /* Try to create the directory if it does not yet exists.  */
590           if (access (dir, F_OK))
591             CreateDirectory (dir, NULL);
592         }
593       else
594         dir = xstrdup ("C:\\gnupg");
595     }
596   return dir;
597 }
598
599
600 /* Retrieve the default home directory.  */
601 const char *
602 default_homedir (void)
603 {
604   static char *dir;
605
606   if (!dir)
607     {
608       dir = getenv ("GNUPGHOME");
609       if (!dir || !*dir)
610         {
611           char *tmp;
612
613           tmp = read_w32_registry_string (NULL, GNUPG_REGKEY, "HomeDir");
614           if (tmp && !*tmp)
615             {
616               free (tmp);
617               tmp = NULL;
618             }
619           if (tmp)
620             dir = tmp;
621           else
622             dir = xstrdup (standard_homedir ());
623         }
624       else
625         dir = xstrdup (dir);
626     }
627
628   return dir;
629 }
630
631 /* Return the data dir used for forms etc.   Returns NULL on error. */
632 char *
633 get_data_dir (void)
634 {
635   char *instdir;
636   char *p;
637   char *dname;
638
639   instdir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", GNUPG_REGKEY,
640                                       "Install Directory");
641   if (!instdir)
642     return NULL;
643   
644   /* Build the key: "<instdir>/share/gpgol".  */
645 #define SDDIR "\\share\\gpgol"
646   dname = malloc (strlen (instdir) + strlen (SDDIR) + 1);
647   if (!dname)
648     {
649       free (instdir);
650       return NULL;
651     }
652   p = dname;
653   strcpy (p, instdir);
654   p += strlen (instdir);
655   strcpy (p, SDDIR);
656   
657   free (instdir);
658   
659 #undef SDDIR
660   return dname;
661 }
662
663
664
665 /* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
666    Returns the new length of the buffer and stores true at R_SLBRK if
667    the line ended with a soft line break; false is stored if not.
668    This fucntion asssumes that a complete line is passed in
669    buffer.  */
670 size_t
671 qp_decode (char *buffer, size_t length, int *r_slbrk)
672 {
673   char *d, *s;
674
675   if (r_slbrk)
676     *r_slbrk = 0;
677
678   /* Fixme:  We should remove trailing white space first.  */
679   for (s=d=buffer; length; length--)
680     if (*s == '=')
681       {
682         if (length > 2 && hexdigitp (s+1) && hexdigitp (s+2))
683           {
684             s++;
685             *(unsigned char*)d++ = xtoi_2 (s);
686             s += 2;
687             length -= 2;
688           }
689         else if (length > 2 && s[1] == '\r' && s[2] == '\n')
690           {
691             /* Soft line break.  */
692             s += 3;
693             length -= 2;
694             if (r_slbrk && length == 1)
695               *r_slbrk = 1;
696           }
697         else if (length > 1 && s[1] == '\n')
698           {
699             /* Soft line break with only a Unix line terminator. */
700             s += 2;
701             length -= 1;
702             if (r_slbrk && length == 1)
703               *r_slbrk = 1;
704           }
705         else if (length == 1)
706           {
707             /* Soft line break at the end of the line. */
708             s += 1;
709             if (r_slbrk)
710               *r_slbrk = 1;
711           }
712         else
713           *d++ = *s++;
714       }
715     else
716       *d++ = *s++;
717
718   return d - buffer;
719 }
720
721
722 /* Initialize the Base 64 decoder state.  */
723 void b64_init (b64_state_t *state)
724 {
725   state->idx = 0;
726   state->val = 0;
727   state->stop_seen = 0;
728   state->invalid_encoding = 0;
729 }
730
731
732 /* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Returns
733    the new length of the buffer. STATE is required to return errors and
734    to maintain the state of the decoder.  */
735 size_t
736 b64_decode (b64_state_t *state, char *buffer, size_t length)
737 {
738   int idx = state->idx;
739   unsigned char val = state->val;
740   int c;
741   char *d, *s;
742
743   if (state->stop_seen)
744     return 0;
745
746   for (s=d=buffer; length; length--, s++)
747     {
748       if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
749         continue;
750       if (*s == '=')
751         {
752           /* Pad character: stop */
753           if (idx == 1)
754             *d++ = val;
755           state->stop_seen = 1;
756           break;
757         }
758
759       if ((c = asctobin[*(unsigned char *)s]) == 255)
760         {
761           if (!state->invalid_encoding)
762             log_debug ("%s: invalid base64 character %02X at pos %d skipped\n",
763                        __func__, *(unsigned char*)s, (int)(s-buffer));
764           state->invalid_encoding = 1;
765           continue;
766         }
767
768       switch (idx)
769         {
770         case 0:
771           val = c << 2;
772           break;
773         case 1:
774           val |= (c>>4)&3;
775           *d++ = val;
776           val = (c<<4)&0xf0;
777           break;
778         case 2:
779           val |= (c>>2)&15;
780           *d++ = val;
781           val = (c<<6)&0xc0;
782           break;
783         case 3:
784           val |= c&0x3f;
785           *d++ = val;
786           break;
787         }
788       idx = (idx+1) % 4;
789     }
790
791
792   state->idx = idx;
793   state->val = val;
794   return d - buffer;
795 }
796
797
798 /* Create a boundary.  Note that mimemaker.c knows about the structure
799    of the boundary (i.e. that it starts with "=-=") so that it can
800    protect against accidently used boundaries within the content.  */
801 char *
802 generate_boundary (char *buffer)
803 {
804   char *p = buffer;
805   int i;
806
807 #if RAND_MAX < (64*2*BOUNDARYSIZE)
808 #error RAND_MAX is way too small
809 #endif
810
811   *p++ = '=';
812   *p++ = '-';
813   *p++ = '=';
814   for (i=0; i < BOUNDARYSIZE-6; i++)
815     *p++ = bintoasc[rand () % 64];
816   *p++ = '=';
817   *p++ = '-';
818   *p++ = '=';
819   *p = 0;
820
821   return buffer;
822 }
823
824
825 /* Fork and exec the program given in CMDLINE with /dev/null as
826    stdin, stdout and stderr.  Returns 0 on success.  */
827 int
828 gpgol_spawn_detached (const char *cmdline)
829 {
830   int rc;
831   SECURITY_ATTRIBUTES sec_attr;
832   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
833   STARTUPINFO si;
834   int cr_flags;
835   char *cmdline_copy;
836
837   memset (&sec_attr, 0, sizeof sec_attr);
838   sec_attr.nLength = sizeof sec_attr;
839   
840   memset (&si, 0, sizeof si);
841   si.cb = sizeof (si);
842   si.dwFlags = STARTF_USESHOWWINDOW;
843   si.wShowWindow = SW_SHOW;
844
845   cr_flags = (CREATE_DEFAULT_ERROR_MODE
846               | GetPriorityClass (GetCurrentProcess ())
847               | CREATE_NEW_PROCESS_GROUP
848               | DETACHED_PROCESS); 
849
850   cmdline_copy = xstrdup (cmdline);
851   rc = CreateProcess (NULL,          /* No appliactionname, use CMDLINE.  */
852                       cmdline_copy,  /* Command line arguments.  */
853                       &sec_attr,     /* Process security attributes.  */
854                       &sec_attr,     /* Thread security attributes.  */
855                       FALSE,          /* Inherit handles.  */
856                       cr_flags,      /* Creation flags.  */
857                       NULL,          /* Environment.  */
858                       NULL,          /* Use current drive/directory.  */
859                       &si,           /* Startup information. */
860                       &pi            /* Returns process information.  */
861                       );
862   xfree (cmdline_copy);
863   if (!rc)
864     {
865       log_error_w32 (-1, "%s:%s: CreateProcess failed", SRCNAME, __func__);
866       return -1;
867     }
868
869   CloseHandle (pi.hThread); 
870   CloseHandle (pi.hProcess);
871   return 0;
872 }
873
874
875
876
877 /* Simple but pretty complete ASN.1 BER parser.  Parse the data at the
878    address of BUFFER with a length given at the address of SIZE.  On
879    success return 0 and update BUFFER and SIZE to point to the value.
880    Do not update them on error.  The information about the object are
881    stored in the caller allocated TI structure.  */
882 int
883 parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti)
884 {
885   int c;
886   unsigned long tag;
887   const unsigned char *buf = (const unsigned char *)(*buffer);
888   size_t length = *size;
889
890   ti->cls = 0;
891   ti->tag = 0;
892   ti->is_cons = 0;
893   ti->is_ndef = 0;
894   ti->length = 0;
895   ti->nhdr = 0;
896
897   if (!length)
898     return -1;
899   c = *buf++; length--; ++ti->nhdr;
900
901   ti->cls = (c & 0xc0) >> 6;
902   ti->is_cons = !!(c & 0x20);
903   tag = c & 0x1f;
904
905   if (tag == 0x1f)
906     {
907       tag = 0;
908       do
909         {
910           tag <<= 7;
911           if (!length)
912             return -1;
913           c = *buf++; length--; ++ti->nhdr;
914           tag |= c & 0x7f;
915         }
916       while (c & 0x80);
917     }
918   ti->tag = tag;
919
920   if (!length)
921     return -1;
922   c = *buf++; length--; ++ti->nhdr;
923
924   if ( !(c & 0x80) )
925     ti->length = c;
926   else if (c == 0x80)
927     ti->is_ndef = 1;
928   else if (c == 0xff)
929     return -1;
930   else
931     {
932       unsigned long len = 0;
933       int count = (c & 0x7f);
934
935       if (count > sizeof (len) || count > sizeof (size_t))
936         return -1;
937
938       for (; count; count--)
939         {
940           len <<= 8;
941           if (!length)
942             return -1;
943           c = *buf++; length--; ++ti->nhdr;
944           len |= c & 0xff;
945         }
946       ti->length = len;
947     }
948   
949   *buffer = buf;
950   *size = length;
951   return 0;
952 }
953
954