/* gpgme_n.c
   Copyright (C) 2003 Daiki Ueno

This file is a part of Ruby-GPGME.

This program 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, or (at your option)  
any later version.                                                   

This program 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 GNU Emacs; see the file COPYING.  If not, write to the    
Free Software Foundation, Inc., 59 Temple Place - Suite 330,         
Boston, MA 02111-1307, USA.  */

/* This module provides low level interface to the GPGME library.
   There is simple strategy for defining ruby API binding, though this
   module was written entirely by hand.

1. Each symbol exported from this module is one of a class, a module
   function, and a constant.  No instance methods are defined.
2. Each symbol exported from this module follows the same naming
   convention of the library API.  That is, symbol names are followed
   by `gpgme_' for functions and are followed by `GPGME_' for
   constants.
3. Output arguments should have to be wrapped.  For example, the 4th
   argument of `gpgme_data_read' has type `size_t *' to store the amount
   read.  The corresponding ruby interface accepts an empty array for
   this purpose.  */

#include "ruby.h"
#include "gpgme.h"

/* StringValuePtr is not available in 1.6. */
#ifndef StringValuePtr
#define StringValuePtr(str) RSTRING(str)->ptr
#endif

/* STR2CSTR is obsoleted in 1.8. */
#ifndef StringValueCStr
#define StringValueCStr STR2CSTR
#endif

#define WRAP_GPGME_DATA(dh)					\
  Data_Wrap_Struct(cGpgmeData, 0, gpgme_data_release, dh)
/* `GpgmeData' is typedef'ed as `struct gpgme_data_s *'. */
#define UNWRAP_GPGME_DATA(vdh, dh)			\
  Data_Get_Struct(vdh, struct gpgme_data_s, dh);

#define WRAP_GPGME_CTX(ctx)				\
  Data_Wrap_Struct(cGpgmeCtx, 0, gpgme_release, ctx)
/* `GpgmeCtx' is typedef'ed as `struct gpgme_context_s *'. */
#define UNWRAP_GPGME_CTX(vctx, ctx)			\
  Data_Get_Struct(vctx, struct gpgme_context_s, ctx)

#define WRAP_GPGME_KEY(key)					\
  Data_Wrap_Struct(cGpgmeKey, 0, gpgme_key_release, key)
/* `GpgmeKey' is typedef'ed as `struct gpgme_key_s *'. */
#define UNWRAP_GPGME_KEY(vkey, key)			\
  Data_Get_Struct(vkey, struct gpgme_key_s, key)

#define WRAP_GPGME_RECIPIENTS(recipients)				\
  Data_Wrap_Struct(cGpgmeRecipients, 0, gpgme_recipients_release, rset)
/* `GpgmeRecipients' is typedef'ed as `struct gpgme_recipients_s *'. */
#define UNWRAP_GPGME_RECIPIENTS(vrecipients, recipients)		\
  Data_Get_Struct(vrecipients, struct gpgme_recipients_s, recipients)

#define WRAP_GPGME_TRUST_ITEM(item)					\
  Data_Wrap_Struct(cGpgmeTrustItem, 0, gpgme_trust_item_release, item)
/* `GpgmeTrustItem' is typedef'ed as `struct gpgme_trust_item_s *'. */
#define UNWRAP_GPGME_TRUST_ITEM(vitem, item)			\
  Data_Get_Struct(vitem, struct gpgme_trust_item_s, item)

static VALUE cGpgmeCtx,
  cGpgmeData,
  cGpgmeRecipients,
  cGpgmeKey,
  cGpgmeTrustItem;

static VALUE
rb_s_gpgme_check_version (dummy, vreq)
     VALUE dummy, vreq;
{
  const char *result = gpgme_check_version (NIL_P(vreq) ? NULL :
					    StringValueCStr(vreq));
  return result ? rb_str_new2 (result) : Qnil;
}

static VALUE
rb_s_gpgme_engine_check_version (dummy, vproto)
     VALUE dummy, vproto;
{
  int err = gpgme_engine_check_version (NUM2INT(vproto));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_get_engine_info (dummy)
     VALUE dummy;
{
  return rb_str_new2 (gpgme_get_engine_info ());
}

static VALUE
rb_s_gpgme_strerror (dummy, verr)
     VALUE dummy, verr;
{
  return rb_str_new2 (gpgme_strerror (NUM2INT(verr)));
}

static VALUE
rb_s_gpgme_data_new (dummy, rdh)
     VALUE dummy, rdh;
{
  GpgmeData dh;
  int err = gpgme_data_new (&dh);

  if (err == GPGME_No_Error)
    rb_ary_push (rdh, WRAP_GPGME_DATA(dh));
  return INT2NUM(err);
}  

static VALUE
rb_s_gpgme_data_new_from_mem (dummy, rdh, vbuffer, vsize, vcopy)
     VALUE dummy, rdh, vbuffer, vsize, vcopy;
{
  GpgmeData dh;
  VALUE vdh;
  size_t size = NUM2UINT(vsize);
  int err;

  if (RSTRING(vbuffer)->len < size)
    rb_raise (rb_eArgError, "argument out of range");

  rb_str_modify (vbuffer);
  err = gpgme_data_new_from_mem (&dh, StringValuePtr(vbuffer), size,
				 NUM2INT(vcopy));
  if (err == GPGME_No_Error)
    {
      vdh = WRAP_GPGME_DATA(dh);
      /* Keep a references to VBUFFER to avoid GC. */
      rb_iv_set (vdh, "@buffer", vbuffer);
      rb_ary_push (rdh, vdh);
    }
  return INT2NUM(err);
}  

static VALUE
rb_s_gpgme_data_new_from_file (dummy, rdh, vfilename, vcopy)
     VALUE dummy, rdh, vfilename, vcopy;
{
  GpgmeData dh;
  int err = gpgme_data_new_from_file (&dh, StringValueCStr(vfilename),
				      NUM2INT(vcopy));
  if (err == GPGME_No_Error)
    rb_ary_push (rdh, WRAP_GPGME_DATA(dh));
  return INT2NUM(err);
}

static int
read_cb (hook, buffer, count, nread)
     void *hook;
     char *buffer;
     size_t count, *nread;
{
  VALUE vcb = (VALUE)hook, vreadfunc, vhook_value, vbuffer, rnread;

  vreadfunc = RARRAY(vcb)->ptr[0];
  vhook_value = RARRAY(vcb)->ptr[1];
  vbuffer = rb_str_new (buffer, count);
  rnread = rb_ary_new ();

  rb_funcall (vreadfunc, rb_intern ("call"), 4,
	      vhook_value, vbuffer, INT2NUM(count), rnread);
  if (RARRAY(rnread)->len < 1)
    rb_raise (rb_eRuntimeError,
	      "can't determine the number of bytes actually read");
  *nread = RARRAY(rnread)->ptr[0];
  memcpy (buffer, StringValuePtr(vbuffer), *nread);
  return *nread;
}

static VALUE
rb_s_gpgme_data_new_with_read_cb (dummy, rdh, vreadfunc, vhook_value)
     VALUE dummy, rdh, vreadfunc, vhook_value;
{
  GpgmeData dh;
  VALUE vdh, vcb = rb_ary_new ();
  int err;

  rb_ary_push (vcb, vreadfunc);
  rb_ary_push (vcb, vhook_value);

  err = gpgme_data_new_with_read_cb (&dh, read_cb, (void*)vcb);
  if (err == GPGME_No_Error)
    {
      vdh = WRAP_GPGME_DATA(dh);
      /* Keep a references to avoid GC. */
      rb_iv_set (vdh, "@read_cb", vcb);
      rb_ary_push (rdh, vdh);
    }
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_data_release (dummy, vdh)
     VALUE dummy, vdh;
{
  GpgmeData dh;

  UNWRAP_GPGME_DATA(vdh, dh);
  if (!dh)
    rb_raise (rb_eRuntimeError,
      "GpgmeData has already been released.");
  gpgme_data_release (dh);
  DATA_PTR(vdh) = NULL;
  return Qnil;
}

static VALUE
rb_s_gpgme_data_release_and_get_mem (dummy, vdh, rlength)
     VALUE dummy, vdh, rlength;
{
  GpgmeData dh;
  char *buffer;
  VALUE vbuffer;
  size_t length;

  UNWRAP_GPGME_DATA(vdh, dh);
  if (!dh)
    rb_raise (rb_eRuntimeError,
      "GpgmeData has already been released.");
  buffer = gpgme_data_release_and_get_mem (dh, &length);
  DATA_PTR(vdh) = NULL;
  if (buffer == NULL)
    return Qnil;
  vbuffer = rb_str_new (buffer, length);
  free (buffer);
  rb_ary_push (rlength, UINT2NUM(length));
  return vbuffer;
}

static VALUE
rb_s_gpgme_data_read (dummy, vdh, rbuffer, vlength, rnread)
     VALUE dummy, vdh, rbuffer, vlength, rnread;
{
  GpgmeData dh;
  int err;
  size_t length = NUM2UINT(vlength), nread;

  if (!NIL_P(rbuffer))
    {
      if (RSTRING(rbuffer)->len < length)
	rb_raise (rb_eArgError, "argument out of range");
      rb_str_modify (rbuffer);
    }
  UNWRAP_GPGME_DATA(vdh, dh);
  err = gpgme_data_read (dh, NIL_P(rbuffer) ? NULL : StringValuePtr(rbuffer),
			 length, &nread);
  if (err == GPGME_No_Error)
    rb_ary_push (rnread, UINT2NUM(nread));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_data_rewind (dummy, vdh)
     VALUE dummy, vdh;
{
  GpgmeData dh;
  int err;

  UNWRAP_GPGME_DATA(vdh, dh);
  err = gpgme_data_rewind (dh);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_data_write (dummy, vdh, vbuf, vlen)
     VALUE dummy, vdh, vbuf, vlen;
{
  GpgmeData dh;
  int err;

  UNWRAP_GPGME_DATA(vdh, dh);
  err = gpgme_data_write (dh, StringValuePtr(vbuf), NUM2UINT(vlen));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_data_get_type (dummy, vdh)
     VALUE dummy, vdh;
{
  GpgmeData dh;
  int err;

  UNWRAP_GPGME_DATA(vdh, dh);
  err = gpgme_data_get_type (dh);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_data_get_encoding (dummy, vdh)
     VALUE dummy, vdh;
{
  GpgmeData dh;
  int err;

  UNWRAP_GPGME_DATA(vdh, dh);
  err = gpgme_data_get_encoding (dh);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_data_set_encoding (dummy, vdh, venc)
     VALUE dummy, vdh, venc;
{
  GpgmeData dh;
  int err;

  UNWRAP_GPGME_DATA(vdh, dh);
  err = gpgme_data_set_encoding (dh, NUM2INT(venc));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_new (dummy, rctx)
     VALUE dummy, rctx;
{
  GpgmeCtx ctx;
  int err = gpgme_new (&ctx);

  if (err == GPGME_No_Error)
    rb_ary_push (rctx, WRAP_GPGME_CTX(ctx));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_release (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;

  UNWRAP_GPGME_CTX(vctx, ctx);
  if (!ctx)
    rb_raise (rb_eRuntimeError,
      "GpgmeCtx has already been released.");
  gpgme_release (ctx);
  DATA_PTR(vctx) = NULL;
  return Qnil;
}

static VALUE
rb_s_gpgme_set_protocol (dummy, vctx, vproto)
     VALUE dummy, vctx, vproto;
{
  GpgmeCtx ctx;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_set_protocol (ctx, NUM2INT(vproto));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_get_protocol (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  GpgmeProtocol proto;

  UNWRAP_GPGME_CTX(vctx, ctx);
  proto = gpgme_get_protocol (ctx);
  return INT2NUM(proto);
}

static VALUE
rb_s_gpgme_set_armor (dummy, vctx, vyes)
     VALUE dummy, vctx, vyes;
{
  GpgmeCtx ctx;

  UNWRAP_GPGME_CTX(vctx, ctx);
  gpgme_set_armor (ctx, NUM2INT(vyes));

  return Qnil;
}

static VALUE
rb_s_gpgme_get_armor (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  int yes;

  UNWRAP_GPGME_CTX(vctx, ctx);
  yes = gpgme_get_armor (ctx);
  return INT2NUM(yes);
}

static VALUE
rb_s_gpgme_set_textmode (dummy, vctx, vyes)
     VALUE dummy, vctx, vyes;
{
  GpgmeCtx ctx;

  UNWRAP_GPGME_CTX(vctx, ctx);
  gpgme_set_textmode (ctx, NUM2INT(vyes));
  return Qnil;
}     

static VALUE
rb_s_gpgme_get_textmode (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  int yes;

  UNWRAP_GPGME_CTX(vctx, ctx);
  yes = gpgme_get_textmode (ctx);
  return INT2NUM(yes);
}     

static VALUE
rb_s_gpgme_set_include_certs (dummy, vctx, vnr_of_certs)
     VALUE dummy, vctx, vnr_of_certs;
{
  GpgmeCtx ctx;

  UNWRAP_GPGME_CTX(vctx, ctx);
  gpgme_set_include_certs (ctx, NUM2INT(vnr_of_certs));
  return Qnil;
}

static VALUE
rb_s_gpgme_get_include_certs (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_get_include_certs (ctx);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_set_keylist_mode (dummy, vctx, vmode)
     VALUE dummy, vctx, vmode;
{
  GpgmeCtx ctx;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_set_keylist_mode (ctx, NUM2INT(vmode));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_get_keylist_mode (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  int mode;

  UNWRAP_GPGME_CTX(vctx, ctx);
  mode = gpgme_get_keylist_mode (ctx);
  return INT2NUM(mode);
}

static const char *
passphrase_cb (hook, desc, r_hd)
     void *hook, **r_hd;
     const char *desc;
{
  VALUE vcb = (VALUE)hook, vpassfunc, vhook_value, vr_hd;

  vpassfunc = RARRAY(vcb)->ptr[0];
  vhook_value = RARRAY(vcb)->ptr[1];

  if (!*r_hd)
    *r_hd = (void*)rb_ary_new ();
  vr_hd = (VALUE)*r_hd;

  /* If DESC is not `NULL', the function should return a passphrase
     for the context. */
  if (desc)
    {
      VALUE vpassphrase = rb_funcall (vpassfunc, rb_intern ("call"), 3,
				      vhook_value, rb_str_new2 (desc), vr_hd);
      return StringValueCStr(vpassphrase);
    }

  /* If DESC is `NULL', GPGME would requests the passphrase is no
     longer needed. */
  rb_funcall (vpassfunc, rb_intern ("call"), 3, vhook_value, Qnil, vr_hd);
  return NULL;
}

static VALUE
rb_s_gpgme_set_passphrase_cb (dummy, vctx, vpassfunc, vhook_value)
     VALUE dummy, vctx, vpassfunc, vhook_value;
{
  GpgmeCtx ctx;
  VALUE vcb = rb_ary_new ();

  rb_ary_push (vcb, vpassfunc);
  rb_ary_push (vcb, vhook_value);
  /* Keep a references to avoid GC. */
  rb_iv_set (vctx, "@passphrase_cb", vcb);

  UNWRAP_GPGME_CTX(vctx, ctx);
  gpgme_set_passphrase_cb (ctx, passphrase_cb, (void*)vcb);
  return Qnil;
}

static VALUE
rb_s_gpgme_get_passphrase_cb (dummy, vctx, rpassfunc, rhook_value)
     VALUE dummy, vctx, rpassfunc, rhook_value;
{
  VALUE vcb = rb_iv_get (vctx, "@passphrase_cb");

  /* No need to call gpgme_get_passphrase_cb. */
  rb_ary_push (rpassfunc, RARRAY(vcb)->ptr[0]);
  rb_ary_push (rhook_value, RARRAY(vcb)->ptr[1]);
  return Qnil;
}

static void
progress_cb (hook, what, type, current, total)
     void *hook;
     const char *what;
     int type, current, total;
{
  VALUE vcb = (VALUE)hook, vprogfunc, vhook_value;

  vprogfunc = RARRAY(vcb)->ptr[0];
  vhook_value = RARRAY(vcb)->ptr[1];

  rb_funcall (vprogfunc, rb_intern ("call"), 5, vhook_value, INT2NUM(type),
	      INT2NUM(current), INT2NUM(total));
}

static VALUE
rb_s_gpgme_set_progress_cb (dummy, vctx, vprogfunc, vhook_value)
     VALUE dummy, vctx, vprogfunc, vhook_value;
{
  GpgmeCtx ctx;
  VALUE vcb = rb_ary_new ();

  rb_ary_push (vcb, vprogfunc);
  rb_ary_push (vcb, vhook_value);
  /* Keep a references to avoid GC. */
  rb_iv_set (vctx, "@progress_cb", vcb);

  UNWRAP_GPGME_CTX(vctx, ctx);
  gpgme_set_progress_cb (ctx, progress_cb, (void*)vctx);

  return Qnil;
}

static VALUE
rb_s_gpgme_get_progress_cb (dummy, vctx, rprogfunc, rhook_value)
     VALUE dummy, vctx, rprogfunc, rhook_value;
{
  VALUE vcb = rb_iv_get (vctx, "@progress_cb");
  rb_ary_push (rprogfunc, RARRAY(vcb)->ptr[0]);
  rb_ary_push (rhook_value, RARRAY(vcb)->ptr[1]);
  return Qnil;
}

static VALUE
rb_s_gpgme_op_keylist_start (dummy, vctx, vpattern, vsecret_only)
     VALUE dummy, vctx, vpattern, vsecret_only;
{
  GpgmeCtx ctx;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_op_keylist_start (ctx, NIL_P(vpattern) ? NULL :
				StringValueCStr(vpattern),
				NUM2INT(vsecret_only));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_keylist_ext_start (dummy, vctx, vpattern, vsecret_only)
     VALUE dummy, vctx, vpattern, vsecret_only;
{
  GpgmeCtx ctx;
  const char **pattern = NULL;
  int i, err;

  UNWRAP_GPGME_CTX(vctx, ctx);

  if (!NIL_P(vpattern))
    {
      /* Convert RARRAY into `const char *' array. */
      pattern = (const char **)ALLOCA_N(const char *,
					RARRAY(vpattern)->len + 1);
      for (i = 0; i<RARRAY(vpattern)->len; i++)
	pattern[i] = StringValueCStr(RARRAY(vpattern)->ptr[i]);
      pattern[RARRAY(vpattern)->len] = NULL;
    }

  err = gpgme_op_keylist_ext_start (ctx, pattern, NUM2INT(vsecret_only), 0);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_keylist_next (dummy, vctx, rkey)
     VALUE dummy, vctx, rkey;
{
  GpgmeCtx ctx;
  GpgmeKey key;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_op_keylist_next (ctx, &key);
  if (err == GPGME_No_Error)
    rb_ary_push (rkey, WRAP_GPGME_KEY(key));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_keylist_end (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_op_keylist_end (ctx);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_key_get_as_xml (dummy, vkey)
     VALUE dummy, vkey;
{
  GpgmeKey key;
  const char *xml;

  UNWRAP_GPGME_KEY(vkey, key);
  xml = gpgme_key_get_as_xml (key);
  if (!xml)
    return Qnil;
  return rb_str_new2 (xml);
}

static VALUE
rb_s_gpgme_key_get_string_attr (dummy, vkey, vwhat, vidx)
     VALUE dummy, vkey, vwhat, vidx;
{
  GpgmeKey key;
  const char *attr;

  UNWRAP_GPGME_KEY(vkey, key);
  attr = gpgme_key_get_string_attr (key, NUM2INT(vwhat), NULL, NUM2INT(vidx));
  if (!attr)
    return Qnil;
  return rb_str_new2 (attr);
}

static VALUE
rb_s_gpgme_key_get_ulong_attr (dummy, vkey, vwhat, vidx)
     VALUE dummy, vkey, vwhat, vidx;
{
  GpgmeKey key;
  unsigned long attr;

  UNWRAP_GPGME_KEY(vkey, key);
  attr = gpgme_key_get_ulong_attr (key, NUM2INT(vwhat), NULL,
				   NUM2INT(vidx));
  return ULONG2NUM(attr);
}

static VALUE
rb_s_gpgme_key_ref (dummy, vkey)
     VALUE dummy, vkey;
{
  GpgmeKey key;
  
  UNWRAP_GPGME_KEY(vkey, key);
  gpgme_key_ref (key);
  return Qnil;
}

static VALUE
rb_s_gpgme_key_unref (dummy, vkey)
     VALUE dummy, vkey;
{
  GpgmeKey key;

  UNWRAP_GPGME_KEY(vkey, key);
  gpgme_key_unref (key);
  return Qnil;
}

static VALUE
rb_s_gpgme_op_genkey (dummy, vctx, vparms, vpubkey, vseckey)
     VALUE dummy, vctx, vparms, vpubkey, vseckey;
{
  GpgmeCtx ctx;
  GpgmeData pubkey = NULL, seckey = NULL;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  if (!NIL_P(vpubkey))
    UNWRAP_GPGME_DATA(vpubkey, pubkey);
  if (!NIL_P(vseckey))
    UNWRAP_GPGME_DATA(vseckey, seckey);
  err = gpgme_op_genkey (ctx, StringValueCStr(vparms), pubkey, seckey);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_genkey_start (dummy, vctx, vparms, vpubkey, vseckey)
     VALUE dummy, vctx, vparms, vpubkey, vseckey;
{
  GpgmeCtx ctx;
  GpgmeData pubkey = NULL, seckey = NULL;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  if (!NIL_P(vpubkey))
    UNWRAP_GPGME_DATA(vpubkey, pubkey);
  if (!NIL_P(vseckey))
    UNWRAP_GPGME_DATA(vseckey, seckey);
  err = gpgme_op_genkey_start (ctx, StringValueCStr(vparms), pubkey, seckey);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_export (dummy, vctx, vrecipients, vkeydata)
     VALUE dummy, vctx, vrecipients, vkeydata;
{
  GpgmeCtx ctx;
  GpgmeRecipients recipients;
  GpgmeData keydata;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_RECIPIENTS(vrecipients, recipients);
  UNWRAP_GPGME_DATA(vkeydata, keydata);

  err = gpgme_op_export (ctx, recipients, keydata);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_export_start (dummy, vctx, vrecipients, vkeydata)
     VALUE dummy, vctx, vrecipients, vkeydata;
{
  GpgmeCtx ctx;
  GpgmeRecipients recipients;
  GpgmeData keydata;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_RECIPIENTS(vrecipients, recipients);
  UNWRAP_GPGME_DATA(vkeydata, keydata);

  err = gpgme_op_export_start (ctx, recipients, keydata);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_import (dummy, vctx, vkeydata)
     VALUE dummy, vctx, vkeydata;
{
  GpgmeCtx ctx;
  GpgmeData keydata;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vkeydata, keydata);

  err = gpgme_op_import (ctx, keydata);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_import_start (dummy, vctx, vkeydata)
     VALUE dummy, vctx, vkeydata;
{
  GpgmeCtx ctx;
  GpgmeData keydata;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vkeydata, keydata);

  err = gpgme_op_import_start (ctx, keydata);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_import_ext (dummy, vctx, vkeydata, rnr)
     VALUE dummy, vctx, vkeydata, rnr;
{
  GpgmeCtx ctx;
  GpgmeData keydata;
  int nr, err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vkeydata, keydata);

  err = gpgme_op_import_ext (ctx, keydata, &nr);
  if (err == GPGME_No_Error)
    rb_ary_push (rnr, INT2NUM(nr));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_delete (dummy, vctx, vkey, vallow_secret)
     VALUE dummy, vctx, vkey, vallow_secret;
{
  GpgmeCtx ctx;
  GpgmeKey key;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_KEY(vkey, key);

  err = gpgme_op_delete (ctx, key, NUM2INT(vallow_secret));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_delete_start (dummy, vctx, vkey, vallow_secret)
     VALUE dummy, vctx, vkey, vallow_secret;
{
  GpgmeCtx ctx;
  GpgmeKey key;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_KEY(vkey, key);

  err = gpgme_op_delete_start (ctx, key, NUM2INT(vallow_secret));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_trustlist_start (dummy, vctx, vpattern, vmax_level)
     VALUE dummy, vctx, vpattern, vmax_level;
{
  GpgmeCtx ctx;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_op_trustlist_start (ctx, StringValueCStr(vpattern),
				  NUM2INT(vmax_level));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_trustlist_next (dummy, vctx, ritem)
     VALUE dummy, vctx, ritem;
{
  GpgmeCtx ctx;
  GpgmeTrustItem item;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_op_trustlist_next (ctx, &item);
  if (err == GPGME_No_Error)
    rb_ary_push (ritem, WRAP_GPGME_TRUST_ITEM(item));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_trustlist_end (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_op_trustlist_end (ctx);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_trust_item_get_string_attr (dummy, vitem, vwhat, vidx)
     VALUE dummy, vitem, vwhat, vidx;
{
  GpgmeTrustItem item;
  const char *attr;

  UNWRAP_GPGME_TRUST_ITEM(vitem, item);
  attr = gpgme_trust_item_get_string_attr (item, NUM2INT(vwhat), NULL,
					   NUM2INT(vidx));
  if (!attr)
    return Qnil;
  return rb_str_new2 (attr);
}

static VALUE
rb_s_gpgme_trust_item_get_int_attr (dummy, vitem, vwhat, vidx)
     VALUE dummy, vitem, vwhat, vidx;
{
  GpgmeTrustItem item;
  int attr;

  UNWRAP_GPGME_TRUST_ITEM(vitem, item);
  attr = gpgme_trust_item_get_int_attr (item, NUM2INT(vwhat), NULL,
					NUM2INT(vidx));
  return INT2NUM(attr);
}

static VALUE
rb_s_gpgme_trust_item_release (dummy, vitem)
     VALUE dummy, vitem;
{
  GpgmeTrustItem item;

  UNWRAP_GPGME_TRUST_ITEM(vitem, item);
  if (!item)
    rb_raise (rb_eRuntimeError,
      "GpgmeTrustItem has already been released.");
  gpgme_trust_item_release (item);
  DATA_PTR(vitem) = NULL;
  return Qnil;
}

static VALUE
rb_s_gpgme_op_decrypt (dummy, vctx, vcipher, vplain)
     VALUE dummy, vctx, vcipher, vplain;
{
  GpgmeCtx ctx;
  GpgmeData cipher, plain;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vcipher, cipher);
  UNWRAP_GPGME_DATA(vplain, plain);

  err = gpgme_op_decrypt (ctx, cipher, plain);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_decrypt_start (dummy, vctx, vcipher, vplain)
     VALUE dummy, vctx, vcipher, vplain;
{
  GpgmeCtx ctx;
  GpgmeData cipher, plain;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vcipher, cipher);
  UNWRAP_GPGME_DATA(vplain, plain);

  err = gpgme_op_decrypt_start (ctx, cipher, plain);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_verify (dummy, vctx, vsig, vplain, rstat)
     VALUE dummy, vctx, vsig, vplain, rstat;
{
  GpgmeCtx ctx;
  GpgmeData sig, plain;
  GpgmeSigStat stat;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vsig, sig);
  UNWRAP_GPGME_DATA(vplain, plain);

  err = gpgme_op_verify (ctx, sig, plain, &stat);
  if (err == GPGME_No_Error)
    rb_ary_push (rstat, INT2NUM(stat));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_verify_start (dummy, vctx, vsig, vplain)
     VALUE dummy, vctx, vsig, vplain;
{
  GpgmeCtx ctx;
  GpgmeData sig, plain;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vsig, sig);
  UNWRAP_GPGME_DATA(vplain, plain);

  err = gpgme_op_verify_start (ctx, sig, plain);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_get_sig_status (dummy, vctx, vidx, rstat, rcreated)
     VALUE dummy, vctx, vidx, rstat, rcreated;
{
  GpgmeCtx ctx;
  GpgmeSigStat stat;
  time_t created;
  const char *fingerprint;

  UNWRAP_GPGME_CTX(vctx, ctx);
  fingerprint = gpgme_get_sig_status (ctx, NUM2INT(vidx), &stat, &created);
  if (!fingerprint)
    return Qnil;
  rb_ary_push (rstat, INT2NUM(stat));
  rb_ary_push (rcreated, rb_time_new (created, 0));
  return rb_str_new2 (fingerprint);
}

static VALUE
rb_s_gpgme_get_sig_string_attr (dummy, vctx, vidx, vwhat, vwhatidx)
     VALUE dummy, vctx, vidx, vwhat, vwhatidx;
{
  GpgmeCtx ctx;
  const char *attr;

  UNWRAP_GPGME_CTX(vctx, ctx);
  attr = gpgme_get_sig_string_attr (ctx, NUM2INT(vidx), NUM2INT(vwhat),
				    NUM2INT(vwhatidx));
  if (!attr)
    return Qnil;
  return rb_str_new2 (attr);
}

static VALUE
rb_s_gpgme_get_sig_ulong_attr (dummy, vctx, vidx, vwhat, vwhatidx)
     VALUE dummy, vctx, vidx, vwhat, vwhatidx;
{
  GpgmeCtx ctx;
  unsigned long attr;

  UNWRAP_GPGME_CTX(vctx, ctx);
  attr = gpgme_get_sig_ulong_attr (ctx, NUM2INT(vidx), NUM2INT(vwhat),
				   NUM2INT(vwhatidx));
  return ULONG2NUM(attr);
}

static VALUE
rb_s_gpgme_get_sig_key (dummy, vctx, vidx, rkey)
     VALUE dummy, vctx, vidx, rkey;
{
  GpgmeCtx ctx;
  GpgmeKey key;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  err = gpgme_get_sig_key (ctx, NUM2INT(vidx), &key);
  if (err == GPGME_No_Error)
    rb_ary_push (rkey, WRAP_GPGME_KEY(key));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_get_notation (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  char *notation;

  UNWRAP_GPGME_CTX(vctx, ctx);
  notation = gpgme_get_notation (ctx);
  if (!notation)
    return Qnil;
  return rb_str_new2 (notation);
}

static VALUE
rb_s_gpgme_op_decrypt_verify (dummy, vctx, vcipher, vplain, rstat)
     VALUE dummy, vctx, vcipher, vplain, rstat;
{
  GpgmeCtx ctx;
  GpgmeData cipher, plain;
  GpgmeSigStat stat;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vcipher, cipher);
  UNWRAP_GPGME_DATA(vplain, plain);

  err = gpgme_op_decrypt_verify (ctx, cipher, plain, &stat);
  if (err == GPGME_No_Error)
    rb_ary_push (rstat, INT2NUM(stat));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_decrypt_verify_start (dummy, vctx, vcipher, vplain)
     VALUE dummy, vctx, vcipher, vplain;
{
  GpgmeCtx ctx;
  GpgmeData cipher, plain;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vcipher, cipher);
  UNWRAP_GPGME_DATA(vplain, plain);

  err = gpgme_op_decrypt_verify_start (ctx, cipher, plain);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_signers_clear (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;

  UNWRAP_GPGME_CTX(vctx, ctx);
  gpgme_signers_clear (ctx);
  return Qnil;
}

static VALUE
rb_s_gpgme_signers_add (dummy, vctx, vkey)
     VALUE dummy, vctx, vkey;
{
  GpgmeCtx ctx;
  GpgmeKey key;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_KEY(vkey, key);

  err = gpgme_signers_add (ctx, key);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_signers_enum (dummy, vctx, vseq)
     VALUE dummy, vctx, vseq;
{
  GpgmeCtx ctx;
  GpgmeKey key;

  UNWRAP_GPGME_CTX(vctx, ctx);

  key = gpgme_signers_enum (ctx, NUM2INT(vseq));
  if (!key)
    return Qnil;
  return WRAP_GPGME_KEY(key);
}

static VALUE
rb_s_gpgme_op_sign (dummy, vctx, vplain, vsig, vmode)
     VALUE dummy, vctx, vplain, vsig, vmode;
{
  GpgmeCtx ctx;
  GpgmeData plain, sig;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vplain, plain);
  UNWRAP_GPGME_DATA(vsig, sig);

  err = gpgme_op_sign (ctx, plain, sig, NUM2INT(vmode));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_sign_start (dummy, vctx, vplain, vsig, vmode)
     VALUE dummy, vctx, vplain, vsig, vmode;
{
  GpgmeCtx ctx;
  GpgmeData plain, sig;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  UNWRAP_GPGME_DATA(vplain, plain);
  UNWRAP_GPGME_DATA(vsig, sig);

  err = gpgme_op_sign_start (ctx, plain, sig, NUM2INT(vmode));
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_recipients_new (dummy, rrset)
     VALUE dummy, rrset;
{
  GpgmeRecipients rset;
  int err;

  err = gpgme_recipients_new (&rset);
  if (err == GPGME_No_Error)
    {
      VALUE vrset = WRAP_GPGME_RECIPIENTS(rset);
      rb_iv_set (vrset, "@names", rb_ary_new ());
      rb_ary_push (rrset, vrset);
    }
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_recipients_release (dummy, vrset)
     VALUE dummy, vrset;
{
  GpgmeRecipients rset;

  rb_iv_set (vrset, "@names", Qnil);
  UNWRAP_GPGME_RECIPIENTS(vrset, rset);
  if (!rset)
    rb_raise (rb_eRuntimeError,
      "GpgmeRecipients has already been released.");
  gpgme_recipients_release (rset);
  DATA_PTR(vrset) = NULL;
  return Qnil;
}

static VALUE
rb_s_gpgme_recipients_add_name (dummy, vrset, vname)
     VALUE dummy, vrset, vname;
{
  GpgmeRecipients rset;
  int err;

  UNWRAP_GPGME_RECIPIENTS(vrset, rset);

  err = gpgme_recipients_add_name (rset, StringValueCStr(vname));
  if (err == GPGME_No_Error)
    {
      /* Keep a references to VNAME to avoid GC. */
      VALUE vnames = rb_iv_get (vrset, "@names");
      if (rb_ary_includes (vnames, vname) == Qfalse)
	rb_ary_push (vnames, vname);
    }
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_recipients_add_name_with_validity (dummy, vrset, vname, vval)
     VALUE dummy, vrset, vname, vval;
{
  GpgmeRecipients rset;
  int err;

  UNWRAP_GPGME_RECIPIENTS(vrset, rset);

  err = gpgme_recipients_add_name_with_validity (rset, StringValueCStr(vname),
						 NUM2INT(vval));
  if (err == GPGME_No_Error)
    {
      /* Keep a references to VNAME to avoid GC. */
      VALUE vnames = rb_iv_get (vrset, "@names");
      if (rb_ary_includes (vnames, vname) == Qfalse)
	rb_ary_push (vnames, vname);
    }
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_recipients_count (dummy, vrset)
     VALUE dummy, vrset;
{
  VALUE vnames = rb_iv_get (vrset, "@names");
  return UINT2NUM(RARRAY(vnames)->len);
}

static VALUE
rb_s_gpgme_op_encrypt (dummy, vctx, vrset, vplain, vcipher)
     VALUE dummy, vctx, vrset, vplain, vcipher;
{
  GpgmeCtx ctx;
  GpgmeRecipients rset = NULL;
  GpgmeData plain, cipher;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  /* If RECP is `NULL', symmetric rather than public key encryption is
     performed. */
  if (!NIL_P(vrset))
    UNWRAP_GPGME_RECIPIENTS(vrset, rset);
  UNWRAP_GPGME_DATA(vplain, plain);
  UNWRAP_GPGME_DATA(vcipher, cipher);

  err = gpgme_op_encrypt (ctx, rset, plain, cipher);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_encrypt_start (dummy, vctx, vrset, vplain, vcipher)
     VALUE dummy, vctx, vrset, vplain, vcipher;
{
  GpgmeCtx ctx;
  GpgmeRecipients rset = NULL;
  GpgmeData plain, cipher;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  /* If RECP is `NULL', symmetric rather than public key encryption is
     performed. */
  if (!NIL_P(vrset))
    UNWRAP_GPGME_RECIPIENTS(vrset, rset);
  UNWRAP_GPGME_DATA(vplain, plain);
  UNWRAP_GPGME_DATA(vcipher, cipher);

  err = gpgme_op_encrypt_start (ctx, rset, plain, cipher);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_encrypt_sign (dummy, vctx, vrset, vplain, vcipher)
     VALUE dummy, vctx, vrset, vplain, vcipher;
{
  GpgmeCtx ctx;
  GpgmeRecipients rset = NULL;
  GpgmeData plain, cipher;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  /* If RECP is `NULL', symmetric rather than public key encryption is
     performed. */
  if (!NIL_P(vrset))
    UNWRAP_GPGME_RECIPIENTS(vrset, rset);
  UNWRAP_GPGME_DATA(vplain, plain);
  UNWRAP_GPGME_DATA(vcipher, cipher);

  err = gpgme_op_encrypt_sign (ctx, rset, plain, cipher);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_op_encrypt_sign_start (dummy, vctx, vrset, vplain, vcipher)
     VALUE dummy, vctx, vrset, vplain, vcipher;
{
  GpgmeCtx ctx;
  GpgmeRecipients rset = NULL;
  GpgmeData plain, cipher;
  int err;

  UNWRAP_GPGME_CTX(vctx, ctx);
  /* If RECP is `NULL', symmetric rather than public key encryption is
     performed. */
  if (!NIL_P(vrset))
    UNWRAP_GPGME_RECIPIENTS(vrset, rset);
  UNWRAP_GPGME_DATA(vplain, plain);
  UNWRAP_GPGME_DATA(vcipher, cipher);

  err = gpgme_op_encrypt_sign_start (ctx, rset, plain, cipher);
  return INT2NUM(err);
}

static VALUE
rb_s_gpgme_get_op_info (dummy, vctx)
     VALUE dummy, vctx;
{
  GpgmeCtx ctx;
  char *info;

  UNWRAP_GPGME_CTX(vctx, ctx);

  info = gpgme_get_op_info (ctx, 0);
  if (!info)
    return Qnil;
  return rb_str_new2 (info);
}

static VALUE
rb_s_gpgme_wait (dummy, vctx, rstatus, vhang)
     VALUE dummy, vctx, rstatus, vhang;
{
  GpgmeCtx ctx = NULL;
  GpgmeError status;

  /* The CTX argument can be `NULL'.  In that case, `gpgme_wait' waits
     for any context to complete its operation. */
  if (!NIL_P(vctx))
    UNWRAP_GPGME_CTX(vctx, ctx);

  ctx = gpgme_wait (ctx, &status, NUM2INT(vhang));
  rb_ary_push (rstatus, INT2NUM(status));

  return WRAP_GPGME_CTX(ctx);
}

void Init_gpgme_n ()
{
  VALUE mGPGME;

  mGPGME = rb_define_module ("GPGME");

  rb_define_module_function (mGPGME, "gpgme_check_version",
			     rb_s_gpgme_check_version, 1);

  rb_define_module_function (mGPGME, "gpgme_engine_check_version",
			     rb_s_gpgme_engine_check_version, 1);
  /* gpgme_check_engine is not supported because it is obsoleted by
     gpgme_engine_check_version. */

  rb_define_module_function (mGPGME, "gpgme_get_engine_info",
			     rb_s_gpgme_get_engine_info, 0);
  rb_define_module_function (mGPGME, "gpgme_strerror",
			     rb_s_gpgme_strerror, 1);

  cGpgmeCtx =
    rb_define_class_under (mGPGME, "GpgmeCtx", rb_cObject);
  cGpgmeData =
    rb_define_class_under (mGPGME, "GpgmeData", rb_cObject);
  cGpgmeRecipients =
    rb_define_class_under (mGPGME, "GpgmeRecipients", rb_cObject);
  cGpgmeKey =
    rb_define_class_under (mGPGME, "GpgmeKey", rb_cObject);
  cGpgmeTrustItem =
    rb_define_class_under (mGPGME, "GpgmeTrustItem", rb_cObject);

  /* Creating Data Buffers
   *
   * gpgme_data_new_from_filepart is not currently supported.
   */
  rb_define_module_function (mGPGME, "gpgme_data_new",
			     rb_s_gpgme_data_new, 1);
  rb_define_module_function (mGPGME, "gpgme_data_new_from_mem",
			     rb_s_gpgme_data_new_from_mem, 4);
  rb_define_module_function (mGPGME, "gpgme_data_new_from_file",
			     rb_s_gpgme_data_new_from_file, 3);
  rb_define_module_function (mGPGME, "gpgme_data_new_with_read_cb",
			     rb_s_gpgme_data_new_with_read_cb, 3);

  /* Destroying Data Buffers */
  rb_define_module_function (mGPGME, "gpgme_data_release",
			     rb_s_gpgme_data_release, 1);
  rb_define_module_function (mGPGME, "gpgme_data_release_and_get_mem",
			     rb_s_gpgme_data_release_and_get_mem, 2);

  /* Manipulating Data Buffers */
  rb_define_module_function (mGPGME, "gpgme_data_read",
			     rb_s_gpgme_data_read, 4);
  rb_define_module_function (mGPGME, "gpgme_data_rewind",
			     rb_s_gpgme_data_rewind, 1);
  rb_define_module_function (mGPGME, "gpgme_data_write",
			     rb_s_gpgme_data_write, 3);
  rb_define_module_function (mGPGME, "gpgme_data_get_type",
			     rb_s_gpgme_data_get_type, 1);
  rb_define_module_function (mGPGME, "gpgme_data_get_encoding",
			     rb_s_gpgme_data_get_encoding, 1);
  rb_define_module_function (mGPGME, "gpgme_data_set_encoding",
			     rb_s_gpgme_data_set_encoding, 2);

  /* Creating Contexts */
  rb_define_module_function (mGPGME, "gpgme_new",
			     rb_s_gpgme_new, 1);

  /* Destroying Contexts */
  rb_define_module_function (mGPGME, "gpgme_release",
			     rb_s_gpgme_release, 2);

  /* Context Attributes */
  rb_define_module_function (mGPGME, "gpgme_set_protocol",
			     rb_s_gpgme_set_protocol, 2);
  rb_define_module_function (mGPGME, "gpgme_get_protocol",
			     rb_s_gpgme_get_protocol, 1);
  rb_define_module_function (mGPGME, "gpgme_set_armor",
			     rb_s_gpgme_set_armor, 2);
  rb_define_module_function (mGPGME, "gpgme_get_armor",
			     rb_s_gpgme_get_armor, 1);
  rb_define_module_function (mGPGME, "gpgme_set_textmode",
			     rb_s_gpgme_set_textmode, 2);
  rb_define_module_function (mGPGME, "gpgme_get_textmode",
			     rb_s_gpgme_get_textmode, 1);
  rb_define_module_function (mGPGME, "gpgme_set_include_certs",
			     rb_s_gpgme_set_include_certs, 2);
  rb_define_module_function (mGPGME, "gpgme_get_include_certs",
			     rb_s_gpgme_get_include_certs, 1);
  rb_define_module_function (mGPGME, "gpgme_set_keylist_mode",
			     rb_s_gpgme_set_keylist_mode, 2);
  rb_define_module_function (mGPGME, "gpgme_get_keylist_mode",
			     rb_s_gpgme_get_keylist_mode, 1);
  rb_define_module_function (mGPGME, "gpgme_set_passphrase_cb",
			     rb_s_gpgme_set_passphrase_cb, 3);
  rb_define_module_function (mGPGME, "gpgme_get_passphrase_cb",
			     rb_s_gpgme_get_passphrase_cb, 3);
  rb_define_module_function (mGPGME, "gpgme_set_progress_cb",
			     rb_s_gpgme_set_progress_cb, 3);
  rb_define_module_function (mGPGME, "gpgme_get_progress_cb",
			     rb_s_gpgme_get_progress_cb, 3);

  /* Key Management */
  rb_define_module_function (mGPGME, "gpgme_op_keylist_start",
			     rb_s_gpgme_op_keylist_start, 3);
  rb_define_module_function (mGPGME, "gpgme_op_keylist_ext_start",
			     rb_s_gpgme_op_keylist_ext_start, 4);
  rb_define_module_function (mGPGME, "gpgme_op_keylist_next",
			     rb_s_gpgme_op_keylist_next, 2);
  rb_define_module_function (mGPGME, "gpgme_op_keylist_end",
			     rb_s_gpgme_op_keylist_end, 1);
  rb_define_module_function (mGPGME, "gpgme_key_get_as_xml",
			     rb_s_gpgme_key_get_as_xml, 1);
  rb_define_module_function (mGPGME, "gpgme_key_get_string_attr",
			     rb_s_gpgme_key_get_string_attr, 3);
  rb_define_module_function (mGPGME, "gpgme_key_get_ulong_attr",
			     rb_s_gpgme_key_get_ulong_attr, 3);
  rb_define_module_function (mGPGME, "gpgme_key_ref",
			     rb_s_gpgme_key_ref, 1);
  rb_define_module_function (mGPGME, "gpgme_key_unref",
			     rb_s_gpgme_key_unref, 1);
  rb_define_module_function (mGPGME, "gpgme_op_genkey",
			     rb_s_gpgme_op_genkey, 4);
  rb_define_module_function (mGPGME, "gpgme_op_genkey_start",
			     rb_s_gpgme_op_genkey_start, 4);
  rb_define_module_function (mGPGME, "gpgme_op_export",
			     rb_s_gpgme_op_export, 3);
  rb_define_module_function (mGPGME, "gpgme_op_export_start",
			     rb_s_gpgme_op_export_start, 3);
  rb_define_module_function (mGPGME, "gpgme_op_import",
			     rb_s_gpgme_op_import, 2);
  rb_define_module_function (mGPGME, "gpgme_op_import_start",
			     rb_s_gpgme_op_import_start, 2);
  rb_define_module_function (mGPGME, "gpgme_op_import_ext",
			     rb_s_gpgme_op_import_ext, 3);
  rb_define_module_function (mGPGME, "gpgme_op_delete",
			     rb_s_gpgme_op_delete, 3);
  rb_define_module_function (mGPGME, "gpgme_op_delete_start",
			     rb_s_gpgme_op_delete_start, 3);

  /* Trust Item Management */
  rb_define_module_function (mGPGME, "gpgme_op_trustlist_start",
			     rb_s_gpgme_op_trustlist_start, 3);
  rb_define_module_function (mGPGME, "gpgme_op_trustlist_next",
			     rb_s_gpgme_op_trustlist_next, 2);
  rb_define_module_function (mGPGME, "gpgme_op_trustlist_end",
			     rb_s_gpgme_op_trustlist_end, 1);
  rb_define_module_function (mGPGME, "gpgme_trust_item_get_string_attr",
			     rb_s_gpgme_trust_item_get_string_attr, 3);
  rb_define_module_function (mGPGME, "gpgme_trust_item_get_int_attr",
			     rb_s_gpgme_trust_item_get_int_attr, 3);
  rb_define_module_function (mGPGME, "gpgme_trust_item_release",
			     rb_s_gpgme_trust_item_release, 1);

  /* Decrypt */
  rb_define_module_function (mGPGME, "gpgme_op_decrypt",
			     rb_s_gpgme_op_decrypt, 3);
  rb_define_module_function (mGPGME, "gpgme_op_decrypt_start",
			     rb_s_gpgme_op_decrypt_start, 3);

  /* Verify */
  rb_define_module_function (mGPGME, "gpgme_op_verify",
			     rb_s_gpgme_op_verify, 4);
  rb_define_module_function (mGPGME, "gpgme_op_verify_start",
			     rb_s_gpgme_op_verify_start, 3);
  rb_define_module_function (mGPGME, "gpgme_get_sig_status",
			     rb_s_gpgme_get_sig_status, 4);
  rb_define_module_function (mGPGME, "gpgme_get_sig_string_attr",
			     rb_s_gpgme_get_sig_string_attr, 4);
  rb_define_module_function (mGPGME, "gpgme_get_sig_ulong_attr",
			     rb_s_gpgme_get_sig_ulong_attr, 4);
  rb_define_module_function (mGPGME, "gpgme_get_sig_key",
			     rb_s_gpgme_get_sig_key, 3);
  rb_define_module_function (mGPGME, "gpgme_get_notation",
			     rb_s_gpgme_get_notation, 1);

  /* Decrypt and Verify */
  rb_define_module_function (mGPGME, "gpgme_op_decrypt_verify",
			     rb_s_gpgme_op_decrypt_verify, 4);
  rb_define_module_function (mGPGME, "gpgme_op_decrypt_verify_start",
			     rb_s_gpgme_op_decrypt_verify_start, 3);

  /* Sign */
  rb_define_module_function (mGPGME, "gpgme_signers_clear",
			     rb_s_gpgme_signers_clear, 1);
  rb_define_module_function (mGPGME, "gpgme_signers_add",
			     rb_s_gpgme_signers_add, 2);
  rb_define_module_function (mGPGME, "gpgme_signers_enum",
			     rb_s_gpgme_signers_enum, 2);
  rb_define_module_function (mGPGME, "gpgme_op_sign",
			     rb_s_gpgme_op_sign, 4);
  rb_define_module_function (mGPGME, "gpgme_op_sign_start",
			     rb_s_gpgme_op_sign_start, 4);

  /* Encrypt
   *
   * The following functions are not currently supported:
   * - gpgme_recipients_enum_open
   * - gpgme_recipients_enum_read
   * - gpgme_recipients_enum_close
   */
  rb_define_module_function (mGPGME, "gpgme_recipients_new",
			     rb_s_gpgme_recipients_new, 1);
  rb_define_module_function (mGPGME, "gpgme_recipients_release",
			     rb_s_gpgme_recipients_release, 1);
  rb_define_module_function (mGPGME, "gpgme_recipients_add_name",
			     rb_s_gpgme_recipients_add_name, 2);
  rb_define_module_function (mGPGME, "gpgme_recipients_add_name_with_validity",
			     rb_s_gpgme_recipients_add_name_with_validity, 3);
  rb_define_module_function (mGPGME, "gpgme_recipients_count",
			     rb_s_gpgme_recipients_count, 1);

  rb_define_module_function (mGPGME, "gpgme_op_encrypt",
			     rb_s_gpgme_op_encrypt, 4);
  rb_define_module_function (mGPGME, "gpgme_op_encrypt_start",
			     rb_s_gpgme_op_encrypt_start, 4);
  rb_define_module_function (mGPGME, "gpgme_op_encrypt_sign",
			     rb_s_gpgme_op_encrypt_sign, 4);
  rb_define_module_function (mGPGME, "gpgme_op_encrypt_sign_start",
			     rb_s_gpgme_op_encrypt_sign_start, 4);

  /* Detailed Results */
  rb_define_module_function (mGPGME, "gpgme_get_op_info",
			     rb_s_gpgme_get_op_info, 1);

  /* Run Control */
  rb_define_module_function (mGPGME, "gpgme_wait",
			     rb_s_gpgme_wait, 3);

  /* GpgmeError */
  rb_define_const (mGPGME, "GPGME_EOF",
		   INT2FIX(GPGME_EOF));
  rb_define_const (mGPGME, "GPGME_No_Error",
		   INT2FIX(GPGME_No_Error));
  rb_define_const (mGPGME, "GPGME_General_Error",
		   INT2FIX(GPGME_General_Error));
  rb_define_const (mGPGME, "GPGME_Out_Of_Core",
		   INT2FIX(GPGME_Out_Of_Core));
  rb_define_const (mGPGME, "GPGME_Invalid_Value",
		   INT2FIX(GPGME_Invalid_Value));
  rb_define_const (mGPGME, "GPGME_Busy",
		   INT2FIX(GPGME_Busy));
  rb_define_const (mGPGME, "GPGME_No_Request",
		   INT2FIX(GPGME_No_Request));
  rb_define_const (mGPGME, "GPGME_Exec_Error",
		   INT2FIX(GPGME_Exec_Error));
  rb_define_const (mGPGME, "GPGME_Too_Many_Procs",
		   INT2FIX(GPGME_Too_Many_Procs));
  rb_define_const (mGPGME, "GPGME_Pipe_Error",
		   INT2FIX(GPGME_Pipe_Error));
  rb_define_const (mGPGME, "GPGME_No_Recipients",
		   INT2FIX(GPGME_No_Recipients));
  rb_define_const (mGPGME, "GPGME_No_Data",
		   INT2FIX(GPGME_No_Data));
  rb_define_const (mGPGME, "GPGME_Conflict",
		   INT2FIX(GPGME_Conflict));
  rb_define_const (mGPGME, "GPGME_Not_Implemented",
		   INT2FIX(GPGME_Not_Implemented));
  rb_define_const (mGPGME, "GPGME_Read_Error",
		   INT2FIX(GPGME_Read_Error));
  rb_define_const (mGPGME, "GPGME_Write_Error",
		   INT2FIX(GPGME_Write_Error));
  rb_define_const (mGPGME, "GPGME_Invalid_Type",
		   INT2FIX(GPGME_Invalid_Type));
  rb_define_const (mGPGME, "GPGME_Invalid_Mode",
		   INT2FIX(GPGME_Invalid_Mode));
  rb_define_const (mGPGME, "GPGME_File_Error",
		   INT2FIX(GPGME_File_Error));
  rb_define_const (mGPGME, "GPGME_Decryption_Failed",
		   INT2FIX(GPGME_Decryption_Failed));
  rb_define_const (mGPGME, "GPGME_No_Passphrase",
		   INT2FIX(GPGME_No_Passphrase));
  rb_define_const (mGPGME, "GPGME_Canceled",
		   INT2FIX(GPGME_Canceled));
  rb_define_const (mGPGME, "GPGME_Invalid_Key",
		   INT2FIX(GPGME_Invalid_Key));
  rb_define_const (mGPGME, "GPGME_Invalid_Engine",
		   INT2FIX(GPGME_Invalid_Engine));
  rb_define_const (mGPGME, "GPGME_Invalid_Recipients",
		   INT2FIX(GPGME_Invalid_Recipients));

  /* GpgmeDataType */
  rb_define_const (mGPGME, "GPGME_DATA_TYPE_NONE",
		   INT2FIX(GPGME_DATA_TYPE_NONE));
  rb_define_const (mGPGME, "GPGME_DATA_TYPE_MEM",
		   INT2FIX(GPGME_DATA_TYPE_MEM));
  rb_define_const (mGPGME, "GPGME_DATA_TYPE_FD",
		   INT2FIX(GPGME_DATA_TYPE_FD));
  rb_define_const (mGPGME, "GPGME_DATA_TYPE_FILE",
		   INT2FIX(GPGME_DATA_TYPE_FILE));
  rb_define_const (mGPGME, "GPGME_DATA_TYPE_CB",
		   INT2FIX(GPGME_DATA_TYPE_CB));

  /* GpgmeDataEncoding */
  rb_define_const (mGPGME, "GPGME_DATA_ENCODING_NONE",
		   INT2FIX(GPGME_DATA_ENCODING_NONE));
  rb_define_const (mGPGME, "GPGME_DATA_ENCODING_BINARY",
		   INT2FIX(GPGME_DATA_ENCODING_BINARY));
  rb_define_const (mGPGME, "GPGME_DATA_ENCODING_BASE64",
		   INT2FIX(GPGME_DATA_ENCODING_BASE64));
  rb_define_const (mGPGME, "GPGME_DATA_ENCODING_ARMOR",
		   INT2FIX(GPGME_DATA_ENCODING_ARMOR));

  /* GpgmeSigStat */
  rb_define_const (mGPGME, "GPGME_SIG_STAT_NONE",
		   INT2FIX(GPGME_SIG_STAT_NONE));
  rb_define_const (mGPGME, "GPGME_SIG_STAT_GOOD",
		   INT2FIX(GPGME_SIG_STAT_GOOD));
  rb_define_const (mGPGME, "GPGME_SIG_STAT_BAD",
		   INT2FIX(GPGME_SIG_STAT_BAD));
  rb_define_const (mGPGME, "GPGME_SIG_STAT_NOKEY",
		   INT2FIX(GPGME_SIG_STAT_NOKEY));
  rb_define_const (mGPGME, "GPGME_SIG_STAT_NOSIG",
		   INT2FIX(GPGME_SIG_STAT_NOSIG));
  rb_define_const (mGPGME, "GPGME_SIG_STAT_ERROR",
		   INT2FIX(GPGME_SIG_STAT_ERROR));
  rb_define_const (mGPGME, "GPGME_SIG_STAT_DIFF",
		   INT2FIX(GPGME_SIG_STAT_DIFF));
  rb_define_const (mGPGME, "GPGME_SIG_STAT_GOOD_EXP",
		   INT2FIX(GPGME_SIG_STAT_GOOD_EXP));
  rb_define_const (mGPGME, "GPGME_SIG_STAT_GOOD_EXPKEY",
		   INT2FIX(GPGME_SIG_STAT_GOOD_EXPKEY));

  /* Flags used with the GPGME_ATTR_SIG_SUMMARY. */
  rb_define_const (mGPGME, "GPGME_SIGSUM_VALID",
		   INT2FIX(GPGME_SIGSUM_VALID));
  rb_define_const (mGPGME, "GPGME_SIGSUM_GREEN",
		   INT2FIX(GPGME_SIGSUM_GREEN));
  rb_define_const (mGPGME, "GPGME_SIGSUM_RED",
		   INT2FIX(GPGME_SIGSUM_RED));
  rb_define_const (mGPGME, "GPGME_SIGSUM_KEY_REVOKED",
		   INT2FIX(GPGME_SIGSUM_KEY_REVOKED));
  rb_define_const (mGPGME, "GPGME_SIGSUM_KEY_EXPIRED",
		   INT2FIX(GPGME_SIGSUM_KEY_EXPIRED));
  rb_define_const (mGPGME, "GPGME_SIGSUM_SIG_EXPIRED",
		   INT2FIX(GPGME_SIGSUM_SIG_EXPIRED));
  rb_define_const (mGPGME, "GPGME_SIGSUM_KEY_MISSING",
		   INT2FIX(GPGME_SIGSUM_KEY_MISSING));
  rb_define_const (mGPGME, "GPGME_SIGSUM_CRL_MISSING",
		   INT2FIX(GPGME_SIGSUM_CRL_MISSING));
  rb_define_const (mGPGME, "GPGME_SIGSUM_CRL_TOO_OLD",
		   INT2FIX(GPGME_SIGSUM_CRL_TOO_OLD));
  rb_define_const (mGPGME, "GPGME_SIGSUM_BAD_POLICY",
		   INT2FIX(GPGME_SIGSUM_BAD_POLICY));
  rb_define_const (mGPGME, "GPGME_SIGSUM_SYS_ERROR",
		   INT2FIX(GPGME_SIGSUM_SYS_ERROR));

  /* GpgmeSigMode */
  rb_define_const (mGPGME, "GPGME_SIG_MODE_NORMAL",
		   INT2FIX(GPGME_SIG_MODE_NORMAL));
  rb_define_const (mGPGME, "GPGME_SIG_MODE_DETACH",
		   INT2FIX(GPGME_SIG_MODE_DETACH));
  rb_define_const (mGPGME, "GPGME_SIG_MODE_CLEAR",
		   INT2FIX(GPGME_SIG_MODE_CLEAR));

  /* GpgmeAttr */
  rb_define_const (mGPGME, "GPGME_ATTR_KEYID",
		   INT2FIX(GPGME_ATTR_KEYID));
  rb_define_const (mGPGME, "GPGME_ATTR_FPR",
		   INT2FIX(GPGME_ATTR_FPR));
  rb_define_const (mGPGME, "GPGME_ATTR_ALGO",
		   INT2FIX(GPGME_ATTR_ALGO));
  rb_define_const (mGPGME, "GPGME_ATTR_LEN",
		   INT2FIX(GPGME_ATTR_LEN));
  rb_define_const (mGPGME, "GPGME_ATTR_CREATED",
		   INT2FIX(GPGME_ATTR_CREATED));
  rb_define_const (mGPGME, "GPGME_ATTR_EXPIRE",
		   INT2FIX(GPGME_ATTR_EXPIRE));
  rb_define_const (mGPGME, "GPGME_ATTR_OTRUST",
		   INT2FIX(GPGME_ATTR_OTRUST));
  rb_define_const (mGPGME, "GPGME_ATTR_USERID",
		   INT2FIX(GPGME_ATTR_USERID));
  rb_define_const (mGPGME, "GPGME_ATTR_NAME",
		   INT2FIX(GPGME_ATTR_NAME));
  rb_define_const (mGPGME, "GPGME_ATTR_EMAIL",
		   INT2FIX(GPGME_ATTR_EMAIL));
  rb_define_const (mGPGME, "GPGME_ATTR_COMMENT",
		   INT2FIX(GPGME_ATTR_COMMENT));
  rb_define_const (mGPGME, "GPGME_ATTR_VALIDITY",
		   INT2FIX(GPGME_ATTR_VALIDITY));
  rb_define_const (mGPGME, "GPGME_ATTR_LEVEL",
		   INT2FIX(GPGME_ATTR_LEVEL));
  rb_define_const (mGPGME, "GPGME_ATTR_TYPE",
		   INT2FIX(GPGME_ATTR_TYPE));
  rb_define_const (mGPGME, "GPGME_ATTR_IS_SECRET",
		   INT2FIX(GPGME_ATTR_IS_SECRET));
  rb_define_const (mGPGME, "GPGME_ATTR_KEY_REVOKED",
		   INT2FIX(GPGME_ATTR_KEY_REVOKED));
  rb_define_const (mGPGME, "GPGME_ATTR_KEY_INVALID",
		   INT2FIX(GPGME_ATTR_KEY_INVALID));
  rb_define_const (mGPGME, "GPGME_ATTR_UID_REVOKED",
		   INT2FIX(GPGME_ATTR_UID_REVOKED));
  rb_define_const (mGPGME, "GPGME_ATTR_UID_INVALID",
		   INT2FIX(GPGME_ATTR_UID_INVALID));
  rb_define_const (mGPGME, "GPGME_ATTR_KEY_CAPS",
		   INT2FIX(GPGME_ATTR_KEY_CAPS));
  rb_define_const (mGPGME, "GPGME_ATTR_CAN_ENCRYPT",
		   INT2FIX(GPGME_ATTR_CAN_ENCRYPT));
  rb_define_const (mGPGME, "GPGME_ATTR_CAN_SIGN",
		   INT2FIX(GPGME_ATTR_CAN_SIGN));
  rb_define_const (mGPGME, "GPGME_ATTR_CAN_CERTIFY",
		   INT2FIX(GPGME_ATTR_CAN_CERTIFY));
  rb_define_const (mGPGME, "GPGME_ATTR_KEY_EXPIRED",
		   INT2FIX(GPGME_ATTR_KEY_EXPIRED));
  rb_define_const (mGPGME, "GPGME_ATTR_KEY_DISABLED",
		   INT2FIX(GPGME_ATTR_KEY_DISABLED));
  rb_define_const (mGPGME, "GPGME_ATTR_SERIAL",
		   INT2FIX(GPGME_ATTR_SERIAL));
  rb_define_const (mGPGME, "GPGME_ATTR_ISSUER",
		   INT2FIX(GPGME_ATTR_ISSUER));
  rb_define_const (mGPGME, "GPGME_ATTR_CHAINID",
		   INT2FIX(GPGME_ATTR_CHAINID));
  rb_define_const (mGPGME, "GPGME_ATTR_SIG_STATUS",
		   INT2FIX(GPGME_ATTR_SIG_STATUS));
  rb_define_const (mGPGME, "GPGME_ATTR_ERRTOK",
		   INT2FIX(GPGME_ATTR_ERRTOK));
  rb_define_const (mGPGME, "GPGME_ATTR_SIG_SUMMARY",
		   INT2FIX(GPGME_ATTR_SIG_SUMMARY));

  /* GpgmeValidity */
  rb_define_const (mGPGME, "GPGME_VALIDITY_UNKNOWN",
		   INT2FIX(GPGME_VALIDITY_UNKNOWN));
  rb_define_const (mGPGME, "GPGME_VALIDITY_UNDEFINED",
		   INT2FIX(GPGME_VALIDITY_UNDEFINED));
  rb_define_const (mGPGME, "GPGME_VALIDITY_NEVER",
		   INT2FIX(GPGME_VALIDITY_NEVER));
  rb_define_const (mGPGME, "GPGME_VALIDITY_MARGINAL",
		   INT2FIX(GPGME_VALIDITY_MARGINAL));
  rb_define_const (mGPGME, "GPGME_VALIDITY_FULL",
		   INT2FIX(GPGME_VALIDITY_FULL));
  rb_define_const (mGPGME, "GPGME_VALIDITY_ULTIMATE",
		   INT2FIX(GPGME_VALIDITY_ULTIMATE));

  /* GpgmeProtocol */
  rb_define_const (mGPGME, "GPGME_PROTOCOL_OpenPGP",
		   INT2FIX(GPGME_PROTOCOL_OpenPGP));
  rb_define_const (mGPGME, "GPGME_PROTOCOL_CMS",
		   INT2FIX(GPGME_PROTOCOL_CMS));
  rb_define_const (mGPGME, "GPGME_PROTOCOL_AUTO",
		   INT2FIX(GPGME_PROTOCOL_AUTO));

  /* GpgmeStatusCode */
  rb_define_const (mGPGME, "GPGME_STATUS_EOF",
		   INT2FIX(GPGME_STATUS_EOF));
  /* mkstatus starts here */
  rb_define_const (mGPGME, "GPGME_STATUS_ENTER",
		   INT2FIX(GPGME_STATUS_ENTER));
  rb_define_const (mGPGME, "GPGME_STATUS_LEAVE",
		   INT2FIX(GPGME_STATUS_LEAVE));
  rb_define_const (mGPGME, "GPGME_STATUS_ABORT",
		   INT2FIX(GPGME_STATUS_ABORT));

  rb_define_const (mGPGME, "GPGME_STATUS_GOODSIG",
		   INT2FIX(GPGME_STATUS_GOODSIG));
  rb_define_const (mGPGME, "GPGME_STATUS_BADSIG",
		   INT2FIX(GPGME_STATUS_BADSIG));
  rb_define_const (mGPGME, "GPGME_STATUS_ERRSIG",
		   INT2FIX(GPGME_STATUS_ERRSIG));

  rb_define_const (mGPGME, "GPGME_STATUS_BADARMOR",
		   INT2FIX(GPGME_STATUS_BADARMOR));

  rb_define_const (mGPGME, "GPGME_STATUS_RSA_OR_IDEA",
		   INT2FIX(GPGME_STATUS_RSA_OR_IDEA));
  rb_define_const (mGPGME, "GPGME_STATUS_KEYEXPIRED",
		   INT2FIX(GPGME_STATUS_KEYEXPIRED));
  rb_define_const (mGPGME, "GPGME_STATUS_KEYREVOKED",
		   INT2FIX(GPGME_STATUS_KEYREVOKED));

  rb_define_const (mGPGME, "GPGME_STATUS_TRUST_UNDEFINED",
		   INT2FIX(GPGME_STATUS_TRUST_UNDEFINED));
  rb_define_const (mGPGME, "GPGME_STATUS_TRUST_NEVER",
		   INT2FIX(GPGME_STATUS_TRUST_NEVER));
  rb_define_const (mGPGME, "GPGME_STATUS_TRUST_MARGINAL",
		   INT2FIX(GPGME_STATUS_TRUST_MARGINAL));
  rb_define_const (mGPGME, "GPGME_STATUS_TRUST_FULLY",
		   INT2FIX(GPGME_STATUS_TRUST_FULLY));
  rb_define_const (mGPGME, "GPGME_STATUS_TRUST_ULTIMATE",
		   INT2FIX(GPGME_STATUS_TRUST_ULTIMATE));

  rb_define_const (mGPGME, "GPGME_STATUS_SHM_INFO",
		   INT2FIX(GPGME_STATUS_SHM_INFO));
  rb_define_const (mGPGME, "GPGME_STATUS_SHM_GET",
		   INT2FIX(GPGME_STATUS_SHM_GET));
  rb_define_const (mGPGME, "GPGME_STATUS_SHM_GET_BOOL",
		   INT2FIX(GPGME_STATUS_SHM_GET_BOOL));
  rb_define_const (mGPGME, "GPGME_STATUS_SHM_GET_HIDDEN",
		   INT2FIX(GPGME_STATUS_SHM_GET_HIDDEN));

  rb_define_const (mGPGME, "GPGME_STATUS_NEED_PASSPHRASE",
		   INT2FIX(GPGME_STATUS_NEED_PASSPHRASE));
  rb_define_const (mGPGME, "GPGME_STATUS_VALIDSIG",
		   INT2FIX(GPGME_STATUS_VALIDSIG));
  rb_define_const (mGPGME, "GPGME_STATUS_SIG_ID",
		   INT2FIX(GPGME_STATUS_SIG_ID));
  rb_define_const (mGPGME, "GPGME_STATUS_ENC_TO",
		   INT2FIX(GPGME_STATUS_ENC_TO));
  rb_define_const (mGPGME, "GPGME_STATUS_NODATA",
		   INT2FIX(GPGME_STATUS_NODATA));
  rb_define_const (mGPGME, "GPGME_STATUS_BAD_PASSPHRASE",
		   INT2FIX(GPGME_STATUS_BAD_PASSPHRASE));
  rb_define_const (mGPGME, "GPGME_STATUS_NO_PUBKEY",
		   INT2FIX(GPGME_STATUS_NO_PUBKEY));
  rb_define_const (mGPGME, "GPGME_STATUS_NO_SECKEY",
		   INT2FIX(GPGME_STATUS_NO_SECKEY));
  rb_define_const (mGPGME, "GPGME_STATUS_NEED_PASSPHRASE_SYM",
		   INT2FIX(GPGME_STATUS_NEED_PASSPHRASE_SYM));
  rb_define_const (mGPGME, "GPGME_STATUS_DECRYPTION_FAILED",
		   INT2FIX(GPGME_STATUS_DECRYPTION_FAILED));
  rb_define_const (mGPGME, "GPGME_STATUS_DECRYPTION_OKAY",
		   INT2FIX(GPGME_STATUS_DECRYPTION_OKAY));
  rb_define_const (mGPGME, "GPGME_STATUS_MISSING_PASSPHRASE",
		   INT2FIX(GPGME_STATUS_MISSING_PASSPHRASE));
  rb_define_const (mGPGME, "GPGME_STATUS_GOOD_PASSPHRASE",
		   INT2FIX(GPGME_STATUS_GOOD_PASSPHRASE));
  rb_define_const (mGPGME, "GPGME_STATUS_GOODMDC",
		   INT2FIX(GPGME_STATUS_GOODMDC));
  rb_define_const (mGPGME, "GPGME_STATUS_BADMDC",
		   INT2FIX(GPGME_STATUS_BADMDC));
  rb_define_const (mGPGME, "GPGME_STATUS_ERRMDC",
		   INT2FIX(GPGME_STATUS_ERRMDC));
  rb_define_const (mGPGME, "GPGME_STATUS_IMPORTED",
		   INT2FIX(GPGME_STATUS_IMPORTED));
  rb_define_const (mGPGME, "GPGME_STATUS_IMPORT_RES",
		   INT2FIX(GPGME_STATUS_IMPORT_RES));
  rb_define_const (mGPGME, "GPGME_STATUS_FILE_START",
		   INT2FIX(GPGME_STATUS_FILE_START));
  rb_define_const (mGPGME, "GPGME_STATUS_FILE_DONE",
		   INT2FIX(GPGME_STATUS_FILE_DONE));
  rb_define_const (mGPGME, "GPGME_STATUS_FILE_ERROR",
		   INT2FIX(GPGME_STATUS_FILE_ERROR));

  rb_define_const (mGPGME, "GPGME_STATUS_BEGIN_DECRYPTION",
		   INT2FIX(GPGME_STATUS_BEGIN_DECRYPTION));
  rb_define_const (mGPGME, "GPGME_STATUS_END_DECRYPTION",
		   INT2FIX(GPGME_STATUS_END_DECRYPTION));
  rb_define_const (mGPGME, "GPGME_STATUS_BEGIN_ENCRYPTION",
		   INT2FIX(GPGME_STATUS_BEGIN_ENCRYPTION));
  rb_define_const (mGPGME, "GPGME_STATUS_END_ENCRYPTION",
		   INT2FIX(GPGME_STATUS_END_ENCRYPTION));

  rb_define_const (mGPGME, "GPGME_STATUS_DELETE_PROBLEM",
		   INT2FIX(GPGME_STATUS_DELETE_PROBLEM));
  rb_define_const (mGPGME, "GPGME_STATUS_GET_BOOL",
		   INT2FIX(GPGME_STATUS_GET_BOOL));
  rb_define_const (mGPGME, "GPGME_STATUS_GET_LINE",
		   INT2FIX(GPGME_STATUS_GET_LINE));
  rb_define_const (mGPGME, "GPGME_STATUS_GET_HIDDEN",
		   INT2FIX(GPGME_STATUS_GET_HIDDEN));
  rb_define_const (mGPGME, "GPGME_STATUS_GOT_IT",
		   INT2FIX(GPGME_STATUS_GOT_IT));
  rb_define_const (mGPGME, "GPGME_STATUS_PROGRESS",
		   INT2FIX(GPGME_STATUS_PROGRESS));
  rb_define_const (mGPGME, "GPGME_STATUS_SIG_CREATED",
		   INT2FIX(GPGME_STATUS_SIG_CREATED));
  rb_define_const (mGPGME, "GPGME_STATUS_SESSION_KEY",
		   INT2FIX(GPGME_STATUS_SESSION_KEY));
  rb_define_const (mGPGME, "GPGME_STATUS_NOTATION_NAME",
		   INT2FIX(GPGME_STATUS_NOTATION_NAME));
  rb_define_const (mGPGME, "GPGME_STATUS_NOTATION_DATA",
		   INT2FIX(GPGME_STATUS_NOTATION_DATA));
  rb_define_const (mGPGME, "GPGME_STATUS_POLICY_URL",
		   INT2FIX(GPGME_STATUS_POLICY_URL));
  rb_define_const (mGPGME, "GPGME_STATUS_BEGIN_STREAM",
		   INT2FIX(GPGME_STATUS_BEGIN_STREAM));
  rb_define_const (mGPGME, "GPGME_STATUS_END_STREAM",
		   INT2FIX(GPGME_STATUS_END_STREAM));
  rb_define_const (mGPGME, "GPGME_STATUS_KEY_CREATED",
		   INT2FIX(GPGME_STATUS_KEY_CREATED));
  rb_define_const (mGPGME, "GPGME_STATUS_USERID_HINT",
		   INT2FIX(GPGME_STATUS_USERID_HINT));
  rb_define_const (mGPGME, "GPGME_STATUS_UNEXPECTED",
		   INT2FIX(GPGME_STATUS_UNEXPECTED));
  rb_define_const (mGPGME, "GPGME_STATUS_INV_RECP",
		   INT2FIX(GPGME_STATUS_INV_RECP));
  rb_define_const (mGPGME, "GPGME_STATUS_NO_RECP",
		   INT2FIX(GPGME_STATUS_NO_RECP));
  rb_define_const (mGPGME, "GPGME_STATUS_ALREADY_SIGNED",
		   INT2FIX(GPGME_STATUS_ALREADY_SIGNED));
  rb_define_const (mGPGME, "GPGME_STATUS_SIGEXPIRED",
		   INT2FIX(GPGME_STATUS_SIGEXPIRED));
  rb_define_const (mGPGME, "GPGME_STATUS_EXPSIG",
		   INT2FIX(GPGME_STATUS_EXPSIG));
  rb_define_const (mGPGME, "GPGME_STATUS_EXPKEYSIG",
		   INT2FIX(GPGME_STATUS_EXPKEYSIG));
  rb_define_const (mGPGME, "GPGME_STATUS_TRUNCATED",
		   INT2FIX(GPGME_STATUS_TRUNCATED));
  rb_define_const (mGPGME, "GPGME_STATUS_ERROR",
		   INT2FIX(GPGME_STATUS_ERROR));

  /* The available keylist mode flags.  */
  rb_define_const (mGPGME, "GPGME_KEYLIST_MODE_LOCAL",
		   INT2FIX(GPGME_KEYLIST_MODE_LOCAL));
  rb_define_const (mGPGME, "GPGME_KEYLIST_MODE_EXTERN",
		   INT2FIX(GPGME_KEYLIST_MODE_EXTERN));
  rb_define_const (mGPGME, "GPGME_KEYLIST_MODE_SIGS",
		   INT2FIX(GPGME_KEYLIST_MODE_SIGS));
}
