Fix sign+encr problem.
[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
632 /* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
633    Returns the new length of the buffer and stores true at R_SLBRK if
634    the line ended with a soft line break; false is stored if not.
635    This fucntion asssumes that a complete line is passed in
636    buffer.  */
637 size_t
638 qp_decode (char *buffer, size_t length, int *r_slbrk)
639 {
640   char *d, *s;
641
642   if (r_slbrk)
643     *r_slbrk = 0;
644
645   /* Fixme:  We should remove trailing white space first.  */
646   for (s=d=buffer; length; length--)
647     if (*s == '=')
648       {
649         if (length > 2 && hexdigitp (s+1) && hexdigitp (s+2))
650           {
651             s++;
652             *(unsigned char*)d++ = xtoi_2 (s);
653             s += 2;
654             length -= 2;
655           }
656         else if (length > 2 && s[1] == '\r' && s[2] == '\n')
657           {
658             /* Soft line break.  */
659             s += 3;
660             length -= 2;
661             if (r_slbrk && length == 1)
662               *r_slbrk = 1;
663           }
664         else if (length > 1 && s[1] == '\n')
665           {
666             /* Soft line break with only a Unix line terminator. */
667             s += 2;
668             length -= 1;
669             if (r_slbrk && length == 1)
670               *r_slbrk = 1;
671           }
672         else if (length == 1)
673           {
674             /* Soft line break at the end of the line. */
675             s += 1;
676             if (r_slbrk)
677               *r_slbrk = 1;
678           }
679         else
680           *d++ = *s++;
681       }
682     else
683       *d++ = *s++;
684
685   return d - buffer;
686 }
687
688
689 /* Initialize the Base 64 decoder state.  */
690 void b64_init (b64_state_t *state)
691 {
692   state->idx = 0;
693   state->val = 0;
694   state->stop_seen = 0;
695   state->invalid_encoding = 0;
696 }
697
698
699 /* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Returns
700    the new length of the buffer. STATE is required to return errors and
701    to maintain the state of the decoder.  */
702 size_t
703 b64_decode (b64_state_t *state, char *buffer, size_t length)
704 {
705   int idx = state->idx;
706   unsigned char val = state->val;
707   int c;
708   char *d, *s;
709
710   if (state->stop_seen)
711     return 0;
712
713   for (s=d=buffer; length; length--, s++)
714     {
715       if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
716         continue;
717       if (*s == '=')
718         {
719           /* Pad character: stop */
720           if (idx == 1)
721             *d++ = val;
722           state->stop_seen = 1;
723           break;
724         }
725
726       if ((c = asctobin[*(unsigned char *)s]) == 255)
727         {
728           if (!state->invalid_encoding)
729             log_debug ("%s: invalid base64 character %02X at pos %d skipped\n",
730                        __func__, *(unsigned char*)s, (int)(s-buffer));
731           state->invalid_encoding = 1;
732           continue;
733         }
734
735       switch (idx)
736         {
737         case 0:
738           val = c << 2;
739           break;
740         case 1:
741           val |= (c>>4)&3;
742           *d++ = val;
743           val = (c<<4)&0xf0;
744           break;
745         case 2:
746           val |= (c>>2)&15;
747           *d++ = val;
748           val = (c<<6)&0xc0;
749           break;
750         case 3:
751           val |= c&0x3f;
752           *d++ = val;
753           break;
754         }
755       idx = (idx+1) % 4;
756     }
757
758
759   state->idx = idx;
760   state->val = val;
761   return d - buffer;
762 }
763
764
765 /* Create a boundary.  Note that mimemaker.c knows about the structure
766    of the boundary (i.e. that it starts with "=-=") so that it can
767    protect against accidently used boundaries within the content.  */
768 char *
769 generate_boundary (char *buffer)
770 {
771   char *p = buffer;
772   int i;
773
774 #if RAND_MAX < (64*2*BOUNDARYSIZE)
775 #error RAND_MAX is way too small
776 #endif
777
778   *p++ = '=';
779   *p++ = '-';
780   *p++ = '=';
781   for (i=0; i < BOUNDARYSIZE-6; i++)
782     *p++ = bintoasc[rand () % 64];
783   *p++ = '=';
784   *p++ = '-';
785   *p++ = '=';
786   *p = 0;
787
788   return buffer;
789 }
790
791
792 /* Fork and exec the program given in CMDLINE with /dev/null as
793    stdin, stdout and stderr.  Returns 0 on success.  */
794 int
795 gpgol_spawn_detached (const char *cmdline)
796 {
797   int rc;
798   SECURITY_ATTRIBUTES sec_attr;
799   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
800   STARTUPINFO si;
801   int cr_flags;
802   char *cmdline_copy;
803
804   memset (&sec_attr, 0, sizeof sec_attr);
805   sec_attr.nLength = sizeof sec_attr;
806   
807   memset (&si, 0, sizeof si);
808   si.cb = sizeof (si);
809   si.dwFlags = STARTF_USESHOWWINDOW;
810   si.wShowWindow = SW_SHOW;
811
812   cr_flags = (CREATE_DEFAULT_ERROR_MODE
813               | GetPriorityClass (GetCurrentProcess ())
814               | CREATE_NEW_PROCESS_GROUP
815               | DETACHED_PROCESS); 
816
817   cmdline_copy = xstrdup (cmdline);
818   rc = CreateProcess (NULL,          /* No appliactionname, use CMDLINE.  */
819                       cmdline_copy,  /* Command line arguments.  */
820                       &sec_attr,     /* Process security attributes.  */
821                       &sec_attr,     /* Thread security attributes.  */
822                       FALSE,          /* Inherit handles.  */
823                       cr_flags,      /* Creation flags.  */
824                       NULL,          /* Environment.  */
825                       NULL,          /* Use current drive/directory.  */
826                       &si,           /* Startup information. */
827                       &pi            /* Returns process information.  */
828                       );
829   xfree (cmdline_copy);
830   if (!rc)
831     {
832       log_error_w32 (-1, "%s:%s: CreateProcess failed", SRCNAME, __func__);
833       return -1;
834     }
835
836   CloseHandle (pi.hThread); 
837   CloseHandle (pi.hProcess);
838   return 0;
839 }
840
841
842
843
844 /* Simple but pretty complete ASN.1 BER parser.  Parse the data at the
845    address of BUFFER with a length given at the address of SIZE.  On
846    success return 0 and update BUFFER and SIZE to point to the value.
847    Do not update them on error.  The information about the object are
848    stored in the caller allocated TI structure.  */
849 int
850 parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti)
851 {
852   int c;
853   unsigned long tag;
854   const unsigned char *buf = (const unsigned char *)(*buffer);
855   size_t length = *size;
856
857   ti->cls = 0;
858   ti->tag = 0;
859   ti->is_cons = 0;
860   ti->is_ndef = 0;
861   ti->length = 0;
862   ti->nhdr = 0;
863
864   if (!length)
865     return -1;
866   c = *buf++; length--; ++ti->nhdr;
867
868   ti->cls = (c & 0xc0) >> 6;
869   ti->is_cons = !!(c & 0x20);
870   tag = c & 0x1f;
871
872   if (tag == 0x1f)
873     {
874       tag = 0;
875       do
876         {
877           tag <<= 7;
878           if (!length)
879             return -1;
880           c = *buf++; length--; ++ti->nhdr;
881           tag |= c & 0x7f;
882         }
883       while (c & 0x80);
884     }
885   ti->tag = tag;
886
887   if (!length)
888     return -1;
889   c = *buf++; length--; ++ti->nhdr;
890
891   if ( !(c & 0x80) )
892     ti->length = c;
893   else if (c == 0x80)
894     ti->is_ndef = 1;
895   else if (c == 0xff)
896     return -1;
897   else
898     {
899       unsigned long len = 0;
900       int count = (c & 0x7f);
901
902       if (count > sizeof (len) || count > sizeof (size_t))
903         return -1;
904
905       for (; count; count--)
906         {
907           len <<= 8;
908           if (!length)
909             return -1;
910           c = *buf++; length--; ++ti->nhdr;
911           len |= c & 0xff;
912         }
913       ti->length = len;
914     }
915   
916   *buffer = buf;
917   *size = length;
918   return 0;
919 }
920
921