[pan2: 243/268] basic gpg support with gmime 2.6



commit 5cecf5150b47edde007ff02525dbe3f4fd1c7840
Author: Heinrich MÃller <henmull src gnome org>
Date:   Mon Dec 12 22:58:33 2011 +0100

    basic gpg support with gmime 2.6

 README                          |    3 +-
 configure.in                    |   13 +-
 gtkspell/examples/advanced.c    |   82 --
 gtkspell/examples/simple.c      |   58 -
 gtkspell/gtkspell/deprecated.c  |   35 -
 gtkspell/gtkspell/gtkspell.c    |  888 -------------
 pan/data-impl/article-filter.cc |   10 +-
 pan/data-impl/profiles.cc       |    1 -
 pan/data/article-cache.cc       |   14 +-
 pan/data/article-cache.h        |   11 +-
 pan/gui/Makefile.am             |   11 +-
 pan/gui/body-pane.cc            |  108 +--
 pan/gui/body-pane.h             |   11 +-
 pan/gui/gpg.cc                  |  133 --
 pan/gui/gpg.h                   |   79 --
 pan/gui/gui.cc                  |   18 +-
 pan/gui/pan.cc                  |    6 +-
 pan/gui/post-ui.cc              |   51 +-
 pan/gui/post-ui.h               |    4 -
 pan/gui/profiles-dialog.cc      |   80 +-
 pan/gui/profiles-dialog.h       |    3 +-
 pan/tasks/task-upload.cc        |    2 -
 pan/usenet-utils/Makefile.am    |   10 +-
 pan/usenet-utils/gpg.cc         |  134 ++
 pan/usenet-utils/gpg.h          |  132 ++
 pan/usenet-utils/mime-utils.cc  |  591 +++------
 pan/usenet-utils/mime-utils.h   |   40 +-
 uulib/uuscan.c                  |   70 +-
 yenclib/crc32.c                 |  614 ---------
 yenclib/crc32.h                 |   38 -
 yenclib/uuencode.c              | 2692 ---------------------------------------
 yenclib/uunconc.c               | 1718 -------------------------
 32 files changed, 612 insertions(+), 7048 deletions(-)
---
diff --git a/README b/README
index 0896543..05322cd 100644
--- a/README
+++ b/README
@@ -7,7 +7,7 @@ REQUIREMENTS
 
     Pan requires these libraries:
     * GTK+ 2.16.0 or higher (optionally GTK+ 3.0.0 or higher) <http://www.gtk.org/>
-    * gmime 2.4.0 or higher <http://spruce.sourceforge.net/gmime/>
+    * gmime 2.6.0 or higher <http://spruce.sourceforge.net/gmime/>
 
     Spellchecking requires the following library:
     * gtkspell 2.0.7 or higher <http://gtkspell.sourceforge.net>
@@ -16,7 +16,6 @@ REQUIREMENTS
     * Libnotify (0.4.1)
     * Gnome-Keyring (3.2.2)
     * DBUS
-    * GPGME(made-easy) (1.3.0)    
 
     Most Linux distributions already have these; they can also be 
     downloaded from their home pages or installed via packet managers.
diff --git a/configure.in b/configure.in
index a89b89a..1c85995 100644
--- a/configure.in
+++ b/configure.in
@@ -46,7 +46,7 @@ dnl GtkSpell is optional: GTKSPELL_REQUIRED refers to the minimum version
 dnl needed if you want to build Pan with spellchecking in the Post window.
 
 GLIB_REQUIRED=2.14.0
-GMIME_REQUIRED=2.4.0
+GMIME_REQUIRED=2.6.0
 GTK_REQUIRED=2.16.0
 GTK3_REQUIRED=3.0.0
 GTKSPELL_REQUIRED=2.0.7
@@ -54,7 +54,6 @@ OPENSSL_REQUIRED=1.0.0
 LIBNOTIFY_REQUIRED=0.4.1
 LIBGSASL_REQUIRED=1.6.1
 LIBGKR_REQUIRED=3.2.2
-LIBGPGME_REQUIRED=1.3.0
 AC_SUBST(GLIB_REQUIRED)
 AC_SUBST(GMIME_REQUIRED)
 AC_SUBST(GTK_REQUIRED)
@@ -156,16 +155,6 @@ if test "x$enable_gkr" = "xyes" ; then
   fi
 fi
 
-dnl Check for gpgme for message encryption / signing
-AC_ARG_ENABLE([gpgme],
-AC_HELP_STRING([--enable-gpgme],[enable gpgme support]),[enable_gpgme=$enableval],[enable_gpgme=yes])
-if test "x$enable_gpgme" = "xyes" ; then
-  AM_PATH_GPGME([$LIBGPGME_REQUIRED],[HAVE_GPGME="yes"],[HAVE_GPGME="no"])
-  if test "x$HAVE_GPGME" = "xyes"; then
-    AC_DEFINE([HAVE_GPGME],[1],[gpgme for message encryption / signing])
-  fi
-fi
-
 dnl Check to see if strftime supports the use of %l and %k
 AC_MSG_CHECKING(for %l and %k support in strftime)
 AC_TRY_RUN([
diff --git a/pan/data-impl/article-filter.cc b/pan/data-impl/article-filter.cc
index 8bee5a7..82f2dce 100644
--- a/pan/data-impl/article-filter.cc
+++ b/pan/data-impl/article-filter.cc
@@ -189,13 +189,9 @@ ArticleFilter :: test_article (const Data        & data,
         {
           if (cache.contains(article.message_id)) {
             ArticleCache::mid_sequence_t mid(1, article.message_id);
-#ifdef HAVE_GPGME
-            GPGDecErr unused_for_now;
-            GPGSignersInfo unused;
-            GMimeMessage *msg = cache.get_message(mid, unused, unused_for_now);
-#else
-            GMimeMessage *msg = cache.get_message(mid);
-#endif
+            GPGDecErr err;
+            GMimeMessage *msg = cache.get_message(mid,err);
+
             const char *hdr = g_mime_object_get_header(GMIME_OBJECT(msg), criteria._header);
             pass = criteria._text.test (hdr);
             g_object_unref(msg);
diff --git a/pan/data-impl/profiles.cc b/pan/data-impl/profiles.cc
index b844689..646977a 100644
--- a/pan/data-impl/profiles.cc
+++ b/pan/data-impl/profiles.cc
@@ -105,7 +105,6 @@ namespace
           p.use_sigfile = !strcmp (*v, "true");
         p.sig_type = p.GPGSIG;
         p.use_gpgsig = true;
-        std::cerr<<"got profile "<<p.use_sigfile<<" "<<p.use_gpgsig<<"\n";
       }
     }
   }
diff --git a/pan/data/article-cache.cc b/pan/data/article-cache.cc
index f76333c..2d82a31 100644
--- a/pan/data/article-cache.cc
+++ b/pan/data/article-cache.cc
@@ -398,11 +398,7 @@ ArticleCache :: get_message_mem_stream (const Quark& mid) const
 }
 
 GMimeMessage*
-#ifdef HAVE_GPGME
-ArticleCache :: get_message (const mid_sequence_t& mids, GPGSignersInfo& signer_info, GPGDecErr& err) const
-#else
-ArticleCache :: get_message (const mid_sequence_t& mids) const
-#endif
+ArticleCache :: get_message (const mid_sequence_t& mids, GPGDecErr& err) const
 {
    debug ("trying to get a message with " << mids.size() << " parts");
    GMimeMessage * retval = NULL;
@@ -423,13 +419,11 @@ ArticleCache :: get_message (const mid_sequence_t& mids) const
         streams.push_back (stream);
    }
 
+
    // build the message
    if (!streams.empty())
-#ifdef HAVE_GPGME
-     retval = mime :: construct_message (&streams.front(), streams.size(), signer_info, err);
-#else
-     retval = mime :: construct_message (&streams.front(), streams.size());
-#endif
+     retval = mime :: construct_message (&streams.front(), streams.size(), err);
+
    // cleanup
    foreach (streams_t, streams, it)
      g_object_unref (*it);
diff --git a/pan/data/article-cache.h b/pan/data/article-cache.h
index 31937e8..bffe5a7 100644
--- a/pan/data/article-cache.h
+++ b/pan/data/article-cache.h
@@ -28,9 +28,7 @@ extern "C" {
 #include <pan/general/string-view.h>
 #include <pan/general/quark.h>
 
-#ifdef HAVE_GPGME
-  #include <pan/gui/gpg.h>
-#endif
+#include <pan/usenet-utils/gpg.h>
 
 extern "C"
 {
@@ -74,11 +72,8 @@ namespace pan
       void resize ();
       void clear ();
 
-#ifdef HAVE_GPGME
-      GMimeMessage* get_message (const mid_sequence_t&, GPGSignersInfo&, GPGDecErr&) const;
-#else
-      GMimeMessage* get_message (const mid_sequence_t&) const;
-#endif
+      GMimeMessage* get_message (const mid_sequence_t&, GPGDecErr&) const;
+
       typedef std::vector<std::string> strings_t;
       strings_t get_filenames (const mid_sequence_t&);
 
diff --git a/pan/gui/Makefile.am b/pan/gui/Makefile.am
index 2e930cf..7730a7c 100644
--- a/pan/gui/Makefile.am
+++ b/pan/gui/Makefile.am
@@ -1,5 +1,5 @@
 AM_CPPFLAGS = -I top_srcdir@ @GTKSPELL_CFLAGS@ @GTK_CFLAGS@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ \
-							@OPENSSL_CFLAGS@ @LIBNOTIFY_CFLAGS@ @LIBGNOME_KEYRING_1_CFLAGS@ @GPGME_CFLAGS@ -DPANLOCALEDIR=\""$(panlocaledir)"\"
+							@OPENSSL_CFLAGS@ @LIBNOTIFY_CFLAGS@ @LIBGNOME_KEYRING_1_CFLAGS@ -DPANLOCALEDIR=\""$(panlocaledir)"\"
 
 noinst_LIBRARIES = libpangui.a
 
@@ -33,8 +33,7 @@ libpangui_a_SOURCES = \
  server-ui.cc \
  task-pane.cc \
  xface.c \
- url.cc \
- gpg.cc
+ url.cc
 
 noinst_HEADERS = \
  action-manager.h \
@@ -76,8 +75,7 @@ noinst_HEADERS = \
  task-pane.h \
  url.h \
  wait.h \
- xface.h \
- gpg.h
+ xface.h
 
 EXTRA_DIST = \
  panrc.rc
@@ -97,8 +95,7 @@ endif
 
 pan_SOURCES = gui.cc pan.cc $(WINRC)
 pan_LDADD = ./libpangui.a $(WINRCOBJ) ../data-impl/libpandata.a ../tasks/libtasks.a ../data/libdata.a ../usenet-utils/libusenetutils.a ../general/libgeneralutils.a \
-            ../../uulib/libuu.a @GTKSPELL_LIBS@ @GTK_LIBS@ @GMIME_LIBS@ @GLIB_LIBS@ @OPENSSL_LIBS@ @LIBNOTIFY_LIBS@ @LIBGNOME_KEYRING_1_LIBS@ @GPGME_LIBS@
-
+            ../../uulib/libuu.a @GTKSPELL_LIBS@ @GTK_LIBS@ @GMIME_LIBS@ @GLIB_LIBS@ @OPENSSL_LIBS@ @LIBNOTIFY_LIBS@ @LIBGNOME_KEYRING_1_LIBS@
 if HAVE_WIN32
 pan_LDFLAGS = -mwindows
 endif
diff --git a/pan/gui/body-pane.cc b/pan/gui/body-pane.cc
index bd0a79e..55f80c0 100644
--- a/pan/gui/body-pane.cc
+++ b/pan/gui/body-pane.cc
@@ -916,25 +916,6 @@ namespace
 
 }
 
-#ifdef HAVE_GPGME
-bool
-BodyPane ::get_gpgsig_from_gmime_part (GMimeObject* parent, GMimeObject* base, GMimePart * part)
-{
-  GMimeDataWrapper * wrapper (g_mime_part_get_content_object (part));
-  GMimeStream * mem_stream (g_mime_stream_mem_new ());
-  if (wrapper)
-  {
-    g_mime_data_wrapper_write_to_stream (wrapper, mem_stream);
-    g_mime_stream_reset(mem_stream);
-    gpg_decrypt_and_verify(_signer_info, _gpgerr, mem_stream,
-                           g_mime_multipart_index_of(GMIME_MULTIPART(parent),base),
-                           parent);
-    return true;
-  }
-  return false;
-}
-#endif
-
 void
 BodyPane :: append_part (GMimeObject * parent, GMimeObject * obj, GtkAllocation * widget_size)
 {
@@ -1000,8 +981,7 @@ BodyPane :: append_part (GMimeObject * parent, GMimeObject * obj, GtkAllocation
   }
 
   // or, if it's text, display it
-  else if (g_mime_content_type_is_type (type, "text", "*") ||
-           (g_mime_content_type_is_type (type, "*", "pgp-signature")))
+  else if (g_mime_content_type_is_type (type, "text", "*"))
   {
     const char * fallback_charset (_charset.c_str());
     const char * p_flowed (g_mime_object_get_content_type_parameter(obj,"format"));
@@ -1017,16 +997,6 @@ BodyPane :: append_part (GMimeObject * parent, GMimeObject * obj, GtkAllocation
     const bool do_urls (_prefs.get_flag ("highlight-urls", true));
     append_text_buffer_nolock (&_tm, _buffer, str, do_mute, do_smilies, do_markup, do_urls);
     is_done = true;
-#ifdef HAVE_GPGME
-    /* verify signature */
-
-    if (g_mime_content_type_is_type (type, "*", "pgp-signature"))
-    {
-      bool res = get_gpgsig_from_gmime_part(parent, obj, part);
-      std::cerr<<"1023\n";
-      if (res) update_sig_valid(_gpgerr.verify_ok);
-    }
-#endif
   }
 
   // otherwise, bitch and moan.
@@ -1218,6 +1188,7 @@ BodyPane :: set_text_from_message (GMimeMessage * message)
   // the all-headers don't get included in the followup
 
   // set the text buffer...
+
   if (message)
     g_mime_message_foreach (message, foreach_part_cb, this);
 
@@ -1231,7 +1202,6 @@ BodyPane :: set_text_from_message (GMimeMessage * message)
     gtk_text_buffer_get_start_iter  (_buffer, &iter);
     gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW(_text), &iter, 0.0, true, 0.0, 0.0);
   }
-  std::cerr<<"1234\n";
 
 }
 
@@ -1244,17 +1214,23 @@ BodyPane :: refresh ()
 namespace
 {
 
-  std::string get_email_address(std::string& s)
+  /** Separates user id into name and email address */
+  std::pair<std::string,std::string> get_email_address(std::string& s)
   {
+    std::pair<std::string,std::string> ret;
     size_t in = s.find("<");
     size_t out = s.find(">");
-    if (in == std::string::npos || out == std::string::npos) return "...";
+    if (in == std::string::npos ||
+        out == std::string::npos)
+      return ret;
+
+    ret.first = s.substr(0,in-1);
+    ret.second = s.substr (in+1,out-in-1);
 
-    return s.substr (in+1,out-in-1);
+    return ret;
   }
 }
 
-#ifdef HAVE_GPGME
 gboolean
 BodyPane:: on_tooltip_query(GtkWidget  *widget,
                             gint        x,
@@ -1265,27 +1241,23 @@ BodyPane:: on_tooltip_query(GtkWidget  *widget,
 {
   BodyPane* pane = static_cast<BodyPane*>(data);
   GPGDecErr& err = pane->_gpgerr;
-  GPGSignersInfo& info = pane->_signer_info;
-
-//  g_return_val_if_fail(err.dec_ok, false);
-  g_return_val_if_fail(err.err == GPG_ERR_NO_ERROR || err.err == GPG_ERR_NO_DATA, false);
+  GPGSignersInfo& info = err.signers;
 
   if (err.no_sigs) return false;
-  if (!err.v_res) return false;
-  if (!err.v_res->signatures) return false;
-  if (!err.v_res->signatures->fpr) return false;
+  if (info.signers.empty()) return false;
 
   EvolutionDateMaker ed;
 
   char buf[2048];
+  std::pair<std::string,std::string> name_and_email = get_email_address(info.signers[0].name);
   g_snprintf(buf, sizeof(buf),
-             "<u>This is a <b>GPG-Signed</b> message.</u>\n\n"
-             "<b>Signer</b> : %s (\"%s\")\n"
+             "<u>This is a <b>PGP-Signed</b> message.</u>\n\n"
+             "<b>Signer</b> : %s ('%s')\n"
              "<b>Valid until</b> : %s\n"
              "<b>Created on</b> : %s",
-             info.real_name.c_str(), get_email_address(info.uid).c_str(),
-             ed.get_date_string(info.expires),
-             ed.get_date_string(info.creation_timestamp)
+             name_and_email.first.c_str(), name_and_email.second.c_str(),
+             (info.signers[0].never_expires ? "always" : ed.get_date_string(info.signers[0].expires)),
+             ed.get_date_string(info.signers[0].created)
              );
 
   gtk_tooltip_set_icon_from_stock (tooltip, GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
@@ -1299,12 +1271,8 @@ void
 BodyPane :: update_sig_valid(int i)
 {
 
-  std::cerr<<"update sig "<<i<<"\n";
-
   gtk_image_clear(GTK_IMAGE(_sig_icon));
 
-  i = 1;
-
   switch (i)
   {
     case 0:
@@ -1316,36 +1284,30 @@ BodyPane :: update_sig_valid(int i)
       break;
   }
 }
-#endif
 
 void
 BodyPane :: set_article (const Article& a)
 {
   _article = a;
 
-  const char* gpg_sign(0);
-
   if (_message)
     g_object_unref (_message);
-#ifdef HAVE_GPGME
-  _message = _cache.get_message (_article.get_part_mids(), _signer_info, _gpgerr);
-  gpg_sign = g_mime_object_get_header(GMIME_OBJECT(_message), "X-GPG-Signed");
-#else
-  _message = _cache.get_message (_article.get_part_mids());
-#endif
+
+  _gpgerr.clear();
+
+  _message = _cache.get_message (_article.get_part_mids(), _gpgerr);
 
   int val(-1);
-  if (gpg_sign)
   {
-    if (!strcmp(gpg_sign, "valid"))
+    if (_gpgerr.verify_ok && !_gpgerr.no_sigs)
       val = 1;
-    else if (!strcmp(gpg_sign, "invalid"))
+    else if (!_gpgerr.verify_ok && !_gpgerr.no_sigs)
       val = 0;
+    else
+      val = -1;
   }
-#ifdef HAVE_GPGME
-  std::cerr<<"1344\n";
+
   update_sig_valid(val);
-#endif
   refresh ();
 
   _data.mark_read (_article);
@@ -1358,9 +1320,8 @@ BodyPane :: clear ()
     g_object_unref (_message);
   _message = 0;
   refresh ();
-#ifdef HAVE_GPGME
   update_sig_valid(-1);
-#endif
+
 }
 
 void
@@ -1545,7 +1506,8 @@ BodyPane :: BodyPane (Data& data, ArticleCache& cache, Prefs& prefs):
   _cache (cache),
   _hscroll_visible (false),
   _vscroll_visible (false),
-  _message (0)
+  _message (0),
+  _gpgerr(GPG_DECODE)
 {
 
   for (guint i=0; i<NUM_ICONS; ++i)
@@ -1585,12 +1547,10 @@ BodyPane :: BodyPane (Data& data, ArticleCache& cache, Prefs& prefs):
   gtk_label_set_ellipsize (GTK_LABEL(w), PANGO_ELLIPSIZE_MIDDLE);
   gtk_label_set_use_markup (GTK_LABEL(w), true);
   gtk_box_pack_start (GTK_BOX(hbox), w, true, true, PAD_SMALL);
-#ifdef HAVE_GPGME
   gtk_widget_set_size_request (_sig_icon, 32, 32);
   gtk_box_pack_start (GTK_BOX(hbox), _sig_icon, true, true, PAD_SMALL);
   gtk_widget_set_has_tooltip (_sig_icon, true);
   g_signal_connect(_sig_icon,"query-tooltip",G_CALLBACK(on_tooltip_query), this);
-#endif
   w = _xface = gtk_image_new();
   gtk_widget_set_size_request (w, 48, 48);
   gtk_box_pack_start (GTK_BOX(hbox), w, false, false, PAD_SMALL);
@@ -1887,7 +1847,9 @@ BodyPane :: create_followup_or_reply (bool is_reply)
     g_object_unref (wrapper);
     g_object_unref (part);
     g_object_unref (stream);
-//std::cerr << LINE_ID << " here is the modified clone\n [" << g_mime_object_to_string((GMimeObject *)msg) << ']' << std::endl;
+
+  //std::cerr << LINE_ID << " here is the modified clone\n [" << g_mime_object_to_string((GMimeObject *)msg) << ']' << std::endl;
+
   }
 
   return msg;
diff --git a/pan/gui/body-pane.h b/pan/gui/body-pane.h
index 2120f50..8ced5d0 100644
--- a/pan/gui/body-pane.h
+++ b/pan/gui/body-pane.h
@@ -42,15 +42,16 @@ namespace pan
       Data& _data;
       ArticleCache& _cache;
       GtkWidget* _sig_icon;
-#ifdef HAVE_GPGME
+
       void update_sig_valid(int i);
+
       static gboolean on_tooltip_query(GtkWidget  *widget,
                                        gint        x,
                                        gint        y,
                                        gboolean    keyboard_tip,
                                        GtkTooltip *tooltip,
                                        gpointer    data);
-#endif
+
     public:
       BodyPane (Data&, ArticleCache&, Prefs&);
       ~BodyPane ();
@@ -111,11 +112,6 @@ namespace pan
 
       /* updated with values from gmimemessage */
    public:
-#ifdef HAVE_GPGME
-      GPGDecErr _gpgerr;
-      GPGSignersInfo _signer_info;
-      bool get_gpgsig_from_gmime_part (GMimeObject* parent, GMimeObject* base, GMimePart * part);
-#endif
 
     private:
       std::string _hover_url;
@@ -135,6 +131,7 @@ namespace pan
       GMimeMessage * _message;
       TextMassager _tm;
       std::string _charset;
+      GPGDecErr _gpgerr;
   };
 }
 
diff --git a/pan/gui/gui.cc b/pan/gui/gui.cc
index aa8e1ce..334f7b5 100644
--- a/pan/gui/gui.cc
+++ b/pan/gui/gui.cc
@@ -69,9 +69,7 @@ extern "C" {
 
 #include "profiles-dialog.h"
 
-#ifdef HAVE_GPGME
-  #include "gpg.h"
-#endif
+#include <pan/usenet-utils/gpg.h>
 
 namespace pan
 {
@@ -344,9 +342,8 @@ GUI :: GUI (Data& data, Queue& queue, Prefs& prefs, GroupPrefs& group_prefs):
         on_queue_task_active_changed (queue, *(*it), true);
     }
   }
-#ifdef HAVE_GPGME
+
   init_gpg();
-#endif
 }
 
 namespace
@@ -396,9 +393,7 @@ GUI :: ~GUI ()
     g_object_unref (*it);
   g_object_unref (G_OBJECT(_ui_manager));
 
-#ifdef HAVE_GPGME
   deinit_gpg();
-#endif
 }
 
 /***
@@ -695,13 +690,8 @@ namespace
     virtual void on_progress_finished (Progress&, int status)
     {
       if (status == OK) {
-#ifdef HAVE_GPGME
-        GPGDecErr unused;
-        GPGSignersInfo unuse;
-        GMimeMessage * message = _cache.get_message (_article.get_part_mids(), unuse, unused);
-#else
-        GMimeMessage * message = _cache.get_message (_article.get_part_mids());
-#endif
+        GPGDecErr err;
+        GMimeMessage * message = _cache.get_message (_article.get_part_mids(),err);
         g_mime_message_foreach (message, foreach_part_cb, this);
         g_object_unref (message);
       }
diff --git a/pan/gui/pan.cc b/pan/gui/pan.cc
index 9dd8968..bb16456 100644
--- a/pan/gui/pan.cc
+++ b/pan/gui/pan.cc
@@ -51,11 +51,7 @@ extern "C" {
   #include <pan/tasks/socket-impl-openssl.h>
 #endif
 
-#ifdef HAVE_GPGME
-  #include <gpgme.h>
-  #include <pan/gui/gpg.h>
-#endif
-
+#include <pan/usenet-utils/gpg.h>
 #include <pan/data/cert-store.h>
 #include <pan/tasks/socket-impl-gio.h>
 #include <pan/tasks/socket-impl-main.h>
diff --git a/pan/gui/post-ui.cc b/pan/gui/post-ui.cc
index 9d7fd94..ca0247d 100644
--- a/pan/gui/post-ui.cc
+++ b/pan/gui/post-ui.cc
@@ -38,6 +38,7 @@ extern "C" {
 #include <pan/general/macros.h>
 #include <pan/general/utf8-utils.h>
 #include <pan/usenet-utils/gnksa.h>
+#include <pan/usenet-utils/gpg.h>
 #include <pan/usenet-utils/message-check.h>
 #include <pan/usenet-utils/mime-utils.h>
 #include <pan/data/data.h>
@@ -59,11 +60,6 @@ extern "C" {
 #define DEFAULT_SPELLCHECK_FLAG false
 #endif
 
-#ifdef HAVE_GPGME
-  #include <gpgme.h>
-  #include <pan/gui/gpg.h>
-#endif
-
 using namespace pan;
 
 #define USER_AGENT_PREFS_KEY "add-user-agent-header-when-posting"
@@ -132,7 +128,6 @@ namespace pan
     if (!self->_realized) return;
 
     gpg_sign = gtk_toggle_action_get_active (toggle);
-    std::cerr<<"gpg sign toggle "<<gpg_sign<<"\n";
   }
 
   void on_spellcheck_toggled (GtkToggleAction * toggle, gpointer post_g)
@@ -1025,44 +1020,19 @@ PostUI :: maybe_post_message (GMimeMessage * message)
 
   if(_file_queue_empty)
   {
-#ifdef HAVE_GPGME
-    GPGEncErr fail;
-    if (user_has_gpg && gpg_enc && !gpg_sign)
-    {
-      std::cerr<<"encrypt\n";
-      Profile p(get_current_profile());
-      std::string res = gpg_encrypt(p.gpg_sig_uid, get_body(), fail);
-      if (gpgme_err_code(fail.err) == GPG_ERR_NO_ERROR)
-        gtk_text_buffer_set_text (_body_buf, res.c_str(), res.size());
-      else
-      {
-        Log::add_err_va("Failed to encode the Message with your key : \"%s\"",gpgme_strerror(fail.err));
-        return false;
-      }
-    }
-    if (user_has_gpg && gpg_enc && gpg_sign)
-    {
-      std::cerr<<"encrypt\n";
-      Profile p(get_current_profile());
-      std::string res = gpg_encrypt_and_sign(p.gpg_sig_uid,get_body(), fail);
-      if (gpgme_err_code(fail.err) == GPG_ERR_NO_ERROR)
-        gtk_text_buffer_set_text (_body_buf, res.c_str(), res.size());
-      else
-      {
-        Log::add_err_va("Failed to sign and encode the Message with your key : \"%s\"",gpgme_strerror(fail.err));
-        return false;
-      }
-    }
 
-#endif
     GMimeMessage* msg = new_message_from_ui(POSTING);
     bool go_on(true);
 
-#ifdef HAVE_GPGME
+    GPtrArray * rcp = g_ptr_array_new();
     Profile p(get_current_profile());
+    g_ptr_array_add(rcp, (gpointer)p.gpg_sig_uid.c_str());
     if (user_has_gpg && gpg_sign && !gpg_enc)
-      go_on = go_on && message_add_signed_part(p.gpg_sig_uid, get_body(), msg, fail);
-#endif
+      go_on = go_on && message_add_signed_part(p.gpg_sig_uid, get_body(), msg);
+    else if (user_has_gpg && gpg_enc && !gpg_sign)
+      go_on = go_on && gpg_encrypt(p.gpg_sig_uid, get_body(), msg, rcp, false);
+    else if (user_has_gpg && gpg_enc && gpg_sign)
+      go_on = go_on && gpg_encrypt(p.gpg_sig_uid, get_body(), msg, rcp, true);
 
     if (go_on)
     {
@@ -1070,6 +1040,7 @@ PostUI :: maybe_post_message (GMimeMessage * message)
       _post_task->add_listener (this);
       _queue.add_task (_post_task, Queue::TOP);
     }
+
   } else {
 
     // prepend header for xml file (if one was chosen)
@@ -1545,7 +1516,7 @@ PostUI :: new_message_from_ui (Mode mode, bool copy_body)
 
     GMimeContentType * type = g_mime_content_type_new_from_string (pch);
     g_free (pch);
-//    g_mime_object_set_content_type ((GMimeObject *) part, type); // part owns type now. type isn't refcounted.
+    g_mime_object_set_content_type ((GMimeObject *) part, type); // part owns type now. type isn't refcounted.
     g_mime_part_set_content_object (part, content_object);
     g_mime_part_set_content_encoding (part, GMIME_CONTENT_ENCODING_8BIT);
     g_object_unref (content_object);
@@ -1782,7 +1753,7 @@ namespace
     }
     else if (type == Profile::GPGSIG)
     {
-      /// TODO : Perhaps show but omit in gmimemessage, or make a multipart ??
+      /// TODO : Perhaps show but omit in gmimemessage ??
     }
 
     /* Convert signature to UTF-8. Since the signature is a local file,
diff --git a/pan/gui/post-ui.h b/pan/gui/post-ui.h
index c51319a..4ae458c 100644
--- a/pan/gui/post-ui.h
+++ b/pan/gui/post-ui.h
@@ -31,10 +31,6 @@
 
 #include <pan/usenet-utils/MersenneTwister.h>
 
-#ifdef HAVE_GPGME
-  #include <gpgme.h>
-#endif
-
 namespace pan
 {
   class Profiles;
diff --git a/pan/gui/profiles-dialog.cc b/pan/gui/profiles-dialog.cc
index e6f317d..14716f6 100644
--- a/pan/gui/profiles-dialog.cc
+++ b/pan/gui/profiles-dialog.cc
@@ -35,10 +35,7 @@ extern "C" {
 #include "pan-file-entry.h"
 #include "profiles-dialog.h"
 
-#ifdef HAVE_GPGME
-  #include <gpgme.h>
-  #include <pan/gui/gpg.h>
-#endif
+#include <pan/usenet-utils/gpg.h>
 
 using namespace pan;
 
@@ -74,13 +71,15 @@ namespace
 
     if (row == 2) // GPG
     {
+      gtk_widget_set_tooltip_text(d->_signature_file_combo_box,
+                                  _("Please choose your Email Address according to your PGP key's user id."));
       gtk_widget_hide (d->_signature_file);
-      gtk_widget_show (d->_gpg_sig_entry);
+
     }
     else
     {
+      gtk_widget_set_has_tooltip(d->_signature_file_combo_box,false);
       gtk_widget_show (d->_signature_file);
-      gtk_widget_hide (d->_gpg_sig_entry);
     }
   }
 
@@ -115,7 +114,6 @@ namespace
   }
 }
 
-/// TODO (perhaps) beautify this!
 
 ProfileDialog :: ProfileDialog (const Data         & data,
                                 const StringView   & profile_name,
@@ -148,6 +146,7 @@ ProfileDialog :: ProfileDialog (const Data         & data,
     HIG :: workarea_add_row (t, &row, _("_Full Name:"), w);
     w = _address_entry = gtk_entry_new ();
     set_entry (w, profile.address);
+    gtk_widget_set_tooltip_text(w, _("Your Email Address. Note that this has to match your GPG Signature's Address to verify messages correctly."));
     HIG :: workarea_add_row (t, &row, _("_Email Address:"), w);
     w = _server_combo = make_servers_combo (data, profile.posting_server);
     HIG :: workarea_add_row (t, &row, _("_Post Articles via:"), w);
@@ -167,49 +166,18 @@ ProfileDialog :: ProfileDialog (const Data         & data,
     GtkTreeIter iter;
     GtkListStore * store;
     GtkCellRenderer * renderer;
-#ifdef HAVE_GPGME
-    std::map<std::string, int> author_numbers;
-    store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
-    int cnt(0);
-    foreach (signers_m, gpg_signers, it)
-    {
-      gtk_list_store_append (store, &iter);
-      gtk_list_store_set (store, &iter, 0, it->second.real_name.c_str(),  1, it->first.c_str(), -1);
-      author_numbers.insert(std::pair<std::string, int>(it->first,cnt++));
-    }
-    w = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
-    hbox = gtk_hbox_new(FALSE, 3);
-    l = gtk_label_new(_("Signer : "));
-    gtk_misc_set_alignment (GTK_MISC(l), 0.0f, 0.5f);
-    gtk_box_pack_start(GTK_BOX(hbox), l, false, false, 0);
-    gtk_box_pack_start(GTK_BOX(hbox), w, true, true, 0);
-    _gpg_sig_entry = hbox;
-    _gpg_sig_entry_box = w;
-
-    int signer_no(0);
-    if (!profile.gpg_sig_uid.empty())
-    {
-      if (author_numbers.count(profile.gpg_sig_uid) != 0)
-        signer_no = author_numbers.find(profile.gpg_sig_uid)->second;
-    }
-    gtk_combo_box_set_active (GTK_COMBO_BOX(w), signer_no);
 
-    renderer = gtk_cell_renderer_text_new ();
-    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (w), renderer, true);
-    gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (w), renderer, "text", 0, NULL);
-#endif
     store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
     gtk_list_store_append (store, &iter);
     gtk_list_store_set (store, &iter, 0, _("Text File"),    1, Profile::FILE, -1);
     gtk_list_store_append (store, &iter);
     gtk_list_store_set (store, &iter, 0, _("Text"),         1, Profile::TEXT, -1);
     gtk_list_store_append (store, &iter);
-#ifdef HAVE_GPGME
     gtk_list_store_set (store, &iter, 0, _("PGP Signature"),1, Profile::GPGSIG, -1);
     gtk_list_store_append (store, &iter);
-#endif
     gtk_list_store_set (store, &iter, 0, _("Command"),      1, Profile::COMMAND, -1);
     w = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
+
     hbox = gtk_hbox_new(FALSE, 3);
     l = gtk_label_new(_("Signature Type : "));
     gtk_misc_set_alignment (GTK_MISC(l), 0.0f, 0.5f);
@@ -217,32 +185,22 @@ ProfileDialog :: ProfileDialog (const Data         & data,
     gtk_box_pack_start(GTK_BOX(hbox), w, true, true, 0);
     _signature_file_combo = hbox;
     _signature_file_combo_box = w;
-#ifdef HAVE_GPGME
+
     g_signal_connect (w, "changed", G_CALLBACK(on_signature_type_changed), this);
-#endif
+
     renderer = gtk_cell_renderer_text_new ();
     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (w), renderer, true);
     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (w), renderer, "text", 0, NULL);
 
     int active = ROW_FILE;
     if (profile.sig_type == profile.TEXT) active = ROW_TEXT;
-#ifdef HAVE_GPGME
     if (profile.sig_type == profile.GPGSIG) active = ROW_GPGSIG;
     if (profile.sig_type == profile.COMMAND) active = ROW_COMMAND;
-#else
-    if (profile.sig_type == profile.COMMAND) active = ROW_GPGSIG;
-#endif
-
 
     gtk_combo_box_set_active (GTK_COMBO_BOX(w), active);
-
     GtkWidget* vbox = gtk_vbox_new(TRUE, 3);
-
     gtk_box_pack_start(GTK_BOX(vbox), _signature_file_combo, false, false, 0);
     gtk_box_pack_start(GTK_BOX(vbox), _signature_file, false, false, 0);
-#ifdef HAVE_GPGME
-    gtk_box_pack_start(GTK_BOX(vbox), _gpg_sig_entry, false, false, 0);
-#endif
     HIG :: workarea_add_row (t, &row, "",vbox);
 
   HIG :: workarea_add_section_divider (t, &row);
@@ -302,10 +260,8 @@ ProfileDialog :: ProfileDialog (const Data         & data,
     gtk_container_add (GTK_CONTAINER(eventbox), scrolled_window);
     HIG :: workarea_add_row (t, &row, _("E_xtra Headers:"), eventbox, w);
 
-  /// REMOVED for now!
-//  on_sig_file_toggled (GTK_TOGGLE_BUTTON(_signature_file_check), _gpg_sig_entry_box);
-//  on_sig_file_toggled (GTK_TOGGLE_BUTTON(_signature_file_check), _signature_file);
-//  on_sig_file_toggled (GTK_TOGGLE_BUTTON(_signature_file_check), _signature_file_combo_box);
+  on_sig_file_toggled (GTK_TOGGLE_BUTTON(_signature_file_check), _signature_file);
+  on_sig_file_toggled (GTK_TOGGLE_BUTTON(_signature_file_check), _signature_file_combo_box);
 
   gtk_box_pack_start (GTK_BOX( gtk_dialog_get_content_area( GTK_DIALOG(_root))), t, true, true, 0);
   gtk_widget_show_all (t);
@@ -314,9 +270,8 @@ ProfileDialog :: ProfileDialog (const Data         & data,
     gtk_window_set_transient_for (GTK_WINDOW(_root), parent);
     gtk_window_set_position (GTK_WINDOW(_root), GTK_WIN_POS_CENTER_ON_PARENT);
   }
-#ifdef HAVE_GPGME
+
   on_signature_type_changed(GTK_COMBO_BOX(_signature_file_combo_box), this);
-#endif
 }
 
 ProfileDialog :: ~ProfileDialog ()
@@ -380,14 +335,9 @@ ProfileDialog :: get_profile (std::string& profile_name, Profile& profile)
   profile.use_gpgsig = (type == profile.GPGSIG);
   if (!profile.use_gpgsig)
     from_entry (file_entry_gtk_entry(_signature_file), profile.signature_file);
-#ifdef HAVE_GPGME
-  char* uid;
-  combo = GTK_COMBO_BOX (_gpg_sig_entry_box);
-  gtk_combo_box_get_active_iter (combo, &iter);
-  model = gtk_combo_box_get_model (combo);
-  gtk_tree_model_get (model, &iter, 1, &uid, -1);
-  profile.gpg_sig_uid = uid;
-#endif
+
+  profile.gpg_sig_uid = profile.address;
+
   char * pch;
   combo = GTK_COMBO_BOX (_server_combo);
   gtk_combo_box_get_active_iter (combo, &iter);
diff --git a/pan/gui/profiles-dialog.h b/pan/gui/profiles-dialog.h
index b595a4d..28a4296 100644
--- a/pan/gui/profiles-dialog.h
+++ b/pan/gui/profiles-dialog.h
@@ -55,11 +55,10 @@ namespace pan
       GtkWidget * _signature_file_check;
       GtkWidget * _server_combo;
       GtkWidget * _extra_headers_tv;
-      GtkWidget * _signature_file_combo_box;
       GtkWidget * _signature_file_combo;
-      GtkWidget * _gpg_sig_entry_box;
     public:
 
+      GtkWidget * _signature_file_combo_box;
       GtkWidget * _signature_file;
       GtkWidget * _gpg_sig_entry;
 
diff --git a/pan/tasks/task-upload.cc b/pan/tasks/task-upload.cc
index e487ca8..d4b1f99 100644
--- a/pan/tasks/task-upload.cc
+++ b/pan/tasks/task-upload.cc
@@ -212,8 +212,6 @@ TaskUpload :: prepend_headers(GMimeMessage* msg, TaskUpload::Needed * n, std::st
       all = g_mime_object_to_string ((GMimeObject *) msg);
     else if (_first && _queue_pos == 0)
       all = g_mime_object_get_headers ((GMimeObject *) msg);
-    else
-      all = g_mime_object_get_headers ((GMimeObject *) msg);
 
     out << all << "\n";
     if (_first && _queue_pos == -1) g_free(all);
diff --git a/pan/usenet-utils/Makefile.am b/pan/usenet-utils/Makefile.am
index 1ebac86..33889ad 100644
--- a/pan/usenet-utils/Makefile.am
+++ b/pan/usenet-utils/Makefile.am
@@ -1,6 +1,4 @@
-AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@ @GPGME_CFLAGS@
-
-AM_LDFLAGS = @GPGME_LIBS@
+AM_CPPFLAGS = -I top_srcdir@ @GMIME_CFLAGS@ @GLIB_CFLAGS@
 
 noinst_LIBRARIES = libusenetutils.a
 
@@ -14,7 +12,8 @@ libusenetutils_a_SOURCES = \
  scorefile.cc \
  text-massager.cc \
  url-find.cc \
- blowfish.cc
+ blowfish.cc \
+ gpg.cc
 
 noinst_HEADERS = \
  defgroup.h \
@@ -29,7 +28,8 @@ noinst_HEADERS = \
  url-find.h \
  ssl-utils.h \
  blowfish.h \
- blowfish_cyphers.h
+ blowfish_cyphers.h \
+ gpg.h
 
 #noinst_PROGRAMS = \
 # gnksa-test \
diff --git a/pan/usenet-utils/gpg.cc b/pan/usenet-utils/gpg.cc
new file mode 100644
index 0000000..869e2c7
--- /dev/null
+++ b/pan/usenet-utils/gpg.cc
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006  Charles Kerr <charles rebelbase com>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 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 <vector>
+#include <iostream>
+#include <pan/general/log.h>
+#include <pan/general/macros.h>
+#include "gpg.h"
+
+extern "C" {
+  #include <stdlib.h>
+  #include <unistd.h>
+  #include <string.h>
+}
+
+namespace pan
+{
+
+  static gboolean
+  request_passwd (GMimeCryptoContext *ctx, const char *user_id, const char *prompt_ctx,
+                  gboolean reprompt, GMimeStream *response, GError **err)
+  {
+    return TRUE;
+  }
+
+  GMimeCryptoContext *gpg_ctx;
+  bool gpg_inited;
+
+
+  void deinit_gpg()
+  {
+    gpg_inited=false;
+    g_object_unref (gpg_ctx);
+  }
+
+  void fill_signer_info(GPGSignersInfo& info, GMimeSignatureList * sig_list)
+  {
+    g_return_if_fail(sig_list);
+
+    int l = g_mime_signature_list_length(sig_list);
+    info.signers.reserve(l);
+    GMimeSignature * sig(0);
+    Signer signer;
+    for (int i=0;i<l;++i)
+    {
+      sig = g_mime_signature_list_get_signature (sig_list, i);
+
+      signer.name = sig->cert->name ? sig->cert->name : "(null)";
+      signer.key_id = sig->cert->keyid ? sig->cert->keyid : "(null)";
+      signer.fpr = sig->cert->fingerprint ? sig->cert->fingerprint : "(null)";
+
+      switch (sig->cert->trust) {
+      case GMIME_CERTIFICATE_TRUST_NONE:
+        signer.trust = "None";
+        break;
+      case GMIME_CERTIFICATE_TRUST_NEVER:
+        signer.trust = "Never";
+      case GMIME_CERTIFICATE_TRUST_UNDEFINED:
+        signer.trust = "Undefined";
+        break;
+      case GMIME_CERTIFICATE_TRUST_MARGINAL:
+        signer.trust = "Marginal";
+        break;
+      case GMIME_CERTIFICATE_TRUST_FULLY:
+        signer.trust = "Fully";
+        break;
+      case GMIME_CERTIFICATE_TRUST_ULTIMATE:
+        signer.trust = "Ultimate";
+        break;
+      }
+
+      switch (sig->status) {
+      case GMIME_SIGNATURE_STATUS_GOOD:
+        signer.status = "GOOD";
+        break;
+      case GMIME_SIGNATURE_STATUS_BAD:
+        signer.status = "BAD";
+        break;
+      case GMIME_SIGNATURE_STATUS_ERROR:
+        signer.status = "ERROR";
+        break;
+      }
+
+      signer.created = sig->created;
+      signer.expires = sig->expires;
+      if (sig->expires == (time_t) 0)
+        signer.never_expires = true;
+
+      if (sig->errors) {
+
+        if (sig->errors & GMIME_SIGNATURE_ERROR_EXPSIG)
+          signer.error = "Expired";
+        if (sig->errors & GMIME_SIGNATURE_ERROR_NO_PUBKEY)
+          signer.error = "No Pub Key";
+        if (sig->errors & GMIME_SIGNATURE_ERROR_EXPKEYSIG)
+          signer.error = "Key Expired";
+        if (sig->errors & GMIME_SIGNATURE_ERROR_REVKEYSIG)
+          signer.error = "Key Revoked";
+      } else {
+          signer.error = "No errors for this signer";
+      }
+
+      info.signers.push_back(signer);
+    }
+  }
+
+  void init_gpg()
+  {
+    gpg_ctx = g_mime_gpg_context_new (request_passwd, "gpg");
+    if (!gpg_ctx) gpg_inited = false; else gpg_inited = true;
+    g_mime_gpg_context_set_auto_key_retrieve(GMIME_GPG_CONTEXT(gpg_ctx),true);
+    g_mime_gpg_context_set_always_trust(GMIME_GPG_CONTEXT(gpg_ctx),false);
+    g_mime_gpg_context_set_use_agent(GMIME_GPG_CONTEXT(gpg_ctx), true);
+  }
+
+
+}
diff --git a/pan/usenet-utils/gpg.h b/pan/usenet-utils/gpg.h
new file mode 100644
index 0000000..e959597
--- /dev/null
+++ b/pan/usenet-utils/gpg.h
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Pan - A Newsreader for Gtk+
+ * Copyright (C) 2002-2006  Charles Kerr <charles rebelbase com>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _HAVE_GPGDEFS_H
+#define _HAVE_GPGDEFS_H
+
+#include <gmime/gmime.h>
+#include <map>
+#include <vector>
+
+namespace pan
+{
+
+  struct Signer
+  {
+    std::string name;
+    std::string key_id;
+    std::string fpr;
+    std::string trust;
+    std::string status;
+    std::string error;
+
+    bool ok;
+    bool never_expires;
+    time_t created, expires;
+
+    Signer() : ok(false), never_expires(false), created((time_t)0), expires((time_t)0)  {}
+  };
+
+  struct GPGSignersInfo
+  {
+    std::vector<Signer> signers;
+  };
+
+  typedef std::map<std::string,GPGSignersInfo> signers_m;
+
+  extern GMimeCryptoContext* gpg_ctx;
+  extern bool gpg_inited;
+
+  enum GPGDecType
+  {
+    GPG_VERIFY,
+    GPG_DECODE,
+    GPG_VERIFY_AND_DECODE
+  };
+
+  enum GPGEncType
+  {
+    GPG_ENCODE,
+    GPG_SIGN,
+    GPG_ENCODE_AND_SIGN
+  };
+
+  /* Error struct for gpg_decrypt */
+  struct GPGDecErr
+  {
+    GError* err;
+    std::string output;
+    bool dec_ok;
+    bool verify_ok;
+    bool no_sigs;
+    GPGDecType type;
+    GPGSignersInfo signers;
+    GMimeObject * decrypted;
+    GMimeDecryptResult * result;
+
+    GPGDecErr(GPGDecType t) : err(NULL), type(t), decrypted(0), result(g_mime_decrypt_result_new())  {}
+    ~GPGDecErr()
+      {
+        if (err) g_error_free(err);
+        err = NULL;
+        if (decrypted) g_object_unref(decrypted) ;
+        if (result) g_object_unref(result);
+      }
+      GPGDecErr() : no_sigs(true) {}
+
+    void clear()
+    {
+      if (err) g_error_free(err);
+      err = NULL;
+      signers.signers.clear();
+      verify_ok = false;
+      dec_ok = false;
+      no_sigs = true;
+    }
+
+  };
+
+  /* Error struct for gpg_sign_and_encrypt */
+  struct GPGEncErr
+  {
+    GError* err;
+    std::string output;
+    bool enc_ok;
+    bool sign_ok;
+    bool no_sigs;
+    GPGEncType type;
+    GPGSignersInfo signers;
+
+    GPGEncErr(GPGEncType t) : err(NULL), type(t), no_sigs(true)  {}
+    ~GPGEncErr()
+    {
+      if (err) g_error_free(err);
+      err = NULL;
+    }
+
+  };
+
+  void init_gpg();
+  void deinit_gpg();
+  void fill_signer_info(GPGSignersInfo& info, GMimeSignatureList * sig_list);
+
+}
+
+#endif
+
diff --git a/pan/usenet-utils/mime-utils.cc b/pan/usenet-utils/mime-utils.cc
index d888773..ee32bd6 100644
--- a/pan/usenet-utils/mime-utils.cc
+++ b/pan/usenet-utils/mime-utils.cc
@@ -35,10 +35,6 @@ extern "C"
 #include <pan/general/log.h>
 #include "mime-utils.h"
 
-#ifdef HAVE_GPGME
-  #include <pan/gui/gpg.h>
-#endif
-
 #define is_nonempty_string(a) ((a) && (*a))
 
 using namespace pan;
@@ -334,53 +330,6 @@ namespace
    }
 }
 
-/***
-**** GPG
-***/
-
-namespace
-{
-
-  bool
-  gpg_is_beginning_line (const StringView& line)
-  {
-    if (line.len <= 1) return false;
-    StringView l(line);
-    return  !strncmp (l.str, GPG_MARKER_BEGIN, GPG_MARKER_BEGIN_LEN) ||
-            !strncmp (l.str, GPG_MARKER_SIGNED_BEGIN, GPG_MARKER_SIGNED_BEGIN_LEN) ;
-  }
-
-  bool
-  gpg_is_ending_line (const StringView& line)
-  {
-    if (line.len <= 1) return false;
-    StringView l(line);
-    return  !strncmp (l.str, GPG_MARKER_END, GPG_MARKER_END_LEN) ||
-            !strncmp (l.str, GPG_MARKER_SIGNED_END, GPG_MARKER_SIGNED_END_LEN);
-  }
-
-  bool
-  gpg_is_signed_begin_line (const StringView& line)
-  {
-    if (line.len <= 1) return false;
-    StringView l(line);
-    return !strncmp (l.str, GPG_MARKER_SIGNED_BEGIN, GPG_MARKER_SIGNED_BEGIN_LEN);
-  }
-
-  bool
-  gpg_is_signed_end_line (const StringView& line)
-  {
-    if (line.len <= 1) return false;
-    StringView l(line);
-    return !strncmp (l.str, GPG_MARKER_SIGNED_END, GPG_MARKER_SIGNED_END_LEN);
-  }
-
-}
-
-/***
-****
-***/
-
 namespace
 {
   guint
@@ -411,11 +360,9 @@ namespace
 
 enum EncType
 {
-	ENC_PLAIN = 1 ,
-	ENC_YENC = 1 << 1,
-	ENC_UU = 1 << 2,
-	ENC_GPG = 1 << 3,
-	ENC_BASE64 = 1<< 4
+	ENC_PLAIN ,
+	ENC_YENC,
+	ENC_UU
 };
 
 namespace pan
@@ -483,7 +430,7 @@ namespace pan
 
     if (!part->stream) {
       part->stream = g_mime_stream_mem_new ();
-      if (part->type != ENC_PLAIN && part->type != ENC_GPG) {
+      if (part->type != ENC_PLAIN) {
         part->filter_stream = g_mime_stream_filter_new (part->stream);
         switch (part->type)
         {
@@ -501,8 +448,8 @@ namespace pan
       }
     }
 
-    g_mime_stream_write_to_stream (s, (part->type == ENC_PLAIN || part->type == ENC_GPG) ?
-				   part->stream : part->filter_stream);
+    g_mime_stream_write_to_stream (s, (part->type == ENC_PLAIN ?
+				   part->stream : part->filter_stream));
     g_object_unref (s);
   }
 
@@ -511,12 +458,7 @@ namespace pan
     temp_parts_t master_list;
     temp_parts_t current_list;
     TempPart *uu_temp;
-    std::string gpg_verified;
-#ifdef HAVE_GPGME
-    GPGDecErr gpgerr;
-    GPGSignersInfo signer_info;
-#endif
-    sep_state():uu_temp(NULL), gpg_verified("") {};
+    sep_state():uu_temp(NULL) {};
   };
 
   bool
@@ -528,9 +470,6 @@ namespace pan
     EncType type = ENC_PLAIN;
     GByteArray * line;
     gboolean yenc_looking_for_part_line = FALSE;
-    gboolean gpg_looking_for_line = FALSE;
-    gboolean gpg_is_signed = FALSE;
-    gboolean gpg_signed_end_found = FALSE;
     gint64 linestart_pos = 0;
     gint64 sub_begin = 0;
     gint64 signed_msg_start = 0;
@@ -553,17 +492,6 @@ namespace pan
         line_len = pch - line_str;
       }
 
-      if (gpg_is_signed_begin_line(line_str))
-      {
-        gpg_is_signed = true;
-        signed_msg_start = linestart_pos;
-      }
-      if (gpg_is_signed_end_line(line_str))
-      {
-        gboolean gpg_signed_end_found = true;
-        signed_msg_end = linestart_pos+line_len;
-      }
-
       switch (type)
       {
         case ENC_PLAIN:
@@ -629,14 +557,6 @@ namespace pan
               yenc_looking_for_part_line = cur->y_part!=0;
             }
           }
-          else if (gpg_is_beginning_line (line_str))
-          {
-
-            found = true;
-            cur = new TempPart (type = ENC_GPG);
-            gpg_looking_for_line = true;
-            sub_begin = linestart_pos;
-          }
           else if (state.uu_temp != NULL && is_uu_line(line_str, line_len) )
           {
             // continue an incomplete uu decode
@@ -727,36 +647,6 @@ namespace pan
           }
           break;
         }
-#ifdef HAVE_GPGME
-        case ENC_GPG:
-        {
-          if (gpg_is_ending_line(line_str))
-          {
-            GMimeStream * stream = g_mime_stream_substream (istream, sub_begin, linestart_pos+line_len);
-            GMimeStream * dec = gpg_decrypt_and_verify(state.signer_info, state.gpgerr, stream);
-            if (state.gpgerr.verify_ok)
-              state.gpg_verified = "valid";
-            else if (!state.gpgerr.verify_ok && !state.gpgerr.no_sigs)
-              state.gpg_verified = "invalid";
-
-            gpg_looking_for_line = false;
-            if (state.gpgerr.dec_ok)
-            {
-              apply_source_and_maybe_filter (cur, dec);
-              if( append_if_not_present (master, cur) )
-                append_if_not_present (appendme, cur);
-            }
-            cur = NULL;
-            type = ENC_PLAIN;
-            sub_begin = -1;
-          }
-          else if (gpg_looking_for_line)
-          {
-            ++cur->valid_lines;
-          }
-          break;
-        }
-#endif
       }
     }
 
@@ -990,12 +880,27 @@ namespace
   }
 }
 
-namespace{
+namespace pan
+{
   struct temp_p {
     GMimeObject *parent,*part;
 
     temp_p(GMimeObject *p, GMimeObject *par):parent(p),part(par) {};
   };
+
+  struct QueryMPType
+  {
+    GMimeObject* obj;
+    GPGDecType type;
+    std::string algo;
+
+    QueryMPType() : obj(0), type(GPG_DECODE) {}
+  };
+}
+
+namespace
+{
+
   typedef std::vector<temp_p> temp_p_t;
 
   void find_text_cb(GMimeObject *parent, GMimeObject *part, gpointer data)
@@ -1011,18 +916,53 @@ namespace{
     v->push_back(temp_p(parent,part) );
   }
 
-  void find_gpg_parts_cb(GMimeObject *parent, GMimeObject *part, gpointer data)
+
+  void mixed_mp_cb(GMimeObject *parent, GMimeObject *part, gpointer data)
   {
     if(!GMIME_IS_PART(part))
       return;
 
-    temp_p_t *v( (temp_p_t *) data);
+    QueryMPType * type = static_cast<QueryMPType*>(data);
 
     GMimeContentType * content_type = g_mime_object_get_content_type (part);
-    if (!(g_mime_content_type_is_type (content_type, "multipart", "encrypted") ||
-          g_mime_content_type_is_type (content_type, "text", "plain")))
+//    if (!g_mime_content_type_is_type (content_type, "text", "plain") &&
+//        !g_mime_content_type_is_type (content_type, "application", "pgp-signature"))
+//      return;
+
+//    if (g_mime_content_type_is_type (content_type, "application", "pgp-signature"))
+//    {
+//      g_mime_object_set_content_type_parameter(part, "micalg", "pgp-sha1");//type->algo.c_str());
+//      std::cerr<<g_mime_object_to_string(part)<<"\n";
+//    }
+
+    g_mime_multipart_add (GMIME_MULTIPART(type->obj), part);
+  }
+
+
+  void mixed_mp_find_gpg_params_cb (GMimeObject *parent, GMimeObject *part, gpointer data)
+  {
+
+    if(!GMIME_IS_PART(part))
       return;
-    v->push_back(temp_p(parent,part) );
+
+    QueryMPType * type = static_cast<QueryMPType*>(data);
+
+//    const char* micalg = g_mime_object_get_content_type_parameter (GMIME_OBJECT (part), "micalg");
+//    if (micalg)
+//    {
+//      std::cerr<<"micalg found : "<<micalg<<"\n";
+//      type->algo = micalg;
+//    }
+
+    GMimeContentType * content_type = g_mime_object_get_content_type (part);
+
+    if (!content_type) return;
+
+    if (g_mime_content_type_is_type (content_type, "application", "pgp-signature"))
+      type->type = GPG_VERIFY;
+    else if (g_mime_content_type_is_type (content_type, "application", "pgp-encrypted"))
+      type->type = GPG_DECODE;
+
   }
 
 }
@@ -1031,17 +971,10 @@ namespace{
 ****
 ***/
 
-#ifdef HAVE_GPGME
 GMimeMessage*
 mime :: construct_message (GMimeStream    ** istreams,
-                           int             qty,
-                           GPGSignersInfo & signer_info,
-                           GPGDecErr      & gpgerr)
-#else
-GMimeMessage*
-mime :: construct_message (GMimeStream    ** istreams,
-                           int             qty)
-#endif
+                           int               qty,
+                           GPGDecErr      &  err)
 {
   const char * message_id = "Foo <bar mum>";
   GMimeMessage * retval = 0;
@@ -1049,16 +982,75 @@ mime :: construct_message (GMimeStream    ** istreams,
   // sanity clause
   pan_return_val_if_fail (is_nonempty_string(message_id), NULL);
   pan_return_val_if_fail (istreams!=NULL, NULL);
-  pan_return_val_if_fail (qty>=1, NULL);
+  pan_return_val_if_fail (qty != 0, NULL);
   for (int i=0; i<qty; ++i)
     pan_return_val_if_fail (GMIME_IS_STREAM(istreams[i]), NULL);
 
   // build the GMimeMessages
-  GMimeParser * parser = g_mime_parser_new ();
+  GMimeParser * parser;// = g_mime_parser_new ();
   GMimeMessage ** messages = g_new (GMimeMessage*, qty);
+
   for (int i=0; i<qty; ++i) {
-    g_mime_parser_init_with_stream (parser, istreams[i]);
-    messages[i] = g_mime_parser_construct_message (parser);
+    parser = g_mime_parser_new_with_stream (istreams[i]);
+    messages[i] = g_mime_parser_construct_message(parser);
+    g_object_unref(parser);
+    g_mime_stream_reset(istreams[i]);
+    parser = g_mime_parser_new_with_stream (istreams[i]);
+    GMimeObject* part = g_mime_parser_construct_part(parser);
+    GMimeContentType * type = g_mime_object_get_content_type (part);
+    const bool multipart (GMIME_IS_MULTIPART_SIGNED(part) || GMIME_IS_MULTIPART_ENCRYPTED(part));
+
+    if (GMIME_IS_MULTIPART_SIGNED(part))
+    {
+      err.type = GPG_VERIFY;
+      err.verify_ok = gpg_verify_mps(part, err);
+    }
+    else if (GMIME_IS_MULTIPART_ENCRYPTED(part))
+    {
+      err.type = GPG_DECODE;
+      err.verify_ok =  gpg_verify_mps(part, err);
+    }
+
+    if (type)
+    {
+      if (g_mime_content_type_is_type (type, "multipart", "mixed"))
+      {
+        QueryMPType qtype;
+        g_mime_multipart_foreach (GMIME_MULTIPART(part), mixed_mp_find_gpg_params_cb, &qtype);
+        GMimeObject* o(0);
+
+        if (qtype.type == GPG_VERIFY)
+        {
+          GMimeMultipartSigned* new_mp = g_mime_multipart_signed_new();
+          err.type = GPG_VERIFY;
+          qtype.obj = o = GMIME_OBJECT(new_mp);
+          g_mime_multipart_foreach (GMIME_MULTIPART(part), mixed_mp_cb, &qtype);
+          err.verify_ok = gpg_verify_mps(GMIME_OBJECT(new_mp), err);
+          g_mime_message_set_mime_part(messages[i], GMIME_OBJECT(new_mp));
+          std::cerr<<"algo : "<<g_mime_object_to_string(GMIME_OBJECT(new_mp))<<"\n";
+        }
+
+        if (qtype.type == GPG_DECODE)
+        {
+          GMimeMultipartEncrypted* new_mp = g_mime_multipart_encrypted_new();
+          err.type = GPG_DECODE;
+          qtype.obj = o = GMIME_OBJECT(new_mp);
+          g_mime_multipart_foreach (GMIME_MULTIPART(part), mixed_mp_cb, &qtype);
+          err.verify_ok =  gpg_verify_mps(GMIME_OBJECT(new_mp), err);
+          g_mime_message_set_mime_part(messages[i], GMIME_OBJECT(new_mp));
+        }
+
+        g_object_unref(o);
+
+      }
+      else if (multipart)
+      {
+        if (err.decrypted)
+          g_mime_message_set_mime_part(messages[i], err.decrypted);
+      } else
+          g_mime_message_set_mime_part(messages[i], part);
+    }
+
   }
   g_object_unref (parser);
 
@@ -1084,16 +1076,11 @@ mime :: construct_message (GMimeStream    ** istreams,
   sep_state state;
   if (retval != NULL)
     g_mime_message_foreach(retval, find_text_cb, &partslist);
+
   foreach(temp_p_t, partslist, it)
   {
     temp_p &data(*it);
     handle_uu_and_yenc_in_text_plain_cb(data.parent, data.part, &state);
-    /* set gpg signature verify success/fail flag */
-#ifdef HAVE_GPGME
-    g_mime_object_set_header(GMIME_OBJECT(data.parent), "X-GPG-Signed", state.gpg_verified.c_str());
-    gpgerr = state.gpgerr;
-    signer_info = state.signer_info;
-#endif
   }
 
   // cleanup
@@ -1288,6 +1275,7 @@ namespace
   GMimeObject *
   handle_multipart_mixed (GMimeMultipart *multipart, gboolean *is_html)
   {
+
     GMimeObject *mime_part, *text_part = NULL;
     GMimeContentType *type, *first_type = NULL;
     int count = g_mime_multipart_get_count (multipart);
@@ -1421,121 +1409,7 @@ void pan::pan_g_mime_message_set_message_id (GMimeMessage *msg, const char *mid)
 }
 
 namespace pan
-
 {
-  #ifdef HAVE_GPGME
-  GMimeStream* gpg_decrypt_and_verify (GPGSignersInfo& signer_info, GPGDecErr& info,
-                                       GMimeStream* s, int index, GMimeObject* parent)
-  {
-
-    GMimeStream* decrypted = g_mime_stream_mem_new ();
-
-    ssize_t stream_len = g_mime_stream_length(s);
-
-    char* streambuf = new char[stream_len];
-
-    g_mime_stream_read(s, streambuf, stream_len);
-    g_object_unref(s);
-
-    info.err = GPG_ERR_NO_ERROR;
-
-    gpgme_data_t gpg_buf, gpg_out_buf;
-    gpgme_key_t key;
-
-    StringView v(streambuf);
-    gpgme_data_new_from_mem (&gpg_buf, v.str, v.len, 0);
-
-    gpgme_strerror(gpgme_data_new (&gpg_out_buf));
-
-    gpgme_data_set_encoding (gpg_out_buf, GPGME_DATA_ENCODING_NONE);
-
-    info.err = gpgme_op_decrypt_verify (gpg_ctx, gpg_buf, gpg_out_buf);
-
-    // no data to decrypt, check for signature validity anyway....
-    if (gpgme_err_code(info.err) == GPG_ERR_NO_DATA || gpgme_err_code(info.err) == GPG_ERR_NO_ERROR)
-      info.dec_ok = true;
-    else
-      return decrypted;
-
-    info.dec_res  = gpgme_op_decrypt_result (gpg_ctx);
-    info.v_res    = gpgme_op_verify_result  (gpg_ctx);
-
-    // verify attached sigs, too. that means, no data to decrypt and no signatures found, yet
-    if (gpgme_err_code(info.err) == GPG_ERR_NO_DATA &&
-        gpgme_err_code(info.v_res->signatures->status) == GPG_ERR_BAD_SIGNATURE && parent)
-    {
-      int count(0); int no(0);
-      size_t len;
-      char* body(0);
-      count = g_mime_multipart_get_count (GMIME_MULTIPART(parent));
-      no = index;
-      gpgme_data_t body_data;
-
-      for (int i=0;i<count;++i)
-      {
-
-        if (i == no) continue;
-        GMimeObject* part_of = g_mime_multipart_get_part (GMIME_MULTIPART(parent), i);
-        if (part_of)
-        {
-          body = pan_g_mime_part_get_content(GMIME_PART(part_of),&len);
-          if (body)
-          {
-            gpgme_data_new_from_mem (&body_data, body, len, 0);
-            info.err  = gpgme_op_verify (gpg_ctx, gpg_buf, body_data, 0);
-            info.v_res= gpgme_op_verify_result  (gpg_ctx);
-            gpgme_data_release(body_data);
-            g_free(body);
-            if (info.err == GPG_ERR_NO_ERROR &&
-                gpgme_err_code(info.v_res->signatures->status) == GPG_ERR_NO_ERROR) break;
-          }
-        }
-      }
-    }
-
-    if (info.v_res->signatures)
-    {
-      info.no_sigs = false;
-      if (gpgme_err_code(info.v_res->signatures->status) == GPG_ERR_NO_ERROR)
-        info.verify_ok = true;
-    }
-    else
-      info.no_sigs = true;
-
-    delete streambuf;
-
-    gpgme_data_seek (gpg_out_buf,SEEK_SET, 0);
-
-    ssize_t ret(0);
-    char buffer[4096]={0};
-    gint64 len(0);
-
-    while ((ret = gpgme_data_read (gpg_out_buf, buffer, sizeof(buffer))) > 0)
-    {
-      len += g_mime_stream_write(decrypted, buffer, ret);
-    }
-
-    g_mime_stream_flush (decrypted);
-    g_mime_stream_reset(decrypted);
-
-    gpgme_data_release(gpg_buf);
-    gpgme_data_release(gpg_out_buf);
-
-    GPGSignersInfo si;
-
-    if (!info.no_sigs)
-    {
-      if (info.v_res->signatures->fpr)
-        gpgme_get_key (gpg_ctx, info.v_res->signatures->fpr, &key, 0);
-      if (key)
-        fill_signer_info(si, key);
-    }
-
-    signer_info = si;
-    info.err = GPG_ERR_NO_ERROR;
-
-    return decrypted;
-  }
 
   void
   mime_part_set_content (GMimePart *part, const char *str)
@@ -1551,167 +1425,126 @@ namespace pan
     g_object_unref (content);
   }
 
-  GMimeMessage*
-  message_add_signed_part (const std::string& uid, const std::string& body_str, GMimeMessage* body, GPGEncErr& fail)
+  GMimeSignatureStatus
+  get_sig_status (GMimeSignatureList *signatures)
   {
-    if (uid.empty()) return 0;
-
-    GMimeMultipart *mp = g_mime_multipart_new_with_subtype ("mixed");
-    g_mime_multipart_set_boundary(mp, NULL);
-    g_mime_multipart_add(mp,g_mime_message_get_mime_part(body));
+    GMimeSignatureStatus status = GMIME_SIGNATURE_STATUS_GOOD;
+    GMimeSignature *sig;
+    int i;
 
-    gpgme_data_t gpg_buf, gpg_out_buf;
-    gpgme_key_t mykey(0), key;
+    if (!signatures || signatures->array->len == 0)
+      return GMIME_SIGNATURE_STATUS_ERROR;
 
-    StringView v(body_str);
-    gpgme_data_new_from_mem (&gpg_buf, v.str, v.len, 0);
-    gpgme_data_new (&gpg_out_buf);
-  //  gpgme_data_set_encoding (gpg_out_buf, GPGME_DATA_ENCODING_BASE64);
-  //  gpgme_data_set_file_name(gpg_out_buf, "signature.asc");
-
-    fail.err = gpgme_op_keylist_start (gpg_ctx, 0, 0);
-    while (!fail.err)
-    {
-      fail.err = gpgme_op_keylist_next (gpg_ctx, &key);
-      if (fail.err) break;
-      if (strcmp(key->subkeys->keyid, uid.c_str()) == 0) { mykey = key; break; }
-    }
-    if (!mykey) { fail.err = GPG_ERR_NO_PUBKEY; return 0; }
-
-    gpgme_signers_clear(gpg_ctx);
-    gpgme_signers_add(gpg_ctx, mykey);
-
-    fail.err      = gpgme_op_sign (gpg_ctx, gpg_buf, gpg_out_buf, GPGME_SIG_MODE_DETACH);
-    fail.sign_res = gpgme_op_sign_result (gpg_ctx);
-    if (fail.err) return 0;
-
-    gpgme_data_seek (gpg_out_buf,SEEK_SET, 0);
-    ssize_t ret;
-    std::stringstream ret_str;
-    char buffer[4096]={0};
-
-    while ((ret = gpgme_data_read (gpg_out_buf, buffer, sizeof(buffer))) > 0)
-    {
-      ret_str << buffer;
+    for (i = 0; i < g_mime_signature_list_length (signatures); i++) {
+      sig = g_mime_signature_list_get_signature (signatures, i);
+      status = MAX (status, sig->status);
     }
 
-    GMimePart *sig = g_mime_part_new_with_type("multipart", "signed");
-    g_mime_object_set_content_type_parameter(GMIME_OBJECT(sig),"protocol","pgp-signature");
-    mime_part_set_content (sig, ret_str.str().c_str());
-
-    gpgme_data_release(gpg_buf);
-    gpgme_data_release(gpg_out_buf);
-
-    g_mime_multipart_add (GMIME_MULTIPART (mp), GMIME_OBJECT (sig));
-
-    g_mime_message_set_mime_part(body,GMIME_OBJECT(mp));
-    g_object_unref(mp);
-
-    fail.err = GPG_ERR_NO_ERROR;
-
-    return body;
+    return status;
   }
 
-  std::string
-  gpg_encrypt(const std::string& uid, const std::string& body, GPGEncErr& fail)
+  bool
+  gpg_verify_mps (GMimeObject* obj, GPGDecErr& info)
   {
-    fail.err = GPG_ERR_GENERAL;
-
-    if (uid.empty()) return "";
 
-    gpgme_data_t gpg_buf, gpg_out_buf;
-    gpgme_key_t mykey(0), key;
+    if (!gpg_inited) return false;
 
-    StringView v(body);
-    gpgme_data_new_from_mem (&gpg_buf, v.str, v.len, 0);
-    gpgme_data_new (&gpg_out_buf);
-    gpgme_data_set_encoding (gpg_out_buf, GPGME_DATA_ENCODING_BASE64);
+    GMimeMultipartSigned * mps(0);
+    GMimeMultipartEncrypted * mpe(0);
 
-    /* find key to uid */
-    fail.err = gpgme_op_keylist_start (gpg_ctx, 0, 0);
-    while (!fail.err)
+    switch (info.type)
     {
-      fail.err = gpgme_op_keylist_next (gpg_ctx, &key);
-      if (fail.err) break;
-      if (strcmp(key->subkeys->keyid, uid.c_str()) == 0) { mykey = key; break; }
+      case GPG_VERIFY:
+        mps = (GMimeMultipartSigned *)obj;
+        break;
+
+      case GPG_DECODE:
+        mpe = (GMimeMultipartEncrypted *)obj;
+        break;
     }
-    if (!mykey) { fail.err = GPG_ERR_NO_PUBKEY; return std::string(""); }
 
-    gpgme_key_t enc_keys[] = { mykey, NULL};
+    info.clear();
 
-    fail.err     = gpgme_op_encrypt (gpg_ctx, enc_keys, GPGME_ENCRYPT_PREPARE, gpg_buf, gpg_out_buf);
-    fail.enc_res = gpgme_op_encrypt_result (gpg_ctx);
-    if (fail.err) return std::string("");
+    if (info.type == GPG_VERIFY)
+    {
+      GMimeSignatureList * sig_list = g_mime_multipart_signed_verify (mps, gpg_ctx, &info.err);
+      if (sig_list) info.no_sigs = false;
+      if (!sig_list) return false;
+      fill_signer_info(info.signers, sig_list);
 
-    gpgme_data_seek (gpg_out_buf,SEEK_SET, 0);
-    ssize_t ret;
-    std::stringstream ret_str;
-    char buffer[4096]={0};
+      return get_sig_status(sig_list) == GMIME_SIGNATURE_STATUS_GOOD;
+    }
 
-    while ((ret = gpgme_data_read (gpg_out_buf, buffer, sizeof(buffer))) > 0)
+    if (info.type == GPG_DECODE)
     {
-      ret_str << buffer;
-    }
+      info.decrypted = g_mime_multipart_encrypted_decrypt (mpe, gpg_ctx, &info.result, &info.err);
+      if (!info.decrypted)
+        if (info.err) return false;
 
-    gpgme_data_release(gpg_buf);
-    gpgme_data_release(gpg_out_buf);
+      GMimeSignatureList * sigs = g_mime_decrypt_result_get_signatures (info.result);
+      if (sigs)
+      {
+        info.no_sigs = false;
+        fill_signer_info(info.signers, sigs);
+      }
+      return get_sig_status(info.result->signatures) == GMIME_SIGNATURE_STATUS_GOOD || !info.err;
+    }
+    return false;
 
-    fail.err = GPG_ERR_NO_ERROR;
-    return ret_str.str();
   }
 
-  std::string
-  gpg_encrypt_and_sign(const std::string& uid, const std::string& body, GPGEncErr& fail)
+  GMimeMessage*
+  message_add_signed_part (const std::string& uid, const std::string& body_str, GMimeMessage* body)
   {
-    fail.err = GPG_ERR_GENERAL;
-
-    if (uid.empty()) return "";
+    if (uid.empty()) return 0;
 
-    gpgme_data_t gpg_buf, gpg_out_buf;
-    gpgme_key_t mykey(0), key;
+    GMimeMultipartSigned *mps;
+    GError* err(NULL);
+    GMimePart* part = g_mime_part_new_with_type("text", "plain");
+    mime_part_set_content (part, body_str.c_str());
 
-    StringView v(body);
-    gpgme_data_new_from_mem (&gpg_buf, v.str, v.len, 0);
-    gpgme_data_new (&gpg_out_buf);
-    gpgme_data_set_encoding (gpg_out_buf, GPGME_DATA_ENCODING_BASE64);
+    mps = g_mime_multipart_signed_new ();
 
-    /* find key to uid */
-    fail.err = gpgme_op_keylist_start (gpg_ctx, 0, 0);
-    while (!fail.err)
+    /* sign the part */
+    if (g_mime_multipart_signed_sign (mps, GMIME_OBJECT (part), gpg_ctx, uid.c_str(), GMIME_DIGEST_ALGO_SHA1, &err) <0)
     {
-      fail.err = gpgme_op_keylist_next (gpg_ctx, &key);
-      if (fail.err) break;
-      if (strcmp(key->subkeys->keyid, uid.c_str()) == 0) { mykey = key; break; }
+      g_object_unref(mps);
+      g_object_unref(G_OBJECT(part));
+      return 0;
     }
-    if (!mykey) { fail.err = GPG_ERR_NO_PUBKEY; return std::string(""); }
 
-    gpgme_signers_clear(gpg_ctx);
-    gpgme_signers_add(gpg_ctx, mykey);
+    g_mime_message_set_mime_part(body,GMIME_OBJECT(mps));
+    g_object_unref(G_OBJECT(part));
+    g_object_unref(mps);
+
+    return body;
+  }
 
-    gpgme_key_t enc_keys[] = { mykey, NULL};
+  GMimeMessage*
+  gpg_encrypt (const std::string& uid, const std::string& body_str,
+               GMimeMessage* body, GPtrArray* rcp, bool sign)
+  {
 
-    fail.err     = gpgme_op_encrypt_sign (gpg_ctx, enc_keys, GPGME_ENCRYPT_PREPARE, gpg_buf, gpg_out_buf);
-    fail.enc_res = gpgme_op_encrypt_result (gpg_ctx);
-    fail.sign_res= gpgme_op_sign_result (gpg_ctx);
-    if (fail.err) return std::string("");
+    GError* err(0);
+    GMimePart* part = g_mime_part_new_with_type("text", "plain");
+    mime_part_set_content (part, body_str.c_str());
 
-    gpgme_data_seek (gpg_out_buf,SEEK_SET, 0);
-    ssize_t ret;
-    std::stringstream ret_str;
-    char buffer[4096]={0};
+    GMimeMultipartEncrypted * mpe = g_mime_multipart_encrypted_new();
 
-    while ((ret = gpgme_data_read (gpg_out_buf, buffer, sizeof(buffer))) > 0)
+    if (g_mime_multipart_encrypted_encrypt(mpe, GMIME_OBJECT (part), gpg_ctx, sign,
+                                           uid.c_str(), GMIME_DIGEST_ALGO_SHA1, rcp, &err) < 0)
     {
-      ret_str << buffer;
+      g_object_unref(mpe);
+      g_object_unref(G_OBJECT(part));
+      return 0;
     }
 
-    gpgme_data_release(gpg_buf);
-    gpgme_data_release(gpg_out_buf);
+    g_mime_message_set_mime_part(body,GMIME_OBJECT(mpe));
+    g_object_unref(G_OBJECT(part));
+    g_object_unref(mpe);
 
-    fail.err = GPG_ERR_NO_ERROR;
-    return ret_str.str();
   }
-#endif
+
 }
 
 
diff --git a/pan/usenet-utils/mime-utils.h b/pan/usenet-utils/mime-utils.h
index b43650d..15e2188 100644
--- a/pan/usenet-utils/mime-utils.h
+++ b/pan/usenet-utils/mime-utils.h
@@ -26,11 +26,7 @@
 #include <gmime/gmime-stream.h>
 #include <gmime/gmime-message.h>
 #include <pan/general/string-view.h>
-
-#ifdef HAVE_GPGME
-  #include <gpgme.h>
-  #include <pan/gui/gpg.h>
-#endif
+#include <pan/usenet-utils/gpg.h>
 
 /***
 **** YENC
@@ -60,27 +56,12 @@
 #define YENC_SHIFT             42
 #define YENC_QUOTE_SHIFT       64
 
-/***
-**** GPG
-***/
-
-#define GPG_MARKER_BEGIN            "-----BEGIN PGP MESSAGE-----"
-#define GPG_MARKER_BEGIN_LEN        27
-#define GPG_MARKER_END              "-----END PGP MESSAGE-----"
-#define GPG_MARKER_END_LEN          25
-#define GPG_MARKER_SIGNED_BEGIN     "-----BEGIN PGP SIGNED MESSAGE-----"
-#define GPG_MARKER_SIGNED_BEGIN_LEN 34
-#define GPG_MARKER_SIGNED_END       "-----END PGP SIGNATURE-----"
-#define GPG_MARKER_SIGNED_END_LEN   27
-
 namespace pan
 {
-#ifdef HAVE_GPGME
-  GMimeStream* gpg_decrypt_and_verify (GPGSignersInfo& signer_info, GPGDecErr& info, GMimeStream* s, int index=0, GMimeObject* parent=0);
-  GMimeMessage* message_add_signed_part (const std::string& uid, const std::string& body_str, GMimeMessage* body, GPGEncErr& fail);
-  std::string gpg_encrypt(const std::string& uid, const std::string& body, GPGEncErr& fail);
-  std::string gpg_encrypt_and_sign(const std::string& uid, const std::string& body, GPGEncErr& fail);
-#endif
+
+  GMimeMessage* message_add_signed_part (const std::string& uid, const std::string& body_str, GMimeMessage* body);
+  GMimeMessage* gpg_encrypt (const std::string& uid, const std::string& body_str, GMimeMessage* body, GPtrArray* rcp, bool sign);
+  bool gpg_verify_mps (GMimeObject*, GPGDecErr&);
 
   /**
    * Utilities to build and parse GMimeMessages.
@@ -93,17 +74,10 @@ namespace pan
    */
   struct mime
   {
-#ifdef HAVE_GPGME
     static GMimeMessage *
     construct_message (GMimeStream      ** istreams,
-                         int              qty,
-                         GPGSignersInfo & signer_info,
-                         GPGDecErr      & gpgerr);
-#else
-    static GMimeMessage *
-    construct_message (GMimeStream      ** istreams,
-                         int              qty);
-#endif
+                       int                 qty,
+                       GPGDecErr         &);
 
     static const char *
     get_charset (GMimeMessage * message);
diff --git a/uulib/uuscan.c b/uulib/uuscan.c
index 55b0b09..f66868f 100644
--- a/uulib/uuscan.c
+++ b/uulib/uuscan.c
@@ -490,7 +490,7 @@ ParseHeader (headers *theheaders, char *line)
      * Some encoders mention the original filename as parameter to
      * Content-Type, others as parameter to Content-Disposition. We
      * do prefer the first solution, but accept this situation, too.
-     * TODO: Read RFC1806
+     * !!Read RFC1806
      */
     if ((ptr = _FP_stristr (line, "name")) != NULL) {
       if (theheaders->fname == NULL && (thenew=ParseValue(ptr)) != NULL) {
@@ -563,12 +563,12 @@ IsKnownHeader (char *line)
         *pch++ = tolower (*line++);
       *pch = '\0';
       pch = buf;
- 
-      // search for that in knownmsgheaders 
+
+      // search for that in knownmsgheaders
       if (bsearch (&pch, knownmsgheaders, n_msg, sizeof(char*), bsearch_strcmp) != NULL)
         retval = 1;
 
-      // search for that in knownmimeheaders 
+      // search for that in knownmimeheaders
       else if (bsearch (&pch, knownmimeheaders, n_mime, sizeof(char*), bsearch_strcmp) != NULL)
         retval = 2;
     }
@@ -717,7 +717,7 @@ ScanData (FILE *datei, char *fname, int *errcode,
       dontcare=0;
     }
 
-    if (boundary != NULL && 
+    if (boundary != NULL &&
 	line[0] == '-' && line[1] == '-' &&
 	strncmp (line+2, boundary, blen) == 0) {
       fseek (datei, oldposition, SEEK_SET);
@@ -746,14 +746,14 @@ ScanData (FILE *datei, char *fname, int *errcode,
 	fseek (datei, oldposition, SEEK_SET);
 	break;
       }
-      
+
       if (*line == '<')
 	ptr = line + 10;
       else
 	ptr = line + 5;
 
       while (*ptr == ' ') ptr++;
-      while (isdigit (*ptr)) 
+      while (isdigit (*ptr))
 	result->mode = result->mode * 8 + *ptr++ - '0';
       while (*ptr == ' ') ptr++;
 
@@ -801,7 +801,7 @@ ScanData (FILE *datei, char *fname, int *errcode,
 	ptr += 8;
 	while (isspace (*ptr)) ptr++;
 	p2 = ptr;
-	while (isalnum(*p2) || 
+	while (isalnum(*p2) ||
 	       *p2 == '.' || *p2=='_' || *p2 == '-' ||
 	       *p2 == '!' || *p2=='@' || *p2 == '$')
 	  p2++;
@@ -874,7 +874,7 @@ ScanData (FILE *datei, char *fname, int *errcode,
 	}
 	else {
 	  p2 = ptr;
-	  while (isalnum(*p2) || 
+	  while (isalnum(*p2) ||
 		 *p2 == '.' || *p2=='_' || *p2 == '-' ||
 		 *p2 == '!' || *p2=='@' || *p2 == '$')
 	    p2++;
@@ -908,8 +908,8 @@ ScanData (FILE *datei, char *fname, int *errcode,
 	  *p2 = c;
 	}
       }
-      
-      /* 
+
+      /*
        * Handling for very short Base64 files.
        */
       if (uu_tinyb64 && !ismime && !uu_more_mime) {
@@ -965,7 +965,7 @@ ScanData (FILE *datei, char *fname, int *errcode,
       /*
        * name continues to the end of the line
        */
-      
+
       _FP_free (result->filename);
       ptr = _FP_strstr (line, " name=") + 6;
       result->filename = _FP_strdup (ptr);
@@ -1007,7 +1007,7 @@ ScanData (FILE *datei, char *fname, int *errcode,
 	if ((ptr = _FP_strstr (line, " end=")) == NULL) {
 	  break;
 	}
-       
+
 	yepartends = atoi (ptr + 5);
       }
       else {
@@ -1113,7 +1113,7 @@ ScanData (FILE *datei, char *fname, int *errcode,
 	if (vflag == BH_ENCODED && bhnf == 0 && result->filename == NULL) {
 	  if (bhdsp == bhds2 ||
 	      ((bhdsp-bhds2) <= (int) bhds2[0] &&
-	       (bhdsp-bhds2) <  256)) { 
+	       (bhdsp-bhds2) <  256)) {
 	    dcc = UUDecodeLine (line, bhds1, BH_ENCODED);
 	    UUbhdecomp (bhds1, bhdsp, &bhl, &bhrpc,
 			dcc, 256-(bhdsp-bhds2), &bhopc);
@@ -1307,7 +1307,7 @@ ScanData (FILE *datei, char *fname, int *errcode,
 
 	  continue;
 	}
-	
+
 	/*
 	 * Select the encoding with the best "history"
 	 */
@@ -1750,7 +1750,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
 
     blen   = strlen (sstate.envelope.boundary);
     lcount = 0;
-    
+
     while (!feof (datei)) {
       if (_FP_fgets (line, line_len, datei) == NULL)
 	break;
@@ -1928,7 +1928,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
 	  preheaders = prevpos;
 	  lcount     = 0;
 	}
-	hcount++; 
+	hcount++;
 	lcount++;
 
 	if (hcount >= hlcount.restart) {
@@ -2083,7 +2083,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
    * stack and dive into the new environment, starting with another
    * preamble.
    */
-			   
+
   if (sstate.ismime && sstate.mimestate == MS_SUBPART) {
     memset (&localenv, 0, sizeof (headers));
     result->startpos = ftell (datei);
@@ -2114,18 +2114,18 @@ ScanPart (FILE *datei, char *fname, int *errcode)
       }
       sstate.isfolder = 0;
       sstate.ismime   = 0;
-      
+
       UUkillheaders (&localenv);
       *errcode = UURET_NOMEM;
       _FP_free (result);
       return NULL;
     }
-    
+
     /* Scan subheader. But what if there is no subheader? */
     hcount = 0;
     lcount = 0;
     preheaders = prevpos;
-    
+
     if (_FP_fgets (line, line_len, datei) == NULL) {
       sstate.isfolder = 0;
       sstate.ismime   = 0;
@@ -2247,7 +2247,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
       prevpos          = ftell (datei);
       blen = strlen (sstate.envelope.boundary);
       lcount = 0;
-      
+
       while (!feof (datei)) {
 	if (_FP_fgets (line, line_len, datei) == NULL) {
 	  line[0] = '\0';
@@ -2449,7 +2449,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
     else {
       UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
 		 uustring (S_MIME_B_NOT_FOUND));
-      
+
       while (mssdepth) {
 	mssdepth--;
 	UUkillheaders (&(multistack[mssdepth].envelope));
@@ -2469,7 +2469,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
        * Retry, listening to headers this time
        */
       fseek (datei, result->startpos, SEEK_SET);
-      
+
       UUkillfread (result);
       if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
 	*errcode = UURET_NOMEM;
@@ -2575,7 +2575,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
      * kill local envelope
      */
     UUkillheaders (&localenv);
-    
+
     return result;
   }
 
@@ -2718,7 +2718,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
 	  }
 	}
 
-	while (!feof (datei) && !IsLineEmpty (line)) { 
+	while (!feof (datei) && !IsLineEmpty (line)) {
 	  if (IsKnownHeader (line))
 	    hcount++;
 	  lcount++;
@@ -2819,7 +2819,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
     }
     result->partno = sstate.envelope.partno;
     result->maxpno = sstate.envelope.numparts;
-    result->flags  = FL_PARTIAL | 
+    result->flags  = FL_PARTIAL |
       ((res==1 || uu_fast_scanning) ? FL_PROPER : 0) |
 	((uu_fast_scanning) ? FL_TOEND : 0);
     result->mimeid = _FP_strdup (sstate.envelope.mimeid);
@@ -2848,7 +2848,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
       sstate.isfolder  = 1;
       sstate.ismime    = 0;
       sstate.mimestate = MS_HEADERS;
-      
+
       UUkillheaders (&sstate.envelope);
       memset (&sstate.envelope, 0, sizeof (headers));
     }
@@ -2921,7 +2921,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
     }
 
     result->startpos = prevpos = ftell (datei);
-    
+
     /*
      * If this is Quoted-Printable or Plain Text, just try looking
      * for the next message header. If uu_fast_scanning, we know
@@ -2951,7 +2951,7 @@ ScanPart (FILE *datei, char *fname, int *errcode)
 	  }
 	}
 
-	while (!feof (datei) && !IsLineEmpty (line)) { 
+	while (!feof (datei) && !IsLineEmpty (line)) {
 	  if (IsKnownHeader (line))
 	    hcount++;
 	  lcount++;
@@ -3131,13 +3131,13 @@ ScanPart (FILE *datei, char *fname, int *errcode)
 
 	sstate.envelope.mimevers = _FP_strdup ("1.0");
 	sstate.envelope.boundary = _FP_strdup (line+2);
-	
+
 	/*
 	 * need restart
 	 */
-	
+
 	fseek (datei, prevpos, SEEK_SET);
-	
+
 	_FP_free (result);
 	return NULL;
       }
@@ -3158,8 +3158,8 @@ ScanPart (FILE *datei, char *fname, int *errcode)
 
   if (sstate.envelope.ctype)
     result->mimetype = _FP_strdup (sstate.envelope.ctype);
-  
-  if ((res=ScanData (datei, fname, errcode, NULL, 
+
+  if ((res=ScanData (datei, fname, errcode, NULL,
 		     sstate.ismime, 1, result))==-1) {
     /* oops, something went wrong */
     sstate.isfolder = 0;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]