30f22f74fbcc4310adc34633fc4aa288e812f1cb
[gpgol.git] / src / main.c
1 /* main.c - DLL entry point
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
22 #include <windows.h>
23 #include <wincrypt.h>
24 #include <ctype.h>
25 #include <winnls.h>
26 #include <unistd.h>
27
28 #include "mymapi.h"
29 #include "mymapitags.h"
30
31 #include "common.h"
32 #include "mymapi.h"
33
34 /* Local function prototypes. */
35 static char *get_locale_dir (void);
36 static void drop_locale_dir (char *locale_dir);
37
38 /* The major version of Outlook we are attached to */
39 int g_ol_version_major;
40
41
42 /* For certain operations we need to acquire a log on the logging
43    functions.  This lock is controlled by this Mutex. */
44 HANDLE log_mutex;
45
46 /* Early initialization of this module.  This is done right at startup
47    with only one thread running.  Should be called only once. Returns
48    0 on success. */
49 static int
50 initialize_main (void)
51 {
52   SECURITY_ATTRIBUTES sa;
53
54   memset (&sa, 0, sizeof sa);
55   sa.bInheritHandle = FALSE;
56   sa.lpSecurityDescriptor = NULL;
57   sa.nLength = sizeof sa;
58   log_mutex = CreateMutex (&sa, FALSE, NULL);
59   return log_mutex? 0 : -1;
60 }
61
62 void
63 i18n_init (void)
64 {
65   char *locale_dir;
66
67 #ifdef ENABLE_NLS
68 # ifdef HAVE_LC_MESSAGES
69   setlocale (LC_TIME, "");
70   setlocale (LC_MESSAGES, "");
71 # else
72   setlocale (LC_ALL, "" );
73 # endif
74 #endif
75
76   locale_dir = get_locale_dir ();
77   if (locale_dir)
78     {
79       bindtextdomain (PACKAGE_GT, locale_dir);
80       drop_locale_dir (locale_dir);
81     }
82   textdomain (PACKAGE_GT);
83 }
84
85 static char *
86 get_gpgme_w32_inst_dir (void)
87 {
88   char *gpg4win_dir = get_gpg4win_dir ();
89   char *tmp;
90   gpgrt_asprintf (&tmp, "%s\\bin\\gpgme-w32spawn.exe", gpg4win_dir);
91   memdbg_alloc (tmp);
92
93   if (!access(tmp, R_OK))
94     {
95       xfree (tmp);
96       gpgrt_asprintf (&tmp, "%s\\bin", gpg4win_dir);
97       memdbg_alloc (tmp);
98       xfree (gpg4win_dir);
99       return tmp;
100     }
101   xfree (tmp);
102   gpgrt_asprintf (&tmp, "%s\\gpgme-w32spawn.exe", gpg4win_dir);
103   memdbg_alloc (tmp);
104
105   if (!access(tmp, R_OK))
106     {
107       xfree (tmp);
108       return gpg4win_dir;
109     }
110   OutputDebugString("Failed to find gpgme-w32spawn.exe!");
111   return NULL;
112 }
113
114 /* Entry point called by DLL loader. */
115 int WINAPI
116 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
117 {
118   (void)reserved;
119
120   if (reason == DLL_PROCESS_ATTACH)
121     {
122       set_global_hinstance (hinst);
123
124       gpg_err_init ();
125
126       /* Set the installation directory for GpgME so that
127          it can find tools like gpgme-w32-spawn correctly. */
128       char *instdir = get_gpgme_w32_inst_dir();
129       gpgme_set_global_flag ("w32-inst-dir", instdir);
130       xfree (instdir);
131
132       /* The next call initializes subsystems of gpgme and should be
133          done as early as possible.  The actual return value (the
134          version string) is not used here.  It may be called at any
135          time later for this. */
136       gpgme_check_version (NULL);
137
138       /* Early initializations of our subsystems. */
139       if (initialize_main ())
140         return FALSE;
141     }
142   else if (reason == DLL_PROCESS_DETACH)
143     {
144       gpg_err_deinit (0);
145     }
146
147   return TRUE;
148 }
149
150 static char *
151 get_locale_dir (void)
152 {
153   char *instdir;
154   char *p;
155   char *dname;
156
157   instdir = get_gpg4win_dir();
158   if (!instdir)
159     return NULL;
160
161   /* Build the key: "<instdir>/share/locale".  */
162 #define SLDIR "\\share\\locale"
163   dname = xmalloc (strlen (instdir) + strlen (SLDIR) + 1);
164   if (!dname)
165     {
166       xfree (instdir);
167       return NULL;
168     }
169   p = dname;
170   strcpy (p, instdir);
171   p += strlen (instdir);
172   strcpy (p, SLDIR);
173
174   xfree (instdir);
175
176   return dname;
177 }
178
179
180 static void
181 drop_locale_dir (char *locale_dir)
182 {
183   xfree (locale_dir);
184 }
185
186
187 static int
188 get_conf_bool (const char *name, int defaultVal)
189 {
190   char *val = NULL;
191   int ret;
192   load_extension_value (name, &val);
193   ret = val == NULL ? defaultVal : *val != '1' ? 0 : 1;
194   xfree (val);
195   return ret;
196 }
197
198 static int
199 dbg_compat (int oldval)
200 {
201   // We broke the debug levels at some point
202   // This is cmpatibility code with the old
203   // levels.
204
205 #define DBG_MEMORY_OLD     (1<<5) // 32
206 #define DBG_MIME_PARSER_OLD (1<<7) // 128 Unified as DBG_DATA
207 #define DBG_MIME_DATA_OLD   (1<<8) // 256 Unified in read_options
208 #define DBG_OOM_OLD        (1<<9) // 512 Unified as DBG_OOM
209 #define DBG_OOM_EXTRA_OLD  (1<<10)// 1024 Unified in read_options
210   int new_dbg = oldval;
211   if ((oldval & DBG_MEMORY_OLD))
212     {
213       new_dbg |= DBG_MEMORY;
214       new_dbg -= DBG_MEMORY_OLD;
215     }
216   if ((oldval & DBG_OOM_OLD))
217     {
218       new_dbg |= DBG_OOM;
219       new_dbg -= DBG_OOM_OLD;
220     }
221   if ((oldval & DBG_MIME_PARSER_OLD))
222     {
223       new_dbg |= DBG_DATA;
224       new_dbg -= DBG_MIME_PARSER_OLD;
225     }
226   if ((oldval & DBG_MIME_DATA_OLD))
227     {
228       new_dbg |= DBG_DATA;
229       new_dbg -= DBG_MIME_DATA_OLD;
230     }
231   if ((oldval & DBG_OOM_OLD))
232     {
233       new_dbg |= DBG_OOM;
234       new_dbg -= DBG_OOM_OLD;
235     }
236   if ((oldval & DBG_OOM_EXTRA_OLD))
237     {
238       new_dbg |= DBG_OOM;
239       new_dbg -= DBG_OOM_EXTRA_OLD;
240     }
241 #undef DBG_MEMORY_OLD
242 #undef DBG_MIME_PARSER_OLD
243 #undef DBG_MIME_DATA_OLD
244 #undef DBG_OOM_OLD
245 #undef DBG_OOM_EXTRA_OLD
246   return new_dbg;
247 }
248
249 /* Read option settings from the Registry. */
250 void
251 read_options (void)
252 {
253   char *val = NULL;
254
255   /* Set the log file first so that output from this function is
256      logged too.  */
257   load_extension_value ("logFile", &val);
258   set_log_file (val);
259   xfree (val); val = NULL;
260
261   /* Parse the debug flags.  */
262   load_extension_value ("enableDebug", &val);
263   opt.enable_debug = 0;
264   if (val)
265     {
266       char *p, *pend;
267
268       trim_spaces (val);
269       for (p = val; p; p = pend)
270         {
271           pend = strpbrk (p, ", \t\n\r\f");
272           if (pend)
273             {
274               *pend++ = 0;
275               pend += strspn (pend, ", \t\n\r\f");
276             }
277           if (isascii (*p) && isdigit (*p))
278             {
279               opt.enable_debug |= dbg_compat (strtoul (p, NULL, 0));
280
281             }
282           else if (!strcmp (p, "memory"))
283             opt.enable_debug |= DBG_MEMORY;
284           else if (!strcmp (p, "mime-parser"))
285             opt.enable_debug |= DBG_DATA;
286           else if (!strcmp (p, "mime-data"))
287             opt.enable_debug |= DBG_DATA;
288           else if (!strcmp (p, "oom"))
289             opt.enable_debug |= DBG_OOM;
290           else if (!strcmp (p, "oom-extra"))
291             opt.enable_debug |= DBG_OOM;
292           else
293             log_debug ("invalid debug flag `%s' ignored", p);
294         }
295     }
296   else
297     {
298       /* To help the user enable debugging make sure that the registry
299          key exists.  Note that the other registry keys are stored
300          after using the configuration dialog.  */
301       store_extension_value ("enableDebug", "0");
302     }
303   /* Yes we use free here because memtracing did not track the alloc
304      as the option for debuging was not read before. */
305   free (val); val = NULL;
306   if (opt.enable_debug)
307     log_debug ("enabled debug flags:%s%s%s\n",
308                (opt.enable_debug & DBG_MEMORY)? " memory":"",
309                (opt.enable_debug & DBG_DATA)? " data":"",
310                (opt.enable_debug & DBG_OOM)? " oom":""
311                );
312
313   opt.enable_smime = get_conf_bool ("enableSmime", 0);
314   opt.encrypt_default = get_conf_bool ("encryptDefault", 0);
315   opt.sign_default = get_conf_bool ("signDefault", 0);
316   opt.inline_pgp = get_conf_bool ("inlinePGP", 0);
317   opt.reply_crypt = get_conf_bool ("replyCrypt", 1);
318   opt.prefer_smime = get_conf_bool ("preferSmime", 0);
319   opt.autoresolve = get_conf_bool ("autoresolve", 1);
320   opt.automation = get_conf_bool ("automation", 1);
321   opt.autosecure = get_conf_bool ("autosecure", 1);
322   opt.autotrust = get_conf_bool ("autotrust", 0);
323   opt.smime_html_warn_shown = get_conf_bool ("smimeHtmlWarnShown", 0);
324
325   if (!opt.automation)
326     {
327       // Disabling automation is a shorthand to disable the
328       // others, too.
329       opt.autosecure = 0;
330       opt.autoresolve = 0;
331       opt.autotrust = 0;
332     }
333
334   /* Hidden options  */
335   opt.sync_enc = get_conf_bool ("_syncEnc", 0);
336 }
337
338
339 /* Write current options back to the Registry. */
340 int
341 write_options (void)
342 {
343   struct
344   {
345     const char *name;
346     int  mode;
347     int  value;
348     char *s_val;
349   } table[] = {
350     {"smimeHtmlWarnShown",       0, opt.smime_html_warn_shown, NULL},
351     {NULL, 0, 0, NULL}
352   };
353   char buf[32];
354   int rc, i;
355   const char *string;
356
357   for (i=0; table[i].name; i++)
358     {
359       switch (table[i].mode)
360         {
361         case 0:
362           string = table[i].value? "1": "0";
363           log_debug ("storing option `%s' value=`%s'\n",
364                      table[i].name, string);
365           rc = store_extension_value (table[i].name, string);
366           break;
367         case 1:
368           sprintf (buf, "%d", table[i].value);
369           log_debug ("storing option `%s' value=`%s'\n",
370                      table[i].name, buf);
371           rc = store_extension_value (table[i].name, buf);
372           break;
373         case 2:
374           string = table[i].s_val? table[i].s_val : "";
375           log_debug ("storing option `%s' value=`%s'\n",
376                      table[i].name, string);
377           rc = store_extension_value (table[i].name, string);
378           break;
379 /*         case 3: */
380 /*           buf[0] = '0'; */
381 /*           buf[1] = 0; */
382 /*           switch (opt.default_protocol) */
383 /*             { */
384 /*             case PROTOCOL_UNKNOWN: buf[0] = '0'; /\* auto *\/ break; */
385 /*             case PROTOCOL_OPENPGP: buf[0] = '1'; break; */
386 /*             case PROTOCOL_SMIME:   buf[0] = '2'; break; */
387 /*             } */
388 /*           log_debug ("storing option `%s' value=`%s'\n", */
389 /*                      table[i].name, buf); */
390 /*           rc = store_extension_value (table[i].name, buf); */
391 /*           break;   */
392
393         case 4:
394           sprintf (buf, "0x%x", table[i].value);
395           log_debug ("storing option `%s' value=`%s'\n",
396                      table[i].name, buf);
397           rc = store_extension_value (table[i].name, buf);
398           break;
399
400         default:
401           rc = -1;
402           break;
403         }
404       if (rc)
405         log_error ("error storing option `%s': rc = %d\n", table[i].name, rc);
406     }
407
408   return 0;
409 }