008-11-03 Marcus Brinkmann <marcus@g10code.com>
[gpgme.git] / complus / igpgme.c
1 /* igpgme.c - COM+ class IGpgme
2  *      Copyright (C) 2001 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GPGME 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28 #include <time.h>
29 #include <windows.h>
30
31 #include "../gpgme/gpgme.h"
32
33 /* FIXME: Put them into an extra header */
34 void *_gpgme_malloc (size_t n );
35 void *_gpgme_calloc (size_t n, size_t m );
36 void *_gpgme_realloc (void *p, size_t n);
37 char *_gpgme_strdup (const char *p);
38 void  _gpgme_free ( void *a );
39
40
41
42 #define INITGUID
43 #include "igpgme.h"
44
45 /*
46  * Declare the interface implementation structures
47  */
48 typedef struct IGpgmeImpl IGpgmeImpl;
49 typedef struct IClassFactoryImpl IClassFactoryImpl;
50
51 static HANDLE my_exit_event;
52
53 struct IGpgmeImpl {
54     /* IUnknown required stuff */
55     ICOM_VFIELD (IGpgme);
56     DWORD        ref;
57     /* Delegation to IDispatch */
58     struct {
59         IUnknown *disp;
60         ITypeInfo *tinfo;
61     } std_disp;
62     /* Our stuff */
63     GpgmeCtx mainctx;
64     GpgmeData plaintext;
65     int plaintext_given_as_bstr;
66     GpgmeData ciphertext;
67     int ciphertext_is_armored;
68     GpgmeRecipients rset;
69 };
70
71
72 struct IClassFactoryImpl {
73     /* IUnknown fields */
74     ICOM_VFIELD(IClassFactory);
75     DWORD       ref;
76 };
77
78 /**********************************************************
79  **************  helper functions  ************************
80  *********************************************************/
81 static HRESULT
82 map_gpgme_error (GpgmeError err)
83 {
84     HRESULT hr;
85
86     if (!err)
87         return 0;
88     if ( err < 0 || err > 0x1000 ) {
89         fprintf (stderr,"*** GpgmeError `%s' mapped to GPGME_General_Error\n",
90                  gpgme_strerror (err) );
91         err = GPGME_General_Error;
92     }
93     hr = MAKE_HRESULT (SEVERITY_ERROR, FACILITY_ITF, 0x1000 + err);
94     fprintf (stderr,"*** GpgmeError `%s' mapped to %lx\n",
95              gpgme_strerror (err), (unsigned long)hr );
96     return hr;
97 }
98
99
100 /**********************************************************
101  **************  IGpgme Implementation  *******************
102  *********************************************************/
103
104 static HRESULT WINAPI
105 m_IGpgme_QueryInterface (IGpgme *iface, REFIID refiid, LPVOID *obj)
106 {
107     ICOM_THIS (IGpgmeImpl,iface);
108
109     /*fprintf (stderr,"*** m_IGpgme_QueryInterface(%p,%s)",
110       This, debugstr_guid(refiid));*/
111     if ( IsEqualGUID (&IID_IUnknown, refiid)
112          || IsEqualGUID (&IID_IGpgme, refiid) ) {
113         *obj = This;
114         IGpgme_AddRef (iface);
115         fprintf (stderr," -> got %p\n", *obj);
116         return 0;
117     }
118     else if ( IsEqualGUID (&IID_IDispatch, refiid) ) {
119         HRESULT hr = IDispatch_QueryInterface (This->std_disp.disp,
120                                                refiid, obj);
121         /*fprintf (stderr," -> delegated, hr=%lx, got %p\n",
122            hr, hr? NULL: *obj);*/
123         return hr;
124     }
125     /*fprintf (stderr," -> none\n");*/
126     *obj = NULL;
127     return E_NOINTERFACE;
128 }
129
130
131 static ULONG WINAPI
132 m_IGpgme_AddRef (IGpgme *iface)
133 {
134     ICOM_THIS (IGpgmeImpl,iface);
135         
136     return ++This->ref;
137 }
138
139
140 static ULONG WINAPI
141 m_IGpgme_Release (IGpgme *iface)
142 {
143     ICOM_THIS (IGpgmeImpl,iface);
144         
145     if (--This->ref)
146         return This->ref;
147
148     gpgme_release (This->mainctx); This->mainctx = NULL;
149     gpgme_data_release (This->plaintext); This->plaintext = NULL;
150     gpgme_data_release (This->ciphertext); This->ciphertext = NULL;
151     gpgme_recipients_release (This->rset); This->rset = NULL;
152     if (This->std_disp.disp)
153         IDispatch_Release (This->std_disp.disp);
154     if (This->std_disp.tinfo)
155         ITypeInfo_Release (This->std_disp.tinfo);
156     HeapFree(GetProcessHeap(),0,iface);
157     {
158         ULONG count = CoReleaseServerProcess ();
159         if (!count && my_exit_event)
160             SetEvent (my_exit_event);
161     }
162     return 0;
163 }
164
165
166 static HRESULT WINAPI
167 m_stub_IDispatch_GetTypeInfoCount (IGpgme *iface, unsigned int *pctinfo)
168 {
169     return E_NOTIMPL;
170 }
171
172 static HRESULT WINAPI
173 m_stub_IDispatch_GetTypeInfo (IGpgme *iface, UINT iTInfo,
174                               LCID lcid, ITypeInfo **ppTInfo)
175 {
176     return E_NOTIMPL;
177 }
178
179 static HRESULT WINAPI 
180 m_stub_IDispatch_GetIDsOfNames (IGpgme *iface, REFIID riid, 
181                                 LPOLESTR *rgszNames, UINT cNames, 
182                                 LCID lcid, DISPID *rgDispId)
183 {
184     return E_NOTIMPL;
185 }
186
187 static HRESULT WINAPI 
188 m_stub_IDispatch_Invoke (IGpgme *iface, DISPID dispIdMember, 
189                          REFIID riid, LCID lcid, WORD wFlags,
190                          DISPPARAMS *pDispParams, VARIANT *pVarResult, 
191                          EXCEPINFO *pExepInfo,  UINT *puArgErr)
192 {
193   return E_NOTIMPL;
194 }
195
196
197
198 static HRESULT WINAPI
199 m_IGpgme_GetVersion (IGpgme *iface, BSTR *retvat)
200 {
201     return E_NOTIMPL;
202 }
203
204 static HRESULT WINAPI
205 m_IGpgme_GetEngineInfo (IGpgme *iface, BSTR *retval)
206 {
207     return E_NOTIMPL;
208 }
209
210
211 static HRESULT WINAPI
212 m_IGpgme_Cancel (IGpgme *iface)
213 {
214     return E_NOTIMPL;
215 }
216
217
218 static HRESULT WINAPI
219 m_IGpgme_SetArmor (IGpgme *iface, BOOL yes)
220 {
221     ICOM_THIS (IGpgmeImpl,iface);
222
223     gpgme_set_armor (This->mainctx, yes);
224     return 0;
225 }
226
227 static HRESULT WINAPI
228 m_IGpgme_GetArmor (IGpgme *iface, BOOL *retval)
229 {
230     ICOM_THIS (IGpgmeImpl,iface);
231
232     *retval = gpgme_get_armor (This->mainctx);
233     return 0;
234 }
235
236
237 static HRESULT WINAPI
238 m_IGpgme_SetTextmode (IGpgme *iface, BOOL yes)
239 {
240     ICOM_THIS (IGpgmeImpl,iface);
241
242     gpgme_set_textmode (This->mainctx, yes);
243     return 0;
244 }
245
246 static HRESULT WINAPI
247 m_IGpgme_GetTextmode (IGpgme *iface, BOOL *retval)
248 {
249     ICOM_THIS (IGpgmeImpl,iface);
250
251     *retval = gpgme_get_textmode (This->mainctx);
252     return 0;
253 }
254
255
256 /* 
257  * Put the data from VAL into a a Gpgme data object, which is passed by
258  * reference.  Valid types of the Variant are: BSTR, SAFEARRAY of BYTE and
259  * SAFEARRAY of VARIANTS of signed or unsigned integers.
260  */
261 static HRESULT WINAPI
262 set_data_from_variant (GpgmeData *data, VARIANT val, int *given_as_bstr)
263 {
264     GpgmeError err = 0;
265     HRESULT hr;
266     unsigned char *buf;
267     SAFEARRAY *array;
268     size_t len;
269     int i;
270
271     if ( val.vt == VT_BSTR) {
272         len = bstrtoutf8 (val.u.bstrVal, NULL, 0);
273         buf = _gpgme_malloc (len);
274         if (!buf) 
275             return E_OUTOFMEMORY;
276         
277         if (bstrtoutf8 (val.u.bstrVal, buf, len) < 0) {
278             fprintf (stderr,"problem with bstrtoutf8\n");
279             _gpgme_free (buf);
280             return E_FAIL;
281         }
282
283         #if 0
284         fprintf (stderr,"Got a BSTR (utf8):");
285         for (i=0; i < len; i++)
286             fprintf (stderr, " %0X", buf[i] );
287         putc ('\n', stderr);
288         #endif
289         gpgme_data_release (*data); *data = NULL; 
290         err = gpgme_data_new_from_mem (data, buf, len, 0 /*no need to copy*/ );
291         if (!err && given_as_bstr)
292             *given_as_bstr = 1;
293     }
294     else if ( val.vt == (VT_ARRAY|VT_UI1)) {
295         array = val.u.parray;
296
297         /*fprintf (stderr,"Got an ARRAY of bytes:");*/
298         hr = SafeArrayAccessData (array, (void**)&buf);
299         if (hr) {
300             fprintf (stderr,"*** SafeArrayAccessData failed: hr=%lx\n", hr);
301             return hr;
302         }
303         len = array->rgsabound[0].cElements;
304         /*for (i=0; i < len; i++)
305           fprintf (stderr, " %0X", buf[i] );
306           putc ('\n', stderr);*/
307         
308         gpgme_data_release (*data); *data = NULL; 
309         err = gpgme_data_new_from_mem (data, buf, len, 1 );
310         SafeArrayUnaccessData (array);
311         if (given_as_bstr)
312             *given_as_bstr = 0;
313     }
314     else if ( val.vt == (VT_ARRAY|VT_VARIANT)) {
315         VARIANT *vp;
316         array = val.u.parray;
317
318         /*fprintf (stderr,"Got an ARRAY of VARIANTS:");*/
319         hr = SafeArrayAccessData (array, (void**)&vp);
320         if (hr) {
321             fprintf (stderr,"*** SafeArrayAccessData failed: hr=%lx\n", hr);
322             return hr;
323         }
324         len = array->rgsabound[0].cElements;
325         /* allocate the array using the gpgme allocator so that we can
326          * later use a new without the copy set*/
327         buf = _gpgme_malloc (len);
328         if (!buf) {
329             SafeArrayUnaccessData (array);
330             return E_OUTOFMEMORY;
331         }
332         /* coerce all array elements into rawtext */
333         for (i=0; i < len; i++) {
334             switch (vp[i].vt) {
335               case VT_I1:   buf[i] = (BYTE)vp[i].u.cVal; break; 
336               case VT_I2:   buf[i] = ((UINT)vp[i].u.iVal) & 0xff; break; 
337               case VT_I4:   buf[i] = ((ULONG)vp[i].u.lVal) & 0xff; break; 
338               case VT_INT:  buf[i] = ((UINT)vp[i].u.intVal) & 0xff; break; 
339               case VT_UI1:  buf[i] = vp[i].u.bVal; break; 
340               case VT_UI2:  buf[i] = vp[i].u.uiVal & 0xff; break; 
341               case VT_UI4:  buf[i] = vp[i].u.ulVal & 0xff; break; 
342               case VT_UINT: buf[i] = vp[i].u.uintVal & 0xff; break; 
343               default: 
344                 fprintf (stderr, "Invalid value in array as pos %d\n", i);
345                 _gpgme_free (buf);
346                 SafeArrayUnaccessData (array);
347                 return E_INVALIDARG; 
348             }
349         }
350
351         /*for (i=0; i < len; i++)
352           fprintf (stderr, " %0X", buf[i] );
353           putc ('\n', stderr);*/
354         
355         gpgme_data_release (*data); *data = NULL;
356         err = gpgme_data_new_from_mem (data, buf, len, 0);
357         SafeArrayUnaccessData (array);
358         if (given_as_bstr)
359             *given_as_bstr = 0;
360     }
361     else {
362         fprintf (stderr, "Got a variant type = %d (0x%x)\n",
363                  (int)val.vt, (int)val.vt );
364         return E_INVALIDARG; /* not a safearray of bytes */
365     }
366     return map_gpgme_error (err);
367 }
368
369
370 static HRESULT WINAPI
371 set_data_to_variant (GpgmeData data, VARIANT *retval, int use_bstr)
372 {
373     GpgmeError err;
374     HRESULT hr;
375     SAFEARRAY *array;
376     char *p;
377     size_t nread, len;
378     int i;
379
380     /* Get some info on the data */
381     err = gpgme_data_rewind (data);
382     if (err ) {
383         fprintf (stderr, "*** gpgme_data_rewind failed: %d\n", err);
384         return map_gpgme_error (err);
385     }
386     err = gpgme_data_read (data, NULL, 0, &nread);
387     if (err && err != GPGME_EOF ) {
388         fprintf (stderr, "*** gpgme_data_read [length] failed: %d\n", err);
389         return map_gpgme_error (err);
390     }
391     len = nread;  /*(eof returns a length of 0)*/
392     /*fprintf (stderr,"*** %d bytes are availabe\n", (int)len);*/
393
394     /* convert it to the target data type */
395     if (use_bstr) {
396         BSTR bs;
397         unsigned char *helpbuf;
398
399         /* It is easier to allocate some helper storage */
400         helpbuf = _gpgme_malloc (len);
401         if (!helpbuf) 
402             return E_OUTOFMEMORY;
403         err = gpgme_data_read (data, helpbuf, len, &nread);
404         if (err ) {
405             _gpgme_free (helpbuf);
406             fprintf (stderr, "*** gpgme_data_read [data] failed: %d\n", err);
407             return map_gpgme_error (err);
408         }
409
410         bs = SysAllocStringLen (NULL, len+1);
411         if (!bs) {
412             _gpgme_free (helpbuf);
413             return E_OUTOFMEMORY;
414         }
415
416         for (i=0, p=helpbuf; i < len; i++, p++) 
417             bs[i] = *p;
418         bs[i] = 0;
419         _gpgme_free (helpbuf);
420
421         /* Ready */
422         VariantInit (retval);
423         retval->vt = VT_BSTR;
424         retval->u.bstrVal = bs;
425     }
426 #if 0
427     else if (use_byte_array) {
428         array = SafeArrayCreateVector (VT_UI1, 0, len);
429         if (!array)
430             return E_OUTOFMEMORY;
431
432         p = NULL;
433         hr = SafeArrayAccessData (array, (void**)&p);
434         if (hr) {
435             fprintf (stderr,"*** SafeArrayAccessData failed: hr=%lx\n", hr);
436             SafeArrayDestroyData (array);
437             SafeArrayDestroy (array);
438             return hr;
439         }
440         if (len) {
441             err = gpgme_data_read (data, p, len, &nread);
442             if (err ) {
443                 SafeArrayUnaccessData (array);
444                 SafeArrayDestroyData (array);
445                 SafeArrayDestroy (array);
446                 fprintf (stderr, "*** gpgme_data_read [data] failed: %d\n",
447                          err);
448                 return map_gpgme_error (err);
449             }
450         }
451         SafeArrayUnaccessData (array);
452         
453         /* pass the data to the caller */
454         VariantInit (retval);
455         retval->vt = (VT_ARRAY|VT_UI1);
456         retval->u.parray = array;
457     }
458 #endif
459     else { /* Create an array of variants of bytes */
460         VARIANT *v;
461         unsigned char *helpbuf;
462
463         /* It is easier to allocate some helper storage */
464         helpbuf = _gpgme_malloc (len);
465         if (!helpbuf)
466             return E_OUTOFMEMORY;
467         err = gpgme_data_read (data, helpbuf, len, &nread);
468         if (err ) {
469             _gpgme_free (helpbuf);
470             fprintf (stderr, "*** gpgme_data_read [data] failed: %d\n", err);
471             return map_gpgme_error (err);
472         }
473
474         /* The create the array */
475         array = SafeArrayCreateVector (VT_VARIANT, 0, len);
476         if (!array) {
477             _gpgme_free (helpbuf);
478             return E_OUTOFMEMORY;
479         }
480         
481         v = NULL;
482         hr = SafeArrayAccessData (array, (void**)&v);
483         if (hr) {
484             fprintf (stderr,"*** SafeArrayAccessData failed: hr=%lx\n", hr);
485             _gpgme_free (helpbuf);
486             SafeArrayDestroyData (array);
487             SafeArrayDestroy (array);
488             return hr;
489         }
490
491         for (p=helpbuf; len; len--, v++) {
492             VariantInit (v);
493             v->vt = VT_UI1;
494             v->u.bVal = *p;
495         }
496         SafeArrayUnaccessData (array);
497         _gpgme_free (helpbuf);
498         
499         /* pass the data to the caller */
500         VariantInit (retval);
501         retval->vt = (VT_ARRAY|VT_VARIANT);
502         retval->u.parray = array;
503     }
504     return 0;
505 }
506
507
508 static HRESULT WINAPI
509 m_IGpgme_SetPlaintext (IGpgme *iface, VARIANT val)
510 {
511     ICOM_THIS (IGpgmeImpl,iface);
512
513     return set_data_from_variant (&This->plaintext, val,
514                                   &This->plaintext_given_as_bstr); 
515 }
516
517
518 static HRESULT WINAPI
519 m_IGpgme_GetPlaintext (IGpgme *iface, VARIANT *retval)
520 {
521     ICOM_THIS (IGpgmeImpl,iface);
522
523     /*fprintf (stderr,"*** " __PRETTY_FUNCTION__ "(%p)\n", This );*/
524     return set_data_to_variant (This->plaintext, retval,
525                                 This->plaintext_given_as_bstr);
526 }
527
528 static HRESULT WINAPI
529 m_IGpgme_SetCiphertext (IGpgme *iface, VARIANT val)
530 {
531     ICOM_THIS (IGpgmeImpl,iface);
532
533     return set_data_from_variant (&This->ciphertext, val, NULL); 
534 }
535
536 static HRESULT WINAPI
537 m_IGpgme_GetCiphertext (IGpgme *iface, VARIANT *retval)
538 {
539     ICOM_THIS (IGpgmeImpl,iface);
540
541     return set_data_to_variant (This->ciphertext, retval,
542                                 This->ciphertext_is_armored);
543 }
544
545 static HRESULT WINAPI
546 m_IGpgme_ClearRecipients (IGpgme *iface)
547 {
548     ICOM_THIS (IGpgmeImpl,iface);
549
550     gpgme_recipients_release (This->rset); This->rset = NULL;
551     return 0;
552 }
553
554
555 static HRESULT WINAPI
556 m_IGpgme_AddRecipient (IGpgme *iface, BSTR name, signed short int trust)
557 {
558     GpgmeError err;
559     int n;
560     char *p;
561     ICOM_THIS (IGpgmeImpl,iface);
562     
563     /*fprintf (stderr,"*** " __PRETTY_FUNCTION__ "(%p, %d)\n",
564       This, (int)trust);*/
565     if (!This->rset) {
566         err = gpgme_recipients_new (&This->rset);
567         if (err)
568             return map_gpgme_error (err);
569     }
570
571     n = bstrtoutf8 (name, NULL, 0);
572     p = HeapAlloc (GetProcessHeap(), 0, n );
573     if (!p) {
574         fprintf (stderr,"HeapAlloc failed: ec=%d\n", (int)GetLastError () );
575         return E_OUTOFMEMORY;
576     }
577     if (bstrtoutf8 (name, p, n) < 0) {
578         fprintf (stderr,"problem with bstrtoutf8\n");
579         HeapFree (GetProcessHeap(), 0, p);
580         return E_FAIL;
581     }
582     err = gpgme_recipients_add_name (This->rset, p);
583     HeapFree (GetProcessHeap(), 0, p);
584     return map_gpgme_error (err);
585 }
586
587 static HRESULT WINAPI
588 m_IGpgme_ResetSignKeys (IGpgme *iface)
589 {
590     return E_NOTIMPL;
591 }
592
593 static HRESULT WINAPI
594 m_IGpgme_AddSignKey (IGpgme *iface, BSTR name)
595 {
596     return E_NOTIMPL;
597 }
598
599 static HRESULT WINAPI
600 m_IGpgme_Encrypt (IGpgme *iface)
601 {
602     GpgmeError err;
603     ICOM_THIS (IGpgmeImpl,iface);
604
605     gpgme_data_release (This->ciphertext);
606     err = gpgme_data_new (&This->ciphertext);
607     if (err)
608         return map_gpgme_error (err);
609
610     
611     This->ciphertext_is_armored = gpgme_get_armor (This->mainctx);
612     err = gpgme_op_encrypt (This->mainctx, This->rset,
613                             This->plaintext, This->ciphertext);
614 #if 0
615     if (!err ) {
616         char buf[100];
617         size_t nread;
618
619         err = gpgme_data_rewind ( This->ciphertext );
620         if (err ) 
621             fprintf (stderr, "*** gpgme_data_rewind failed: %d\n", err);
622         while ( !(err = gpgme_data_read ( This->ciphertext,
623                                           buf, 100, &nread )) ) {
624             fwrite ( buf, nread, 1, stderr );
625         }
626         if (err != GPGME_EOF) 
627             fprintf (stderr, "*** gpgme_data_read failed: %d\n", err);
628         err = 0;
629     }
630 #endif
631
632     return map_gpgme_error (err);
633 }
634
635 static HRESULT WINAPI
636 m_IGpgme_Sign (IGpgme *iface, short int signmode)
637 {
638     ICOM_THIS (IGpgmeImpl,iface);
639
640     fprintf (stderr,"*** " __PRETTY_FUNCTION__ "(%p)\n", This );
641
642     return E_NOTIMPL;
643 }
644
645 static HRESULT WINAPI
646 m_IGpgme_SignEncrypt (IGpgme *iface, short int signmode)
647 {
648     ICOM_THIS (IGpgmeImpl,iface);
649
650     fprintf (stderr,"*** " __PRETTY_FUNCTION__ "(%p)\n", This );
651
652     return E_NOTIMPL;
653 }
654
655 #if 0
656 static HRESULT WINAPI
657 m_IGpgme_GetSigStatus(GpgmeCtx c, int idx,
658                                   GpgmeSigStat *r_stat, time_t *r_created );
659 {
660     return 0;
661 }
662
663
664 static HRESULT WINAPI
665 m_IGpgme_GetSigKey (GpgmeCtx c, int idx, GpgmeKey *r_key);
666 {
667     return 0;
668 }
669
670 static HRESULT WINAPI
671 m_IGpgme_GetNotation(IGpgme *c, BSTR *retval)
672 {
673     return 0;
674 }
675 #endif
676
677
678 static ICOM_VTABLE(IGpgme) igpgme_vtbl = 
679 {
680     /* IUnknown methods */
681     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
682     m_IGpgme_QueryInterface,
683     m_IGpgme_AddRef,
684     m_IGpgme_Release,
685     /* IDispatch methods */
686     m_stub_IDispatch_GetTypeInfoCount,
687     m_stub_IDispatch_GetTypeInfo,
688     m_stub_IDispatch_GetIDsOfNames,
689     m_stub_IDispatch_Invoke,
690     /* Our methods */
691     m_IGpgme_GetVersion,
692     m_IGpgme_GetEngineInfo,
693     m_IGpgme_Cancel,             
694     m_IGpgme_SetArmor,            
695     m_IGpgme_GetArmor,            
696     m_IGpgme_SetTextmode,         
697     m_IGpgme_GetTextmode,         
698     m_IGpgme_SetPlaintext,
699     m_IGpgme_GetPlaintext,
700     m_IGpgme_SetCiphertext,
701     m_IGpgme_GetCiphertext,
702     m_IGpgme_ClearRecipients,
703     m_IGpgme_AddRecipient,
704     m_IGpgme_ResetSignKeys,
705     m_IGpgme_AddSignKey,
706     m_IGpgme_Encrypt, 
707     m_IGpgme_Sign, 
708     m_IGpgme_SignEncrypt
709 };
710
711
712
713 /***************************************************************
714  ******************  Gpgme Factory  ****************************
715  ***************************************************************/
716
717 static HRESULT WINAPI 
718 m_GpgmeFactory_QueryInterface (IClassFactory *iface,
719                                REFIID refiid, LPVOID *obj)
720 {
721     ICOM_THIS (IClassFactoryImpl,iface);
722
723     /*fprintf (stderr,"*** m_GpgmeFactory_QueryInterface(%p,%s)",
724       This, debugstr_guid(refiid));*/
725     if ( IsEqualGUID (&IID_IUnknown, refiid)
726          || IsEqualGUID (&IID_IClassFactory, refiid) ) {
727         *obj = This;
728         /*fprintf (stderr," -> got %p\n", obj);*/
729         return 0;
730     }
731     *obj = NULL;
732     /*fprintf (stderr," -> none\n");*/
733     return E_NOINTERFACE;
734 }
735
736 static ULONG WINAPI
737 m_GpgmeFactory_AddRef (IClassFactory *iface)
738 {
739     ICOM_THIS(IClassFactoryImpl,iface);
740     return ++(This->ref);
741 }
742
743 static ULONG WINAPI
744 m_GpgmeFactory_Release (IClassFactory *iface)
745 {
746     ICOM_THIS(IClassFactoryImpl,iface);
747     return --(This->ref);
748 }
749
750 static HRESULT WINAPI
751 m_GpgmeFactory_CreateInstance (IClassFactory *iface, IUnknown *outer,
752                                REFIID refiid, LPVOID *r_obj )
753 {
754     /*ICOM_THIS(IClassFactoryImpl,iface);*/
755
756     fprintf (stderr,"*** m_GpgmeFactory_CreateInstance(%s)",
757              debugstr_guid(refiid) );
758     if (   IsEqualGUID (&IID_IUnknown, refiid)
759         || IsEqualGUID (&IID_IGpgme, refiid) ) {
760         IGpgmeImpl *obj;
761         GpgmeCtx ctx;
762         GpgmeError err;
763
764
765         err = gpgme_new (&ctx);
766         if (err) {
767             fprintf (stderr," -> gpgme_new failed: %s\n", gpgme_strerror (err));
768             return E_OUTOFMEMORY;
769         }
770
771         obj = HeapAlloc (GetProcessHeap(), 0, sizeof *obj );
772         if ( !obj) {
773             fprintf (stderr," -> out of core\n");
774             gpgme_release (ctx);
775             return E_OUTOFMEMORY;
776         }
777         memset (obj, 0, sizeof *obj);
778
779         ICOM_VTBL(obj) = &igpgme_vtbl;
780         obj->ref = 1;
781         obj->mainctx = ctx;
782         {   /* Fixme: need to release some stuff on error */
783             HRESULT hr;
784             ITypeLib *pTypeLib;
785
786             hr = LoadRegTypeLib (&TLBID_Gpgcom, 1, 0, LANG_NEUTRAL, &pTypeLib);
787             if (hr) {
788                 fprintf (stderr," -> LoadRegTypeLib failed: %lx\n", hr);
789                 return hr;
790             }
791             hr = ITypeLib_GetTypeInfoOfGuid (pTypeLib, &IID_IGpgme,
792                                              &obj->std_disp.tinfo);
793             ITypeLib_Release (pTypeLib);
794             if (hr) {
795                 fprintf (stderr," -> GetTypeInfoOfGuid failed: %lx\n", hr);
796                 return hr;
797             }
798             hr = CreateStdDispatch ((IUnknown*)obj, obj, obj->std_disp.tinfo,
799                                      &obj->std_disp.disp);
800             if (hr) {
801                 fprintf (stderr," -> CreateStdDispatch failed: %lx\n", hr);
802                 return hr;
803             }
804         }
805
806         CoAddRefServerProcess ();
807         *r_obj = obj;
808         fprintf (stderr," -> created %p\n", obj );
809         return 0;
810     }
811     fprintf (stderr," -> no interface\n" );
812     *r_obj = NULL;
813     return E_NOINTERFACE;
814 }
815
816 static HRESULT WINAPI
817 m_GpgmeFactory_LockServer (IClassFactory *iface, BOOL dolock )
818 {
819     if (dolock) {
820         CoAddRefServerProcess ();
821     }
822     else {
823         ULONG count = CoReleaseServerProcess ();
824         if (!count && my_exit_event)
825             SetEvent (my_exit_event);
826     }
827     return 0;
828 }
829
830 static ICOM_VTABLE(IClassFactory) igpgme_factory_vtbl = {
831     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
832     m_GpgmeFactory_QueryInterface,
833     m_GpgmeFactory_AddRef,
834     m_GpgmeFactory_Release,
835     m_GpgmeFactory_CreateInstance,
836     m_GpgmeFactory_LockServer
837 };
838 static IClassFactoryImpl igpgme_CF = {&igpgme_factory_vtbl, 1 };
839
840 void
841 igpgme_register_exit_event (HANDLE ev)
842 {
843     my_exit_event = ev;
844 }
845
846
847 IClassFactory *
848 igpgme_factory_new ( CLSID *r_clsid )
849 {
850     *r_clsid = CLSID_Gpgme;
851     IClassFactory_AddRef((IClassFactory*)&igpgme_CF);
852     return (IClassFactory*)&igpgme_CF;
853 }
854
855 void
856 igpgme_factory_release ( IClassFactory *factory )
857 {
858     /* it's static - nothing to do */
859 }