860 lines
23 KiB
C
860 lines
23 KiB
C
/* igpgme.c - COM+ class IGpgme
|
|
* Copyright (C) 2001 g10 Code GmbH
|
|
*
|
|
* This file is part of GPGME.
|
|
*
|
|
* GPGME is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GPGME is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
*/
|
|
|
|
|
|
#include <config.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include <windows.h>
|
|
|
|
#include "../gpgme/gpgme.h"
|
|
|
|
/* FIXME: Put them into an extra header */
|
|
void *_gpgme_malloc (size_t n );
|
|
void *_gpgme_calloc (size_t n, size_t m );
|
|
void *_gpgme_realloc (void *p, size_t n);
|
|
char *_gpgme_strdup (const char *p);
|
|
void _gpgme_free ( void *a );
|
|
|
|
|
|
|
|
#define INITGUID
|
|
#include "igpgme.h"
|
|
|
|
/*
|
|
* Declare the interface implementation structures
|
|
*/
|
|
typedef struct IGpgmeImpl IGpgmeImpl;
|
|
typedef struct IClassFactoryImpl IClassFactoryImpl;
|
|
|
|
static HANDLE my_exit_event;
|
|
|
|
struct IGpgmeImpl {
|
|
/* IUnknown required stuff */
|
|
ICOM_VFIELD (IGpgme);
|
|
DWORD ref;
|
|
/* Delegation to IDispatch */
|
|
struct {
|
|
IUnknown *disp;
|
|
ITypeInfo *tinfo;
|
|
} std_disp;
|
|
/* Our stuff */
|
|
GpgmeCtx mainctx;
|
|
GpgmeData plaintext;
|
|
int plaintext_given_as_bstr;
|
|
GpgmeData ciphertext;
|
|
int ciphertext_is_armored;
|
|
GpgmeRecipients rset;
|
|
};
|
|
|
|
|
|
struct IClassFactoryImpl {
|
|
/* IUnknown fields */
|
|
ICOM_VFIELD(IClassFactory);
|
|
DWORD ref;
|
|
};
|
|
|
|
/**********************************************************
|
|
************** helper functions ************************
|
|
*********************************************************/
|
|
static HRESULT
|
|
map_gpgme_error (GpgmeError err)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!err)
|
|
return 0;
|
|
if ( err < 0 || err > 0x1000 ) {
|
|
fprintf (stderr,"*** GpgmeError `%s' mapped to GPGME_General_Error\n",
|
|
gpgme_strerror (err) );
|
|
err = GPGME_General_Error;
|
|
}
|
|
hr = MAKE_HRESULT (SEVERITY_ERROR, FACILITY_ITF, 0x1000 + err);
|
|
fprintf (stderr,"*** GpgmeError `%s' mapped to %lx\n",
|
|
gpgme_strerror (err), (unsigned long)hr );
|
|
return hr;
|
|
}
|
|
|
|
|
|
/**********************************************************
|
|
************** IGpgme Implementation *******************
|
|
*********************************************************/
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_QueryInterface (IGpgme *iface, REFIID refiid, LPVOID *obj)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
/*fprintf (stderr,"*** m_IGpgme_QueryInterface(%p,%s)",
|
|
This, debugstr_guid(refiid));*/
|
|
if ( IsEqualGUID (&IID_IUnknown, refiid)
|
|
|| IsEqualGUID (&IID_IGpgme, refiid) ) {
|
|
*obj = This;
|
|
IGpgme_AddRef (iface);
|
|
fprintf (stderr," -> got %p\n", *obj);
|
|
return 0;
|
|
}
|
|
else if ( IsEqualGUID (&IID_IDispatch, refiid) ) {
|
|
HRESULT hr = IDispatch_QueryInterface (This->std_disp.disp,
|
|
refiid, obj);
|
|
/*fprintf (stderr," -> delegated, hr=%lx, got %p\n",
|
|
hr, hr? NULL: *obj);*/
|
|
return hr;
|
|
}
|
|
/*fprintf (stderr," -> none\n");*/
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
static ULONG WINAPI
|
|
m_IGpgme_AddRef (IGpgme *iface)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
return ++This->ref;
|
|
}
|
|
|
|
|
|
static ULONG WINAPI
|
|
m_IGpgme_Release (IGpgme *iface)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
if (--This->ref)
|
|
return This->ref;
|
|
|
|
gpgme_release (This->mainctx); This->mainctx = NULL;
|
|
gpgme_data_release (This->plaintext); This->plaintext = NULL;
|
|
gpgme_data_release (This->ciphertext); This->ciphertext = NULL;
|
|
gpgme_recipients_release (This->rset); This->rset = NULL;
|
|
if (This->std_disp.disp)
|
|
IDispatch_Release (This->std_disp.disp);
|
|
if (This->std_disp.tinfo)
|
|
ITypeInfo_Release (This->std_disp.tinfo);
|
|
HeapFree(GetProcessHeap(),0,iface);
|
|
{
|
|
ULONG count = CoReleaseServerProcess ();
|
|
if (!count && my_exit_event)
|
|
SetEvent (my_exit_event);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_stub_IDispatch_GetTypeInfoCount (IGpgme *iface, unsigned int *pctinfo)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_stub_IDispatch_GetTypeInfo (IGpgme *iface, UINT iTInfo,
|
|
LCID lcid, ITypeInfo **ppTInfo)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_stub_IDispatch_GetIDsOfNames (IGpgme *iface, REFIID riid,
|
|
LPOLESTR *rgszNames, UINT cNames,
|
|
LCID lcid, DISPID *rgDispId)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_stub_IDispatch_Invoke (IGpgme *iface, DISPID dispIdMember,
|
|
REFIID riid, LCID lcid, WORD wFlags,
|
|
DISPPARAMS *pDispParams, VARIANT *pVarResult,
|
|
EXCEPINFO *pExepInfo, UINT *puArgErr)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetVersion (IGpgme *iface, BSTR *retvat)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetEngineInfo (IGpgme *iface, BSTR *retval)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_Cancel (IGpgme *iface)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_SetArmor (IGpgme *iface, BOOL yes)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
gpgme_set_armor (This->mainctx, yes);
|
|
return 0;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetArmor (IGpgme *iface, BOOL *retval)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
*retval = gpgme_get_armor (This->mainctx);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_SetTextmode (IGpgme *iface, BOOL yes)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
gpgme_set_textmode (This->mainctx, yes);
|
|
return 0;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetTextmode (IGpgme *iface, BOOL *retval)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
*retval = gpgme_get_textmode (This->mainctx);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Put the data from VAL into a a Gpgme data object, which is passed by
|
|
* reference. Valid types of the Variant are: BSTR, SAFEARRAY of BYTE and
|
|
* SAFEARRAY of VARIANTS of signed or unsigned integers.
|
|
*/
|
|
static HRESULT WINAPI
|
|
set_data_from_variant (GpgmeData *data, VARIANT val, int *given_as_bstr)
|
|
{
|
|
GpgmeError err = 0;
|
|
HRESULT hr;
|
|
unsigned char *buf;
|
|
SAFEARRAY *array;
|
|
size_t len;
|
|
int i;
|
|
|
|
if ( val.vt == VT_BSTR) {
|
|
len = bstrtoutf8 (val.u.bstrVal, NULL, 0);
|
|
buf = _gpgme_malloc (len);
|
|
if (!buf)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (bstrtoutf8 (val.u.bstrVal, buf, len) < 0) {
|
|
fprintf (stderr,"problem with bstrtoutf8\n");
|
|
_gpgme_free (buf);
|
|
return E_FAIL;
|
|
}
|
|
|
|
#if 0
|
|
fprintf (stderr,"Got a BSTR (utf8):");
|
|
for (i=0; i < len; i++)
|
|
fprintf (stderr, " %0X", buf[i] );
|
|
putc ('\n', stderr);
|
|
#endif
|
|
gpgme_data_release (*data); *data = NULL;
|
|
err = gpgme_data_new_from_mem (data, buf, len, 0 /*no need to copy*/ );
|
|
if (!err && given_as_bstr)
|
|
*given_as_bstr = 1;
|
|
}
|
|
else if ( val.vt == (VT_ARRAY|VT_UI1)) {
|
|
array = val.u.parray;
|
|
|
|
/*fprintf (stderr,"Got an ARRAY of bytes:");*/
|
|
hr = SafeArrayAccessData (array, (void**)&buf);
|
|
if (hr) {
|
|
fprintf (stderr,"*** SafeArrayAccessData failed: hr=%lx\n", hr);
|
|
return hr;
|
|
}
|
|
len = array->rgsabound[0].cElements;
|
|
/*for (i=0; i < len; i++)
|
|
fprintf (stderr, " %0X", buf[i] );
|
|
putc ('\n', stderr);*/
|
|
|
|
gpgme_data_release (*data); *data = NULL;
|
|
err = gpgme_data_new_from_mem (data, buf, len, 1 );
|
|
SafeArrayUnaccessData (array);
|
|
if (given_as_bstr)
|
|
*given_as_bstr = 0;
|
|
}
|
|
else if ( val.vt == (VT_ARRAY|VT_VARIANT)) {
|
|
VARIANT *vp;
|
|
array = val.u.parray;
|
|
|
|
/*fprintf (stderr,"Got an ARRAY of VARIANTS:");*/
|
|
hr = SafeArrayAccessData (array, (void**)&vp);
|
|
if (hr) {
|
|
fprintf (stderr,"*** SafeArrayAccessData failed: hr=%lx\n", hr);
|
|
return hr;
|
|
}
|
|
len = array->rgsabound[0].cElements;
|
|
/* allocate the array using the gpgme allocator so that we can
|
|
* later use a new without the copy set*/
|
|
buf = _gpgme_malloc (len);
|
|
if (!buf) {
|
|
SafeArrayUnaccessData (array);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
/* coerce all array elements into rawtext */
|
|
for (i=0; i < len; i++) {
|
|
switch (vp[i].vt) {
|
|
case VT_I1: buf[i] = (BYTE)vp[i].u.cVal; break;
|
|
case VT_I2: buf[i] = ((UINT)vp[i].u.iVal) & 0xff; break;
|
|
case VT_I4: buf[i] = ((ULONG)vp[i].u.lVal) & 0xff; break;
|
|
case VT_INT: buf[i] = ((UINT)vp[i].u.intVal) & 0xff; break;
|
|
case VT_UI1: buf[i] = vp[i].u.bVal; break;
|
|
case VT_UI2: buf[i] = vp[i].u.uiVal & 0xff; break;
|
|
case VT_UI4: buf[i] = vp[i].u.ulVal & 0xff; break;
|
|
case VT_UINT: buf[i] = vp[i].u.uintVal & 0xff; break;
|
|
default:
|
|
fprintf (stderr, "Invalid value in array as pos %d\n", i);
|
|
_gpgme_free (buf);
|
|
SafeArrayUnaccessData (array);
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
/*for (i=0; i < len; i++)
|
|
fprintf (stderr, " %0X", buf[i] );
|
|
putc ('\n', stderr);*/
|
|
|
|
gpgme_data_release (*data); *data = NULL;
|
|
err = gpgme_data_new_from_mem (data, buf, len, 0);
|
|
SafeArrayUnaccessData (array);
|
|
if (given_as_bstr)
|
|
*given_as_bstr = 0;
|
|
}
|
|
else {
|
|
fprintf (stderr, "Got a variant type = %d (0x%x)\n",
|
|
(int)val.vt, (int)val.vt );
|
|
return E_INVALIDARG; /* not a safearray of bytes */
|
|
}
|
|
return map_gpgme_error (err);
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
set_data_to_variant (GpgmeData data, VARIANT *retval, int use_bstr)
|
|
{
|
|
GpgmeError err;
|
|
HRESULT hr;
|
|
SAFEARRAY *array;
|
|
char *p;
|
|
size_t nread, len;
|
|
int i;
|
|
|
|
/* Get some info on the data */
|
|
err = gpgme_data_rewind (data);
|
|
if (err ) {
|
|
fprintf (stderr, "*** gpgme_data_rewind failed: %d\n", err);
|
|
return map_gpgme_error (err);
|
|
}
|
|
err = gpgme_data_read (data, NULL, 0, &nread);
|
|
if (err && err != GPGME_EOF ) {
|
|
fprintf (stderr, "*** gpgme_data_read [length] failed: %d\n", err);
|
|
return map_gpgme_error (err);
|
|
}
|
|
len = nread; /*(eof returns a length of 0)*/
|
|
/*fprintf (stderr,"*** %d bytes are availabe\n", (int)len);*/
|
|
|
|
/* convert it to the target data type */
|
|
if (use_bstr) {
|
|
BSTR bs;
|
|
unsigned char *helpbuf;
|
|
|
|
/* It is easier to allocate some helper storage */
|
|
helpbuf = _gpgme_malloc (len);
|
|
if (!helpbuf)
|
|
return E_OUTOFMEMORY;
|
|
err = gpgme_data_read (data, helpbuf, len, &nread);
|
|
if (err ) {
|
|
_gpgme_free (helpbuf);
|
|
fprintf (stderr, "*** gpgme_data_read [data] failed: %d\n", err);
|
|
return map_gpgme_error (err);
|
|
}
|
|
|
|
bs = SysAllocStringLen (NULL, len+1);
|
|
if (!bs) {
|
|
_gpgme_free (helpbuf);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
for (i=0, p=helpbuf; i < len; i++, p++)
|
|
bs[i] = *p;
|
|
bs[i] = 0;
|
|
_gpgme_free (helpbuf);
|
|
|
|
/* Ready */
|
|
VariantInit (retval);
|
|
retval->vt = VT_BSTR;
|
|
retval->u.bstrVal = bs;
|
|
}
|
|
#if 0
|
|
else if (use_byte_array) {
|
|
array = SafeArrayCreateVector (VT_UI1, 0, len);
|
|
if (!array)
|
|
return E_OUTOFMEMORY;
|
|
|
|
p = NULL;
|
|
hr = SafeArrayAccessData (array, (void**)&p);
|
|
if (hr) {
|
|
fprintf (stderr,"*** SafeArrayAccessData failed: hr=%lx\n", hr);
|
|
SafeArrayDestroyData (array);
|
|
SafeArrayDestroy (array);
|
|
return hr;
|
|
}
|
|
if (len) {
|
|
err = gpgme_data_read (data, p, len, &nread);
|
|
if (err ) {
|
|
SafeArrayUnaccessData (array);
|
|
SafeArrayDestroyData (array);
|
|
SafeArrayDestroy (array);
|
|
fprintf (stderr, "*** gpgme_data_read [data] failed: %d\n",
|
|
err);
|
|
return map_gpgme_error (err);
|
|
}
|
|
}
|
|
SafeArrayUnaccessData (array);
|
|
|
|
/* pass the data to the caller */
|
|
VariantInit (retval);
|
|
retval->vt = (VT_ARRAY|VT_UI1);
|
|
retval->u.parray = array;
|
|
}
|
|
#endif
|
|
else { /* Create an array of variants of bytes */
|
|
VARIANT *v;
|
|
unsigned char *helpbuf;
|
|
|
|
/* It is easier to allocate some helper storage */
|
|
helpbuf = _gpgme_malloc (len);
|
|
if (!helpbuf)
|
|
return E_OUTOFMEMORY;
|
|
err = gpgme_data_read (data, helpbuf, len, &nread);
|
|
if (err ) {
|
|
_gpgme_free (helpbuf);
|
|
fprintf (stderr, "*** gpgme_data_read [data] failed: %d\n", err);
|
|
return map_gpgme_error (err);
|
|
}
|
|
|
|
/* The create the array */
|
|
array = SafeArrayCreateVector (VT_VARIANT, 0, len);
|
|
if (!array) {
|
|
_gpgme_free (helpbuf);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
v = NULL;
|
|
hr = SafeArrayAccessData (array, (void**)&v);
|
|
if (hr) {
|
|
fprintf (stderr,"*** SafeArrayAccessData failed: hr=%lx\n", hr);
|
|
_gpgme_free (helpbuf);
|
|
SafeArrayDestroyData (array);
|
|
SafeArrayDestroy (array);
|
|
return hr;
|
|
}
|
|
|
|
for (p=helpbuf; len; len--, v++) {
|
|
VariantInit (v);
|
|
v->vt = VT_UI1;
|
|
v->u.bVal = *p;
|
|
}
|
|
SafeArrayUnaccessData (array);
|
|
_gpgme_free (helpbuf);
|
|
|
|
/* pass the data to the caller */
|
|
VariantInit (retval);
|
|
retval->vt = (VT_ARRAY|VT_VARIANT);
|
|
retval->u.parray = array;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_SetPlaintext (IGpgme *iface, VARIANT val)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
return set_data_from_variant (&This->plaintext, val,
|
|
&This->plaintext_given_as_bstr);
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetPlaintext (IGpgme *iface, VARIANT *retval)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
/*fprintf (stderr,"*** " __PRETTY_FUNCTION__ "(%p)\n", This );*/
|
|
return set_data_to_variant (This->plaintext, retval,
|
|
This->plaintext_given_as_bstr);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_SetCiphertext (IGpgme *iface, VARIANT val)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
return set_data_from_variant (&This->ciphertext, val, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetCiphertext (IGpgme *iface, VARIANT *retval)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
return set_data_to_variant (This->ciphertext, retval,
|
|
This->ciphertext_is_armored);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_ClearRecipients (IGpgme *iface)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
gpgme_recipients_release (This->rset); This->rset = NULL;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_AddRecipient (IGpgme *iface, BSTR name, signed short int trust)
|
|
{
|
|
GpgmeError err;
|
|
int n;
|
|
char *p;
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
/*fprintf (stderr,"*** " __PRETTY_FUNCTION__ "(%p, %d)\n",
|
|
This, (int)trust);*/
|
|
if (!This->rset) {
|
|
err = gpgme_recipients_new (&This->rset);
|
|
if (err)
|
|
return map_gpgme_error (err);
|
|
}
|
|
|
|
n = bstrtoutf8 (name, NULL, 0);
|
|
p = HeapAlloc (GetProcessHeap(), 0, n );
|
|
if (!p) {
|
|
fprintf (stderr,"HeapAlloc failed: ec=%d\n", (int)GetLastError () );
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if (bstrtoutf8 (name, p, n) < 0) {
|
|
fprintf (stderr,"problem with bstrtoutf8\n");
|
|
HeapFree (GetProcessHeap(), 0, p);
|
|
return E_FAIL;
|
|
}
|
|
err = gpgme_recipients_add_name (This->rset, p);
|
|
HeapFree (GetProcessHeap(), 0, p);
|
|
return map_gpgme_error (err);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_ResetSignKeys (IGpgme *iface)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_AddSignKey (IGpgme *iface, BSTR name)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_Encrypt (IGpgme *iface)
|
|
{
|
|
GpgmeError err;
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
gpgme_data_release (This->ciphertext);
|
|
err = gpgme_data_new (&This->ciphertext);
|
|
if (err)
|
|
return map_gpgme_error (err);
|
|
|
|
|
|
This->ciphertext_is_armored = gpgme_get_armor (This->mainctx);
|
|
err = gpgme_op_encrypt (This->mainctx, This->rset,
|
|
This->plaintext, This->ciphertext);
|
|
#if 0
|
|
if (!err ) {
|
|
char buf[100];
|
|
size_t nread;
|
|
|
|
err = gpgme_data_rewind ( This->ciphertext );
|
|
if (err )
|
|
fprintf (stderr, "*** gpgme_data_rewind failed: %d\n", err);
|
|
while ( !(err = gpgme_data_read ( This->ciphertext,
|
|
buf, 100, &nread )) ) {
|
|
fwrite ( buf, nread, 1, stderr );
|
|
}
|
|
if (err != GPGME_EOF)
|
|
fprintf (stderr, "*** gpgme_data_read failed: %d\n", err);
|
|
err = 0;
|
|
}
|
|
#endif
|
|
|
|
return map_gpgme_error (err);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_Sign (IGpgme *iface, short int signmode)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
fprintf (stderr,"*** " __PRETTY_FUNCTION__ "(%p)\n", This );
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_SignEncrypt (IGpgme *iface, short int signmode)
|
|
{
|
|
ICOM_THIS (IGpgmeImpl,iface);
|
|
|
|
fprintf (stderr,"*** " __PRETTY_FUNCTION__ "(%p)\n", This );
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
#if 0
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetSigStatus(GpgmeCtx c, int idx,
|
|
GpgmeSigStat *r_stat, time_t *r_created );
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetSigKey (GpgmeCtx c, int idx, GpgmeKey *r_key);
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_IGpgme_GetNotation(IGpgme *c, BSTR *retval)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
static ICOM_VTABLE(IGpgme) igpgme_vtbl =
|
|
{
|
|
/* IUnknown methods */
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
m_IGpgme_QueryInterface,
|
|
m_IGpgme_AddRef,
|
|
m_IGpgme_Release,
|
|
/* IDispatch methods */
|
|
m_stub_IDispatch_GetTypeInfoCount,
|
|
m_stub_IDispatch_GetTypeInfo,
|
|
m_stub_IDispatch_GetIDsOfNames,
|
|
m_stub_IDispatch_Invoke,
|
|
/* Our methods */
|
|
m_IGpgme_GetVersion,
|
|
m_IGpgme_GetEngineInfo,
|
|
m_IGpgme_Cancel,
|
|
m_IGpgme_SetArmor,
|
|
m_IGpgme_GetArmor,
|
|
m_IGpgme_SetTextmode,
|
|
m_IGpgme_GetTextmode,
|
|
m_IGpgme_SetPlaintext,
|
|
m_IGpgme_GetPlaintext,
|
|
m_IGpgme_SetCiphertext,
|
|
m_IGpgme_GetCiphertext,
|
|
m_IGpgme_ClearRecipients,
|
|
m_IGpgme_AddRecipient,
|
|
m_IGpgme_ResetSignKeys,
|
|
m_IGpgme_AddSignKey,
|
|
m_IGpgme_Encrypt,
|
|
m_IGpgme_Sign,
|
|
m_IGpgme_SignEncrypt
|
|
};
|
|
|
|
|
|
|
|
/***************************************************************
|
|
****************** Gpgme Factory ****************************
|
|
***************************************************************/
|
|
|
|
static HRESULT WINAPI
|
|
m_GpgmeFactory_QueryInterface (IClassFactory *iface,
|
|
REFIID refiid, LPVOID *obj)
|
|
{
|
|
ICOM_THIS (IClassFactoryImpl,iface);
|
|
|
|
/*fprintf (stderr,"*** m_GpgmeFactory_QueryInterface(%p,%s)",
|
|
This, debugstr_guid(refiid));*/
|
|
if ( IsEqualGUID (&IID_IUnknown, refiid)
|
|
|| IsEqualGUID (&IID_IClassFactory, refiid) ) {
|
|
*obj = This;
|
|
/*fprintf (stderr," -> got %p\n", obj);*/
|
|
return 0;
|
|
}
|
|
*obj = NULL;
|
|
/*fprintf (stderr," -> none\n");*/
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
m_GpgmeFactory_AddRef (IClassFactory *iface)
|
|
{
|
|
ICOM_THIS(IClassFactoryImpl,iface);
|
|
return ++(This->ref);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
m_GpgmeFactory_Release (IClassFactory *iface)
|
|
{
|
|
ICOM_THIS(IClassFactoryImpl,iface);
|
|
return --(This->ref);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_GpgmeFactory_CreateInstance (IClassFactory *iface, IUnknown *outer,
|
|
REFIID refiid, LPVOID *r_obj )
|
|
{
|
|
/*ICOM_THIS(IClassFactoryImpl,iface);*/
|
|
|
|
fprintf (stderr,"*** m_GpgmeFactory_CreateInstance(%s)",
|
|
debugstr_guid(refiid) );
|
|
if ( IsEqualGUID (&IID_IUnknown, refiid)
|
|
|| IsEqualGUID (&IID_IGpgme, refiid) ) {
|
|
IGpgmeImpl *obj;
|
|
GpgmeCtx ctx;
|
|
GpgmeError err;
|
|
|
|
|
|
err = gpgme_new (&ctx);
|
|
if (err) {
|
|
fprintf (stderr," -> gpgme_new failed: %s\n", gpgme_strerror (err));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
obj = HeapAlloc (GetProcessHeap(), 0, sizeof *obj );
|
|
if ( !obj) {
|
|
fprintf (stderr," -> out of core\n");
|
|
gpgme_release (ctx);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
memset (obj, 0, sizeof *obj);
|
|
|
|
ICOM_VTBL(obj) = &igpgme_vtbl;
|
|
obj->ref = 1;
|
|
obj->mainctx = ctx;
|
|
{ /* Fixme: need to release some stuff on error */
|
|
HRESULT hr;
|
|
ITypeLib *pTypeLib;
|
|
|
|
hr = LoadRegTypeLib (&TLBID_Gpgcom, 1, 0, LANG_NEUTRAL, &pTypeLib);
|
|
if (hr) {
|
|
fprintf (stderr," -> LoadRegTypeLib failed: %lx\n", hr);
|
|
return hr;
|
|
}
|
|
hr = ITypeLib_GetTypeInfoOfGuid (pTypeLib, &IID_IGpgme,
|
|
&obj->std_disp.tinfo);
|
|
ITypeLib_Release (pTypeLib);
|
|
if (hr) {
|
|
fprintf (stderr," -> GetTypeInfoOfGuid failed: %lx\n", hr);
|
|
return hr;
|
|
}
|
|
hr = CreateStdDispatch ((IUnknown*)obj, obj, obj->std_disp.tinfo,
|
|
&obj->std_disp.disp);
|
|
if (hr) {
|
|
fprintf (stderr," -> CreateStdDispatch failed: %lx\n", hr);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
CoAddRefServerProcess ();
|
|
*r_obj = obj;
|
|
fprintf (stderr," -> created %p\n", obj );
|
|
return 0;
|
|
}
|
|
fprintf (stderr," -> no interface\n" );
|
|
*r_obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
m_GpgmeFactory_LockServer (IClassFactory *iface, BOOL dolock )
|
|
{
|
|
if (dolock) {
|
|
CoAddRefServerProcess ();
|
|
}
|
|
else {
|
|
ULONG count = CoReleaseServerProcess ();
|
|
if (!count && my_exit_event)
|
|
SetEvent (my_exit_event);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static ICOM_VTABLE(IClassFactory) igpgme_factory_vtbl = {
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
m_GpgmeFactory_QueryInterface,
|
|
m_GpgmeFactory_AddRef,
|
|
m_GpgmeFactory_Release,
|
|
m_GpgmeFactory_CreateInstance,
|
|
m_GpgmeFactory_LockServer
|
|
};
|
|
static IClassFactoryImpl igpgme_CF = {&igpgme_factory_vtbl, 1 };
|
|
|
|
void
|
|
igpgme_register_exit_event (HANDLE ev)
|
|
{
|
|
my_exit_event = ev;
|
|
}
|
|
|
|
|
|
IClassFactory *
|
|
igpgme_factory_new ( CLSID *r_clsid )
|
|
{
|
|
*r_clsid = CLSID_Gpgme;
|
|
IClassFactory_AddRef((IClassFactory*)&igpgme_CF);
|
|
return (IClassFactory*)&igpgme_CF;
|
|
}
|
|
|
|
void
|
|
igpgme_factory_release ( IClassFactory *factory )
|
|
{
|
|
/* it's static - nothing to do */
|
|
}
|