Move more things into common_indep
[gpgol.git] / src / common_indep.c
1 /* common_indep.c - Common, platform indepentent routines used by GpgOL
2  *    Copyright (C) 2005, 2007, 2008 g10 Code GmbH
3  *    Copyright (C) 2016 Intevation GmbH
4  *
5  * This file is part of GpgOL.
6  *
7  * GpgOL is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1
10  * of the License, or (at your option) any later version.
11  *
12  * GpgOL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "common_indep.h"
22 #ifdef HAVE_W32_SYSTEM
23 #include <windows.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <ctype.h>
28
29 /* The base-64 list used for base64 encoding. */
30 static unsigned char bintoasc[64+1] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
31                                        "abcdefghijklmnopqrstuvwxyz"
32                                        "0123456789+/");
33
34 /* The reverse base-64 list used for base-64 decoding. */
35 static unsigned char const asctobin[256] = {
36   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
37   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
38   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
40   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
41   0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
42   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
43   0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
44   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
45   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
46   0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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, 0xff, 0xff, 0xff, 0xff, 0xff,
52   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57   0xff, 0xff, 0xff, 0xff
58 };
59
60 void
61 out_of_core (void)
62 {
63 #ifdef HAVE_W32_SYSTEM
64   MessageBox (NULL, "Out of core!", "Fatal Error", MB_OK);
65 #endif
66   abort ();
67 }
68
69 void*
70 xmalloc (size_t n)
71 {
72   void *p = malloc (n);
73   if (!p)
74     out_of_core ();
75   return p;
76 }
77
78 void*
79 xcalloc (size_t m, size_t n)
80 {
81   void *p = calloc (m, n);
82   if (!p)
83     out_of_core ();
84   return p;
85 }
86
87 void *
88 xrealloc (void *a, size_t n)
89 {
90   void *p = realloc (a, n);
91   if (!p)
92     out_of_core ();
93   return p;
94 }
95
96 char*
97 xstrdup (const char *s)
98 {
99   char *p = xmalloc (strlen (s)+1);
100   strcpy (p, s);
101   return p;
102 }
103
104 void
105 xfree (void *p)
106 {
107   if (p)
108     free (p);
109 }
110
111 /* Strip off leading and trailing white spaces from STRING.  Returns
112    STRING. */
113 char *
114 trim_spaces (char *arg_string)
115 {
116   char *string = arg_string;
117   char *p, *mark;
118
119   /* Find first non space character. */
120   for (p = string; *p && isascii (*p) && isspace (*p) ; p++ )
121     ;
122   /* Move characters. */
123   for (mark = NULL; (*string = *p); string++, p++ )
124     {
125       if (isascii (*p) && isspace (*p))
126         {
127           if (!mark)
128             mark = string;
129         }
130       else
131         mark = NULL ;
132     }
133   if (mark)
134     *mark = 0;
135
136   return arg_string;
137 }
138 /* Assume STRING is a Latin-1 encoded and convert it to utf-8.
139    Returns a newly malloced UTF-8 string. */
140 char *
141 latin1_to_utf8 (const char *string)
142 {
143   const char *s;
144   char *buffer, *p;
145   size_t n;
146
147   for (s=string, n=0; *s; s++)
148     {
149       n++;
150       if (*s & 0x80)
151         n++;
152     }
153   buffer = xmalloc (n + 1);
154   for (s=string, p=buffer; *s; s++)
155     {
156       if (*s & 0x80)
157         {
158           *p++ = 0xc0 | ((*s >> 6) & 3);
159           *p++ = 0x80 | (*s & 0x3f);
160         }
161       else
162         *p++ = *s;
163     }
164   *p = 0;
165   return buffer;
166 }
167
168
169 /* This function is similar to strncpy().  However it won't copy more
170    than N - 1 characters and makes sure that a Nul is appended. With N
171    given as 0, nothing will happen.  With DEST given as NULL, memory
172    will be allocated using xmalloc (i.e. if it runs out of core the
173    function terminates).  Returns DEST or a pointer to the allocated
174    memory.  */
175 char *
176 mem2str (char *dest, const void *src, size_t n)
177 {
178   char *d;
179   const char *s;
180
181   if (n)
182     {
183       if (!dest)
184         dest = xmalloc (n);
185       d = dest;
186       s = src ;
187       for (n--; n && *s; n--)
188         *d++ = *s++;
189       *d = 0;
190     }
191   else if (!dest)
192     {
193       dest = xmalloc (1);
194       *dest = 0;
195     }
196
197   return dest;
198 }
199
200
201 /* Strip off trailing white spaces from STRING.  Returns STRING. */
202 char *
203 trim_trailing_spaces (char *string)
204 {
205   char *p, *mark;
206
207   for (mark=NULL, p=string; *p; p++)
208     {
209       if (strchr (" \t\r\n", *p ))
210         {
211           if (!mark)
212             mark = p;
213         }
214       else
215         mark = NULL;
216     }
217
218   if (mark)
219     *mark = 0;
220   return string;
221 }
222
223 /* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
224    Returns the new length of the buffer and stores true at R_SLBRK if
225    the line ended with a soft line break; false is stored if not.
226    This fucntion asssumes that a complete line is passed in
227    buffer.  */
228 size_t
229 qp_decode (char *buffer, size_t length, int *r_slbrk)
230 {
231   char *d, *s;
232
233   if (r_slbrk)
234     *r_slbrk = 0;
235
236   /* Fixme:  We should remove trailing white space first.  */
237   for (s=d=buffer; length; length--)
238     if (*s == '=')
239       {
240         if (length > 2 && hexdigitp (s+1) && hexdigitp (s+2))
241           {
242             s++;
243             *(unsigned char*)d++ = xtoi_2 (s);
244             s += 2;
245             length -= 2;
246           }
247         else if (length > 2 && s[1] == '\r' && s[2] == '\n')
248           {
249             /* Soft line break.  */
250             s += 3;
251             length -= 2;
252             if (r_slbrk && length == 1)
253               *r_slbrk = 1;
254           }
255         else if (length > 1 && s[1] == '\n')
256           {
257             /* Soft line break with only a Unix line terminator. */
258             s += 2;
259             length -= 1;
260             if (r_slbrk && length == 1)
261               *r_slbrk = 1;
262           }
263         else if (length == 1)
264           {
265             /* Soft line break at the end of the line. */
266             s += 1;
267             if (r_slbrk)
268               *r_slbrk = 1;
269           }
270         else
271           *d++ = *s++;
272       }
273     else
274       *d++ = *s++;
275
276   return d - buffer;
277 }
278
279 /* Return the a quoted printable encoded version of the
280    input string. If outlen is not null the size of the
281    quoted printable string is returned. String will be
282    malloced and zero terminated. Aborts if the output
283    is more then three times the size of the input.
284    This is only basic and does not handle mutliline data. */
285 char *
286 qp_encode (const char *input, size_t inlen, size_t *r_outlen)
287 {
288   size_t max_len = inlen * 3 +1;
289   char *outbuf = xmalloc (max_len);
290   size_t outlen = 0;
291   const unsigned char *p;
292
293   memset (outbuf, 0, max_len);
294
295   for (p = input; inlen; p++, inlen--)
296     {
297       if (*p >= '!' && *p <= '~' && *p != '=')
298         {
299           outbuf[outlen++] = *p;
300         }
301       else if (*p == ' ')
302         {
303           /* Outlook does it this way */
304           outbuf[outlen++] = '_';
305         }
306       else
307         {
308           outbuf[outlen++] = '=';
309           outbuf[outlen++] = tohex ((*p>>4)&15);
310           outbuf[outlen++] = tohex (*p&15);
311         }
312       if (outlen == max_len -1)
313         {
314           log_error ("Quoted printable too long. Bug.");
315           r_outlen = NULL;
316           return NULL;
317         }
318     }
319   if (r_outlen)
320     *r_outlen = outlen;
321   return outbuf;
322 }
323
324
325 /* Initialize the Base 64 decoder state.  */
326 void b64_init (b64_state_t *state)
327 {
328   state->idx = 0;
329   state->val = 0;
330   state->stop_seen = 0;
331   state->invalid_encoding = 0;
332 }
333
334
335 /* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Returns
336    the new length of the buffer. STATE is required to return errors and
337    to maintain the state of the decoder.  */
338 size_t
339 b64_decode (b64_state_t *state, char *buffer, size_t length)
340 {
341   int idx = state->idx;
342   unsigned char val = state->val;
343   int c;
344   char *d, *s;
345
346   if (state->stop_seen)
347     return 0;
348
349   for (s=d=buffer; length; length--, s++)
350     {
351       if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
352         continue;
353       if (*s == '=')
354         {
355           /* Pad character: stop */
356           if (idx == 1)
357             *d++ = val;
358           state->stop_seen = 1;
359           break;
360         }
361
362       if ((c = asctobin[*(unsigned char *)s]) == 255)
363         {
364           if (!state->invalid_encoding)
365             log_debug ("%s: invalid base64 character %02X at pos %d skipped\n",
366                        __func__, *(unsigned char*)s, (int)(s-buffer));
367           state->invalid_encoding = 1;
368           continue;
369         }
370
371       switch (idx)
372         {
373         case 0:
374           val = c << 2;
375           break;
376         case 1:
377           val |= (c>>4)&3;
378           *d++ = val;
379           val = (c<<4)&0xf0;
380           break;
381         case 2:
382           val |= (c>>2)&15;
383           *d++ = val;
384           val = (c<<6)&0xc0;
385           break;
386         case 3:
387           val |= c&0x3f;
388           *d++ = val;
389           break;
390         }
391       idx = (idx+1) % 4;
392     }
393
394
395   state->idx = idx;
396   state->val = val;
397   return d - buffer;
398 }
399
400
401 /* Base 64 encode the input. If input is null returns NULL otherwise
402    a pointer to the malloced encoded string. */
403 char *
404 b64_encode (const char *input, size_t length)
405 {
406   size_t out_len = 4 * ((length + 2) / 3);
407   char *ret;
408   int i, j;
409
410   if (!length || !input)
411     {
412       return NULL;
413     }
414   ret = xmalloc (out_len);
415   memset (ret, 0, out_len);
416
417   for (i = 0, j = 0; i < length;)
418     {
419       unsigned int a = i < length ? (unsigned char)input[i++] : 0;
420       unsigned int b = i < length ? (unsigned char)input[i++] : 0;
421       unsigned int c = i < length ? (unsigned char)input[i++] : 0;
422
423       unsigned int triple = (a << 0x10) + (b << 0x08) + c;
424
425       ret[j++] = bintoasc[(triple >> 3 * 6) & 0x3F];
426       ret[j++] = bintoasc[(triple >> 2 * 6) & 0x3F];
427       ret[j++] = bintoasc[(triple >> 1 * 6) & 0x3F];
428       ret[j++] = bintoasc[(triple >> 0 * 6) & 0x3F];
429     }
430
431   if (length % 3)
432     {
433       ret [j - 1] = '=';
434     }
435   if (length % 3 == 1)
436     {
437       ret [j - 2] = '=';
438     }
439
440   return ret;
441 }
442
443 /* Create a boundary.  Note that mimemaker.c knows about the structure
444    of the boundary (i.e. that it starts with "=-=") so that it can
445    protect against accidently used boundaries within the content.  */
446 char *
447 generate_boundary (char *buffer)
448 {
449   char *p = buffer;
450   int i;
451
452 #if RAND_MAX < (64*2*BOUNDARYSIZE)
453 #error RAND_MAX is way too small
454 #endif
455
456   *p++ = '=';
457   *p++ = '-';
458   *p++ = '=';
459   for (i=0; i < BOUNDARYSIZE-6; i++)
460     *p++ = bintoasc[rand () % 64];
461   *p++ = '=';
462   *p++ = '-';
463   *p++ = '=';
464   *p = 0;
465
466   return buffer;
467 }
468
469 /* The malloced name of the logfile and the logging stream.  If
470    LOGFILE is NULL, no logging is done. */
471 static char *logfile;
472 static FILE *logfp;
473
474 #ifdef HAVE_W32_SYSTEM
475
476 /* Acquire the mutex for logging.  Returns 0 on success. */
477 static int
478 lock_log (void)
479 {
480   int code = WaitForSingleObject (log_mutex, INFINITE);
481   return code != WAIT_OBJECT_0;
482 }
483
484 /* Release the mutex for logging. No error return is done because this
485    is a fatal error anyway and we have no means for proper
486    notification. */
487 static void
488 unlock_log (void)
489 {
490   ReleaseMutex (log_mutex);
491 }
492 #endif
493
494 const char *
495 get_log_file (void)
496 {
497   return logfile? logfile : "";
498 }
499
500 void
501 set_log_file (const char *name)
502 {
503 #ifdef HAVE_W32_SYSTEM
504   if (!lock_log ())
505     {
506 #endif
507       if (logfp)
508         {
509           fclose (logfp);
510           logfp = NULL;
511         }
512       xfree (logfile);
513       if (!name || *name == '\"' || !*name)
514         logfile = NULL;
515       else
516         logfile = xstrdup (name);
517 #ifdef HAVE_W32_SYSTEM
518       unlock_log ();
519     }
520 #endif
521 }
522
523 static void
524 do_log (const char *fmt, va_list a, int w32err, int err,
525         const void *buf, size_t buflen)
526 {
527   if (!logfile)
528     return;
529
530 #ifdef HAVE_W32_SYSTEM
531   if (lock_log ())
532     return;
533 #endif
534
535   if (!strcmp (logfile, "stdout"))
536     {
537       logfp = stdout;
538     }
539   else if (!strcmp (logfile, "stderr"))
540     {
541       logfp = stderr;
542     }
543   if (!logfp)
544     logfp = fopen (logfile, "a+");
545 #ifdef HAVE_W32_SYSTEM
546   if (!logfp)
547     {
548       unlock_log ();
549       return;
550     }
551
552   char time_str[9];
553   SYSTEMTIME utc_time;
554   GetSystemTime (&utc_time);
555   if (GetTimeFormatA (LOCALE_INVARIANT,
556                       TIME_FORCE24HOURFORMAT | LOCALE_USE_CP_ACP,
557                       &utc_time,
558                       "HH:mm:ss",
559                       time_str,
560                       9))
561     {
562       fprintf (logfp, "%s/%lu/",
563                time_str,
564                (unsigned long)GetCurrentThreadId ());
565     }
566   else
567     {
568       fprintf (logfp, "unknown/%lu/",
569                (unsigned long)GetCurrentThreadId ());
570     }
571 #endif
572
573   if (err == 1)
574     fputs ("ERROR/", logfp);
575   vfprintf (logfp, fmt, a);
576 #ifdef HAVE_W32_SYSTEM
577   if (w32err)
578     {
579       char tmpbuf[256];
580
581       FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, w32err,
582                      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
583                      tmpbuf, sizeof (tmpbuf)-1, NULL);
584       fputs (": ", logfp);
585       if (*tmpbuf && tmpbuf[strlen (tmpbuf)-1] == '\n')
586         tmpbuf[strlen (tmpbuf)-1] = 0;
587       if (*tmpbuf && tmpbuf[strlen (tmpbuf)-1] == '\r')
588         tmpbuf[strlen (tmpbuf)-1] = 0;
589       fprintf (logfp, "%s (%d)", tmpbuf, w32err);
590     }
591 #endif
592   if (buf)
593     {
594       const unsigned char *p = (const unsigned char*)buf;
595
596       for ( ; buflen; buflen--, p++)
597         fprintf (logfp, "%02X", *p);
598       putc ('\n', logfp);
599     }
600   else if ( *fmt && fmt[strlen (fmt) - 1] != '\n')
601     putc ('\n', logfp);
602
603   fflush (logfp);
604 #ifdef HAVE_W32_SYSTEM
605   unlock_log ();
606 #endif
607 }
608
609 const char *
610 log_srcname (const char *file)
611 {
612   const char *s = strrchr (file, '/');
613   return s? s+1:file;
614 }
615
616 void
617 log_debug (const char *fmt, ...)
618 {
619   va_list a;
620
621   va_start (a, fmt);
622   do_log (fmt, a, 0, 0, NULL, 0);
623   va_end (a);
624 }
625
626 void
627 log_error (const char *fmt, ...)
628 {
629   va_list a;
630
631   va_start (a, fmt);
632   do_log (fmt, a, 0, 1, NULL, 0);
633   va_end (a);
634 }
635
636 void
637 log_vdebug (const char *fmt, va_list a)
638 {
639   do_log (fmt, a, 0, 0, NULL, 0);
640 }
641
642 void
643 log_hexdump (const void *buf, size_t buflen, const char *fmt, ...)
644 {
645   va_list a;
646
647   va_start (a, fmt);
648   do_log (fmt, a, 0, 2, buf, buflen);
649   va_end (a);
650 }
651
652 #ifdef HAVE_W32_SYSTEM
653 void
654 log_debug_w32 (int w32err, const char *fmt, ...)
655 {
656   va_list a;
657
658   if (w32err == -1)
659     w32err = GetLastError ();
660
661   va_start (a, fmt);
662   do_log (fmt, a, w32err, 0, NULL, 0);
663   va_end (a);
664 }
665
666 void
667 log_error_w32 (int w32err, const char *fmt, ...)
668 {
669   va_list a;
670
671   if (w32err == -1)
672     w32err = GetLastError ();
673
674   va_start (a, fmt);
675   do_log (fmt, a, w32err, 1, NULL, 0);
676   va_end (a);
677 }
678
679 static void
680 do_log_window_info (HWND window, int level)
681 {
682   char buf[1024+1];
683   char name[200];
684   int nname;
685   char *pname;
686   DWORD pid;
687
688   if (!window)
689     return;
690
691   GetWindowThreadProcessId (window, &pid);
692   if (pid != GetCurrentProcessId ())
693     return;
694
695   memset (buf, 0, sizeof (buf));
696   GetWindowText (window, buf, sizeof (buf)-1);
697   nname = GetClassName (window, name, sizeof (name)-1);
698   if (nname)
699     pname = name;
700   else
701     pname = NULL;
702
703   if (level == -1)
704     log_debug ("  parent=%p/%lu (%s) `%s'", window, (unsigned long)pid,
705                pname? pname:"", buf);
706   else
707     log_debug ("    %*shwnd=%p/%lu (%s) `%s'", level*2, "", window,
708                (unsigned long)pid, pname? pname:"", buf);
709 }
710
711
712 /* Helper to log_window_hierarchy.  */
713 static HWND
714 do_log_window_hierarchy (HWND parent, int level)
715 {
716   HWND child;
717
718   child = GetWindow (parent, GW_CHILD);
719   while (child)
720     {
721       do_log_window_info (child, level);
722       do_log_window_hierarchy (child, level+1);
723       child = GetNextWindow (child, GW_HWNDNEXT);
724     }
725
726   return NULL;
727 }
728
729
730 /* Print a debug message using the format string FMT followed by the
731    window hierarchy of WINDOW.  */
732 void
733 log_window_hierarchy (HWND window, const char *fmt, ...)
734 {
735   va_list a;
736
737   va_start (a, fmt);
738   do_log (fmt, a, 0, 0, NULL, 0);
739   va_end (a);
740   if (window)
741     {
742       do_log_window_info (window, -1);
743       do_log_window_hierarchy (window, 0);
744     }
745 }
746
747 void
748 set_default_key (const char *name)
749 {
750   if (!lock_log ())
751     {
752       if (!name || *name == '\"' || !*name)
753         {
754           xfree (opt.default_key);
755           opt.default_key = NULL;
756         }
757       else
758         {
759           xfree (opt.default_key);
760           opt.default_key = xstrdup (name);;
761         }
762       unlock_log ();
763     }
764 }
765 #endif