Added translation framework and translated a few strings.
[gpgol.git] / src / main.c
1 /* main.c - DLL entry point
2  *      Copyright (C) 2005 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 GPGol; if not, write to the Free Software Foundation, 
18  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
19  */
20
21 #include <config.h>
22
23 #include <windows.h>
24
25 #include <gpgme.h>
26
27 #include "mymapi.h"
28 #include "mymapitags.h"
29
30
31 #include "intern.h"
32 #include "passcache.h"
33 #include "msgcache.h"
34 #include "mymapi.h"
35
36 /* Registry key for this software. */
37 #define REGKEY "Software\\GNU\\GnuPG"
38
39 /* The malloced name of the logfile and the logging stream.  If
40    LOGFILE is NULL, no logging is done. */
41 static char *logfile;
42 static FILE *logfp;
43
44 /* For certain operations we need to acquire a log on the logging
45    functions.  This lock is controlled by this Mutex. */
46 static HANDLE log_mutex;
47
48
49 /* Local function prototypes. */
50 static char *get_locale_dir (void);
51 static void drop_locale_dir (char *locale_dir);
52
53
54 \f
55 /* Initialization of gloabl options.  These are merely the defaults
56    and will get updated later from the Registry.  That is done later
57    at the time Outlook calls its entry point the first time. */
58 static void
59 init_options (void)
60 {
61   opt.passwd_ttl = 10; /* Seconds. Use a small value, so that no
62                           multiple prompts for attachment encryption
63                           are issued. */
64   opt.enc_format = GPG_FMT_CLASSIC;
65   opt.add_default_key = 1;
66 }
67
68
69 /* Early initialization of this module.  This is done right at startup
70    with only one thread running.  Should be called only once. Returns
71    0 on success. */
72 static int
73 initialize_main (void)
74 {
75   SECURITY_ATTRIBUTES sa;
76   
77   memset (&sa, 0, sizeof sa);
78   sa.bInheritHandle = FALSE;
79   sa.lpSecurityDescriptor = NULL;
80   sa.nLength = sizeof sa;
81   log_mutex = CreateMutex (&sa, FALSE, NULL);
82   return log_mutex? 0 : -1;
83 }
84
85 static void
86 i18n_init (void)
87 {
88   char *locale_dir;
89
90 #ifdef ENABLE_NLS
91 # ifdef HAVE_LC_MESSAGES
92   setlocale (LC_TIME, "");
93   setlocale (LC_MESSAGES, "");
94 # else
95   setlocale (LC_ALL, "" );
96 # endif
97 #endif
98
99   locale_dir = get_locale_dir ();
100   if (locale_dir)
101     {
102       bindtextdomain (PACKAGE_GT, locale_dir);
103       drop_locale_dir (locale_dir);
104     }
105   textdomain (PACKAGE_GT);
106 }
107
108
109 /* Entry point called by DLL loader. */
110 int WINAPI
111 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
112 {
113   if (reason == DLL_PROCESS_ATTACH)
114     {
115       set_global_hinstance (hinst);
116       /* The next call initializes subsystems of gpgme and should be
117          done as early as possible.  The actual return value is (the
118          version string) is not used here.  It may be called at any
119          time later for this. */
120       gpgme_check_version (NULL);
121
122       /* Early initializations of our subsystems. */
123       if (initialize_main ())
124         return FALSE;
125       i18n_init ();
126       if (initialize_passcache ())
127         return FALSE;
128       if (initialize_msgcache ())
129         return FALSE;
130       init_options ();
131     }
132   else if (reason == DLL_PROCESS_DETACH)
133     {
134       watcher_free_hook ();
135     }
136   
137   return TRUE;
138 }
139
140
141 /* Acquire the mutex for logging.  Returns 0 on success. */
142 static int 
143 lock_log (void)
144 {
145   int code = WaitForSingleObject (log_mutex, INFINITE);
146   return code != WAIT_OBJECT_0;
147 }
148
149 /* Release the mutex for logging. No error return is done because this
150    is a fatal error anyway and we have no means for proper
151    notification. */
152 static void
153 unlock_log (void)
154 {
155   ReleaseMutex (log_mutex);
156 }
157
158
159
160 static void
161 do_log (const char *fmt, va_list a, int w32err, int err,
162         const void *buf, size_t buflen)
163 {
164   if (!logfile)
165     return;
166
167   if (lock_log ())
168     return;
169   
170   if (!logfp)
171     logfp = fopen (logfile, "a+");
172   if (!logfp)
173     {
174       unlock_log ();
175       return;
176     }
177   
178   fprintf (logfp, "%lu/", (unsigned long)GetCurrentThreadId ());
179   if (err == 1)
180     fputs ("ERROR/", logfp);
181   vfprintf (logfp, fmt, a);
182   if (w32err) 
183     {
184       char tmpbuf[256];
185       
186       FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, w32err, 
187                      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), 
188                      tmpbuf, sizeof (tmpbuf)-1, NULL);
189       fputs (": ", logfp);
190       fputs (tmpbuf, logfp);
191     }
192   if (buf)
193     {
194       const unsigned char *p = (const unsigned char*)buf;
195
196       for ( ; buflen; buflen--, p++)
197         fprintf (logfp, "%02X", *p);
198       putc ('\n', logfp);
199     }
200   else if ( *fmt && fmt[strlen (fmt) - 1] != '\n')
201     putc ('\n', logfp);
202
203   fflush (logfp);
204   unlock_log ();
205 }
206
207
208 void 
209 log_debug (const char *fmt, ...)
210 {
211   va_list a;
212   
213   va_start (a, fmt);
214   do_log (fmt, a, 0, 0, NULL, 0);
215   va_end (a);
216 }
217
218 void 
219 log_error (const char *fmt, ...)
220 {
221   va_list a;
222   
223   va_start (a, fmt);
224   do_log (fmt, a, 0, 1, NULL, 0);
225   va_end (a);
226 }
227
228 void 
229 log_vdebug (const char *fmt, va_list a)
230 {
231   do_log (fmt, a, 0, 0, NULL, 0);
232 }
233
234
235 void 
236 log_debug_w32 (int w32err, const char *fmt, ...)
237 {
238   va_list a;
239
240   if (w32err == -1)
241       w32err = GetLastError ();
242   
243   va_start (a, fmt);
244   do_log (fmt, a, w32err, 0, NULL, 0);
245   va_end (a);
246 }
247
248 void 
249 log_error_w32 (int w32err, const char *fmt, ...)
250 {
251   va_list a;
252
253   if (w32err == -1)
254       w32err = GetLastError ();
255   
256   va_start (a, fmt);
257   do_log (fmt, a, w32err, 1, NULL, 0);
258   va_end (a);
259 }
260
261
262 void 
263 log_hexdump (const void *buf, size_t buflen, const char *fmt, ...)
264 {
265   va_list a;
266
267   va_start (a, fmt);
268   do_log (fmt, a, 0, 2, buf, buflen);
269   va_end (a);
270 }
271
272 const char *
273 log_srcname (const char *file)
274 {
275   const char *s = strrchr (file, '/');
276   return s? s+1:file;
277 }
278
279 const char *
280 get_log_file (void)
281 {
282   return logfile? logfile : "";
283 }
284
285 void
286 set_log_file (const char *name)
287 {
288   if (!lock_log ())
289     {
290       if (logfp)
291         {
292           fclose (logfp);
293           logfp = NULL;
294         }
295       xfree (logfile);
296       if (!name || *name == '\"' || !*name) 
297         logfile = NULL;
298       else
299         logfile = xstrdup (name);
300       unlock_log ();
301     }
302 }
303
304 void
305 set_default_key (const char *name)
306 {
307   if (!lock_log ())
308     {
309       if (!name || *name == '\"' || !*name)
310         {
311           xfree (opt.default_key);
312           opt.default_key = NULL;
313         }
314       else
315         {
316           xfree (opt.default_key);
317           opt.default_key = xstrdup (name);;
318         }
319       unlock_log ();
320     }
321 }
322
323
324 static char *
325 get_locale_dir (void)
326 {
327   char *instdir;
328   char *p;
329   char *dname;
330
331   instdir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", REGKEY,
332                                       "Install Directory");
333   if (!instdir)
334     return NULL;
335   
336   /* Build the key: "<instdir>/share/locale".  */
337 #define SLDIR "\\share\\locale"
338   dname = malloc (strlen (instdir) + strlen (SLDIR) + 1);
339   if (!dname)
340     {
341       free (instdir);
342       return NULL;
343     }
344   p = dname;
345   strcpy (p, instdir);
346   p += strlen (instdir);
347   strcpy (p, SLDIR);
348   
349   free (instdir);
350   
351   return dname;
352 }
353
354
355 static void
356 drop_locale_dir (char *locale_dir)
357 {
358   free (locale_dir);
359 }
360
361
362 /* Read option settings from the Registry. */
363 void
364 read_options (void)
365 {
366   char *val = NULL;
367  
368   load_extension_value ("autoSignAttachments", &val);
369   opt.auto_sign_attach = val == NULL || *val != '1' ? 0 : 1;
370   xfree (val); val = NULL;
371   
372   load_extension_value ("saveDecryptedAttachments", &val);
373   opt.save_decrypted_attach = val == NULL || *val != '1'? 0 : 1;
374   xfree (val); val = NULL;
375
376   load_extension_value ("encryptDefault", &val);
377   opt.encrypt_default = val == NULL || *val != '1'? 0 : 1;
378   xfree (val); val = NULL;
379
380   load_extension_value ("signDefault", &val);
381   opt.sign_default = val == NULL || *val != '1'? 0 : 1;
382   xfree (val); val = NULL;
383
384   load_extension_value ("addDefaultKey", &val);
385   opt.add_default_key = val == NULL || *val != '1' ? 0 : 1;
386   xfree (val); val = NULL;
387
388   load_extension_value ("storePasswdTime", &val);
389   opt.passwd_ttl = val == NULL || *val == '0'? 0 : atol (val);
390   xfree (val); val = NULL;
391
392   load_extension_value ("encodingFormat", &val);
393   opt.enc_format = val == NULL? GPG_FMT_CLASSIC  : atol (val);
394   xfree (val); val = NULL;
395
396   load_extension_value ("logFile", &val);
397   set_log_file (val);
398   xfree (val); val = NULL;
399   
400   load_extension_value ("defaultKey", &val);
401   set_default_key (val);
402   xfree (val); val = NULL;
403
404   /* Note, that on purpose these flags are only Registry changeable.
405      The format of the entry is a string of of "0" and "1" digits; see
406      the switch below for a description. */
407   memset (&opt.compat, 0, sizeof opt.compat);
408   load_extension_value ("compatFlags", &val);
409   if (val)
410     {
411       const char *s = val;
412       int i, x;
413
414       for (s=val, i=0; *s; s++, i++)
415         {
416           x = *s == '1';
417           switch (i)
418             {
419             case 0: opt.compat.no_msgcache = x; break;
420             case 1: opt.compat.no_pgpmime = x; break;
421             case 2: opt.compat.no_oom_write = x; break;
422             case 3: opt.compat.preview_decryption = x; break;
423             case 4: opt.compat.old_reply_hack = x; break;
424             case 5: opt.compat.auto_decrypt = x; break;
425             case 6: opt.compat.no_attestation = x; break;
426             }
427         }
428       log_debug ("Note: using compatibility flags: %s", val);
429     }
430   xfree (val); val = NULL;
431 }
432
433
434 /* Write current options back to the Registry. */
435 int
436 write_options (void)
437 {
438   struct 
439   {
440     const char *name;
441     int  mode;
442     int  value;
443     char *s_val;
444   } table[] = {
445     {"encryptDefault",           0, opt.encrypt_default},
446     {"signDefault",              0, opt.sign_default},
447     {"addDefaultKey",            0, opt.add_default_key},
448     {"saveDecryptedAttachments", 0, opt.save_decrypted_attach},
449     {"autoSignAttachments",      0, opt.auto_sign_attach},
450     {"storePasswdTime",          1, opt.passwd_ttl},
451     {"encodingFormat",           1, opt.enc_format},
452     {"logFile",                  2, 0, logfile},
453     {"defaultKey",               2, 0, opt.default_key},
454     {NULL, 0}
455   };
456   char buf[32];
457   int rc, i;
458
459   for (i=0; table[i].name; i++) 
460     {
461       log_debug ("storing option `%s'\n", table[i].name);
462       switch (table[i].mode)
463         {
464         case 0:
465           rc = store_extension_value (table[i].name, table[i].value? "1": "0");
466           break;
467         case 1:
468           sprintf (buf, "%d", table[i].value);
469           rc = store_extension_value (table[i].name, buf);
470           break;
471         case 2:
472           rc = store_extension_value (table[i].name,
473                                       table[i].s_val? table[i].s_val : "");
474           break;
475         default:
476           rc = -1;
477           break;
478         }
479       if (rc)
480         log_error ("error storing option `%s': rc = %d\n", table[i].name, rc);
481     }
482   
483   return 0;
484 }