[Winpt-commits] r340 - trunk/Src

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Sun Nov 27 14:15:10 CET 2011


Author: twoaday
Date: 2011-11-27 14:15:07 +0100 (Sun, 27 Nov 2011)
New Revision: 340

Added:
   trunk/Src/wptBalloonPop.cpp
   trunk/Src/wptDNSKeys.cpp
   trunk/Src/wptJPG.cpp
   trunk/Src/wptKeyEditDlgs.cpp
Removed:
   trunk/Src/wptKeyEditDlgs.cpp
   trunk/Src/wptMDSumDlg.cpp
Modified:
   trunk/Src/ChangeLog
   trunk/Src/Makefile.am
   trunk/Src/wptCurrWnd.cpp
   trunk/Src/wptGPG.cpp
   trunk/Src/wptKeyCache.cpp
   trunk/Src/wptKeyserver.cpp
   trunk/Src/wptMAPI.cpp
   trunk/Src/wptPassphraseCB.cpp
   trunk/Src/wptPassphraseDlg.cpp
   trunk/Src/wptUtil.cpp
Log:


Modified: trunk/Src/ChangeLog
===================================================================
--- trunk/Src/ChangeLog	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/ChangeLog	2011-11-27 13:15:07 UTC (rev 340)
@@ -1,3 +1,9 @@
+2011-11-25  Timo Schulz  <twoaday at gmx.net>
+
+        * WinPT.cpp (check_os_version): New. Separated
+	function to check the OS verson.
+	Removed emulate utf8 bug legacy code.
+	
 2007-08-03  Timo Schulz  <twoaday at gmx.net>
 
 	* wptMainproc.cpp (wpt_main_proc): A single click

Modified: trunk/Src/Makefile.am
===================================================================
--- trunk/Src/Makefile.am	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/Makefile.am	2011-11-27 13:15:07 UTC (rev 340)
@@ -17,8 +17,8 @@
 AM_CPPFLAGS = -I$(top_srcdir)/Include \
               -I$(top_srcdir)/Gnupg -I$(top_srcdir)/PTD  \
               -DWIN32 -D_WINDOWS -D_MBCS
-AM_CFLAGS   = -fexceptions  $(GPGME_CFLAGS)
-AM_CXXFLAGS = -fexceptions  $(GPGME_CFLAGS)
+AM_CFLAGS   = -fstack-protector-all -fexceptions  $(GPGME_CFLAGS)
+AM_CXXFLAGS = -fstack-protector-all -fexceptions  $(GPGME_CFLAGS)
 AM_LDFLAGS  = -mwindows
 
 resource_files = \
@@ -62,7 +62,6 @@
 	wptKeysigDlg.cpp \
 	wptKeysignDlg.cpp \
 	wptKeyTrustPathDlg.cpp \
-	wptMDSumDlg.cpp \
 	wptOwnertrustDlg.cpp \
 	wptPassphraseDlg.cpp \
 	wptPINDlg.cpp \
@@ -132,5 +131,3 @@
 .rc.o:
 	$(WINDRES) -I $(srcdir) -I . -I $(top_srcdir)/Ico \
               -I $(top_srcdir)/icons `test -f '$<' || echo '$(srcdir)/'`$< $@
-
-

Added: trunk/Src/wptBalloonPop.cpp
===================================================================
--- trunk/Src/wptBalloonPop.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptBalloonPop.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -0,0 +1,280 @@
+/* wptBalloonPop.cpp - Balloon Popup-Box
+ *	Copyright (C) 2009 Timo Schulz
+ * 
+ * This file is part of WinPT.
+ *
+ * WinPT is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation; either version 2 
+ * of the License, or (at your option) any later version.
+ *  
+ * WinPT 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.
+ */
+
+
+/* The idea is to use a balloon style 'error message' which
+   points to the control the error happened at. For instance
+   if no valid E-Mail address was entered, the balloon message
+   contains an error description with an arrow to the edit field
+   the address was supposed to be entered in. */
+
+#include <windows.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "wptTypes.h"
+
+#define BT_WINDOWNAME		"WinPT_BalloonPop"
+#define BT_TIMER_IDENTIFIER	23
+#define BT_IOFFSET               8
+
+
+extern HINSTANCE glob_hinst;
+
+struct balloon_ctx_s {
+    LPCTSTR text;
+    LPCTSTR icon_name;
+    POINT   pos;
+    HWND    hwnd;
+};
+static struct balloon_ctx_s glob_msg;
+static BOOL window_class_registered = FALSE;
+
+
+static void 
+display_balloon_text (HWND hwnd, HDC hdc, const char *text)
+{
+    RECT rc;    
+    memset (&rc, 0, sizeof (rc));    
+    GetClientRect(hwnd, &rc);
+    
+    POINT pts[3];
+    pts[0].x = rc.left + BT_IOFFSET;
+    pts[0].y = rc.top;
+    pts[1].x = pts[0].x;
+    pts[1].y = pts[0].y + BT_IOFFSET;
+    pts[2].x = pts[1].x + BT_IOFFSET;
+    pts[2].y = pts[1].y;
+    
+    // we merge three regions here:
+    // 1) basis
+    // 2) rounded box
+    // 3) arrow
+    HRGN hrgn = CreateRectRgn(0, 0, 0, 0);    
+    HRGN hrgn1 = CreateRoundRectRgn(rc.left, 
+				    rc.top + BT_IOFFSET,
+				    rc.right,
+				    rc.bottom,
+				    15, 15);
+    HRGN hrgn2 = CreatePolygonRgn(&pts[0], 3, ALTERNATE);
+    CombineRgn(hrgn, hrgn1, hrgn2, RGN_OR);
+    
+    // fill the region and draw a frame  around it
+    FillRgn (hdc, hrgn, GetSysColorBrush(COLOR_INFOBK));
+    FrameRgn (hdc, hrgn, (HBRUSH)GetStockObject (DKGRAY_BRUSH), 1, 1);
+    
+    rc.top = rc.top + BT_IOFFSET*2;
+    rc.bottom = rc.bottom - BT_IOFFSET;
+    rc.left = rc.left + BT_IOFFSET;
+    rc.right = rc.right - BT_IOFFSET;
+    
+    // FIXME: calculate best position
+    HICON hicon = LoadIcon (NULL, glob_msg.icon_name);
+    if (hicon != NULL) {
+	DrawIconEx (hdc, 5, 20, hicon, 28, 28, 0, NULL, DI_NORMAL);
+	DestroyIcon (hicon);
+    }
+    
+    SetTextColor (hdc, GetSysColor (COLOR_INFOTEXT));
+    DrawText (hdc, text, strlen (text), &rc, DT_VCENTER + DT_NOCLIP);
+}
+
+
+// window procedure for the balloon tip.
+static LRESULT CALLBACK
+window_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg) {
+    case WM_PAINT:
+	RECT rc;
+	GetWindowRect (hwnd, &rc);
+	
+	POINT curpos;
+	curpos.x = glob_msg.pos.x;
+	curpos.y = glob_msg.pos.y;
+	
+	rc.right = curpos.x - BT_IOFFSET + 6 + rc.right - rc.left;
+	rc.bottom = curpos.y + 20 + rc.bottom - rc.top;
+	rc.left = curpos.x - BT_IOFFSET + 6;
+	rc.top = curpos.y + 20;
+	MoveWindow (hwnd, rc.left, rc.top, rc.right - rc.left,
+		    rc.bottom - rc.top, FALSE);
+	
+	HDC hdc;
+	PAINTSTRUCT ps;
+	hdc = BeginPaint (hwnd, &ps);
+	
+	LOGFONT lf;
+	memset (&lf, 0, sizeof (lf));
+	lf.lfHeight = 13;
+	lf.lfWeight = FW_NORMAL;
+	lf.lfQuality = ANTIALIASED_QUALITY;
+	strcpy (lf.lfFaceName, "MS Sans Serif");
+	
+	HFONT hfont;
+	hfont = CreateFontIndirect(&lf);
+	HFONT hfont_old;
+	hfont_old = (HFONT)SelectObject(ps.hdc, hfont);
+	
+	DrawText (ps.hdc, glob_msg.text, strlen (glob_msg.text),
+		  &rc, DT_VCENTER+DT_NOCLIP+DT_CALCRECT);
+	rc.right = rc.right + 2*BT_IOFFSET;
+	rc.bottom = rc.bottom + 3*BT_IOFFSET;
+	
+	ShowWindow (hwnd, SW_SHOWNA);
+	MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left,
+		   rc.bottom - rc.top, TRUE);		   
+	SetBkMode(ps.hdc, TRANSPARENT);
+	display_balloon_text (hwnd, ps.hdc, glob_msg.text);
+	
+	// restore old font object
+	SelectObject(ps.hdc, hfont_old);
+	DeleteObject (hfont);
+	EndPaint (hwnd, &ps);
+	break;
+
+    case WM_LBUTTONUP:
+	ShowWindow (hwnd, SW_HIDE);
+	break;
+
+    default:
+	return DefWindowProc (hwnd, msg, wparam, lparam);
+    }
+
+    return FALSE;
+}
+
+
+/* Callback procedure to hide the baloon window after the
+   time has been expired */
+static VOID CALLBACK 
+popup_timer_proc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+    ShowWindow (hwnd, SW_HIDE);
+}
+
+
+/* Register our new window class */
+static void
+register_window_class (HINSTANCE hinst)
+{
+    WNDCLASS wclass;    
+    memset (&wclass, 0, sizeof (wclass));
+    wclass.style = CS_HREDRAW | CS_VREDRAW;
+    wclass.lpfnWndProc = window_proc;
+    wclass.hInstance = hinst;
+    wclass.lpszClassName = BT_WINDOWNAME;
+    
+    if (!RegisterClass (&wclass))
+	abort ();
+}
+
+
+static LPCTSTR
+format_text (LPCTSTR string)
+{
+    const int off = 12;    
+    static char buf[2048];    
+    int n = strlen (string), pos=0, i;
+    
+    memset (buf, 0, DIM (buf));
+    // FIXME: rewrite the function
+    if (n > 1600)
+	abort ();
+
+    buf[pos++] = '\n';
+    for (i=0; i < off; i++)
+	buf[pos++] = ' ';
+    for (i=0; i < n; i++) {
+	buf[pos++] = string[i];
+	if (string[i] == '\n') {
+	    for (int j=0; j < off; j++)
+		buf[pos++] = ' ';
+	}
+    }
+    buf[pos++] = '\n';
+    return buf;
+}
+
+
+/* Display a baloon message box at the given X- Y-coordinates */
+HWND
+show_balloon_msg_pos (HWND hparwnd, int millis, int x, int y,
+		      LPCTSTR string, LPCTSTR icon_name)
+{
+    if (!window_class_registered) {
+	register_window_class (glob_hinst);
+	window_class_registered = TRUE;
+    }
+
+    // if no icon is requsted, print the text as it is.
+    if (!icon_name)
+	glob_msg.text = string;
+    else
+	glob_msg.text = format_text (string);
+    glob_msg.icon_name = icon_name;
+    
+    if (x > 0 && y > 0) { // use specific coordinates
+	glob_msg.pos.x = x;
+	glob_msg.pos.y = y;
+    }
+    else { // point to the lower left region of the control
+	RECT rect;
+	GetWindowRect (hparwnd, &rect);
+	glob_msg.pos.x = rect.left;
+	glob_msg.pos.y = rect.bottom - 20;
+    }
+    
+    // we use a persistent window for the balloon messages
+    // instead of destroy/create we hide the window whenever it
+    // is unused.
+    if (!glob_msg.hwnd) {
+	glob_msg.hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+					BT_WINDOWNAME, BT_WINDOWNAME,
+					WS_POPUP, 1, 1, 1, 1,
+					NULL, NULL, glob_hinst, NULL);
+	if (!glob_msg.hwnd)
+	    BUG (0);
+    }
+    
+    // ensure 'parent' never loses focus.
+    HWND hwnd = glob_msg.hwnd;
+    ShowWindow (hwnd, SW_SHOW);
+    UpdateWindow (hwnd);
+    EnableWindow (hparwnd, TRUE);
+    SetActiveWindow (NULL);
+
+    // show message for a fixed amount of time
+    SetTimer (hwnd, BT_TIMER_IDENTIFIER, millis, popup_timer_proc);
+
+    return hwnd;
+}
+
+
+/* Show message at the default position for 5 seconds */
+void
+show_balloon_msg (HWND hparwnd, LPCTSTR string, LPCTSTR icon_name)
+{
+    show_balloon_msg_pos (hparwnd, 5000, 0, 0, string ,icon_name);
+}
+
+
+/* Disable the message box (hide the window) */
+void
+balloon_msg_disable (void)
+{
+    ShowWindow (glob_msg.hwnd, SW_HIDE);
+}

Modified: trunk/Src/wptCurrWnd.cpp
===================================================================
--- trunk/Src/wptCurrWnd.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptCurrWnd.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -1,5 +1,5 @@
 /* wptCurrWnd.cpp - Current window code
- *	Copyright (C) 2001-2004, 2006, 2007 Timo Schulz
+ *	Copyright (C) 2001-2004, 2006, 2007, 2011 Timo Schulz
  *
  * This file is part of WinPT.
  *
@@ -29,9 +29,9 @@
 
 
 /* PTD prototypes from the DLL. */
-extern "C" HWND PTD_get_curr_hwnd (void);
-extern "C" BOOL PTD_keyb_send (UINT *keys, UINT n_keys);
-extern "C" int PTD_is_used (void);
+extern "C" HWND PTD_get_current_window (void);
+extern "C" BOOL PTD_keyboard_send_keys (UINT *keys, UINT n_keys);
+extern "C" int PTD_is_hook_used (void);
 
 
 /* Clear the clipboard contents. */
@@ -73,12 +73,12 @@
 {
     unsigned int keys[4];
 
-    if (PTD_is_used ()) {
+    if (PTD_is_hook_used ()) {
 	keys[0] = VK_CONTROL | 0x8000;
 	keys[1] = 'A' | 0x8000;	
 	keys[2] = 'A';	
 	keys[3] = VK_CONTROL;	
-	PTD_keyb_send (keys, 4);
+	PTD_keyboard_send_keys (keys, 4);
 
     }
     else {
@@ -96,12 +96,12 @@
 {
     unsigned int keys[4];
 
-    if (PTD_is_used ()) {
+    if (PTD_is_hook_used ()) {
 	keys[0] = VK_CONTROL | 0x8000;
 	keys[1] = 'V' | 0x8000;
 	keys[2] = 'V';
 	keys[3] = VK_CONTROL;
-	PTD_keyb_send (keys, 4);
+	PTD_keyboard_send_keys (keys, 4);
     }
     else {
 	KEYDOWN (VK_CONTROL, 0x1d);
@@ -118,12 +118,12 @@
 {
     unsigned int keys[4];
 
-    if (PTD_is_used ()) {
+    if (PTD_is_hook_used ()) {
 	keys[0] = VK_CONTROL | 0x8000;
 	keys[1] = 'C' | 0x8000;
 	keys[2] = 'C';
 	keys[3] = VK_CONTROL;
-	PTD_keyb_send (keys, 4);
+	PTD_keyboard_send_keys (keys, 4);
     }
     else {
 	KEYDOWN (VK_CONTROL, 0x1d);
@@ -153,7 +153,7 @@
 	prev = GetForegroundWindow ();
     else {
 	*r_main = GetNextWindow (main, GW_HWNDNEXT);
-	return PTD_get_curr_hwnd ();
+	return PTD_get_current_window ();
     }
 
     SetForegroundWindow (prev);
@@ -161,6 +161,7 @@
 		       GetWindowThreadProcessId (prev, NULL),
 		       TRUE);
     fg = GetFocus ();
+    
     AttachThreadInput (GetCurrentThreadId (),
 			GetWindowThreadProcessId (prev, NULL),
 			FALSE);
@@ -175,8 +176,7 @@
    in @ctx. 
    A return value of 0 indicates a problem. */
 int
-copy_window_content (HWND old_hwnd, HWND *r_main, HWND *r_focus,
-		     int use_hotkey)
+copy_window_content (HWND old_hwnd, HWND *r_main, HWND *r_focus, int use_hotkey)
 {
     HWND hwnd;
     int rc;
@@ -196,14 +196,14 @@
        if the clipboard contains some text. */
     SendMessage (hwnd, WM_COPY, 0, 0);
     if (!clip_check ()) {
-	rc = 0; 
+	rc = WPTERR_SUCESS;
 	goto leave;
     }
     /* Then the check if the window is an edit control */
     window_msg_em_set_pos (hwnd, 0);
     SendMessage (hwnd, WM_COPY, 0, 0);
     if (!clip_check ()) {
-	rc = 0; 
+	rc = WPTERR_SUCESS; 
 	goto leave;
     }
 	
@@ -211,7 +211,7 @@
     window_msg_selectall ();
     window_msg_copy ();
     if (!clip_check ())
-	rc = 0;
+	rc = WPTERR_SUCESS;
 
 leave:
     AttachThreadInput (GetCurrentThreadId (),

Copied: trunk/Src/wptDNSKeys.cpp (from rev 332, trunk/PTD/wptDNSKeys.cpp)
===================================================================
--- trunk/PTD/wptDNSKeys.cpp	2009-09-26 10:02:36 UTC (rev 332)
+++ trunk/Src/wptDNSKeys.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -0,0 +1,192 @@
+#error "do not use it"
+/* wptDNSKeys.cpp - Support for retrieving keys via DNS
+ *	Copyright (C) 2006 Timo Schulz
+ *
+ * This file is part of WinPT.
+ *
+ * WinPT is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * WinPT 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 WinPT; if not, write to the Free Software Foundation, 
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <windows.h>
+#include <windns.h>
+
+#include "wptDNSKeys.h"
+
+
+/* typedef for the function signature. */
+typedef DNS_STATUS (*dns_query_fnc) (LPSTR, WORD, DWORD, PIP4_ARRAY,
+				    PDNS_RECORD*, PVOID *);
+
+typedef void (*dns_record_list_free_fnc) (PDNS_RECORD, DNS_FREE_TYPE);
+
+/* function pointer. */
+static dns_query_fnc dns_query = NULL;
+static dns_record_list_free_fnc dns_record_free = NULL;
+
+/* hinstance handle to the DLL. */
+static HINSTANCE dns_api = NULL;
+
+/* 1 if the DNS api is not available. */
+static int dns_failed = 0;
+
+
+
+/* Initialize the DNS sub system. We do this via dynamic loading
+   because older NT/9X systems do not have this API. */
+static int
+dns_init (void)
+{
+    if (dns_query)
+	return 0;
+    if (dns_failed)
+	return -1;
+    dns_api = LoadLibrary ("dnsapi");
+    if (!dns_api) {
+	dns_failed = 1;
+	return -1;
+    }
+    dns_query = (dns_query_fnc)GetProcAddress (dns_api, "DnsQuery_A");
+    if (!dns_query) {
+	dns_failed = 1;
+	return -1;
+    }
+    dns_record_free = (dns_record_list_free_fnc)
+	GetProcAddress (dns_api, "DnsRecordListFree");
+    if (!dns_record_free) {
+	dns_failed = 1;
+	return -1;
+    }
+    return 0;
+}
+
+
+/* Cleanup static structs. */
+void
+dns_cleanup (void)
+{
+    if (dns_api != NULL)
+	FreeLibrary (dns_api);
+    dns_api = NULL;
+    dns_failed = 0;
+}
+
+
+/* build a DNS name for the PKA lookup. */
+static char*
+email_get_pka_addr (const char *uid)
+{
+    const char *fmt = "._pka.";
+    char *bo;
+    char *pka;
+    int pos=0;
+
+    /* check that the @uid really contains an email address. */
+    if ((bo=strchr (uid, '<')) && strchr (uid, '>'))
+	uid += (bo-uid+1);
+    if (!strchr (uid, '@'))
+	return NULL;
+
+    /* create the user at _pka.domain-part.tlp string. */
+    pka = (char*)calloc (1, strlen (uid)+strlen (fmt)+1);
+    while (uid && *uid != '@')
+	pka[pos++] = *uid++;
+    uid++;
+    strcat (pka, fmt); pos += strlen (fmt);
+    while (uid && *uid && *uid != '>')
+	pka[pos++] = *uid++;
+    return pka;
+}
+
+
+/* Convert the returned data from the PKA (txt) record. */
+pka_info_t
+parse_pka_data (const char *data)
+{
+    enum pka_col_t { COL_VER=1, COL_FPR, COL_URI };
+    pka_info_t pka;
+    char *p;
+    int pos = 1;
+
+    if (strncmp (data, "v=pka1;", 8))
+	return NULL;
+    pka = (pka_info_t)calloc (1, sizeof *pka);
+    p = strtok ((char*)data, ";");
+    while (p != NULL) {
+	switch (pos) {
+	case COL_VER: 
+	    pka->ver = 1; 
+	    break;
+
+	case COL_FPR: 
+	    pka->fpr = strdup (p+strlen ("fpr=")); 
+	    break;
+
+	case COL_URI:  /* optional */
+	    pka->uri = strdup (p+strlen ("uri=")); 
+	    break;
+
+	default:
+	    break;
+	}
+	pos++;
+    }
+    if (pos != 3) {
+	dns_free_pka_record (pka);
+	pka = NULL;
+    }
+    return pka;
+}
+
+
+/* Retrieve a PKA record from the DNS.
+   @userid is used to extract the email address. */
+extern "C" int
+dns_get_pka_record (const char *userid, pka_info_t *r_pka)
+{
+    DNS_STATUS err;
+    DNS_RECORD *rec;
+    char *addr;
+
+    *r_pka = NULL;
+    if (dns_init ())
+	return -1;
+    addr = email_get_pka_addr (userid);
+    if (!addr)
+	return -1;
+    err = dns_query (addr, DNS_TYPE_TEXT, 0, NULL, &rec, NULL);
+    if (err) {
+	free (addr);
+	return -1;
+    }
+    *r_pka = parse_pka_data (rec->Data.Txt.pStringArray[0]);
+
+    dns_record_free (rec, DnsFreeRecordList);
+    free (addr);
+    return 0;
+}
+
+
+/* Release the memory of the @pka structure. */
+extern "C" void
+dns_free_pka_record (pka_info_t pka)
+{
+    if (pka->fpr != NULL)
+	free (pka->fpr);
+    pka->fpr = NULL;
+    if (pka->uri != NULL)
+	free (pka->uri);
+    pka->uri = NULL;
+    free (pka);
+}

Modified: trunk/Src/wptGPG.cpp
===================================================================
--- trunk/Src/wptGPG.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptGPG.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -27,7 +27,7 @@
 
 #include "wptGPG.h"
 #include "wptGPGME.h"
-#include "wptGpgCmds.h"
+#include "wptGPGCmds.h"
 #include "wptTypes.h"
 #include "wptNLS.h"
 #include "wptRegistry.h"

Added: trunk/Src/wptJPG.cpp
===================================================================
--- trunk/Src/wptJPG.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptJPG.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -0,0 +1,303 @@
+/* wptJPG.cpp - Routines for showing JPG pictures
+ *      Copyright (C) 2005-2006, 2008-2009, 2011 Timo Schulz
+ *	Copyright (C) 2001 Dr.Yovav Gad
+ *
+ * This file is part of WinPT.
+ *
+ * WinPT is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * WinPT 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.
+ */
+
+/*-----------------------------------------------------------------------------
+ * Picture (Implementations) Version 1.00
+ * Author: Dr. Yovav Gad, EMail: Sources at SuperMain.com
+ * Web: www.SuperMain.com
+ * 
+ * This version uses a stripped down and heavily modified version of 
+ * Picture.cpp and Picture.h.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+#include <ocidl.h>
+#include <olectl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "wptJPG.h"
+#include "wptErrors.h"
+#include "wptTypes.h"
+
+#define HIMETRIC_INCH	2540
+#define ERROR_TITLE	"WinPT - CJPG Error"
+
+
+/* Constructor to create an empty JPG container. */
+CJPG::CJPG (void)
+{
+    m_IPicture = NULL;
+    m_Height = 0;
+    m_Weight = 0;
+    m_Width = 0;    
+}
+
+
+/* Deconstructor. Free all internal data. */
+CJPG::~CJPG (void)
+{
+    if (m_IPicture != NULL)
+	freePictureData (); 
+}
+
+
+
+/* Free the allocated memory that holdes the IPicture Interface data
+   and clear picture information. */
+void 
+CJPG::freePictureData (void)
+{
+    if (m_IPicture != NULL) {
+	m_IPicture->Release();
+	m_IPicture = NULL;
+    }
+    m_Height = 0;
+    m_Weight = 0;
+    m_Width = 0;
+}
+
+
+/* Open a JPG File And Load It Into IPicture (Interface) */
+BOOL 
+CJPG::load (LPCSTR filepath)
+{    
+    FILE *fp;
+
+    if (m_IPicture != NULL) 
+	freePictureData ();
+
+    fp = fopen (filepath, "rb");
+    if (!fp) {
+	MessageBox (NULL, strerror (errno), ERROR_TITLE, MB_OK|MB_ICONSTOP);
+	return FALSE;
+    }
+
+    /* avoid to load empty JPG files and make sure we still can
+       access the file handle. */
+    struct stat st;
+    if (fstat (fileno (fp), &st) || st.st_size == 0) {
+	fclose (fp);
+	return FALSE;
+    }
+    BYTE *buffer = new BYTE[st.st_size];
+    if  (!buffer)
+	BUG (0);
+    memset (buffer, 0, st.st_size);
+    int n = fread (buffer, 1, st.st_size, fp);
+    fclose (fp);
+
+    /* not the entire file were read in, so abort here. */
+    if (n != st.st_size) {
+	delete []buffer;
+	return FALSE;
+    }
+    if (!loadPictureData (buffer, st.st_size)) {
+	delete []buffer;
+	return FALSE;
+    }
+    delete [] buffer;
+
+    m_Weight = st.st_size; /* Update Picture Size Info... */
+    if (m_IPicture == NULL) {
+	m_Height = 0;
+	m_Width = 0;
+	return FALSE;
+    }
+    m_IPicture->get_Height (&m_Height);
+    m_IPicture->get_Width (&m_Width);
+    /* Calculate Its Size On a "Standard" (96 DPI) Device Context */
+    m_Height = MulDiv (m_Height, 96, HIMETRIC_INCH);
+    m_Width  = MulDiv (m_Width,  96, HIMETRIC_INCH);	
+    return TRUE;
+}
+
+
+
+/* read the picture data from a source (file / resource)
+   and load it into the current IPicture object in use */
+BOOL 
+CJPG::loadPictureData (BYTE *buffer, int nsize)
+{
+    BOOL result = FALSE;
+    
+    HGLOBAL hglobal;
+    hglobal = GlobalAlloc (GMEM_MOVEABLE, nsize);
+    if (hglobal == NULL)
+	BUG (0);
+
+    void *data;
+    data = GlobalLock (hglobal);
+    memcpy (data, buffer, nsize);
+    GlobalUnlock (hglobal);
+    
+    IStream *stream = NULL;
+    if (CreateStreamOnHGlobal (hglobal, TRUE, &stream) != S_OK) {
+	GlobalFree (hglobal);
+	return result;
+    }	
+	
+    HRESULT hr;
+    hr = OleLoadPicture (stream, nsize, FALSE, IID_IPicture,
+			 (LPVOID *)&m_IPicture);
+    if (hr == E_NOINTERFACE) {
+	MessageBox (NULL, "IPicture interface is not supported",
+		    ERROR_TITLE, MB_OK|MB_ICONSTOP);
+    }
+    else if (hr == E_POINTER) {
+	MessageBox (NULL, "The provided stream is not valid",
+		    ERROR_TITLE, MB_ERR);
+    }
+    else { /* S_OK */
+	stream->Release ();
+	stream = NULL;
+	result = TRUE;
+    }
+
+    GlobalFree (hglobal);
+    return result;
+}
+
+
+/* Draw the loaded picture direct to the client DC */
+BOOL 
+CJPG::show (HDC pDC, POINT *leftTop, POINT *widthHeight, 
+	    int magnifyX, int magnifyY)
+
+{
+    RECT drawRect;
+    HRESULT hr;
+    long width  = 0;
+    long height = 0;
+
+    if (pDC == NULL || m_IPicture == NULL) 
+	return FALSE;
+
+    m_IPicture->get_Width (&width);
+    m_IPicture->get_Height (&height);
+	
+    if (magnifyX == 0) 
+	magnifyX = 0;
+    if (magnifyY == 0) 
+	magnifyY = 0;
+    magnifyX = int(MulDiv (width, GetDeviceCaps(pDC, LOGPIXELSX), HIMETRIC_INCH) * magnifyX);
+    magnifyY = int(MulDiv (height, GetDeviceCaps(pDC, LOGPIXELSY), HIMETRIC_INCH) * magnifyY);
+
+    drawRect.left = leftTop->x;
+    drawRect.top = leftTop->y;
+    drawRect.right = magnifyX;
+    drawRect.bottom = magnifyY;
+
+    hr = m_IPicture->Render (pDC,
+			    leftTop->x,               // Left
+			    leftTop->y,               // Top
+			    widthHeight->x +magnifyX, // Width
+			    widthHeight->y +magnifyY, // Height
+			    0,
+			    height,
+			    width,
+			    -height,
+			    &drawRect);
+    if (SUCCEEDED (hr)) 
+	return TRUE;
+    return FALSE;
+}
+
+
+/* Get the original picture pixel size (ignore what current DC is using)
+   pointer to a Device Context is needed for pixel calculation, */
+BOOL 
+CJPG::updateSizeOnDC (HDC pDC)
+
+{	
+    if(pDC == NULL || m_IPicture == NULL) { 
+	m_Height = 0; 
+	m_Width = 0; 
+	return FALSE;
+    }
+
+    m_IPicture->get_Height (&m_Height);
+    m_IPicture->get_Width (&m_Width);
+
+    /* Get Current DPI - Dot Per Inch */
+    int CurrentDPI_X = GetDeviceCaps (pDC, LOGPIXELSX);
+    int CurrentDPI_Y = GetDeviceCaps (pDC, LOGPIXELSY);
+
+    m_Height = MulDiv (m_Height, CurrentDPI_Y, HIMETRIC_INCH);
+    m_Width  = MulDiv (m_Width,  CurrentDPI_X, HIMETRIC_INCH);
+
+    return TRUE;
+}
+
+
+/* Return height of the current image. */
+LONG
+CJPG::getHeight (void)
+{
+    return m_Height;
+}
+
+
+/* Return weight of the current image. */
+LONG 
+CJPG::getWeight (void)
+{
+    return m_Weight;
+}
+
+
+/* Return width of the current image. */
+LONG
+CJPG::getWidth (void)
+{
+    return m_Width;
+}
+
+/* Display a JPG picture in the given window at the given point. */
+int
+jpg_show (HWND hwnd, POINT *p, LPCSTR name)
+{
+    CJPG jpg;        
+    BOOL rc;
+
+    rc = jpg.load (name);
+    if (!rc)
+	return WPTERR_GENERAL;
+    HDC hdc = GetWindowDC (hwnd);
+    rc = jpg.updateSizeOnDC (hdc);
+    if (!rc) {
+	ReleaseDC (hwnd, hdc);
+	return WPTERR_GENERAL;
+    }
+
+    POINT sizewnd;
+    RECT rwnd;
+    GetWindowRect (hwnd, &rwnd);    
+    sizewnd.x = rwnd.right - rwnd.left;
+    sizewnd.y = rwnd.bottom - rwnd.top;
+    rc = jpg.show (hdc, p, &sizewnd, 0, 0);
+
+    ReleaseDC (hwnd, hdc);
+    jpg.freePictureData ();
+    return rc == TRUE? WPTERR_SUCESS : WPTERR_GENERAL;
+}

Modified: trunk/Src/wptKeyCache.cpp
===================================================================
--- trunk/Src/wptKeyCache.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptKeyCache.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -1012,6 +1012,9 @@
 }
 
 
+/* FIXME: rewrite the subpacket part */
+void unhexify_buffer (const char *in, char **r_out);
+
 static gpgme_error_t
 decode_subpacket (const char *subpkt_data, int *type,
 		  char **out, WORD *outlen)

Deleted: trunk/Src/wptKeyEditDlgs.cpp
===================================================================
--- trunk/Src/wptKeyEditDlgs.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptKeyEditDlgs.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -1,2277 +0,0 @@
-/* wptKeyEditDlgs.cpp - GPG key edit dialogs
- *	Copyright (C) 2002-2009 Timo Schulz
- *
- * This file is part of WinPT.
- *
- * WinPT is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * WinPT 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.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <windows.h>
-#include <commctrl.h>
-#include <time.h>
-#include <assert.h>
-
-#include "resource.h"
-#include "wptTypes.h"
-#include "wptW32API.h"
-#include "wptVersion.h"
-#include "wptGPG.h"
-#include "wptCommonCtl.h"
-#include "wptContext.h"
-#include "wptDlgs.h"
-#include "wptNLS.h"
-#include "wptUTF8.h"
-#include "wptErrors.h"
-#include "wptKeylist.h"
-#include "wptKeyManager.h"
-#include "wptRegistry.h"
-#include "wptKeyEdit.h"
-#include "wptKeyserver.h"
-#include "StringBuffer.h"
-
-
-/* All edit key commands. */
-enum keyedit_commands {    
-    CMD_ADDKEY = 0,
-    CMD_ADDUID,
-    CMD_ADDPHOTO,
-    CMD_ADDREVOKER,
-    CMD_DELUID,
-    CMD_DELKEY,
-    CMD_EXPIRE,
-    CMD_SHOWPREF,
-    CMD_SETPREF,
-    CMD_PASSWD,
-    CMD_PRIMARY,
-    CMD_TRUST,
-    CMD_REVUID,
-    CMD_REVKEY,
-    CMD_DISABLE,
-    CMD_ENABLE,    
-    CMD_SIGN,
-    CMD_LSIGN,
-    CMD_CHECK,
-    CMD_CLEAN,
-    CMD_MINIMIZE
-};
-
-struct cmdlist_s {
-    const char   *name;
-    unsigned int  need_pair:1;
-    int	      id;
-} cmdlist[] = {
-    {"ADDKEY", 1, CMD_ADDKEY},
-    {"ADDUID", 1, CMD_ADDUID},
-    {"ADDPHOTO", 1, CMD_ADDPHOTO},
-    {"ADDREVOKER", 1, CMD_ADDREVOKER},
-    {"DELUID", 1, CMD_DELUID},
-    {"DELKEY", 1, CMD_DELKEY},
-    {"EXPIRE", 1, CMD_EXPIRE},
-    {"SHOWPREF", 0, CMD_SHOWPREF},
-    {"PASSWD", 1, CMD_PASSWD},
-    {"PRIMARY", 1, CMD_PRIMARY},
-    {"TRUST", 0, CMD_TRUST},
-    {"REVUID", 1, CMD_REVUID},
-    {"REVKEY", 1, CMD_REVKEY},
-    {"DISABLE", 0, CMD_DISABLE},
-    {"ENABLE", 0, CMD_ENABLE},
-    {"SIGN", 0, CMD_SIGN},
-    {"LSIGN", 0, CMD_LSIGN},
-    {"CHECK", 0, CMD_CHECK},
-    {"CLEAN", 0, CMD_CLEAN},
-    {"MINIMIZE", 0, CMD_MINIMIZE},
-    {NULL, 0}  
-};
-
-
-/* Symbolic ids for the subkey columns. */
-enum subk_col_t {
-    SUBK_COL_DESC	= 0,
-    SUBK_COL_KEYID	= 1,	
-    SUBK_COL_CREATION	= 2,	
-    SUBK_COL_EXPIRES	= 3,
-    SUBK_COL_STATUS	= 4,
-    SUBK_COL_C_FLAG	= 5,
-    SUBK_COL_S_FLAG	= 6,
-    SUBK_COL_E_FLAG	= 7,
-    SUBK_COL_A_FLAG	= 8
-};
-
-/* Symbolic ids for the userid columns. */
-enum uid_col_t {
-    UID_COL_VALID	= 0,
-    UID_COL_NAME	= 1,
-    UID_COL_EMAIL	= 2,
-    UID_COL_CREATION	= 3
-};
-
-/* Key edit callback context. */
-struct keyedit_cb_s {
-    HWND	    parent; /* parent window handle. */
-    const char	   *keyid;  /* key ID of the key. */
-    const char	   *pass;   /* pointer to the passphrase. */
-    listview_ctrl_t lv;
-    int		    lv_pos;
-    void	   *opaque;
-    unsigned int    finished:1;
-    unsigned int    is_protected:1;
-};
-typedef struct keyedit_cb_s *keyedit_cb_t;
-
-
-/* Key generation callback context. */
-struct keygen_cb_s {
-    int    bits;
-    int	   algo;
-    DWORD  expire; /* date of expiration or '0' for infinite valid. */
-    char  *fpr;
-    char  *name;
-    char  *comment;
-    char  *email;
-};
-typedef struct keygen_cb_s *keygen_cb_t;
-
-/* Subclass context for the subkey list. */
-static subclass_s keyedit_subkey_proc;
-
-/* Subclass context for the user-id list. */
-static subclass_s keyedit_uid_proc;
-
-int keygen_check_date (SYSTEMTIME *st);
-void get_userid_preflist (const char *old_prefs, char **r_prefs, int *r_flags);
-char* get_subkey_keyid (const char *keyid);
-void ComboBox_AddString_utf8 (HWND cb, const char *txt);
-
-
-/* Associate each key with a combo box entry. 
-   Skip the key in @k. */
-static void
-do_init_keylist (HWND dlg, const char *keyid)
-{
-    gpg_keycache_t pub;
-    gpgme_key_t key;
-    const char *s, *kid;
-    int i, n;
-
-    pub = keycache_get_ctx (1);
-    gpg_keycache_rewind (pub);
-    while (!gpg_keycache_next_key (pub, 0, &key)) {
-	if (!key_is_useable (key) || key->invalid)
-	    continue;
-	s = key->uids->uid;
-	kid = key->subkeys->keyid;
-	if (!s || !strcmp (kid+8, keyid))
-	    continue;
-	ComboBox_AddString_utf8 (GetDlgItem (dlg, IDC_ADDREV_KEYLIST), s);
-    }
-    
-    gpg_keycache_rewind (pub);
-    /* In the second loop, we set a key pointer for each element. */
-    n = SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_GETCOUNT, 0, 0);
-    for (i = 0; i < n; i++) {
-	gpg_keycache_next_key (pub, 0, &key);
-	SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETITEMDATA, 
-			    (WPARAM)(int)i, (LPARAM)key);
-    }
-    SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETCURSEL, 0, 0);
-}
-
-
-/* Add a new user-id to the list view @lv. */
-static void
-do_add_new_userid (listview_ctrl_t lv, 
-		   const char *utf8_name, const char *email, 
-		   const char *utf8_comment)
-{
-    StringBuffer p;
-    char *native;
-    
-    if (utf8_comment != NULL)
-	p = p + utf8_name + " (" + utf8_comment + ")";
-    else
-	p = p + utf8_name;
-    native = utf8_to_native (p.getBuffer ());
-
-    listview_add_item (lv, "");
-    listview_add_sub_item (lv, 0, UID_COL_VALID, _("Ultimate" ));
-    listview_add_sub_item (lv, 0, UID_COL_NAME, native);
-    listview_add_sub_item (lv, 0, UID_COL_EMAIL, email && *email? email : "");
-    listview_add_sub_item (lv, 0, UID_COL_CREATION, 
-			   get_key_created (time (NULL)));
-    free_if_alloc (native);
-}
-
-
-static void
-do_add_new_subkey (listview_ctrl_t lv, keygen_cb_t keygen, unsigned int flags)
-{
-    char info[128], keyid[32];
-    const char *expdate, *s, *kid;
-    int n;
-    
-    expdate = keygen->expire? get_key_expire_date (keygen->expire) : _("Never");
-    _snprintf (info, DIM (info)-1, "%d-bit %s", keygen->bits,
-	       get_key_pubalgo ((gpgme_pubkey_algo_t)keygen->algo));
-    kid = get_keyid_from_fpr (keygen->fpr);
-    _snprintf (keyid, DIM (keyid)-1, "0x%s", kid);
-    s = get_key_created (time (NULL));
-    n = listview_count_items (lv, 0);
-    listview_add_item_pos (lv, n);
-    listview_add_sub_item (lv, n, SUBK_COL_DESC, info);
-    listview_add_sub_item (lv, n, SUBK_COL_KEYID, keyid);
-    listview_add_sub_item (lv, n, SUBK_COL_CREATION, s);
-    listview_add_sub_item (lv, n, SUBK_COL_EXPIRES, expdate);
-    if (flags & KM_FLAG_REVOKED)
-	s = _("Revoked");	
-    else if (flags & KM_FLAG_EXPIRED)
-	s = _("Expired");
-    else 
-	s = _("OK");
-    listview_add_sub_item (lv, n, SUBK_COL_STATUS, s);
-}
-
-
-/* Try to find the GPG edit key index which belongs to the user ID
-   given by the email address @email, @name is used as a fallback.
-   If @r_inf != NULL, the info context will be returned.
-   Return value: index of the user ID or -1 on error. */
-static int
-do_find_userid (const char *keyid, const char *email, 
-		const char *name, gpg_uid_info_t *r_inf)
-{
-    GpgKeyEdit ke;
-    gpgme_error_t err;
-    gpg_uid_info_t inf, ui;
-    int pos = -1;
-
-    ke.setKeyID (keyid);
-    err = ke.getUseridInfo (&inf);
-    if (err) {
-	log_box (_("user ID"), MB_ERR, 
-		 _("Could not get key information for: \"%s\":\n%s"), 
-		 name, gpgme_strerror (err));
-	return -1;
-    }
-
-    for (ui = inf; ui; ui = ui->next) {
-	if (name && email && ui->email && ui->name) {
-	    if (!strcmp (ui->email, email) && 
-		!strncmp (ui->name, name, strlen (name))) {
-		pos = ui->index;
-		break;
-	    }
-	    continue;
-	}
-	if (email && ui->email) {
-	    if (!strcmp (ui->email, email)) {
-		pos = ui->index;
-		break;
-	    }
-	    /* The email address is more unique, use the name just
-	       as the fallbck when no email address is available. */
-	    continue;
-	}
-	if (ui->name && name && !strcmp (ui->name, name)) {
-	    pos = ui->index;
-	    break;
-	}
-    }
-    if (r_inf)
-	*r_inf = inf;
-    else
-	gpg_uid_info_release (inf);
-    return pos;
-}
-
-
-/* Return true if @fname is a JPEG file. */
-bool
-is_jpg_file (const char *fname)
-{
-    FILE *fp;
-    BYTE buf[10];
-    int n;
-
-    fp = fopen (fname, "rb");
-    if (!fp)
-	return false;
-    n = fread (buf, 1, DIM (buf), fp);
-    fclose (fp);
-    if (n < (int)DIM (buf))
-	return false;
-    return buf[6] == 'J' && buf[7] == 'F' &&
-	   buf[8] == 'I' && buf[9] == 'F';
-}
-
-
-/* Dialog box procedure to add a photo. */
-BOOL CALLBACK
-keyedit_addphoto_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    static keyedit_cb_t cb;
-    gpgme_error_t err;
-    const char *s;    
-    char file[128];
-    int id;
-
-    switch (msg) {
-    case WM_INITDIALOG:
-	cb = (keyedit_cb_t)lparam;
-	if (!cb)
-	    BUG (NULL);
-	SetDlgItemText (dlg, IDC_ADDPHOTO_INF, _("Remember that the image is stored within your public key.  If you use a very large picture, your key will become very large as well! Keeping the image close to 240x288 is advised."));
-	SetDlgItemText (dlg, IDC_ADDPHOTO_FILEINF, _("Pick an image to use for your photo ID.\nThe image must be a JPEG file."));
-	SetDlgItemText (dlg, IDC_ADDPHOTO_PWDINF, _("Passphrase"));
-	SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
-	SetWindowText (dlg, _("Add Photo ID"));
-	SetForegroundWindow (dlg);
-	break;
-	
-    case WM_DESTROY:
-	balloon_msg_disable ();
-	break;
-	
-    case WM_COMMAND:
-	switch( LOWORD (wparam)) {
-	case IDC_ADDPHOTO_SELFILE:
-	    s = get_fileopen_dlg (dlg, _("Select Image File"), 
-				  "JPEG Files (*.jpg, *.jpeg)\0*.jpg;*.jpeg\0\0",
-				  NULL);
-	    if (s && !is_jpg_file (s)) {
-		log_box (_("Add Photo ID"), MB_ERR, 
-			 _("'%s' is not a valid JPEG file."), s);
-		return FALSE;
-	    }
-	    if (s && *s)
-		SetDlgItemText (dlg, IDC_ADDPHOTO_FILE, s);
-	    break;
-
-	case IDOK:
-	    if (!GetDlgItemText (dlg, IDC_ADDPHOTO_FILE, file, sizeof (file)-1)){
-		show_balloon_msg (GetDlgItem (dlg, IDC_ADDPHOTO_FILE),
-				  _("Please enter a file name."), IDI_ERROR);
-		return FALSE;
-	    }
-	    if (get_file_size (file) == 0 || get_file_size (file) > 6144) {
-		id = msg_box (dlg, _("The JPEG is really large.\n"
-				     "Are you sure you want to use it?"), 
-				     _("Add Photo ID"), MB_YESNO|MB_INFO);
-		if (id == IDNO)
-		    return TRUE;
-	    }
-	    
-	    {
-		GpgKeyEdit ke;
-		
-		ke.setKeyID (cb->keyid);
-		if (cb->pass)
-		    ke.setPassphrase (cb->pass);
-		else
-		    ke.setNoPassphrase (true);
-		err = ke.addPhotoid (file);
-	    }
-	    if (err) {
-		msg_box (dlg, gpgme_strerror (err), _("Add Photo ID"), MB_ERR);
-		return FALSE;
-	    }
-	    else {
-		cb->finished = 1;
-		msg_box (dlg, _("Photo successfully added."), 
-			 _("GnuPG Status"), MB_OK);
-	    }
-	    EndDialog (dlg, TRUE);
-	    break;
-
-	case IDCANCEL:
-	    EndDialog (dlg, FALSE);
-	    break;
-	}
-	break;
-    }
-    return FALSE;
-}
-
-
-/* Dialog box procedure to add a designated revoker. */
-BOOL CALLBACK
-keyedit_addrevoker_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    static keyedit_cb_t cb;
-    gpgme_error_t err;
-    char *uid=NULL;
-
-    switch (msg) {
-    case WM_INITDIALOG:
-	cb = (keyedit_cb_t)lparam;
-	if (!cb)
-	    BUG (NULL);
-	do_init_keylist (dlg, cb->keyid);
-	SetDlgItemText (dlg, IDC_ADDREV_INF, 
-			_("Appointing a key as designated revoker cannot be undone."));
-	SetDlgItemText (dlg, IDC_ADDREV_KEYINF, _("Public key:"));
-	SetDlgItemText (dlg, IDC_ADDREV_PWDINF, _("Passphrase"));
-	SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
-	SetWindowText (dlg, _("Add Revoker"));
-	SetForegroundWindow (dlg);
-	center_window (dlg, cb->parent);
-	break;
-
-    case WM_DESTROY:
-	balloon_msg_disable ();
-	break;
-	
-    case WM_COMMAND:
-	switch (LOWORD (wparam)) {
-	case IDOK:
-	    if (!GetDlgItemText_utf8 (dlg, IDC_ADDREV_KEYLIST, &uid)) {
-		show_balloon_msg (GetDlgItem (dlg, IDC_ADDREV_KEYLIST),
-				  _("Please select a user ID."), IDI_ERROR);
-		return FALSE;
-	    }
-	
-	    {
-		GpgKeyEdit ke;
-		
-		ke.setKeyID (cb->keyid);
-		if (cb->pass)
-		    ke.setPassphrase (cb->pass);
-		else
-		    ke.setNoPassphrase (true);
-		err = ke.addDesignatedRevoker (uid);
-	    }
-
-	    safe_free (uid);
-	    if (err) {
-		msg_box (dlg, gpgme_strerror (err), _("Add Revoker"), MB_ERR);
-		return TRUE;
-	    }
-	    else {
-		cb->finished = 1;
-		msg_box (dlg, _("Revoker successfully addded."), 
-			 _("GnuPG Status"), MB_OK);
-	    }
-	    EndDialog (dlg, TRUE);
-	    break;
-
-	case IDCANCEL:
-	    EndDialog (dlg, FALSE);
-	    break;
-	}
-	break;
-    }
-    return FALSE;
-}
-
-
-/* Dialog box procedure to add a new user-ID. */
-BOOL CALLBACK
-keyedit_adduid_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    static keyedit_cb_t ctx;
-    keygen_cb_t keygen;
-    gpgme_error_t err;
-    char *utf8_name = NULL;
-    char *utf8_comment = NULL;
-    char email[128];
-    int rc;
-    
-    switch (msg) {
-    case WM_INITDIALOG:
-        ctx = (keyedit_cb_t)lparam;
-        if (!ctx)
-            dlg_fatal_error(dlg, "Could not get dialog param!");
-        SetWindowText (dlg, _("Add user ID"));
-        SetDlgItemText (dlg, IDC_ADDUID_INFNAME, _("&Name:"));
-        SetDlgItemText (dlg, IDC_ADDUID_INFEMAIL, _("&Email:"));
-        SetDlgItemText (dlg, IDC_ADDUID_INFCOMMENT, _("&Comment:"));
-	SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
-        SetForegroundWindow (dlg);
-	center_window (dlg, ctx->parent);
-        return FALSE;
-        
-    case WM_DESTROY:
-	balloon_msg_disable ();
-	break;
-	
-    case WM_COMMAND:
-        switch ( LOWORD( wparam ) )  {
-        case IDOK:
-	    keygen = (keygen_cb_t)ctx->opaque;
-            rc = GetDlgItemText_utf8 (dlg, IDC_ADDUID_NAME, &utf8_name);
-            if (!rc || rc < 5) {
-		show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_NAME),
-				  _("Please enter a name (min. 5 chars.)"),
-				  IDI_ERROR);
-		free_if_alloc (utf8_name);
-                return FALSE;
-            }
-	    if (strchr (utf8_name, '@')) {
-		show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_NAME),
-				  _("Please enter the email address in the email field and not in the name field"),
-				  IDI_WARNING);
-		free_if_alloc (utf8_name);
-		return FALSE;
-	    }
-
-            if( !GetDlgItemText (dlg, IDC_ADDUID_EMAIL, email, DIM (email) -1)) {
-		show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_EMAIL),
-				  _("Please enter an email address."),IDI_ERROR);				  
-		free_if_alloc (utf8_name);
-                return FALSE;
-            }
-	    if (check_email_address (email)) {
-		show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_EMAIL),
-				  _("Invalid email address."), IDI_ERROR);
-		free_if_alloc (utf8_name);
-		return FALSE;
-	    }
-            
-            rc = GetDlgItemText_utf8 (dlg, IDC_ADDUID_COMMENT, &utf8_comment);
-	    {
-		GpgKeyEdit ke;
-		
-		ke.setKeyID (ctx->keyid);
-		if (ctx->is_protected)
-		    ke.setPassphrase (ctx->pass);
-		else
-		    ke.setNoPassphrase (true);
-		err = ke.addUserid (utf8_name, utf8_comment, email);
-	    }
-	    if (err)
-		msg_box (dlg, gpgme_strerror (err), _("UserID"), MB_ERR);
-	    else {
-		msg_box (dlg, _("user ID successfully added."), _("GnuPG Status"), MB_OK);
-		ctx->finished = 1;
-		/* The caller releases this items later. */
-		keygen->name = utf8_name;
-		keygen->comment = utf8_comment;
-		keygen->email = m_strdup (email);
-	    }
-            EndDialog (dlg, TRUE);
-            return TRUE;
-            
-        case IDCANCEL:
-            EndDialog (dlg, FALSE);
-            return FALSE;
-        }
-        break;
-    }
-    
-    return FALSE;
-}
-
-
-/* Initalize a combo box with default key sizes. */
-static void
-init_keysize_box (HWND dlg, int ctlid)
-{
-    /* Array with standard key-length in bits. */
-    const char *sizelist[] = {
-	"2048", "3072", "4096", NULL
-    };
-
-    for (int i=0; sizelist[i] != NULL; i++)
-	SendDlgItemMessage (dlg, ctlid, CB_ADDSTRING, 0, 
-			    (LPARAM)(char*)sizelist[i]);
-    SendDlgItemMessage (dlg, ctlid, CB_SETCURSEL, (WPARAM)0, 0);
-}
-
-
-static int
-get_keysize_from_box (HWND dlg, int ctlid)
-{
-    int pos;
-    char buf[32];
-
-    pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0);
-    if (pos == CB_ERR)
-	return -1;
-    SendDlgItemMessage (dlg, ctlid, CB_GETLBTEXT, pos, (LPARAM)(char*)buf);
-    return atoi (buf);
-}
-
-
-/* Create a time_t from a system time @st. */
-time_t
-w32_mktime (SYSTEMTIME *st)
-{
-    struct tm tm;
-
-    memset (&tm, 0, sizeof (tm));
-    tm.tm_year = st->wYear-1900;
-    tm.tm_mday = st->wDay;
-    tm.tm_mon = st->wMonth-1;
-    return mktime (&tm);
-}
-
-
-/* Dialog procedure for adding a new secondary key. */
-BOOL CALLBACK
-keyedit_addsubkey_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    static keyedit_cb_t ctx;
-    keygen_cb_t keygen;
-    gpgme_error_t err;
-    SYSTEMTIME st;
-    HWND hwnd;
-    int index, size, valid;
-    
-    switch (msg) {
-    case WM_INITDIALOG:
-        ctx = (keyedit_cb_t)lparam;
-	if (!ctx)
-	    BUG (NULL);
-        SetWindowText (dlg, _("Add Subkey"));
-        SetDlgItemText (dlg, IDC_ADDSUBKEY_INFALGO, _("Key type:"));
-        SetDlgItemText (dlg, IDC_ADDSUBKEY_INFSIZE, _("Size in bits:"));
-        SetDlgItemText (dlg, IDC_ADDSUBKEY_INFVALID, _("Key expiration:"));
-	SetDlgItemText (dlg, IDC_ADDSUBKEY_EXPIRE, _("&Never"));
-	SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
-
-        hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
-        listbox_add_string (hwnd, _("DSA (sign only)"));
-        listbox_add_string (hwnd, _("ElGamal (encrypt only)"));
-        listbox_add_string (hwnd, _("RSA (sign only)"));
-        listbox_add_string (hwnd, _("RSA (encrypt only)"));
-	CheckDlgButton (dlg, IDC_ADDSUBKEY_EXPIRE, BST_CHECKED);
-	EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
-        EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_SIZE), FALSE);
-	init_keysize_box (dlg, IDC_ADDSUBKEY_SIZE);
-        SetForegroundWindow (dlg);
-	center_window (dlg, ctx->parent);
-        return FALSE;
-        
-    case WM_DESTROY:
-	balloon_msg_disable ();
-	break;
-	
-    case WM_COMMAND:
-	if (HIWORD (wparam) == BN_CLICKED && 
-	    LOWORD (wparam) == IDC_ADDSUBKEY_EXPIRE) {
-	    if (IsDlgButtonChecked (dlg, IDC_ADDSUBKEY_EXPIRE))
-		EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
-	    else
-		EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), TRUE);
-	}
-	if (HIWORD (wparam) == LBN_SELCHANGE && 
-	    LOWORD (wparam) == IDC_ADDSUBKEY_ALGO) {
-	    /* If DSA is selected, we disable the selection box since it
-	       is hardocded to 2048-bit. */
-	    index = SendMessage ((HWND)lparam, LB_GETCURSEL, 0, 0);
-	    EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_SIZE), 
-			  index != 0? TRUE : FALSE);
-	}
-
-        switch (LOWORD (wparam)) {
-        case IDOK:
-	    keygen = (keygen_cb_t)ctx->opaque;
-	    if (!keygen)
-		BUG (NULL);
-            hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
-	    int map[4];
-	    /* this is for GPG 1.4.9 */
-	    map[0] = 2;
-	    map[1] = 4;
-	    map[2] = 5;
-	    map[3] = 6;
-	    /* >1.4.10 changed the menu IDs. */
-	    if (gpgver[0] == 1 && gpgver[1] >= 4 && gpgver[2] > 9) {
-		map[0] = 3;
-		map[1] = 5;
-		map[2] = 4;
-		map[3] = 6;
-	    }
-		
-	    /* Map combo box numbers to GPG answers. */
-	    switch (listbox_get_cursel (hwnd)) {
-	    case 0: 
-	    case 1:
-	    case 2:
-	    case 3:
-		break;
-	    default:
-		show_balloon_msg (GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO),
-				  _("Please select one entry."), IDI_ERROR);
-                return FALSE;
-            }
-	    index = map[listbox_get_cursel (hwnd)];
-	    size = get_keysize_from_box (dlg, IDC_ADDSUBKEY_SIZE);
-            if (index == 2) /* DSA */
-                size = 2048;
-
-	    hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE);
-	    DateTime_GetSystemtime (hwnd, &st);
-	    valid = w32_mktime (&st) - time (NULL);
-	    valid /= 86400;
-
-	    keygen->bits = size;
-	    switch (index) {
-	    case 2: keygen->algo = GPGME_PK_DSA; break;
-	    case 4: keygen->algo = GPGME_PK_ELG_E; break;
-	    case 5: keygen->algo = GPGME_PK_RSA_S; break;
-	    case 6: keygen->algo = GPGME_PK_RSA_E; break;
-	    }
-	    if (valid > 0)
-		keygen->expire = time (NULL) + valid*24*60*60;
-
-	    {
-		GpgKeyEdit ke;
-		
-		ke.setKeyID (ctx->keyid);
-		ke.setCallback (keygen_cb, NULL);
-		if (ctx->is_protected)
-		    ke.setPassphrase (ctx->pass);
-		else
-		    ke.setNoPassphrase (true);
-		keygen_cb_dlg_create ();
-		err = ke.addSubkey ((gpgme_pubkey_algo_t)index, size, valid);
-	    }
-	    keygen->fpr = get_subkey_keyid (ctx->keyid);
-	    keygen_cb_dlg_destroy (1);
-	    if (err)
-		msg_box (dlg, gpgme_strerror (err), _("Add Subkey"), MB_ERR);
-	    else {
-		msg_box (dlg, _("Subkey successfully added."), 
-			 _("GnuPG Status"), MB_OK);
-		ctx->finished = 1;
-	    }
-	    EndDialog (dlg, TRUE);
-            return TRUE;
-            
-        case IDCANCEL:
-            EndDialog (dlg, FALSE);
-            return FALSE;
-        }
-        break;
-    }
-    
-    return FALSE;
-}
-
-
-BOOL
-keyedit_add_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    keyedit_cb_s cb;
-    keygen_cb_s keygen;
-    char *pass = NULL;
-    int cancel = 0;
-
-    if (!k->key_pair) {
-	msg_box (dlg, _("There is no secret key available!"), 
-		 _("Add user ID"), MB_ERR);
-        return FALSE;
-    }
-
-    if (k->is_protected) {
-	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;
-    }
-
-    memset (&keygen, 0, sizeof (keygen));
-    memset (&cb, 0, sizeof (cb));
-    cb.parent = dlg;
-    cb.opaque = &keygen;
-    cb.is_protected = k->is_protected;
-    cb.pass = pass;
-    cb.keyid = k->keyid;
-    dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDUID,
-		      dlg, keyedit_adduid_dlg_proc,         
-		      (LPARAM)&cb, _("Add user ID"),
-		      IDS_WINPT_KEYEDIT_ADDUID);
-    if (lv != NULL && cb.finished)
-	do_add_new_userid (lv, keygen.name, keygen.email, keygen.comment);
-    if (cb.finished)
-	k->update = 1;
-
-    free_if_alloc (keygen.name);
-    free_if_alloc (keygen.email);
-    free_if_alloc (keygen.comment);
-    sfree_if_alloc (pass);
-    return TRUE;
-}
-
-
-/* Return the keyID of the last subkey. */
-char*
-get_subkey_keyid (const char *keyid)
-{
-    gpgme_error_t err;
-    gpgme_key_t key;
-    gpgme_ctx_t ctx;
-    gpgme_subkey_t subk;
-    char *kid = NULL;
-
-    err = gpgme_new (&ctx);
-    if (err)
-	return NULL;
-    err = gpgme_get_key (ctx, keyid, &key, 0);
-    gpgme_release (ctx);
-    if (err)
-	return NULL;
-    subk = get_nth_key (key, count_subkeys (key));
-    if (subk != NULL)
-	kid = strdup (subk->keyid);
-    gpgme_key_release (key);
-    return kid;
-}
-
-
-BOOL
-keyedit_add_subkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    keyedit_cb_s cb;
-    keygen_cb_s keygen;
-    char *pass = NULL;
-    int cancel = 0;
-
-    if (!k->key_pair) {
-	msg_box (dlg, _("There is no secret key available!"), 
-		 _("Add Subkey"), MB_ERR);
-        return FALSE;
-    }
-    if (k->is_protected) {
-	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;
-    }
-
-    memset (&keygen, 0, sizeof (keygen));
-    memset (&cb, 0, sizeof (cb));
-    cb.keyid = k->keyid;
-    cb.is_protected = k->is_protected;
-    cb.pass = pass;
-    cb.opaque = &keygen;
-    dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDSUBKEY,    
-		      dlg, keyedit_addsubkey_dlg_proc,
-		      (LPARAM)&cb, _("Add Subkey"),
-		      IDS_WINPT_KEYEDIT_ADDSUBKEY);
-    if (lv != NULL && cb.finished)
-	do_add_new_subkey (lv, &keygen, 0);
-    if (cb.finished)
-	k->update = 1;
-
-    safe_free (keygen.fpr);
-    sfree_if_alloc (pass);
-    return cb.finished? TRUE: FALSE;
-}
-
-
-/* Set the preferred keyserver of the given key @k. */
-BOOL
-keyedit_set_pref_keyserver (winpt_key_t k, HWND dlg)
-{
-    GpgKeyEdit ke;
-    gpgme_error_t err;
-    struct URL_ctx_s *url;
-    char *pass = NULL;
-
-    url = (struct URL_ctx_s *)get_keyserver_URL_dlg (dlg);
-    if (url == NULL || url->cancel == 1) {
-	delete url;
-	return FALSE;
-    }
-
-    pass = request_key_passphrase (k->ctx, _("Key Edit"), &url->cancel);
-    if (url->cancel) {
-	delete url;
-	return FALSE;
-    }
-
-    ke.setKeyID (k->keyid);
-    if (k->is_protected)
-	ke.setPassphrase (pass);
-    else
-	ke.setNoPassphrase (true);
-    err = ke.setPreferredKeyserver (-1, url->url);
-    if (!err)
-	msg_box (dlg, _("Preferred keyserver successfully set."), 
-		 _("Key Edit"), MB_OK);
-    else
-	msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
-
-    keyserver_set_default (url->url, 0);
-    sfree_if_alloc (pass);
-    delete url;
-    return err == 0? 0 : WPTERR_GENERAL;
-}
-
-
-/* Add a photo-ID to the key specified in @k. @dlg is the handle of
-   the calling dialog. */
-BOOL
-keyedit_add_photo (winpt_key_t k, HWND dlg)
-{
-    keyedit_cb_s cb;
-    char *pass = NULL;
-    int cancel;
-    
-    if (!k->key_pair) {
-	msg_box (dlg, _("There is no secret key available!"), 
-		 _("Add Photo ID"), MB_ERR);
-        return FALSE;
-    }
-
-    memset (&cb, 0, sizeof (cb));
-    if (k->is_protected) {
-	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;
-    }
-    cb.parent = dlg;
-    cb.pass = pass;
-    cb.keyid = k->keyid;
-    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDPHOTO, dlg,
-		    keyedit_addphoto_dlg_proc, (LPARAM)&cb);
-
-    if (cb.finished)
-	k->update = 1;
-    sfree_if_alloc (pass);    
-    return TRUE;
-}
-
-
-BOOL
-keyedit_add_revoker (winpt_key_t k, HWND dlg)
-{
-    keyedit_cb_s cb;
-    char *pass = NULL;
-    int cancel;
-
-    if (!k->key_pair) {
-	msg_box (dlg, _("There is no secret key available!"), _("Add Revoker"), MB_ERR);
-        return FALSE;
-    }
-
-    if (k->is_protected) {
-	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;
-    }
-
-    memset (&cb, 0, sizeof (cb));
-    cb.parent = dlg;
-    cb.is_protected = k->is_protected;
-    cb.keyid = k->keyid;
-    cb.pass = pass;
-    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDREV, dlg,
-		    keyedit_addrevoker_dlg_proc, (LPARAM)&cb);
-
-    if (cb.finished)
-	k->update = 1;
-    sfree_if_alloc (pass);
-    return TRUE;
-}
-
-
-/* Change ownertrust of the given key @key.
-   Return TRUE if the ownertrust was changed. */
-BOOL
-keyedit_change_ownertrust (winpt_key_t key, HWND dlg)
-{
-    int rc;
-
-    rc = dialog_box_param (glob_hinst, 
-			     (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,
-			     dlg, keyedit_ownertrust_dlg_proc,
-			     (LPARAM)key, _("Change Ownertrust"),
-			     IDS_WINPT_KEYEDIT_OWNERTRUST);
-    if (rc == TRUE) {
-	msg_box (dlg, _("Key status changed."), _("Key Edit"), MB_OK);
-	key->update = 1;
-    }
-    return rc;
-}
-
-
-/* Check if the given key is supposed to have IDEA
-   for secret key protection. */
-static int
-is_idea_protect_algo (const char *keyid)
-{
-    winpt_key_s k;
-    const unsigned char *sym_prefs;
-    size_t n;
-
-    memset (&k, 0, sizeof (k));
-    if (winpt_get_pubkey (keyid, &k))
-	BUG (NULL);
-    if (!k.is_v3)
-	return 0;
-    sym_prefs = k.ext->sym_prefs;
-    /* Assume that only v3 keys have no symmetric cipher 
-       preferences and thus IDEA is explicit. */
-    if (!sym_prefs)
-	return 1; 
-    for (n = 0; sym_prefs[n]; n++)
-	;
-    if ((n == 0 || n == 1) && *sym_prefs == 0x01)
-	return 1;
-    return 0;
-}
-
-
-BOOL
-keyedit_change_passwd (winpt_key_t k, HWND dlg)
-{
-    gpgme_error_t err;
-    GpgKeyEdit ke;
-    char *old_pass = NULL;
-    char *new_pass = NULL;
-    int cancel = 0;
-
-    if (!k->key_pair) {
-	msg_box (dlg, _("There is no secret key available!"), 
-		 _("Key Edit"), MB_ERR);
-        return FALSE;
-    }
-
-    if (!idea_available && is_idea_protect_algo (k->keyid)) {
-	msg_box (dlg, _("Cannot change passphrase because the key\n"
-	                "is protected with the IDEA encryption algorithm."),
-			_("Key Edit"), MB_ERR);
-	return FALSE;
-    }
-
-    if (k->is_protected) {
-	old_pass = request_passphrase (_("Current (old) Passphrase"), 
-				       PASSDLG_INIT, &cancel);
-	if (cancel)
-	    return FALSE;
-    }
-    new_pass = request_passphrase2 (_("New Passphrase" ), 
-				    PASSDLG_INIT|PASSDLG_WARN_UTF8, &cancel);
-    if (cancel) {
-	sfree_if_alloc (old_pass);
-        return FALSE;
-    }
-
-    if (strlen (new_pass) == 0) {
-	cancel = msg_box (dlg, _("Are you sure that you really don't want a passphrase?\n"
-				 "This is propably a bad idea, continue?"),
-			    _("Key Edit"), MB_WARN_ASK);
-	if (cancel != IDYES) {
-	    sfree_if_alloc (old_pass);
-	    sfree_if_alloc (new_pass);
-	    return FALSE;
-	}
-    }
-
-    ke.setKeyID (k->keyid);
-    ke.setPassphrase (k->is_protected? old_pass : NULL);
-    if (!k->is_protected)
-	ke.setNoPassphrase (true);
-    err = ke.changePassphrase (new_pass, 1);
-    if (err)
-	msg_box (dlg, gpgme_strerror (err), _("Change Password"), MB_ERR);
-    else
-	msg_box (dlg, _("Passphrase successfully changed."),  _("GnuPG Status"), MB_OK);
-    sfree_if_alloc (old_pass);
-    sfree_if_alloc (new_pass);
-
-    return TRUE;
-}
-
-		
-/* Initialize sub key list from key @k and return
-   the new listview control. */
-listview_ctrl_t
-subkey_list_init (HWND dlg, winpt_key_t k)
-{
-    LV_ITEM lvi;
-    gpgme_subkey_t sub;
-    struct listview_column_s cols[] = {
-	{0, 80, (char *)_("Description")},
-	{1, 78, (char *)_("Key ID")},
-        {2, 66, (char *)_("Creation")},
-        {3, 66, (char *)_("Expires")},
-        {4, 64, (char *)_("Status")},
-	{5, 16, (char *) "C"/*ertify*/},
-	{6, 16, (char *) "S"/*ign*/},
-	{7, 16, (char *) "E"/*ncrypt*/},
-	{8, 16, (char *) "A"/*uth*/},
-        {0, 0, 0}
-    };
-    listview_ctrl_t lv;
-    char buf[256], tmp[128];
-    const char *t;
-    int nkeys = 0, i;
-
-    nkeys = count_subkeys (k->ctx);
-    if (!nkeys)
-	BUG (NULL); /* should never happen. */
-        
-    listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
-    for (i = 0; cols[i].fieldname != NULL; i++)
-	listview_add_column (lv, &cols[i]);
-        
-    for (i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next) {
-        listview_add_item (lv, "");
-	listview_add_sub_item (lv, 0, 1, "");
-	memset (&lvi, 0, sizeof (lvi));
-	lvi.mask = LVIF_PARAM;	
-	lvi.lParam = (LPARAM)sub;
-	if (ListView_SetItem (lv->ctrl, &lvi) == FALSE)
-	    BUG (NULL);
-    }
-        
-    listview_set_ext_style (lv);
-    for (i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next) {
-	_snprintf (buf, DIM (buf)-1, "%d-bit %s", sub->length,
-				get_key_pubalgo (sub->pubkey_algo));
-	listview_add_sub_item (lv, i, SUBK_COL_DESC, buf);
-	t = sub->keyid;
-	assert (t != NULL);
-	_snprintf (tmp, DIM (tmp)-1, "0x%s", t+8);
-	listview_add_sub_item (lv, i, SUBK_COL_KEYID, tmp);
-
-	t = get_key_created (sub->timestamp);
-	if (!t)
-	    t = "????" "-??" "-??";
-	listview_add_sub_item (lv, i, SUBK_COL_CREATION, t);
-
-	if (sub->expires) {
-	    t = get_key_created (sub->expires);
-	    listview_add_sub_item (lv, i, SUBK_COL_EXPIRES, t);
-	}
-	else
-	    listview_add_sub_item (lv, i, SUBK_COL_EXPIRES, _("Never"));
-	if (sub->expired)
-	    t = _("Expired");
-	else if (sub->revoked)
-	    t = _("Revoked");
-	else
-	    t = _("OK");
-	listview_add_sub_item (lv, i, SUBK_COL_STATUS, t);
-
-	if (sub->can_certify) t = "*"; else t = "";
-	listview_add_sub_item (lv, i, SUBK_COL_C_FLAG, t);
-	if (sub->can_sign) t = "*"; else t = "";
-	listview_add_sub_item (lv, i, SUBK_COL_S_FLAG, t);
-	if (sub->can_encrypt) t = "*"; else t = "";
-	listview_add_sub_item (lv, i, SUBK_COL_E_FLAG, t);
-	if (sub->can_authenticate) t = "*"; else t = "";
-	listview_add_sub_item (lv, i, SUBK_COL_A_FLAG, t);
-    }
-    return lv;
-}
-
-
-static listview_ctrl_t
-userid_list_init (HWND dlg, winpt_key_t k)
-{
-    listview_ctrl_t lv = NULL;
-    gpgme_key_sig_t ks;
-    struct native_uid_s *u;
-    int nuids = 0, j, u_attr;
-    struct listview_column_s cols[] = {
-        {0,  72, (char *)_("Validity")},
-        {1, 150, (char *)_("Name")},
-	{2, 110, (char *)_("Email")},
-	{3,  76, (char *)_("Creation")},
-        {0, 0, 0}
-    };    
-    const char *attr;
-    
-    nuids = count_userids (k->ctx);
-    if (!nuids)
-	BUG (NULL); /* should never happen. */
-        
-    listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST));
-    for (j = 0; cols[j].fieldname != NULL; j++)
-        listview_add_column (lv, &cols[j]);
-        
-    for (j = 0; j < nuids; j++) {
-	listview_add_item (lv, " ");
-	listview_add_sub_item (lv, 0, 1, " " );        
-    }
-
-    listview_set_ext_style (lv);
-    for (j = 0, u=k->ext->uids; j < nuids; u=u->next, j++) {
-	if (u->revoked)
-	    attr = _("Revoked");
-	else {
-	    u_attr = (int)u->validity;
-	    attr = get_key_trust2 (NULL, u_attr, 0, 0);
-	}
-	listview_add_sub_item (lv, j, UID_COL_VALID, (char *)attr);
-	/* XXX: add comment if available */
-	listview_add_sub_item (lv, j, UID_COL_NAME, 
-			       u->name? u->name : _("Invalid user ID"));
-	if (u->email)
-	    listview_add_sub_item (lv, j, UID_COL_EMAIL, u->email);
-
-	ks = get_selfsig (u->signatures, k->keyid, 1);
-	if (ks)
-	    listview_add_sub_item (lv, j, UID_COL_CREATION, 
-				   get_key_created (ks->timestamp));
-    }
-    if (!k->key_pair) {
-	CheckDlgButton (dlg, IDC_KEYUID_ADD, BST_INDETERMINATE);
-	CheckDlgButton (dlg, IDC_KEYUID_REVOKE, BST_INDETERMINATE);
-    }
-    return lv;
-}
-
-
-static void
-do_init_cmdlist (HWND dlg, int is_keypair)
-{    
-    const char *s;
-    int i;
-
-    for (i = 0; (s=cmdlist[i].name); i++) {
-	if (is_keypair)
-	    SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
-				(LPARAM)(char *)s);
-	else if (!cmdlist[i].need_pair)
-	    SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
-				(LPARAM)(char *)s);
-    }
-    SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_SETCURSEL, 0, 0);
-}
-
-
-/* Return 1 if the requested command is RFC2440. */
-static int
-is_cmd_openpgp (int cmdid)
-{
-    switch (cmdid) {
-    case CMD_ADDKEY:
-    case CMD_ADDPHOTO:
-    case CMD_ADDREVOKER:
-    case CMD_SETPREF:
-	return 1;
-    }
-    return 0;
-}
-
-
-/* Display a message box with a short description of the commands. */
-static void
-do_show_help (HWND dlg)
-{
-    const char *help;
-
-    help =
-	_(
-	 "ADDUID\t\t\tadd a user ID\r\n"
-	 "ADDPHOTO\t\t\tadd a photo ID\r\n"
-	 "DELUID\t\t\tdelete a user ID\r\n"
-	 "ADDKEY\t\t\tadd a secondary key\r\n"
-	 "DELKEY\t\t\tdelete a secondary key\r\n"
-	 "ADDREVOKER\t\t\tadd a revocation key\r\n"
-	 "EXPIRE\t\t\tchange the expire date\r\n"
-	 "SHOWPREF\t\t\tlist preferences (verbose)\r\n"
-	 "PASSWD\t\t\tchange the passphrase\r\n"
-	 "PRIMARY\t\t\tflag user ID as primary\r\n"
-	 "TRUST\t\t\tchange the ownertrust\r\n"
-	 "REVUID\t\t\trevoke a user ID\r\n"
-	 "REVKEY\t\t\trevoke a secondary key\r\n"
-	 "DISABLE\t\t\tdisable a key\r\n"
-	 "ENABLE\t\t\tenable a key\r\n"
-	 "SIGN\t\t\tsign a user-id (exportable)\r\n"
-	 "LSIGN\t\t\tsign a user-id (non-exportable)\r\n"
-	 "CLEAN\t\t\tremove unusable signatures from key\r\n"
-	 "MINIMIZE\t\t\tremove all signatures from key\r\n"
-	 );
-    msg_box (dlg, help, _("Key Edit Help"), MB_OK);
-}
-
-
-static gpgme_subkey_t
-get_subkey_bypos (const char *keyid, int idx)
-{
-    gpgme_key_t key;
-
-    if (get_pubkey (keyid, &key))
-	return NULL;
-    return get_nth_key (key, idx);
-}
-
-
-
-static int
-do_editkey_delkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    gpgme_error_t err;
-    gpgme_subkey_t subk;
-    GpgKeyEdit ke;
-    int pos, id;
-    const char *warn;
-    char tmp[64];
-
-    if (!k->key_pair)
-	return FALSE;
-
-    if (listview_count_items (lv, 0) == 1) {
-	show_balloon_msg (lv->ctrl, _("Primary key can not be deleted!"),
-			  IDI_ERROR);
-        return FALSE;
-    }
-    pos = listview_get_curr_pos (lv);
-    if (pos == -1) {
-	show_balloon_msg (lv->ctrl, _("Please select a key."), IDI_ERROR);
-        return FALSE;
-    }
-    if (pos == 0) {
-	show_balloon_msg (lv->ctrl, _("Primary key can not be deleted!"),
-			 IDI_ERROR);
-        return FALSE;
-    }
-
-    listview_get_item_text (lv, pos, 0, tmp, DIM (tmp) -1);
-    subk = get_subkey_bypos (k->keyid, pos);
-    /* Issue different warning for the different key capabilities. */
-    if (subk->can_encrypt)
-	warn = _("Anything encrypted to the selected subkey cannot be\n"
-	         "decrypted any longer.");
-    else if (subk->can_sign || subk->can_certify)
-	warn = _("Anything signed by the selected subkey cannot be\n"
-		 "verified any longer.");
-    else
-	warn = ""; /* just get rid of the warning. */
-
-    id = log_box (_("Key Edit"), MB_YESNO|MB_ICONWARNING, 
-		  _("\"Subkey %s, ID 0x%s.\"\n\n%s\n\n"
-		    "Do you really want to DELETE this subkey?"), 
-		  tmp, subk->keyid+8, warn);
-    if (id == IDNO)
-	return FALSE;
-
-    ke.setKeyID (k->keyid);
-    err = ke.delKey (pos);
-    if (err)
-	msg_box (dlg, gpgme_strerror (err), _("Delete Subkey"), MB_ERR);
-    else {
-	listview_del_item (lv, pos);
-	k->update = 1;
-	status_box (dlg, _("Subkey successfully deleted."), _("GnuPG Status"));
-    }
-    return err? FALSE : TRUE;
-}
-
-
-/* Set the expiration date for the selected key in list view @lv.
-   Return value: TRUE on success. */
-static int
-do_editkey_expire (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    gpgme_error_t err;
-    GpgKeyEdit ke;
-    date_s udd = {0};
-    char buf[256], * pass = NULL;
-    time_t exp;
-    int pos, cancel = 0;
-
-    if (!k->key_pair) {
-	msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
-        return FALSE;
-    }
-    pos = listview_get_curr_pos (lv);
-    if (pos == -1) {
-	msg_box (dlg, _("Please select a key."), _("Key Edit"), MB_ERR);
-        return FALSE;
-    }
-
-    /* If a key already expired, it is possible the user wants to
-       set a new expiration date.. */
-    listview_get_item_text (lv, pos, SUBK_COL_STATUS, buf, DIM (buf)-1);
-    if (!strcmp (buf, _("Expired"))) {
-	cancel = msg_box (dlg, _("Key already expired.\n\n"
-			  "Do you want to change the expiration date?"),
-		          _("Key Edit"), MB_QUEST_ASK);
-	if (cancel == IDNO)
-	    return FALSE;
-	cancel = 0;
-    }
-
-    memset (&udd, 0, sizeof (udd));
-    udd.text = _("Key Expiration Date");
-    dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_DATE, dlg,    
-		      date_dlg_proc, (LPARAM)&udd,
-		      _("Key Expiration Date"), IDS_WINPT_DATE);
-    if (udd.cancel == 1)
-	return FALSE;
-    if (!keygen_check_date (&udd.st)) {
-	msg_box (dlg, _("The date you have chosen has already passed."), 
-		 _("Key Edit"), MB_ERR);
-        return FALSE;
-    }
-    if (k->is_protected) {
-	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;
-    }
-    exp = w32_mktime (&udd.st);
-
-    ke.setKeyID (k->keyid);
-    if (k->is_protected)
-	ke.setPassphrase (pass);
-    else
-	ke.setNoPassphrase (true);
-    err = ke.setKeyExpireDate (pos, exp, false);
-    if (err)
-	msg_box (dlg, gpgme_strerror (err), _("Expire Subkey"), MB_ERR);
-    else {
-	_snprintf (buf, DIM (buf)-1, "%s", get_key_created (exp));
-	listview_add_sub_item (lv, pos, SUBK_COL_EXPIRES, buf);
-	k->update = 1;
-	msg_box (dlg, _("Subkey expire date successfully set."), 
-		 _("GnuPG Status"), MB_OK);
-    }
-    sfree_if_alloc (pass);
-    return TRUE;
-}
-
-
-/* Revoke the selected key in the list view @lv. @k contains 
-   control information about the global key.
-   Return value: TRUE on success. */
-static int
-do_editkey_revoke (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    gpgme_error_t err;
-    GpgKeyEdit ke;
-    char buf[256];
-    char *pass = NULL;
-    int j, cancel = 0;
-
-    if (!k->key_pair) {
-	msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
-        return FALSE;
-    }
-
-    if ((j = listview_get_curr_pos (lv)) == -1) {
-	msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
-	return FALSE;
-    }
-    else if (listview_count_items (lv, 0) == 1) {
-	msg_box( dlg, _("No subkeys were found, if you want to revoke the\n"
-	                "whole key, please use the Key Manager command directly.\n\n"
-			"This command is only available to revoke single subkeys"),
-		 _("Key Edit"), MB_INFO );
-	return FALSE;
-    }
-	    
-    listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, DIM (buf)-1);
-    if (!strcmp (buf, _("Revoked"))) {
-	msg_box (dlg, _("Key already revoked."), _("Key Edit"), MB_ERR);
-	return FALSE;
-    }
-    
-    if (k->is_protected) {
-	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;	    
-    }
-
-    ke.setKeyID (k->keyid);
-    if (k->is_protected)
-	ke.setPassphrase (pass);
-    else
-	ke.setNoPassphrase (true);
-    err = ke.revokeSubkey (j, 0, NULL);
-    if (err)
-	msg_box( dlg, gpgme_strerror (err), _("Revoke Subkey"), MB_ERR);
-    else {
-	listview_add_sub_item (lv, j, SUBK_COL_STATUS, _("Revoked"));
-	k->update = 1;
-	msg_box( dlg, _("Subkey successfully revoked."), _("GnuPG Status"), MB_OK );
-    }
-    sfree_if_alloc (pass);
-    return TRUE;
-}
-
-
-/* Revoked the selected userid in list view @lv.
-   Return value: TRUE on success. */
-int
-do_editkey_revuid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    gpgme_error_t err;
-    GpgKeyEdit ke;
-    char buf[128], email[128];
-    char inf[512];
-    char *pass = NULL;
-    int cancel = 0, id = 0, j;
-
-    if (!k->key_pair) {
-	msg_box (dlg, _("There is no secret key available!"), 
-		 _("Revoke user ID"), MB_ERR);
-	return FALSE;
-    }
-
-    if (listview_count_items (lv, 0) == 1) {
-	msg_box (dlg, _("Key has only one user ID."), _("Key Edit"), MB_ERR);	
-	return FALSE;
-    }
-
-    if( (j = listview_get_curr_pos( lv )) == -1 ) {
-	msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
-	return FALSE;	
-    }
-	    
-    listview_get_item_text( lv, j, UID_COL_VALID, buf, DIM (buf) - 1);
-    if (strstr (buf, _("Revoked"))) {
-	msg_box (dlg, _("This user ID has been already revoked."), 
-		 _("Key Edit"), MB_INFO);
-	return FALSE;
-    }
-	    
-    listview_get_item_text (lv, j, UID_COL_NAME, buf, sizeof buf -1);
-    _snprintf (inf, DIM (inf) -1, _("user ID \"%s\".\n\n"
-	       "Do you really want to revoke this user ID?"), buf);
-    if (msg_box (dlg, inf, _("Key Edit"), MB_WARN_ASK) == IDNO)
-	return FALSE;
-    if (k->is_protected) {
-	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;	    
-    }
-    listview_get_item_text (lv, j, UID_COL_EMAIL, email, DIM (email)-1);
-    listview_get_item_text (lv, j, UID_COL_NAME, buf, DIM (buf)-1);
-    id = do_find_userid (k->keyid, email, buf, NULL);
-    if (id == -1)
-	BUG (NULL);
-
-    ke.setKeyID (k->keyid);
-    if (k->is_protected)
-	ke.setPassphrase (pass);
-    else
-	ke.setNoPassphrase (true);
-    err = ke.revokeUserid (id);
-    if (err)
-	msg_box (dlg, gpgme_strerror (err), _("Revoke User ID"), MB_ERR);
-    else {
-	listview_add_sub_item (lv, j, 0, _("Revoked"));
-	k->update = 1;
-	status_box (dlg, _("User ID successfully revoked"), _("GnuPG Status"));
-    }
-    sfree_if_alloc (pass);
-    return err? FALSE : TRUE;
-}
-
-
-static int
-do_editkey_primary (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    gpgme_error_t err;
-    GpgKeyEdit ke;
-    int j, id, cancel=0;
-    char valid[32];
-    char buf[256], *pass = NULL;
-
-    if (listview_count_items (lv, 0) == 1)
-	return TRUE;
-    if ((j = listview_get_curr_pos (lv)) == -1) {
-	msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
-	return FALSE;
-    }
-    listview_get_item_text (lv, j, UID_COL_VALID, valid, DIM (valid)-1);
-    if (!strcmp (valid, _("Revoked")))
-	return FALSE;
-    listview_get_item_text (lv, j, UID_COL_EMAIL, buf, DIM (buf)-1);
-    id = do_find_userid (k->keyid, buf, NULL, NULL);
-    if (id == -1)
-	BUG (NULL);
-    if (k->is_protected) {
-	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;
-    }
-
-    ke.setKeyID (k->keyid);
-    if (k->is_protected)
-	ke.setPassphrase (pass);
-    else
-	ke.setNoPassphrase (true);
-    err = ke.setPrimaryUserid (id);
-    if (err)
-	msg_box (dlg, gpgme_strerror (err), _("Primary"), MB_ERR);
-    else {
-	k->update = 1;
-	status_box (dlg, _("User ID successfully flagged"), _("GnuPG Status"));
-    }
-
-    sfree_if_alloc (pass);
-    return err? FALSE : TRUE;
-}
-
-
-
-#define CIPHER	11
-#define HASH	11
-#define COMPR    4
-
-static int
-parse_preflist (HWND dlg, const char *list)
-{
-    char buf[128] = {0};
-    char *p, *pbuf = buf;
-    const char *ciphers[CIPHER] = {"", "IDEA", "3DES", 
-				   "CAST5", "BLOWFISH", "", "", 
-				   "AES", "AES192", "AES256", "TWOFISH"};
-    const char *hash[HASH] = {"", "MD5", "SHA1", "RMD160", "",
-			      "", "", "", "SHA256", "SHA384", "SHA512"};
-    const char *compress[COMPR] = {"", "ZIP", "ZLIB", "BZIP2"};
-    int n=0;
-
-    strncpy (buf, list, 127);
-    p = strtok (pbuf, " ");
-    while (p != NULL) {
-	int algid = atol (p+1);
-	n++;
-	switch (*p) {
-	case 'S':
-	    SendDlgItemMessage (dlg, IDC_SHOWPREF_CIPHERS, LB_ADDSTRING, 0, 
-				(LPARAM)(const char*)ciphers[algid % CIPHER]);
-	    break;
-
-	case 'H':
-	    SendDlgItemMessage (dlg, IDC_SHOWPREF_HASH, LB_ADDSTRING, 0, 
-				(LPARAM)(const char*)hash[algid % HASH]);
-	    break;
-
-	case 'Z':
-	    SendDlgItemMessage (dlg, IDC_SHOWPREF_ZIP, LB_ADDSTRING, 0, 
-				(LPARAM)(const char*)compress[algid % COMPR]);
-	    break;
-
-	default:
-	    n--;
-	}
-	p = strtok (NULL, " ");
-    }
-    return n;
-}
-
-
-/* Dialog box procedure to show the key preferences. */
-BOOL CALLBACK
-showpref_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    static keyedit_cb_t cb = NULL;
-    gpg_uid_info_t inf=NULL, u;
-    gpgme_key_t key;
-    char buf[128];
-    int pos;
-
-    switch (msg) {
-    case WM_INITDIALOG:
-	cb = (keyedit_cb_t)lparam;
-	if (!cb)
-	    BUG (NULL);
-	key = (gpgme_key_t)cb->opaque;
-	listview_get_item_text (cb->lv, cb->lv_pos, 
-				UID_COL_EMAIL, buf, DIM (buf)-1);
-	pos = do_find_userid (cb->keyid, buf, NULL, &inf);
-	if (pos < 0 || !inf) {
-	    gpg_uid_info_release (inf);
-	    EndDialog (dlg, FALSE);
-	    break;
-	}
-	for (u=inf; u; u = u->next) {
-	    if (u->index == pos && u->prefs && *u->prefs) {
-		_snprintf (buf, DIM (buf)-1, "%s", u->name);
-		SetDlgItemText (dlg, IDC_SHOWPREF_INFO, buf);
-		if (parse_preflist (dlg, u->prefs) <= 0)
-		    pos = -1;
-		if (u->flags.mdc)
-		    CheckDlgButton (dlg, IDC_SHOWPREF_MDC, BST_CHECKED);
-		break;
-	    }
-	}
-	gpg_uid_info_release (inf);
-	if (pos == -1) {
-	    msg_box (dlg, _("No preferences available."), _("Key Edit"), MB_ERR);
-	    EndDialog (dlg, FALSE);
-	    break;
-	}
-	SetDlgItemText (dlg, IDC_SHOWPREF_MDC, _("MDC feature"));
-	SetDlgItemText (dlg, IDC_SHOWPREF_PREFINF, _("Preferences"));
-	SetDlgItemText (dlg, IDC_SHOWPREF_UIDHINT, _("user ID:"));
-	SetWindowText (dlg, _("Key Preferences"));
-	SetForegroundWindow (dlg);
-	center_window (dlg, cb->parent);
-	break;
-
-    case WM_COMMAND:
-	switch (LOWORD (wparam)) {
-	case IDOK:
-	    EndDialog (dlg, TRUE);
-	    break;
-
-	case IDCANCEL:
-	    EndDialog (dlg, FALSE);
-	    break;
-	}
-	break;
-    }
-    return FALSE;
-}
-
-
-static int
-do_editkey_showpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    struct keyedit_cb_s cb;
-    char status[32];
-
-    if (k->is_v3)
-	return TRUE;
-
-    if (listview_get_curr_pos (lv) == -1) {
-	msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
-	return FALSE;
-    }
-    memset (&cb, 0, sizeof (cb));
-    cb.parent = dlg;
-    cb.opaque = k->ctx;
-    cb.keyid = k->keyid;
-    cb.lv = lv;
-    cb.lv_pos = listview_get_curr_pos (lv);
-
-    listview_get_item_text (lv, cb.lv_pos, UID_COL_VALID, 
-			    status, DIM (status)-1);
-    if (!strcmp (status, _("Revoked")))
-	return TRUE;
-    
-    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_SHOWPREF, dlg,
-		    showpref_dlg_proc, (LPARAM)&cb);
-    return TRUE;
-}
-
-
-static int
-do_editkey_deluid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
-{
-    gpgme_error_t err;
-    GpgKeyEdit ke;
-    char email[128], name[128];
-    char inf[384];
-    int pos, id = 0;
-
-    if (!k->key_pair)
-	return FALSE;
-
-    if (listview_count_items (lv, 0) == 1) {
-	msg_box (dlg, _("Primary user ID can not be deleted!"),
-		 _("Key Edit"), MB_ERR);
-        return FALSE;
-    }
-    pos = listview_get_curr_pos (lv);
-    if (pos == -1) {
-	msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
-        return FALSE;
-    }
-    
-    listview_get_item_text (lv, pos, UID_COL_NAME, name, DIM(name) -1);
-    _snprintf (inf, DIM (inf)-1, _("user ID \"%s\".\n\n"
-				   "All signatures on this user ID will be also deleted."
-				   "\n\n"
-			           "Do you really want to DELETE this user ID?"),
-			       name);
-    if (msg_box (dlg, inf, _("Key Edit"), MB_YESNO|MB_ICONWARNING) == IDNO)
-	return FALSE;
-    
-    listview_get_item_text (lv, pos, UID_COL_EMAIL, email, DIM (email)-1);
-    listview_get_item_text (lv, pos, UID_COL_NAME, name, DIM (name)-1);
-    id = do_find_userid (k->keyid, email, name, NULL);
-    if (id == -1)
-	BUG (NULL);
-
-    ke.setKeyID (k->keyid);
-    err = ke.delUserid (id);
-    if (err)
-	msg_box (dlg, gpgme_strerror (err), _("Delete User ID"), MB_ERR);
-    else {
-	listview_del_item (lv, pos);
-	k->update = 1;
-	status_box (dlg, _("User ID successfully deleted"), _("GnuPG Status"));
-    }
-    return err? FALSE : TRUE;
-}
-
-
-/* Subclass routine for the subkey listview control to allow shortcuts. */
-static BOOL CALLBACK
-subkey_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    int virt_key = 0;
-    winpt_key_t key;
-
-    switch (msg) {
-    case WM_KEYUP:
-	virt_key = (int)wparam;
-	key = (winpt_key_t)keyedit_subkey_proc.opaque;
-	if (!key || !key->key_pair)
-	    break;
-
-	switch (virt_key) {
-	case VK_DELETE:
-	    SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD, 
-				CB_SETCURSEL, CMD_DELKEY, 0);
-	    send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
-	    break;
-
-	case VK_INSERT:
-	    SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD, 
-				CB_SETCURSEL, CMD_ADDKEY, 0);
-	    send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
-	    break;
-	}
-    }
-    return CallWindowProc (keyedit_subkey_proc.old, dlg, msg, wparam, lparam);
-}
-
-
-static BOOL CALLBACK
-uid_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    int virt_key = 0;
-    winpt_key_t key;
-
-    switch (msg) {
-    case WM_KEYUP:
-	virt_key = (int)wparam;
-	key = (winpt_key_t)keyedit_uid_proc.opaque;
-	if (!key || !key->key_pair)
-	    break;
-
-	switch (virt_key) {
-	case VK_DELETE:
-	    SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
-				CB_SETCURSEL, CMD_DELUID, 0);
-	    send_cmd_id (keyedit_uid_proc.dlg, IDOK);
-	    break;
-
-	case VK_INSERT:
-	    SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
-				CB_SETCURSEL, CMD_ADDUID, 0);
-	    send_cmd_id (keyedit_uid_proc.dlg, IDOK);
-	    break;
-	}
-    }
-    return CallWindowProc (keyedit_uid_proc.old, dlg, msg, wparam, lparam);
-}
-
-
-/* Enable the key @k when @enable is 1, disable it otherwise. */
-static void
-do_editkey_enable_disable (winpt_key_t k, HWND dlg, 
-			   listview_ctrl_t lv, int enable)
-{
-    gpgme_error_t err;
-    gpgme_key_t key;
-    GpgKeyEdit ke;
-    
-    // FIXME: We had to duplicate the code here since the key manager
-    // code uses the listview to get the pointer to the key!
-    key = k->ctx;
-    ke.setKeyID (key->subkeys->keyid);
-    
-    err = enable? ke.enable () : ke.disable ();
-    if (!err) {	
-	show_msg (dlg, 1500, _("Key status changed."));
-	k->update = 1;
-    }
-    else
-	msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);    
-}
-
-
-static void
-do_editkey_minimize (winpt_key_t k, HWND dlg)
-{
-    gpgme_error_t err;
-    GpgKeyEdit ke;
-
-    ke.setKeyID (k->keyid);
-    err = ke.minimizeKey ();
-    if (err)
-	msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
-    else {
-	msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
-	k->update = 1;
-    }
-}
-
-
-static void
-do_editkey_clean (winpt_key_t k, HWND dlg)
-{
-    gpgme_error_t err;
-    GpgKeyEdit ke;
-    
-    ke.setKeyID (k->keyid);
-    err = ke.cleanKey ();
-    if (err)
-	msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);   
-    else {
-	msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
-	k->update = 1;
-    }
-}
-
-
-/* Start the dialog to list and display the status of all 
-   signatures for this key. */
-static void
-do_editkey_check (winpt_key_t k, HWND dlg)
-{
-    if (!k->ctx)
-	get_pubkey (k->keyid, &k->ctx);
-    if (!k->uid && k->ctx)
-	k->uid = k->ctx->uids->uid;
-    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYSIG_TREE, dlg,
-		    sigtree_dlg_proc, (LPARAM)k);
-}
-
-
-static int
-do_editkey_sign_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv, int mode)
-{
-    gpgme_error_t err;
-    winpt_key_s signer;
-    GpgKeyEdit ke;
-    char *pass = NULL;
-    char *defkey;
-    char email[64], name[128], valid[32];
-    int uid_index;
-    int cancel = 0;
-
-    uid_index = listview_get_curr_pos (lv);
-    if (uid_index == -1) {
-	msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
-	return FALSE;
-    }
-    listview_get_item_text (lv, uid_index, UID_COL_VALID, valid, DIM (valid)-1);
-    if (!strcmp (valid, _("Revoked")))
-	return TRUE;
-    if (mode == CMD_SIGN) {
-	cancel = msg_box (dlg, _("Do you really want to make this sig exportable?"),
-			  _("Key Edit"), MB_QUEST_ASK);
-	if (cancel == IDNO)
-	    return FALSE;
-    }
-    listview_get_item_text (lv, uid_index, UID_COL_EMAIL, email, DIM (email)-1);
-    listview_get_item_text (lv, uid_index, UID_COL_NAME, name, DIM (name)-1);
-    uid_index = do_find_userid (k->keyid, email, name, NULL);
-
-    defkey = get_gnupg_default_key ();
-    memset (&signer, 0, sizeof (signer));
-    if (winpt_get_seckey (defkey, &signer)) {
-	log_debug ("do_editkey_sign_userid: no default secret key.\r\n");
-	free_if_alloc (defkey);
-	return FALSE;
-    }
-    if (signer.is_protected) {
-	pass = request_key_passphrase (signer.ctx, _("Key Edit"), &cancel);
-	if (cancel)
-	    return FALSE;
-    }
-    ke.setKeyID (k->keyid);
-    if (signer.is_protected)
-	ke.setPassphrase (pass);
-    else
-	ke.setNoPassphrase (true);
-    ke.setLocalUser (signer.ctx);
-    err = ke.signUserid (uid_index, 
-			  mode == CMD_SIGN? GPG_EDITKEY_SIGN : GPG_EDITKEY_LSIGN,
-			  0, NULL);
-    if (!err) {
-	msg_box (dlg, _("Key successfully signed."), _("Key Edit"), MB_OK);
-	k->update = 1;
-    }
-    else
-	msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
-
-    sfree_if_alloc (pass);
-    return !err? TRUE : FALSE;
-}
-
-
-static int
-lookup_cmd (HWND dlg)
-{
-    char buf[64];
-    int i;
-
-    i = SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_GETCURSEL, 0, 0);
-    if (i == LB_ERR)
-	return LB_ERR;
-    GetDlgItemText (dlg, IDC_KEYEDIT_CMD, buf, DIM (buf)-1);
-    for (i=0; cmdlist[i].name != NULL; i++) {
-	if (!strcmp (buf, cmdlist[i].name))
-	    return cmdlist[i].id;
-    }
-    return LB_ERR;
-}
-
-
-
-gpgme_error_t key_get_revokers (winpt_key_t key, int reload, 
-				gpg_desig_rev_t *r_rev);
-
-/* Check if the key supports designated revokers and if
-    secret keys exist to generate such a revoke cert. */
-static bool
-check_desig_rev (winpt_key_t key)
-{
-    gpg_desig_rev_t rev, u;
-    struct winpt_key_s sk;
-
-    if (!key->ext->gloflags.has_desig_rev)
-	return false;
-    key_get_revokers (key, 0, &rev);
-    for (u = rev; u; u = u->next) {
-	memset (&sk, 0, sizeof (sk));
-	if (!winpt_get_seckey (u->fpr+32, &sk))
-	    return true;
-    }
-    return false;
-}
-
-
-/* Use the gpg --desig-revoker command to create a revocation
-   cert for a key that lists our key as a designated revoker. */
-static void 
-gen_desig_revoke_cert (winpt_key_t key, HWND dlg)
-{
-    const char *warn;
-    char *inf, *p;
-    int id;
-
-    inf = km_key_get_info (key, 0);
-    warn = _("Your keys is listed as a designated revoker for the key\n\n"
-	     "%s\n\n"
-	     "Are you sure you want to create a revocation certificate\n"
-	     "which allows you to revoke the key listed above?");
-    p = new char[strlen (inf)+1+strlen (warn)+1];
-    sprintf (p, warn, inf);
-    free_if_alloc (inf);
-
-    id = msg_box (dlg, p, _("Key Edit"), MB_YESNO|MB_ICONWARNING);
-    free_if_alloc (p);
-    if (id == IDNO)
-	return;
-
-    key->internal = 1;
-    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKE, dlg,
-		    key_revoke_dlg_proc, (LPARAM)key);
-}
-
-
-/* Create tooltip control for the listview header. */
-static HWND
-create_header_tooltip (HWND dlg)
-{
-    TOOLINFO ti;
-    HWND tt;
-
-    tt = CreateWindow (TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP|TTS_BALLOON ,
-			CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
-			CW_USEDEFAULT, 
-			NULL, (HMENU) NULL, glob_hinst, NULL);
-    if (!tt)
-	BUG (NULL);
-    memset (&ti, 0, sizeof (ti));
-    ti.cbSize = sizeof (TOOLINFO); 
-    ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;     
-    ti.hwnd = dlg;     
-    ti.uId = (UINT) ListView_GetHeader (GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
-    ti.hinst = 0;
-    ti.lpszText = (char*)_("Capabilties: C = Certify, S = Sign, E = Encrypt, A = Authenticate");
-    SendMessage(tt, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
-    return tt;
-}
-
-
-#define TTM_POPUP (WM_USER+34)
-
-/* Dialog box procedure for the edit key dialog. */
-BOOL CALLBACK
-keyedit_main_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    static winpt_key_t k;
-    static listview_ctrl_t lvsub = NULL;
-    static listview_ctrl_t lvuid = NULL;
-    static HWND tt = NULL;
-    int cmd;
-    HWND item;
-
-    switch (msg) {
-    case WM_INITDIALOG:
-	k = (winpt_key_t)lparam;
-	if (!k)
-	    BUG (NULL);
-	do_init_cmdlist (dlg, k->key_pair);
-	lvsub = subkey_list_init (dlg, k);
-	lvuid = userid_list_init (dlg, k);
-	item = GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST);
-	keyedit_subkey_proc.opaque = (void*)k;
-	keyedit_subkey_proc.dlg = dlg;
-	keyedit_subkey_proc.current = (WNDPROC)subkey_subclass_proc;
-	keyedit_subkey_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
-	if (keyedit_subkey_proc.old) {
-	    if (!SetWindowLong (item, GWL_WNDPROC, 
-				(LONG)keyedit_subkey_proc.current)) {
-		msg_box (dlg, "Could not set subkey window procedure.", 
-			 _("Key Edit"), MB_ERR);
-		BUG (NULL);
-	    }
-	}
-	tt = create_header_tooltip (dlg);
-	
-	item = GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST);
-	keyedit_uid_proc.opaque = (void*)k;
-	keyedit_uid_proc.dlg = dlg;
-	keyedit_uid_proc.current = (WNDPROC)uid_subclass_proc;
-	keyedit_uid_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
-	if (keyedit_uid_proc.old) {
-	    if (!SetWindowLong (item, GWL_WNDPROC, 
-			        (LONG)keyedit_uid_proc.current)) {
-		msg_box (dlg, "Could not set user ID window procedure.", 
-			 _("Key Edit"), MB_ERR);
-		BUG (NULL);
-	    }
-	}
-	if (k->ctx->revoked || k->ctx->expired) {
-	    EnableWindow (GetDlgItem (dlg, IDC_KEYEDIT_CMD), FALSE);
-	    EnableWindow (GetDlgItem (dlg, IDOK), FALSE);
-	}
-	SetDlgItemText (dlg, IDC_KEYEDIT_CMDINF, _("Command>"));
-	SetDlgItemText (dlg, IDCANCEL, _("&Close"));
-	SetDlgItemText (dlg, IDC_KEYEDIT_HELP, _("&Help"));
-	SetDlgItemText (dlg, IDC_KEYEDIT_REVOKE, _("&Revoke..."));
-	SetDlgItemText (dlg, IDOK, _("&OK"));
-	if (!check_desig_rev (k))
-	    ShowWindow (GetDlgItem (dlg, IDC_KEYEDIT_REVOKE), SW_HIDE);
-	if (k->is_v3)
-	    SetWindowText (dlg, _("Key Edit (PGP 2.6.x mode)"));
-	else
-	    SetWindowText (dlg, _("Key Edit"));
-	SetForegroundWindow (dlg);
-	center_window (dlg, NULL);
-	return TRUE;
-
-    case WM_DESTROY:
-	if (lvsub) {
-	    listview_release (lvsub);
-	    lvsub = NULL;
-	}
-	if (lvuid) {
-	    listview_release (lvuid);
-	    lvuid = NULL;
-	}
-	if (tt != NULL)
-	    DestroyWindow (tt);
-	
-	balloon_msg_disable ();
-	break;
-
-    case WM_NOTIFY:
-	NMHDR *notify;
-        notify = (NMHDR *)lparam;
-	if (!notify || notify->idFrom != IDC_KEYEDIT_UIDLIST)
-	    break;
-	if (notify->code == NM_DBLCLK)
-	    do_editkey_showpref (k, dlg, lvuid);
-	else if (notify->code == NM_RCLICK && k->key_pair) {
-	    if (listview_count_items (lvuid, 0) == 1)
-		break;
-	    HMENU hm = LoadMenu (glob_hinst, MAKEINTRESOURCE (IDR_WINPT_KEYEDIT));
-	    HMENU popup = GetSubMenu (hm, 0);
-	    POINT p;
-
-	    set_menu_text (popup, ID_KEYEDIT_UID_PRIM, _("Flag user ID as &primary"));
-	    set_menu_text (popup, ID_KEYEDIT_UID_DEL, _("&Delete user ID"));
-	    set_menu_text (popup, ID_KEYEDIT_UID_REV, _("&Revoke user ID"));
-	    GetCursorPos (&p);
-	    TrackPopupMenu (popup, TPM_RIGHTALIGN, p.x, p.y, 0, dlg, NULL);
-	    DestroyMenu (hm);
-	    DestroyMenu (popup);
-	}
-	break;
-
-    case WM_COMMAND:
-	switch (LOWORD (wparam)) {
-	case IDOK:
-	    cmd = lookup_cmd (dlg);
-	    if (cmd == LB_ERR) {
-		msg_box (dlg, _("Please select a command."), _("Key Edit"), MB_INFO);
-		return FALSE;
-	    }
-	    if (k->is_v3 && is_cmd_openpgp (cmd)) {
-		msg_box (dlg, _("This command cannot be used with PGP 2 (v3) keys.\n"),
-				_("Key Edit"), MB_ERR);
-		return FALSE;
-	    }
-	    switch (cmd) {
-	    case CMD_SHOWPREF: do_editkey_showpref (k, dlg, lvuid); break;
-	    case CMD_DELKEY: do_editkey_delkey (k, dlg, lvsub); break;
-	    case CMD_ADDKEY: keyedit_add_subkey (k, dlg, lvsub); break;
-	    case CMD_EXPIRE: do_editkey_expire (k, dlg, lvsub); break;
-	    case CMD_REVKEY: do_editkey_revoke (k, dlg, lvsub); break;
-	    case CMD_SETPREF:/*do_editkey_setpref (k, dlg, lvuid);*/ break;
-	    case CMD_ADDUID: keyedit_add_userid( k, dlg, lvuid ); break;
-	    case CMD_ADDREVOKER: keyedit_add_revoker( k, dlg ); break;
-	    case CMD_ADDPHOTO: keyedit_add_photo( k, dlg ); break;
-	    case CMD_REVUID: do_editkey_revuid( k, dlg, lvuid ); break;
-	    case CMD_DELUID: do_editkey_deluid( k, dlg, lvuid ); break;
-	    case CMD_PASSWD: keyedit_change_passwd (k, dlg); break;
-	    case CMD_PRIMARY: do_editkey_primary (k, dlg, lvuid); break;
-	    case CMD_ENABLE: do_editkey_enable_disable (k, dlg, lvsub, 1); break;
-	    case CMD_DISABLE: do_editkey_enable_disable (k, dlg, lvsub, 0); break;
-	    case CMD_CHECK: do_editkey_check (k, dlg); break;
-	    case CMD_TRUST: keyedit_change_ownertrust (k, dlg); break;
-	    case CMD_SIGN:
-	    case CMD_LSIGN: do_editkey_sign_userid (k, dlg, 
-						    lvuid, cmd);
-			    break;
-	    case CMD_CLEAN: do_editkey_clean (k, dlg); break;
-	    case CMD_MINIMIZE: do_editkey_minimize (k, dlg); break;
-	    }
-	    break;	    
-
-	case IDCANCEL:
-	    EndDialog (dlg, FALSE);
-	    break;
-
-	case IDC_KEYEDIT_HELP:
-	    do_show_help (dlg);
-	    break;
-
-	case IDC_KEYEDIT_REVOKE:
-	    gen_desig_revoke_cert (k, dlg);
-	    break;
-
-	case ID_KEYEDIT_UID_PRIM:
-	    do_editkey_primary (k, dlg, lvuid);
-	    break;
-
-	case ID_KEYEDIT_UID_DEL:
-	    do_editkey_deluid (k, dlg, lvuid);
-	    break;
-
-	case ID_KEYEDIT_UID_REV:
-	    do_editkey_revuid (k, dlg, lvuid);
-	    break;
-	}
-	break;
-    }
-    return FALSE;
-}

Added: trunk/Src/wptKeyEditDlgs.cpp
===================================================================
--- trunk/Src/wptKeyEditDlgs.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptKeyEditDlgs.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -0,0 +1,2247 @@
+/* wptKeyEditDlgs.cpp - GPG key edit dialogs
+ *	Copyright (C) 2002-2009 Timo Schulz
+ *
+ * This file is part of WinPT.
+ *
+ * WinPT is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * WinPT 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.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+#include <commctrl.h>
+#include <time.h>
+#include <assert.h>
+
+#include "resource.h"
+#include "wptTypes.h"
+#include "wptW32API.h"
+#include "wptVersion.h"
+#include "wptGPG.h"
+#include "wptCommonCtl.h"
+#include "wptContext.h"
+#include "wptDlgs.h"
+#include "wptNLS.h"
+#include "wptUTF8.h"
+#include "wptErrors.h"
+#include "wptKeylist.h"
+#include "wptKeyManager.h"
+#include "wptRegistry.h"
+#include "wptKeyEdit.h"
+#include "wptKeyserver.h"
+#include "StringBuffer.h"
+
+
+/* All edit key commands. */
+enum keyedit_commands {    
+    CMD_ADDKEY = 0,
+    CMD_ADDUID,
+    CMD_ADDPHOTO,
+    CMD_ADDREVOKER,
+    CMD_DELUID,
+    CMD_DELKEY,
+    CMD_EXPIRE,
+    CMD_SHOWPREF,
+    CMD_SETPREF,
+    CMD_PASSWD,
+    CMD_PRIMARY,
+    CMD_TRUST,
+    CMD_REVUID,
+    CMD_REVKEY,
+    CMD_DISABLE,
+    CMD_ENABLE,    
+    CMD_SIGN,
+    CMD_LSIGN,
+    CMD_CHECK,
+    CMD_CLEAN,
+    CMD_MINIMIZE
+};
+
+struct cmdlist_s {
+    const char   *name;
+    unsigned int  need_pair:1;
+    int	      id;
+} cmdlist[] = {
+    {"ADDKEY", 1, CMD_ADDKEY},
+    {"ADDUID", 1, CMD_ADDUID},
+    {"ADDPHOTO", 1, CMD_ADDPHOTO},
+    {"ADDREVOKER", 1, CMD_ADDREVOKER},
+    {"DELUID", 1, CMD_DELUID},
+    {"DELKEY", 1, CMD_DELKEY},
+    {"EXPIRE", 1, CMD_EXPIRE},
+    {"SHOWPREF", 0, CMD_SHOWPREF},
+    {"PASSWD", 1, CMD_PASSWD},
+    {"PRIMARY", 1, CMD_PRIMARY},
+    {"TRUST", 0, CMD_TRUST},
+    {"REVUID", 1, CMD_REVUID},
+    {"REVKEY", 1, CMD_REVKEY},
+    {"DISABLE", 0, CMD_DISABLE},
+    {"ENABLE", 0, CMD_ENABLE},
+    {"SIGN", 0, CMD_SIGN},
+    {"LSIGN", 0, CMD_LSIGN},
+    {"CHECK", 0, CMD_CHECK},
+    {"CLEAN", 0, CMD_CLEAN},
+    {"MINIMIZE", 0, CMD_MINIMIZE},
+    {NULL, 0}  
+};
+
+
+/* Symbolic ids for the subkey columns. */
+enum subk_col_t {
+    SUBK_COL_DESC	= 0,
+    SUBK_COL_KEYID	= 1,	
+    SUBK_COL_CREATION	= 2,	
+    SUBK_COL_EXPIRES	= 3,
+    SUBK_COL_STATUS	= 4,
+    SUBK_COL_C_FLAG	= 5,
+    SUBK_COL_S_FLAG	= 6,
+    SUBK_COL_E_FLAG	= 7,
+    SUBK_COL_A_FLAG	= 8
+};
+
+/* Symbolic ids for the userid columns. */
+enum uid_col_t {
+    UID_COL_VALID	= 0,
+    UID_COL_NAME	= 1,
+    UID_COL_EMAIL	= 2,
+    UID_COL_CREATION	= 3
+};
+
+/* Key edit callback context. */
+struct keyedit_cb_s {
+    HWND	    parent; /* parent window handle. */
+    const char	   *keyid;  /* key ID of the key. */
+    const char	   *pass;   /* pointer to the passphrase. */
+    listview_ctrl_t lv;
+    int		    lv_pos;
+    void	   *opaque;
+    unsigned int    finished:1;
+    unsigned int    is_protected:1;
+};
+typedef struct keyedit_cb_s *keyedit_cb_t;
+
+
+/* Key generation callback context. */
+struct keygen_cb_s {
+    int    bits;
+    int	   algo;
+    DWORD  expire; /* date of expiration or '0' for infinite valid. */
+    char  *fpr;
+    char  *name;
+    char  *comment;
+    char  *email;
+};
+typedef struct keygen_cb_s *keygen_cb_t;
+
+/* Subclass context for the subkey list. */
+static subclass_s keyedit_subkey_proc;
+
+/* Subclass context for the user-id list. */
+static subclass_s keyedit_uid_proc;
+
+int keygen_check_date (SYSTEMTIME *st);
+void get_userid_preflist (const char *old_prefs, char **r_prefs, int *r_flags);
+char* get_subkey_keyid (const char *keyid);
+void ComboBox_AddString_utf8 (HWND cb, const char *txt);
+
+void set_gpg_auto_passphrase_cb (passphrase_cb_s *cb, const char *title);
+gpgme_error_t passphrase_cb (void *hook, const char *uid_hint,
+	       const char *passphrase_info,
+	       int prev_was_bad, int fd);
+
+/* Associate each key with a combo box entry. 
+   Skip the key in @k. */
+static void
+do_init_keylist (HWND dlg, const char *keyid)
+{
+    gpg_keycache_t pub;
+    gpgme_key_t key;
+    const char *s, *kid;
+    int i, n;
+
+    pub = keycache_get_ctx (1);
+    gpg_keycache_rewind (pub);
+    while (!gpg_keycache_next_key (pub, 0, &key)) {
+	if (!key_is_useable (key) || key->invalid)
+	    continue;
+	s = key->uids->uid;
+	kid = key->subkeys->keyid;
+	if (!s || !strcmp (kid+8, keyid))
+	    continue;
+	ComboBox_AddString_utf8 (GetDlgItem (dlg, IDC_ADDREV_KEYLIST), s);
+    }
+    
+    gpg_keycache_rewind (pub);
+    /* In the second loop, we set a key pointer for each element. */
+    n = SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_GETCOUNT, 0, 0);
+    for (i = 0; i < n; i++) {
+	gpg_keycache_next_key (pub, 0, &key);
+	SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETITEMDATA, 
+			    (WPARAM)(int)i, (LPARAM)key);
+    }
+    SendDlgItemMessage (dlg, IDC_ADDREV_KEYLIST, CB_SETCURSEL, 0, 0);
+}
+
+
+/* Add a new user-id to the list view @lv. */
+static void
+do_add_new_userid (listview_ctrl_t lv, 
+		   const char *utf8_name, const char *email, 
+		   const char *utf8_comment)
+{
+    StringBuffer p;
+    char *native;
+    
+    if (utf8_comment != NULL)
+	p = p + utf8_name + " (" + utf8_comment + ")";
+    else
+	p = p + utf8_name;
+    native = utf8_to_native (p.getBuffer ());
+
+    listview_add_item (lv, "");
+    listview_add_sub_item (lv, 0, UID_COL_VALID, _("Ultimate" ));
+    listview_add_sub_item (lv, 0, UID_COL_NAME, native);
+    listview_add_sub_item (lv, 0, UID_COL_EMAIL, email && *email? email : "");
+    listview_add_sub_item (lv, 0, UID_COL_CREATION, 
+			   get_key_created (time (NULL)));
+    free_if_alloc (native);
+}
+
+
+static void
+do_add_new_subkey (listview_ctrl_t lv, keygen_cb_t keygen, unsigned int flags)
+{
+    char info[128], keyid[32];
+    const char *expdate, *s, *kid;
+    int n;
+    
+    expdate = keygen->expire? get_key_expire_date (keygen->expire) : _("Never");
+    _snprintf (info, DIM (info)-1, "%d-bit %s", keygen->bits,
+	       get_key_pubalgo ((gpgme_pubkey_algo_t)keygen->algo));
+    kid = get_keyid_from_fpr (keygen->fpr);
+    _snprintf (keyid, DIM (keyid)-1, "0x%s", kid);
+    s = get_key_created (time (NULL));
+    n = listview_count_items (lv, 0);
+    listview_add_item_pos (lv, n);
+    listview_add_sub_item (lv, n, SUBK_COL_DESC, info);
+    listview_add_sub_item (lv, n, SUBK_COL_KEYID, keyid);
+    listview_add_sub_item (lv, n, SUBK_COL_CREATION, s);
+    listview_add_sub_item (lv, n, SUBK_COL_EXPIRES, expdate);
+    if (flags & KM_FLAG_REVOKED)
+	s = _("Revoked");	
+    else if (flags & KM_FLAG_EXPIRED)
+	s = _("Expired");
+    else 
+	s = _("OK");
+    listview_add_sub_item (lv, n, SUBK_COL_STATUS, s);
+}
+
+
+/* Try to find the GPG edit key index which belongs to the user ID
+   given by the email address @email, @name is used as a fallback.
+   If @r_inf != NULL, the info context will be returned.
+   Return value: index of the user ID or -1 on error. */
+static int
+do_find_userid (const char *keyid, const char *email, 
+		const char *name, gpg_uid_info_t *r_inf)
+{
+    GpgKeyEdit ke;
+    gpgme_error_t err;
+    gpg_uid_info_t inf, ui;
+    int pos = -1;
+
+    ke.setKeyID (keyid);
+    err = ke.getUseridInfo (&inf);
+    if (err) {
+	log_box (_("user ID"), MB_ERR, 
+		 _("Could not get key information for: \"%s\":\n%s"), 
+		 name, gpgme_strerror (err));
+	return -1;
+    }
+
+    for (ui = inf; ui; ui = ui->next) {
+	if (name && email && ui->email && ui->name) {
+	    if (!strcmp (ui->email, email) && 
+		!strncmp (ui->name, name, strlen (name))) {
+		pos = ui->index;
+		break;
+	    }
+	    continue;
+	}
+	if (email && ui->email) {
+	    if (!strcmp (ui->email, email)) {
+		pos = ui->index;
+		break;
+	    }
+	    /* The email address is more unique, use the name just
+	       as the fallbck when no email address is available. */
+	    continue;
+	}
+	if (ui->name && name && !strcmp (ui->name, name)) {
+	    pos = ui->index;
+	    break;
+	}
+    }
+    if (r_inf)
+	*r_inf = inf;
+    else
+	gpg_uid_info_release (inf);
+    return pos;
+}
+
+
+/* Return true if @fname is a JPEG file. */
+bool
+is_jpg_file (const char *fname)
+{
+    FILE *fp;
+    BYTE buf[10];
+    int n;
+
+    fp = fopen (fname, "rb");
+    if (!fp)
+	return false;
+    n = fread (buf, 1, DIM (buf), fp);
+    fclose (fp);
+    if (n < (int)DIM (buf))
+	return false;
+    return buf[6] == 'J' && buf[7] == 'F' &&
+	   buf[8] == 'I' && buf[9] == 'F';
+}
+
+
+/* Dialog box procedure to add a photo. */
+BOOL CALLBACK
+keyedit_addphoto_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    static keyedit_cb_t cb;
+    gpgme_error_t err;
+    const char *s;    
+    char file[128];
+    int id;
+
+    switch (msg) {
+    case WM_INITDIALOG:
+	cb = (keyedit_cb_t)lparam;
+	if (!cb)
+	    BUG (NULL);
+	SetDlgItemText (dlg, IDC_ADDPHOTO_INF, _("Remember that the image is stored within your public key.  If you use a very large picture, your key will become very large as well! Keeping the image close to 240x288 is advised."));
+	SetDlgItemText (dlg, IDC_ADDPHOTO_FILEINF, _("Pick an image to use for your photo ID.\nThe image must be a JPEG file."));
+	SetDlgItemText (dlg, IDC_ADDPHOTO_PWDINF, _("Passphrase"));
+	SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
+	SetWindowText (dlg, _("Add Photo ID"));
+	SetForegroundWindow (dlg);
+	break;
+	
+    case WM_DESTROY:
+	balloon_msg_disable ();
+	break;
+	
+    case WM_COMMAND:
+	switch (LOWORD (wparam)) {
+	case IDC_ADDPHOTO_SELFILE:
+	    s = get_fileopen_dlg (dlg, _("Select Image File"), 
+				  "JPEG Files (*.jpg, *.jpeg)\0*.jpg;*.jpeg\0\0",
+				  NULL);
+	    if (s && !is_jpg_file (s)) {
+		log_box (_("Add Photo ID"), MB_ERR, 
+			 _("'%s' is not a valid JPEG file."), s);
+		return FALSE;
+	    }
+	    if (s && *s)
+		SetDlgItemText (dlg, IDC_ADDPHOTO_FILE, s);
+	    break;
+
+	case IDOK:
+	    if (!GetDlgItemText (dlg, IDC_ADDPHOTO_FILE, file, DIM (file)-1)){
+		show_balloon_msg (GetDlgItem (dlg, IDC_ADDPHOTO_FILE),
+				  _("Please enter a file name."), IDI_ERROR);
+		return FALSE;
+	    }
+	    if (get_file_size (file) == 0 || get_file_size (file) > 6144) {
+		id = msg_box (dlg, _("The JPEG is really large.\n"
+				     "Are you sure you want to use it?"), 
+				     _("Add Photo ID"), MB_YESNO|MB_INFO);
+		if (id == IDNO)
+		    return TRUE;
+	    }
+	    
+	    {
+		GpgKeyEdit ke;
+		passphrase_cb_s pcb;
+
+		set_gpg_auto_passphrase_cb (&pcb, _("Add Revoker"));
+
+		ke.setPassphraseCallback (passphrase_cb, (void*)&pcb);		
+		ke.setKeyID (cb->keyid);		
+		err = ke.addPhotoid (file);
+
+		release_gpg_passphrase_cb (&pcb);
+	    }
+	    if (err) {
+		msg_box (dlg, gpgme_strerror (err), _("Add Photo ID"), MB_ERR);
+		return FALSE;
+	    }
+	    else {
+		cb->finished = 1;
+		msg_box (dlg, _("Photo successfully added."), 
+			 _("GnuPG Status"), MB_OK);
+	    }
+	    EndDialog (dlg, TRUE);
+	    break;
+
+	case IDCANCEL:
+	    EndDialog (dlg, FALSE);
+	    break;
+	}
+	break;
+    }
+    return FALSE;
+}
+
+
+/* Dialog box procedure to add a designated revoker. */
+BOOL CALLBACK
+keyedit_addrevoker_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    static keyedit_cb_t cb;
+    gpgme_error_t err;
+    char *uid=NULL;
+
+    switch (msg) {
+    case WM_INITDIALOG:
+	cb = (keyedit_cb_t)lparam;
+	if (!cb)
+	    BUG (NULL);
+	do_init_keylist (dlg, cb->keyid);
+	SetDlgItemText (dlg, IDC_ADDREV_INF, 
+			_("Appointing a key as designated revoker cannot be undone."));
+	SetDlgItemText (dlg, IDC_ADDREV_KEYINF, _("Public key:"));
+	SetDlgItemText (dlg, IDC_ADDREV_PWDINF, _("Passphrase"));
+	SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
+	SetWindowText (dlg, _("Add Revoker"));
+	SetForegroundWindow (dlg);
+	center_window (dlg, cb->parent);
+	break;
+
+    case WM_DESTROY:
+	balloon_msg_disable ();
+	break;
+	
+    case WM_COMMAND:
+	switch (LOWORD (wparam)) {
+	case IDOK:
+	    if (!GetDlgItemText_utf8 (dlg, IDC_ADDREV_KEYLIST, &uid)) {
+		show_balloon_msg (GetDlgItem (dlg, IDC_ADDREV_KEYLIST),
+				  _("Please select a user ID."), IDI_ERROR);
+		return FALSE;
+	    }
+	
+	    {
+		GpgKeyEdit ke;
+		passphrase_cb_s pcb;
+
+		set_gpg_auto_passphrase_cb (&pcb, _("Add Revoker"));
+
+		ke.setPassphraseCallback (passphrase_cb, (void*)&pcb);
+		ke.setKeyID (cb->keyid);		
+		err = ke.addDesignatedRevoker (uid);
+
+		release_gpg_passphrase_cb (&pcb);
+	    }
+
+	    safe_free (uid);
+	    if (err) {
+		msg_box (dlg, gpgme_strerror (err), _("Add Revoker"), MB_ERR);
+		return TRUE;
+	    }
+	    else {
+		cb->finished = 1;
+		msg_box (dlg, _("Revoker successfully addded."), 
+			 _("GnuPG Status"), MB_OK);
+	    }
+	    EndDialog (dlg, TRUE);
+	    break;
+
+	case IDCANCEL:
+	    EndDialog (dlg, FALSE);
+	    break;
+	}
+	break;
+    }
+    return FALSE;
+}
+
+
+/* Dialog box procedure to add a new user-ID. */
+BOOL CALLBACK
+keyedit_adduid_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    static keyedit_cb_t ctx;
+    keygen_cb_t keygen;
+    gpgme_error_t err;
+    char *utf8_name = NULL;
+    char *utf8_comment = NULL;
+    char email[128];
+    int rc;
+    
+    switch (msg) {
+    case WM_INITDIALOG:
+        ctx = (keyedit_cb_t)lparam;
+        if (!ctx)
+            dlg_fatal_error(dlg, "Could not get dialog param!");
+        SetWindowText (dlg, _("Add user ID"));
+        SetDlgItemText (dlg, IDC_ADDUID_INFNAME, _("&Name:"));
+        SetDlgItemText (dlg, IDC_ADDUID_INFEMAIL, _("&Email:"));
+        SetDlgItemText (dlg, IDC_ADDUID_INFCOMMENT, _("&Comment:"));
+	SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
+        SetForegroundWindow (dlg);
+	center_window (dlg, ctx->parent);
+        return FALSE;
+        
+    case WM_DESTROY:
+	balloon_msg_disable ();
+	break;
+	
+    case WM_COMMAND:
+        switch ( LOWORD( wparam ) )  {
+        case IDOK:
+	    keygen = (keygen_cb_t)ctx->opaque;
+            rc = GetDlgItemText_utf8 (dlg, IDC_ADDUID_NAME, &utf8_name);
+            if (!rc || rc < 5) {
+		show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_NAME),
+				  _("Please enter a name (min. 5 chars.)"),
+				  IDI_ERROR);
+		free_if_alloc (utf8_name);
+                return FALSE;
+            }
+	    if (strchr (utf8_name, '@')) {
+		show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_NAME),
+				  _("Please enter the email address in the email field and not in the name field"),
+				  IDI_WARNING);
+		free_if_alloc (utf8_name);
+		return FALSE;
+	    }
+
+            if( !GetDlgItemText (dlg, IDC_ADDUID_EMAIL, email, DIM (email) -1)) {
+		show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_EMAIL),
+				  _("Please enter an email address."),IDI_ERROR);				  
+		free_if_alloc (utf8_name);
+                return FALSE;
+            }
+	    if (check_email_address (email)) {
+		show_balloon_msg (GetDlgItem (dlg, IDC_ADDUID_EMAIL),
+				  _("Invalid email address."), IDI_ERROR);
+		free_if_alloc (utf8_name);
+		return FALSE;
+	    }
+            
+            rc = GetDlgItemText_utf8 (dlg, IDC_ADDUID_COMMENT, &utf8_comment);
+	    {
+		GpgKeyEdit ke;
+		passphrase_cb_s pcb;
+
+		set_gpg_auto_passphrase_cb (&pcb, _("Add Revoker"));
+
+		ke.setPassphraseCallback (passphrase_cb, (void*)&pcb);
+		ke.setKeyID (ctx->keyid);
+		err = ke.addUserid (utf8_name, utf8_comment, email);
+
+		release_gpg_passphrase_cb (&pcb);
+	    }
+	    if (err)
+		msg_box (dlg, gpgme_strerror (err), _("UserID"), MB_ERR);
+	    else {
+		msg_box (dlg, _("user ID successfully added."), _("GnuPG Status"), MB_OK);
+		ctx->finished = 1;
+		/* The caller releases this items later. */
+		keygen->name = utf8_name;
+		keygen->comment = utf8_comment;
+		keygen->email = m_strdup (email);
+	    }
+            EndDialog (dlg, TRUE);
+            return TRUE;
+            
+        case IDCANCEL:
+            EndDialog (dlg, FALSE);
+            return FALSE;
+        }
+        break;
+    }
+    
+    return FALSE;
+}
+
+
+/* Initalize a combo box with default key sizes. */
+static void
+init_keysize_box (HWND dlg, int ctlid)
+{
+    /* Array with standard key-length in bits. */
+    const char *sizelist[] = {
+	"2048", "3072", "4096", NULL
+    };
+
+    for (int i=0; sizelist[i] != NULL; i++)
+	SendDlgItemMessage (dlg, ctlid, CB_ADDSTRING, 0, 
+			    (LPARAM)(char*)sizelist[i]);
+    SendDlgItemMessage (dlg, ctlid, CB_SETCURSEL, (WPARAM)0, 0);
+}
+
+
+static int
+get_keysize_from_box (HWND dlg, int ctlid)
+{
+    int pos;
+    char buf[32];
+
+    pos = SendDlgItemMessage (dlg, ctlid, CB_GETCURSEL, 0, 0);
+    if (pos == CB_ERR)
+	return -1;
+    SendDlgItemMessage (dlg, ctlid, CB_GETLBTEXT, pos, (LPARAM)(char*)buf);
+    return atoi (buf);
+}
+
+
+/* Create a time_t from a system time @st. */
+time_t
+w32_mktime (SYSTEMTIME *st)
+{
+    struct tm tm;
+
+    memset (&tm, 0, sizeof (tm));
+    tm.tm_year = st->wYear-1900;
+    tm.tm_mday = st->wDay;
+    tm.tm_mon = st->wMonth-1;
+    return mktime (&tm);
+}
+
+
+/* Dialog procedure for adding a new secondary key. */
+BOOL CALLBACK
+keyedit_addsubkey_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    static keyedit_cb_t ctx;
+    keygen_cb_t keygen;
+    gpgme_error_t err;
+    SYSTEMTIME st;
+    HWND hwnd;
+    int index, size, valid;
+    
+    switch (msg) {
+    case WM_INITDIALOG:
+        ctx = (keyedit_cb_t)lparam;
+	if (!ctx)
+	    BUG (NULL);
+        SetWindowText (dlg, _("Add Subkey"));
+        SetDlgItemText (dlg, IDC_ADDSUBKEY_INFALGO, _("Key type:"));
+        SetDlgItemText (dlg, IDC_ADDSUBKEY_INFSIZE, _("Size in bits:"));
+        SetDlgItemText (dlg, IDC_ADDSUBKEY_INFVALID, _("Key expiration:"));
+	SetDlgItemText (dlg, IDC_ADDSUBKEY_EXPIRE, _("&Never"));
+	SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
+
+        hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
+        listbox_add_string (hwnd, _("DSA (sign only)"));
+        listbox_add_string (hwnd, _("ElGamal (encrypt only)"));
+        listbox_add_string (hwnd, _("RSA (sign only)"));
+        listbox_add_string (hwnd, _("RSA (encrypt only)"));
+	CheckDlgButton (dlg, IDC_ADDSUBKEY_EXPIRE, BST_CHECKED);
+	EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
+        EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_SIZE), FALSE);
+	init_keysize_box (dlg, IDC_ADDSUBKEY_SIZE);
+        SetForegroundWindow (dlg);
+	center_window (dlg, ctx->parent);
+        return FALSE;
+        
+    case WM_DESTROY:
+	balloon_msg_disable ();
+	break;
+	
+    case WM_COMMAND:
+	if (HIWORD (wparam) == BN_CLICKED && 
+	    LOWORD (wparam) == IDC_ADDSUBKEY_EXPIRE) {
+	    if (IsDlgButtonChecked (dlg, IDC_ADDSUBKEY_EXPIRE))
+		EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), FALSE);
+	    else
+		EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE), TRUE);
+	}
+	if (HIWORD (wparam) == LBN_SELCHANGE && 
+	    LOWORD (wparam) == IDC_ADDSUBKEY_ALGO) {
+	    /* If DSA is selected, we disable the selection box since it
+	       is hardocded to 2048-bit. */
+	    index = SendMessage ((HWND)lparam, LB_GETCURSEL, 0, 0);
+	    EnableWindow (GetDlgItem (dlg, IDC_ADDSUBKEY_SIZE), 
+			  index != 0? TRUE : FALSE);
+	}
+
+        switch (LOWORD (wparam)) {
+        case IDOK:
+	    keygen = (keygen_cb_t)ctx->opaque;
+	    if (!keygen)
+		BUG (NULL);
+            hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO);
+	    int map[4];
+	    /* this is for GPG 1.4.9 */
+	    map[0] = 2;
+	    map[1] = 4;
+	    map[2] = 5;
+	    map[3] = 6;
+	    /* >1.4.10 changed the menu IDs. */
+	    if (gpgver[0] == 1 && gpgver[1] >= 4 && gpgver[2] > 9) {
+		map[0] = 3;
+		map[1] = 5;
+		map[2] = 4;
+		map[3] = 6;
+	    }
+		
+	    /* Map combo box numbers to GPG answers. */
+	    switch (listbox_get_cursel (hwnd)) {
+	    case 0: 
+	    case 1:
+	    case 2:
+	    case 3:
+		break;
+	    default:
+		show_balloon_msg (GetDlgItem (dlg, IDC_ADDSUBKEY_ALGO),
+				  _("Please select one entry."), IDI_ERROR);
+                return FALSE;
+            }
+	    index = map[listbox_get_cursel (hwnd)];
+	    size = get_keysize_from_box (dlg, IDC_ADDSUBKEY_SIZE);
+            if (index == 2) /* DSA */
+                size = 2048;
+
+	    hwnd = GetDlgItem (dlg, IDC_ADDSUBKEY_EXPDATE);
+	    DateTime_GetSystemtime (hwnd, &st);
+	    valid = w32_mktime (&st) - time (NULL);
+	    valid /= 86400;
+
+	    keygen->bits = size;
+	    switch (index) {
+	    case 2: keygen->algo = GPGME_PK_DSA; break;
+	    case 4: keygen->algo = GPGME_PK_ELG_E; break;
+	    case 5: keygen->algo = GPGME_PK_RSA_S; break;
+	    case 6: keygen->algo = GPGME_PK_RSA_E; break;
+	    }
+	    if (valid > 0)
+		keygen->expire = time (NULL) + valid*24*60*60;
+
+	    {
+		GpgKeyEdit ke;
+		passphrase_cb_s pcb;
+
+		set_gpg_auto_passphrase_cb (&pcb, _("Add Revoker"));
+
+		ke.setPassphraseCallback (passphrase_cb, (void*)&pcb);
+		ke.setKeyID (ctx->keyid);
+		ke.setCallback (keygen_cb, NULL);
+		keygen_cb_dlg_create ();
+		err = ke.addSubkey ((gpgme_pubkey_algo_t)index, size, valid);
+
+		release_gpg_passphrase_cb (&pcb);
+	    }
+	    keygen->fpr = get_subkey_keyid (ctx->keyid);
+	    keygen_cb_dlg_destroy (1);
+	    if (err)
+		msg_box (dlg, gpgme_strerror (err), _("Add Subkey"), MB_ERR);
+	    else {
+		msg_box (dlg, _("Subkey successfully added."), 
+			 _("GnuPG Status"), MB_OK);
+		ctx->finished = 1;
+	    }
+	    EndDialog (dlg, TRUE);
+            return TRUE;
+            
+        case IDCANCEL:
+            EndDialog (dlg, FALSE);
+            return FALSE;
+        }
+        break;
+    }
+    
+    return FALSE;
+}
+
+
+BOOL
+keyedit_add_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    keyedit_cb_s cb;
+    keygen_cb_s keygen;
+
+    if (!k->key_pair) {
+	msg_box (dlg, _("There is no secret key available!"), 
+		 _("Add user ID"), MB_ERR);
+        return FALSE;
+    }    
+
+    memset (&keygen, 0, sizeof (keygen));
+    memset (&cb, 0, sizeof (cb));
+    cb.parent = dlg;
+    cb.opaque = &keygen;
+    cb.keyid = k->keyid;
+    dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDUID,
+		      dlg, keyedit_adduid_dlg_proc,         
+		      (LPARAM)&cb, _("Add user ID"),
+		      IDS_WINPT_KEYEDIT_ADDUID);
+    if (lv != NULL && cb.finished)
+	do_add_new_userid (lv, keygen.name, keygen.email, keygen.comment);
+    if (cb.finished)
+	k->update = 1;
+
+    free_if_alloc (keygen.name);
+    free_if_alloc (keygen.email);
+    free_if_alloc (keygen.comment);
+    return TRUE;
+}
+
+
+/* Return the keyID of the last subkey. */
+char*
+get_subkey_keyid (const char *keyid)
+{
+    gpgme_error_t err;
+    gpgme_key_t key;
+    gpgme_ctx_t ctx;
+    gpgme_subkey_t subk;
+    char *kid = NULL;
+
+    err = gpgme_new (&ctx);
+    if (err)
+	return NULL;
+    err = gpgme_get_key (ctx, keyid, &key, 0);
+    gpgme_release (ctx);
+    if (err)
+	return NULL;
+    subk = get_nth_key (key, count_subkeys (key));
+    if (subk != NULL)
+	kid = strdup (subk->keyid);
+    gpgme_key_release (key);
+    return kid;
+}
+
+
+BOOL
+keyedit_add_subkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    keyedit_cb_s cb;
+    keygen_cb_s keygen;
+
+    if (!k->key_pair) {
+	msg_box (dlg, _("There is no secret key available!"), 
+		 _("Add Subkey"), MB_ERR);
+        return FALSE;
+    }
+
+    memset (&keygen, 0, sizeof (keygen));
+    memset (&cb, 0, sizeof (cb));
+    cb.keyid = k->keyid;
+    cb.opaque = &keygen;
+    dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_ADDSUBKEY,    
+		      dlg, keyedit_addsubkey_dlg_proc,
+		      (LPARAM)&cb, _("Add Subkey"),
+		      IDS_WINPT_KEYEDIT_ADDSUBKEY);
+    if (lv != NULL && cb.finished)
+	do_add_new_subkey (lv, &keygen, 0);
+    if (cb.finished)
+	k->update = 1;
+
+    safe_free (keygen.fpr);
+    return cb.finished? TRUE: FALSE;
+}
+
+
+/* Set the preferred keyserver of the given key @k. */
+BOOL
+keyedit_set_pref_keyserver (winpt_key_t k, HWND dlg)
+{
+    GpgKeyEdit ke;
+    gpgme_error_t err;
+    struct URL_ctx_s *url;
+    char *pass = NULL;
+
+    url = (struct URL_ctx_s *)get_keyserver_URL_dlg (dlg);
+    if (url == NULL || url->cancel == 1) {
+	delete url;
+	return FALSE;
+    }
+
+    pass = request_key_passphrase (k->ctx, _("Key Edit"), &url->cancel);
+    if (url->cancel) {
+	delete url;
+	return FALSE;
+    }
+
+    ke.setKeyID (k->keyid);
+    if (k->is_protected)
+	ke.setPassphrase (pass);
+    else
+	ke.setNoPassphrase (true);
+    err = ke.setPreferredKeyserver (-1, url->url);
+    if (!err)
+	msg_box (dlg, _("Preferred keyserver successfully set."), 
+		 _("Key Edit"), MB_OK);
+    else
+	msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
+
+    keyserver_set_default (url->url, 0);
+    sfree_if_alloc (pass);
+    delete url;
+    return err == 0? 0 : WPTERR_GENERAL;
+}
+
+
+/* Add a photo-ID to the key specified in @k. @dlg is the handle of
+   the calling dialog. */
+BOOL
+keyedit_add_photo (winpt_key_t k, HWND dlg)
+{
+    keyedit_cb_s cb;
+    
+    if (!k->key_pair) {
+	msg_box (dlg, _("There is no secret key available!"), 
+		 _("Add Photo ID"), MB_ERR);
+        return FALSE;
+    }
+
+    memset (&cb, 0, sizeof (cb));
+    cb.parent = dlg;
+    cb.keyid = k->keyid;
+    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDPHOTO, dlg,
+		    keyedit_addphoto_dlg_proc, (LPARAM)&cb);
+
+    if (cb.finished)
+	k->update = 1;
+    return TRUE;
+}
+
+
+BOOL
+keyedit_add_revoker (winpt_key_t k, HWND dlg)
+{
+    keyedit_cb_s cb;
+
+    if (!k->key_pair) {
+	msg_box (dlg, _("There is no secret key available!"), _("Add Revoker"), MB_ERR);
+        return FALSE;
+    }
+
+    memset (&cb, 0, sizeof (cb));
+    cb.parent = dlg;
+    cb.keyid = k->keyid;
+    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_ADDREV, dlg,
+		    keyedit_addrevoker_dlg_proc, (LPARAM)&cb);
+    if (cb.finished)
+	k->update = 1;
+    return TRUE;
+}
+
+
+/* Change ownertrust of the given key @key.
+   Return TRUE if the ownertrust was changed. */
+BOOL
+keyedit_change_ownertrust (winpt_key_t key, HWND dlg)
+{
+    int rc;
+
+    rc = dialog_box_param (glob_hinst, 
+			     (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,
+			     dlg, keyedit_ownertrust_dlg_proc,
+			     (LPARAM)key, _("Change Ownertrust"),
+			     IDS_WINPT_KEYEDIT_OWNERTRUST);
+    if (rc == TRUE) {
+	msg_box (dlg, _("Key status changed."), _("Key Edit"), MB_OK);
+	key->update = 1;
+    }
+    return rc;
+}
+
+
+/* Check if the given key is supposed to have IDEA
+   for secret key protection. */
+static int
+is_idea_protect_algo (const char *keyid)
+{
+    winpt_key_s k;
+    const unsigned char *sym_prefs;
+    size_t n;
+
+    memset (&k, 0, sizeof (k));
+    if (winpt_get_pubkey (keyid, &k))
+	BUG (NULL);
+    if (!k.is_v3)
+	return 0;
+    sym_prefs = k.ext->sym_prefs;
+    /* Assume that only v3 keys have no symmetric cipher 
+       preferences and thus IDEA is explicit. */
+    if (!sym_prefs)
+	return 1; 
+    for (n = 0; sym_prefs[n]; n++)
+	;
+    if ((n == 0 || n == 1) && *sym_prefs == 0x01)
+	return 1;
+    return 0;
+}
+
+
+BOOL
+keyedit_change_passwd (winpt_key_t k, HWND dlg)
+{
+    gpgme_error_t err;
+    GpgKeyEdit ke;
+    char *old_pass = NULL;
+    char *new_pass = NULL;
+    int cancel = 0;
+
+    if (!k->key_pair) {
+	msg_box (dlg, _("There is no secret key available!"), 
+		 _("Key Edit"), MB_ERR);
+        return FALSE;
+    }
+
+    if (!idea_available && is_idea_protect_algo (k->keyid)) {
+	msg_box (dlg, _("Cannot change passphrase because the key\n"
+	                "is protected with the IDEA encryption algorithm."),
+			_("Key Edit"), MB_ERR);
+	return FALSE;
+    }
+
+    if (k->is_protected) {
+	old_pass = request_passphrase (_("Current (old) Passphrase"), 
+				       PASSDLG_INIT, &cancel);
+	if (cancel)
+	    return FALSE;
+    }
+    new_pass = request_passphrase2 (_("New Passphrase" ), 
+				    PASSDLG_INIT|PASSDLG_WARN_UTF8, &cancel);
+    if (cancel) {
+	sfree_if_alloc (old_pass);
+        return FALSE;
+    }
+
+    if (strlen (new_pass) == 0) {
+	cancel = msg_box (dlg, _("Are you sure that you really don't want a passphrase?\n"
+				 "This is propably a bad idea, continue?"),
+			    _("Key Edit"), MB_WARN_ASK);
+	if (cancel != IDYES) {
+	    sfree_if_alloc (old_pass);
+	    sfree_if_alloc (new_pass);
+	    return FALSE;
+	}
+    }
+
+    ke.setKeyID (k->keyid);
+    ke.setPassphrase (k->is_protected? old_pass : NULL);
+    if (!k->is_protected)
+	ke.setNoPassphrase (true);
+    err = ke.changePassphrase (new_pass, 1);
+    if (err)
+	msg_box (dlg, gpgme_strerror (err), _("Change Password"), MB_ERR);
+    else
+	msg_box (dlg, _("Passphrase successfully changed."),  _("GnuPG Status"), MB_OK);
+    sfree_if_alloc (old_pass);
+    sfree_if_alloc (new_pass);
+
+    return TRUE;
+}
+
+		
+/* Initialize sub key list from key @k and return
+   the new listview control. */
+listview_ctrl_t
+subkey_list_init (HWND dlg, winpt_key_t k)
+{
+    LV_ITEM lvi;
+    gpgme_subkey_t sub;
+    struct listview_column_s cols[] = {
+	{0, 80, (char *)_("Description")},
+	{1, 78, (char *)_("Key ID")},
+        {2, 66, (char *)_("Creation")},
+        {3, 66, (char *)_("Expires")},
+        {4, 64, (char *)_("Status")},
+	{5, 16, (char *) "C"/*ertify*/},
+	{6, 16, (char *) "S"/*ign*/},
+	{7, 16, (char *) "E"/*ncrypt*/},
+	{8, 16, (char *) "A"/*uth*/},
+        {0, 0, 0}
+    };
+    listview_ctrl_t lv;
+    char buf[256], tmp[128];
+    const char *t;
+    int nkeys = 0, i;
+
+    nkeys = count_subkeys (k->ctx);
+    if (!nkeys)
+	BUG (NULL); /* should never happen. */
+        
+    listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
+    for (i = 0; cols[i].fieldname != NULL; i++)
+	listview_add_column (lv, &cols[i]);
+        
+    for (i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next) {
+        listview_add_item (lv, "");
+	listview_add_sub_item (lv, 0, 1, "");
+	memset (&lvi, 0, sizeof (lvi));
+	lvi.mask = LVIF_PARAM;	
+	lvi.lParam = (LPARAM)sub;
+	if (ListView_SetItem (lv->ctrl, &lvi) == FALSE)
+	    BUG (NULL);
+    }
+        
+    listview_set_ext_style (lv);
+    for (i = 0, sub = k->ctx->subkeys; i < nkeys; i++, sub = sub->next) {
+	_snprintf (buf, DIM (buf)-1, "%d-bit %s", sub->length,
+				get_key_pubalgo (sub->pubkey_algo));
+	listview_add_sub_item (lv, i, SUBK_COL_DESC, buf);
+	t = sub->keyid;
+	assert (t != NULL);
+	_snprintf (tmp, DIM (tmp)-1, "0x%s", t+8);
+	listview_add_sub_item (lv, i, SUBK_COL_KEYID, tmp);
+
+	t = get_key_created (sub->timestamp);
+	if (!t)
+	    t = "????" "-??" "-??";
+	listview_add_sub_item (lv, i, SUBK_COL_CREATION, t);
+
+	if (sub->expires) {
+	    t = get_key_created (sub->expires);
+	    listview_add_sub_item (lv, i, SUBK_COL_EXPIRES, t);
+	}
+	else
+	    listview_add_sub_item (lv, i, SUBK_COL_EXPIRES, _("Never"));
+	if (sub->expired)
+	    t = _("Expired");
+	else if (sub->revoked)
+	    t = _("Revoked");
+	else
+	    t = _("OK");
+	listview_add_sub_item (lv, i, SUBK_COL_STATUS, t);
+
+	if (sub->can_certify) t = "*"; else t = "";
+	listview_add_sub_item (lv, i, SUBK_COL_C_FLAG, t);
+	if (sub->can_sign) t = "*"; else t = "";
+	listview_add_sub_item (lv, i, SUBK_COL_S_FLAG, t);
+	if (sub->can_encrypt) t = "*"; else t = "";
+	listview_add_sub_item (lv, i, SUBK_COL_E_FLAG, t);
+	if (sub->can_authenticate) t = "*"; else t = "";
+	listview_add_sub_item (lv, i, SUBK_COL_A_FLAG, t);
+    }
+    return lv;
+}
+
+
+static listview_ctrl_t
+userid_list_init (HWND dlg, winpt_key_t k)
+{
+    listview_ctrl_t lv = NULL;
+    gpgme_key_sig_t ks;
+    struct native_uid_s *u;
+    int nuids = 0, j, u_attr;
+    struct listview_column_s cols[] = {
+        {0,  72, (char *)_("Validity")},
+        {1, 150, (char *)_("Name")},
+	{2, 110, (char *)_("Email")},
+	{3,  76, (char *)_("Creation")},
+        {0, 0, 0}
+    };    
+    const char *attr;
+    
+    nuids = count_userids (k->ctx);
+    if (!nuids)
+	BUG (NULL); /* should never happen. */
+        
+    listview_new (&lv, GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST));
+    for (j = 0; cols[j].fieldname != NULL; j++)
+        listview_add_column (lv, &cols[j]);
+        
+    for (j = 0; j < nuids; j++) {
+	listview_add_item (lv, " ");
+	listview_add_sub_item (lv, 0, 1, " " );        
+    }
+
+    listview_set_ext_style (lv);
+    for (j = 0, u=k->ext->uids; j < nuids; u=u->next, j++) {
+	if (u->revoked)
+	    attr = _("Revoked");
+	else {
+	    u_attr = (int)u->validity;
+	    attr = get_key_trust2 (NULL, u_attr, 0, 0);
+	}
+	listview_add_sub_item (lv, j, UID_COL_VALID, (char *)attr);
+	/* XXX: add comment if available */
+	listview_add_sub_item (lv, j, UID_COL_NAME, 
+			       u->name? u->name : _("Invalid user ID"));
+	if (u->email)
+	    listview_add_sub_item (lv, j, UID_COL_EMAIL, u->email);
+
+	ks = get_selfsig (u->signatures, k->keyid, 1);
+	if (ks)
+	    listview_add_sub_item (lv, j, UID_COL_CREATION, 
+				   get_key_created (ks->timestamp));
+    }
+    if (!k->key_pair) {
+	CheckDlgButton (dlg, IDC_KEYUID_ADD, BST_INDETERMINATE);
+	CheckDlgButton (dlg, IDC_KEYUID_REVOKE, BST_INDETERMINATE);
+    }
+    return lv;
+}
+
+
+static void
+do_init_cmdlist (HWND dlg, int is_keypair)
+{    
+    const char *s;
+    int i;
+
+    for (i = 0; (s=cmdlist[i].name); i++) {
+	if (is_keypair)
+	    SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
+				(LPARAM)(char *)s);
+	else if (!cmdlist[i].need_pair)
+	    SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_ADDSTRING, 0,
+				(LPARAM)(char *)s);
+    }
+    SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_SETCURSEL, 0, 0);
+}
+
+
+/* Return 1 if the requested command is RFC2440. */
+static int
+is_cmd_openpgp (int cmdid)
+{
+    switch (cmdid) {
+    case CMD_ADDKEY:
+    case CMD_ADDPHOTO:
+    case CMD_ADDREVOKER:
+    case CMD_SETPREF:
+	return 1;
+    }
+    return 0;
+}
+
+
+/* Display a message box with a short description of the commands. */
+static void
+do_show_help (HWND dlg)
+{
+    const char *help;
+
+    help =
+	_(
+	 "ADDUID\t\t\tadd a user ID\r\n"
+	 "ADDPHOTO\t\t\tadd a photo ID\r\n"
+	 "DELUID\t\t\tdelete a user ID\r\n"
+	 "ADDKEY\t\t\tadd a secondary key\r\n"
+	 "DELKEY\t\t\tdelete a secondary key\r\n"
+	 "ADDREVOKER\t\t\tadd a revocation key\r\n"
+	 "EXPIRE\t\t\tchange the expire date\r\n"
+	 "SHOWPREF\t\t\tlist preferences (verbose)\r\n"
+	 "PASSWD\t\t\tchange the passphrase\r\n"
+	 "PRIMARY\t\t\tflag user ID as primary\r\n"
+	 "TRUST\t\t\tchange the ownertrust\r\n"
+	 "REVUID\t\t\trevoke a user ID\r\n"
+	 "REVKEY\t\t\trevoke a secondary key\r\n"
+	 "DISABLE\t\t\tdisable a key\r\n"
+	 "ENABLE\t\t\tenable a key\r\n"
+	 "SIGN\t\t\tsign a user-id (exportable)\r\n"
+	 "LSIGN\t\t\tsign a user-id (non-exportable)\r\n"
+	 "CLEAN\t\t\tremove unusable signatures from key\r\n"
+	 "MINIMIZE\t\t\tremove all signatures from key\r\n"
+	 );
+    msg_box (dlg, help, _("Key Edit Help"), MB_OK);
+}
+
+
+static gpgme_subkey_t
+get_subkey_bypos (const char *keyid, int idx)
+{
+    gpgme_key_t key;
+
+    if (get_pubkey (keyid, &key))
+	return NULL;
+    return get_nth_key (key, idx);
+}
+
+
+
+static int
+do_editkey_delkey (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    gpgme_error_t err;
+    gpgme_subkey_t subk;
+    GpgKeyEdit ke;
+    int pos, id;
+    const char *warn;
+    char tmp[64];
+
+    if (!k->key_pair)
+	return FALSE;
+
+    if (listview_count_items (lv, 0) == 1) {
+	show_balloon_msg (lv->ctrl, _("Primary key can not be deleted!"),
+			  IDI_ERROR);
+        return FALSE;
+    }
+    pos = listview_get_curr_pos (lv);
+    if (pos == -1) {
+	show_balloon_msg (lv->ctrl, _("Please select a key."), IDI_ERROR);
+        return FALSE;
+    }
+    if (pos == 0) {
+	show_balloon_msg (lv->ctrl, _("Primary key can not be deleted!"),
+			 IDI_ERROR);
+        return FALSE;
+    }
+
+    listview_get_item_text (lv, pos, 0, tmp, DIM (tmp) -1);
+    subk = get_subkey_bypos (k->keyid, pos);
+    /* Issue different warning for the different key capabilities. */
+    if (subk->can_encrypt)
+	warn = _("Anything encrypted to the selected subkey cannot be\n"
+	         "decrypted any longer.");
+    else if (subk->can_sign || subk->can_certify)
+	warn = _("Anything signed by the selected subkey cannot be\n"
+		 "verified any longer.");
+    else
+	warn = ""; /* just get rid of the warning. */
+
+    id = log_box (_("Key Edit"), MB_YESNO|MB_ICONWARNING, 
+		  _("\"Subkey %s, ID 0x%s.\"\n\n%s\n\n"
+		    "Do you really want to DELETE this subkey?"), 
+		  tmp, subk->keyid+8, warn);
+    if (id == IDNO)
+	return FALSE;
+
+    ke.setKeyID (k->keyid);
+    err = ke.delKey (pos);
+    if (err)
+	msg_box (dlg, gpgme_strerror (err), _("Delete Subkey"), MB_ERR);
+    else {
+	listview_del_item (lv, pos);
+	k->update = 1;
+	status_box (dlg, _("Subkey successfully deleted."), _("GnuPG Status"));
+    }
+    return err? FALSE : TRUE;
+}
+
+
+/* Set the expiration date for the selected key in list view @lv.
+   Return value: TRUE on success. */
+static int
+do_editkey_expire (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    gpgme_error_t err;
+    GpgKeyEdit ke;
+    date_s udd = {0};
+    char buf[256], * pass = NULL;
+    time_t exp;
+    int pos, cancel = 0;
+
+    if (!k->key_pair) {
+	msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
+        return FALSE;
+    }
+    pos = listview_get_curr_pos (lv);
+    if (pos == -1) {
+	msg_box (dlg, _("Please select a key."), _("Key Edit"), MB_ERR);
+        return FALSE;
+    }
+
+    /* If a key already expired, it is possible the user wants to
+       set a new expiration date.. */
+    listview_get_item_text (lv, pos, SUBK_COL_STATUS, buf, DIM (buf)-1);
+    if (!strcmp (buf, _("Expired"))) {
+	cancel = msg_box (dlg, _("Key already expired.\n\n"
+			  "Do you want to change the expiration date?"),
+		          _("Key Edit"), MB_QUEST_ASK);
+	if (cancel == IDNO)
+	    return FALSE;
+	cancel = 0;
+    }
+
+    memset (&udd, 0, sizeof (udd));
+    udd.text = _("Key Expiration Date");
+    dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_DATE, dlg,    
+		      date_dlg_proc, (LPARAM)&udd,
+		      _("Key Expiration Date"), IDS_WINPT_DATE);
+    if (udd.cancel == 1)
+	return FALSE;
+    if (!keygen_check_date (&udd.st)) {
+	msg_box (dlg, _("The date you have chosen has already passed."), 
+		 _("Key Edit"), MB_ERR);
+        return FALSE;
+    }
+    if (k->is_protected) {
+	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
+	if (cancel)
+	    return FALSE;
+    }
+    exp = w32_mktime (&udd.st);
+
+    ke.setKeyID (k->keyid);
+    if (k->is_protected)
+	ke.setPassphrase (pass);
+    else
+	ke.setNoPassphrase (true);
+    err = ke.setKeyExpireDate (pos, exp, false);
+    if (err)
+	msg_box (dlg, gpgme_strerror (err), _("Expire Subkey"), MB_ERR);
+    else {
+	_snprintf (buf, DIM (buf)-1, "%s", get_key_created (exp));
+	listview_add_sub_item (lv, pos, SUBK_COL_EXPIRES, buf);
+	k->update = 1;
+	msg_box (dlg, _("Subkey expire date successfully set."), 
+		 _("GnuPG Status"), MB_OK);
+    }
+    sfree_if_alloc (pass);
+    return TRUE;
+}
+
+
+/* Revoke the selected key in the list view @lv. @k contains 
+   control information about the global key.
+   Return value: TRUE on success. */
+static int
+do_editkey_revoke (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    gpgme_error_t err;
+    GpgKeyEdit ke;
+    char buf[256];
+    char *pass = NULL;
+    int j, cancel = 0;
+
+    if (!k->key_pair) {
+	msg_box (dlg, _("There is no secret key available!"), _("Key Edit"), MB_ERR);
+        return FALSE;
+    }
+
+    if ((j = listview_get_curr_pos (lv)) == -1) {
+	msg_box( dlg, _("Please select a key."), _("Key Edit"), MB_ERR );
+	return FALSE;
+    }
+    else if (listview_count_items (lv, 0) == 1) {
+	msg_box( dlg, _("No subkeys were found, if you want to revoke the\n"
+	                "whole key, please use the Key Manager command directly.\n\n"
+			"This command is only available to revoke single subkeys"),
+		 _("Key Edit"), MB_INFO );
+	return FALSE;
+    }
+	    
+    listview_get_item_text (lv, j, SUBK_COL_STATUS, buf, DIM (buf)-1);
+    if (!strcmp (buf, _("Revoked"))) {
+	msg_box (dlg, _("Key already revoked."), _("Key Edit"), MB_ERR);
+	return FALSE;
+    }
+    
+    if (k->is_protected) {
+	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
+	if (cancel)
+	    return FALSE;	    
+    }
+
+    ke.setKeyID (k->keyid);
+    if (k->is_protected)
+	ke.setPassphrase (pass);
+    else
+	ke.setNoPassphrase (true);
+    err = ke.revokeSubkey (j, 0, NULL);
+    if (err)
+	msg_box( dlg, gpgme_strerror (err), _("Revoke Subkey"), MB_ERR);
+    else {
+	listview_add_sub_item (lv, j, SUBK_COL_STATUS, _("Revoked"));
+	k->update = 1;
+	msg_box( dlg, _("Subkey successfully revoked."), _("GnuPG Status"), MB_OK );
+    }
+    sfree_if_alloc (pass);
+    return TRUE;
+}
+
+
+/* Revoked the selected userid in list view @lv.
+   Return value: TRUE on success. */
+int
+do_editkey_revuid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    gpgme_error_t err;
+    GpgKeyEdit ke;
+    char buf[128], email[128];
+    char inf[512];
+    char *pass = NULL;
+    int cancel = 0, id = 0, j;
+
+    if (!k->key_pair) {
+	msg_box (dlg, _("There is no secret key available!"), 
+		 _("Revoke user ID"), MB_ERR);
+	return FALSE;
+    }
+
+    if (listview_count_items (lv, 0) == 1) {
+	msg_box (dlg, _("Key has only one user ID."), _("Key Edit"), MB_ERR);	
+	return FALSE;
+    }
+
+    if( (j = listview_get_curr_pos( lv )) == -1 ) {
+	msg_box( dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR );
+	return FALSE;	
+    }
+	    
+    listview_get_item_text( lv, j, UID_COL_VALID, buf, DIM (buf) - 1);
+    if (strstr (buf, _("Revoked"))) {
+	msg_box (dlg, _("This user ID has been already revoked."), 
+		 _("Key Edit"), MB_INFO);
+	return FALSE;
+    }
+	    
+    listview_get_item_text (lv, j, UID_COL_NAME, buf, DIM (buf) -1);
+    _snprintf (inf, DIM (inf) -1, _("user ID \"%s\".\n\n"
+	       "Do you really want to revoke this user ID?"), buf);
+    if (msg_box (dlg, inf, _("Key Edit"), MB_WARN_ASK) == IDNO)
+	return FALSE;
+    if (k->is_protected) {
+	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
+	if (cancel)
+	    return FALSE;	    
+    }
+    listview_get_item_text (lv, j, UID_COL_EMAIL, email, DIM (email)-1);
+    listview_get_item_text (lv, j, UID_COL_NAME, buf, DIM (buf)-1);
+    id = do_find_userid (k->keyid, email, buf, NULL);
+    if (id == -1)
+	BUG (NULL);
+
+    ke.setKeyID (k->keyid);
+    if (k->is_protected)
+	ke.setPassphrase (pass);
+    else
+	ke.setNoPassphrase (true);
+    err = ke.revokeUserid (id);
+    if (err)
+	msg_box (dlg, gpgme_strerror (err), _("Revoke User ID"), MB_ERR);
+    else {
+	listview_add_sub_item (lv, j, 0, _("Revoked"));
+	k->update = 1;
+	status_box (dlg, _("User ID successfully revoked"), _("GnuPG Status"));
+    }
+    sfree_if_alloc (pass);
+    return err? FALSE : TRUE;
+}
+
+
+static int
+do_editkey_primary (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    gpgme_error_t err;
+    GpgKeyEdit ke;
+    int j, id, cancel=0;
+    char valid[32];
+    char buf[256], *pass = NULL;
+
+    if (listview_count_items (lv, 0) == 1)
+	return TRUE;
+    if ((j = listview_get_curr_pos (lv)) == -1) {
+	msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
+	return FALSE;
+    }
+    listview_get_item_text (lv, j, UID_COL_VALID, valid, DIM (valid)-1);
+    if (!strcmp (valid, _("Revoked")))
+	return FALSE;
+    listview_get_item_text (lv, j, UID_COL_EMAIL, buf, DIM (buf)-1);
+    id = do_find_userid (k->keyid, buf, NULL, NULL);
+    if (id == -1)
+	BUG (NULL);
+    if (k->is_protected) {
+	pass = request_key_passphrase (k->ctx, _("Key Edit"), &cancel);
+	if (cancel)
+	    return FALSE;
+    }
+
+    ke.setKeyID (k->keyid);
+    if (k->is_protected)
+	ke.setPassphrase (pass);
+    else
+	ke.setNoPassphrase (true);
+    err = ke.setPrimaryUserid (id);
+    if (err)
+	msg_box (dlg, gpgme_strerror (err), _("Primary"), MB_ERR);
+    else {
+	k->update = 1;
+	status_box (dlg, _("User ID successfully flagged"), _("GnuPG Status"));
+    }
+
+    sfree_if_alloc (pass);
+    return err? FALSE : TRUE;
+}
+
+
+
+#define CIPHER	11
+#define HASH	11
+#define COMPR    4
+
+static int
+parse_preflist (HWND dlg, const char *list)
+{
+    char buf[128] = {0};
+    char *p, *pbuf = buf;
+    const char *ciphers[CIPHER] = {"", "IDEA", "3DES", 
+				   "CAST5", "BLOWFISH", "", "", 
+				   "AES", "AES192", "AES256", "TWOFISH"};
+    const char *hash[HASH] = {"", "MD5", "SHA1", "RMD160", "",
+			      "", "", "", "SHA256", "SHA384", "SHA512"};
+    const char *compress[COMPR] = {"", "ZIP", "ZLIB", "BZIP2"};
+    int n=0;
+
+    strncpy (buf, list, 127);
+    p = strtok (pbuf, " ");
+    while (p != NULL) {
+	int algid = atol (p+1);
+	n++;
+	switch (*p) {
+	case 'S':
+	    SendDlgItemMessage (dlg, IDC_SHOWPREF_CIPHERS, LB_ADDSTRING, 0, 
+				(LPARAM)(const char*)ciphers[algid % CIPHER]);
+	    break;
+
+	case 'H':
+	    SendDlgItemMessage (dlg, IDC_SHOWPREF_HASH, LB_ADDSTRING, 0, 
+				(LPARAM)(const char*)hash[algid % HASH]);
+	    break;
+
+	case 'Z':
+	    SendDlgItemMessage (dlg, IDC_SHOWPREF_ZIP, LB_ADDSTRING, 0, 
+				(LPARAM)(const char*)compress[algid % COMPR]);
+	    break;
+
+	default:
+	    n--;
+	}
+	p = strtok (NULL, " ");
+    }
+    return n;
+}
+
+
+/* Dialog box procedure to show the key preferences. */
+BOOL CALLBACK
+showpref_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    static keyedit_cb_t cb = NULL;
+    gpg_uid_info_t inf=NULL, u;
+    gpgme_key_t key;
+    char buf[128];
+    int pos;
+
+    switch (msg) {
+    case WM_INITDIALOG:
+	cb = (keyedit_cb_t)lparam;
+	if (!cb)
+	    BUG (NULL);
+	key = (gpgme_key_t)cb->opaque;
+	listview_get_item_text (cb->lv, cb->lv_pos, 
+				UID_COL_EMAIL, buf, DIM (buf)-1);
+	pos = do_find_userid (cb->keyid, buf, NULL, &inf);
+	if (pos < 0 || !inf) {
+	    gpg_uid_info_release (inf);
+	    EndDialog (dlg, FALSE);
+	    break;
+	}
+	for (u=inf; u; u = u->next) {
+	    if (u->index == pos && u->prefs && *u->prefs) {
+		_snprintf (buf, DIM (buf)-1, "%s", u->name);
+		SetDlgItemText (dlg, IDC_SHOWPREF_INFO, buf);
+		if (parse_preflist (dlg, u->prefs) <= 0)
+		    pos = -1;
+		if (u->flags.mdc)
+		    CheckDlgButton (dlg, IDC_SHOWPREF_MDC, BST_CHECKED);
+		break;
+	    }
+	}
+	gpg_uid_info_release (inf);
+	if (pos == -1) {
+	    msg_box (dlg, _("No preferences available."), _("Key Edit"), MB_ERR);
+	    EndDialog (dlg, FALSE);
+	    break;
+	}
+	SetDlgItemText (dlg, IDC_SHOWPREF_MDC, _("MDC feature"));
+	SetDlgItemText (dlg, IDC_SHOWPREF_PREFINF, _("Preferences"));
+	SetDlgItemText (dlg, IDC_SHOWPREF_UIDHINT, _("user ID:"));
+	SetWindowText (dlg, _("Key Preferences"));
+	SetForegroundWindow (dlg);
+	center_window (dlg, cb->parent);
+	break;
+
+    case WM_COMMAND:
+	switch (LOWORD (wparam)) {
+	case IDOK:
+	    EndDialog (dlg, TRUE);
+	    break;
+
+	case IDCANCEL:
+	    EndDialog (dlg, FALSE);
+	    break;
+	}
+	break;
+    }
+    return FALSE;
+}
+
+
+static int
+do_editkey_showpref (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    struct keyedit_cb_s cb;
+    char status[32];
+
+    if (k->is_v3)
+	return TRUE;
+
+    if (listview_get_curr_pos (lv) == -1) {
+	msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
+	return FALSE;
+    }
+    memset (&cb, 0, sizeof (cb));
+    cb.parent = dlg;
+    cb.opaque = k->ctx;
+    cb.keyid = k->keyid;
+    cb.lv = lv;
+    cb.lv_pos = listview_get_curr_pos (lv);
+
+    listview_get_item_text (lv, cb.lv_pos, UID_COL_VALID, 
+			    status, DIM (status)-1);
+    if (!strcmp (status, _("Revoked")))
+	return TRUE;
+    
+    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYEDIT_SHOWPREF, dlg,
+		    showpref_dlg_proc, (LPARAM)&cb);
+    return TRUE;
+}
+
+
+static int
+do_editkey_deluid (winpt_key_t k, HWND dlg, listview_ctrl_t lv)
+{
+    gpgme_error_t err;
+    GpgKeyEdit ke;
+    char email[128], name[128];
+    char inf[384];
+    int pos, id = 0;
+
+    if (!k->key_pair)
+	return FALSE;
+
+    if (listview_count_items (lv, 0) == 1) {
+	msg_box (dlg, _("Primary user ID can not be deleted!"),
+		 _("Key Edit"), MB_ERR);
+        return FALSE;
+    }
+    pos = listview_get_curr_pos (lv);
+    if (pos == -1) {
+	msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
+        return FALSE;
+    }
+    
+    listview_get_item_text (lv, pos, UID_COL_NAME, name, DIM(name) -1);
+    _snprintf (inf, DIM (inf)-1, _("user ID \"%s\".\n\n"
+				   "All signatures on this user ID will be also deleted."
+				   "\n\n"
+			           "Do you really want to DELETE this user ID?"),
+			       name);
+    if (msg_box (dlg, inf, _("Key Edit"), MB_YESNO|MB_ICONWARNING) == IDNO)
+	return FALSE;
+    
+    listview_get_item_text (lv, pos, UID_COL_EMAIL, email, DIM (email)-1);
+    listview_get_item_text (lv, pos, UID_COL_NAME, name, DIM (name)-1);
+    id = do_find_userid (k->keyid, email, name, NULL);
+    if (id == -1)
+	BUG (NULL);
+
+    ke.setKeyID (k->keyid);
+    err = ke.delUserid (id);
+    if (err)
+	msg_box (dlg, gpgme_strerror (err), _("Delete User ID"), MB_ERR);
+    else {
+	listview_del_item (lv, pos);
+	k->update = 1;
+	status_box (dlg, _("User ID successfully deleted"), _("GnuPG Status"));
+    }
+    return err? FALSE : TRUE;
+}
+
+
+/* Subclass routine for the subkey listview control to allow shortcuts. */
+static BOOL CALLBACK
+subkey_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    int virt_key = 0;
+    winpt_key_t key;
+
+    switch (msg) {
+    case WM_KEYUP:
+	virt_key = (int)wparam;
+	key = (winpt_key_t)keyedit_subkey_proc.opaque;
+	if (!key || !key->key_pair)
+	    break;
+
+	switch (virt_key) {
+	case VK_DELETE:
+	    SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD, 
+				CB_SETCURSEL, CMD_DELKEY, 0);
+	    send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
+	    break;
+
+	case VK_INSERT:
+	    SendDlgItemMessage (keyedit_subkey_proc.dlg, IDC_KEYEDIT_CMD, 
+				CB_SETCURSEL, CMD_ADDKEY, 0);
+	    send_cmd_id (keyedit_subkey_proc.dlg, IDOK);
+	    break;
+	}
+    }
+    return CallWindowProc (keyedit_subkey_proc.old, dlg, msg, wparam, lparam);
+}
+
+
+static BOOL CALLBACK
+uid_subclass_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    int virt_key = 0;
+    winpt_key_t key;
+
+    switch (msg) {
+    case WM_KEYUP:
+	virt_key = (int)wparam;
+	key = (winpt_key_t)keyedit_uid_proc.opaque;
+	if (!key || !key->key_pair)
+	    break;
+
+	switch (virt_key) {
+	case VK_DELETE:
+	    SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
+				CB_SETCURSEL, CMD_DELUID, 0);
+	    send_cmd_id (keyedit_uid_proc.dlg, IDOK);
+	    break;
+
+	case VK_INSERT:
+	    SendDlgItemMessage (keyedit_uid_proc.dlg, IDC_KEYEDIT_CMD,
+				CB_SETCURSEL, CMD_ADDUID, 0);
+	    send_cmd_id (keyedit_uid_proc.dlg, IDOK);
+	    break;
+	}
+    }
+    return CallWindowProc (keyedit_uid_proc.old, dlg, msg, wparam, lparam);
+}
+
+
+/* Enable the key @k when @enable is 1, disable it otherwise. */
+static void
+do_editkey_enable_disable (winpt_key_t k, HWND dlg, 
+			   listview_ctrl_t lv, int enable)
+{
+    gpgme_error_t err;
+    gpgme_key_t key;
+    GpgKeyEdit ke;
+    
+    // FIXME: We had to duplicate the code here since the key manager
+    // code uses the listview to get the pointer to the key!
+    key = k->ctx;
+    ke.setKeyID (key->subkeys->keyid);
+    
+    err = enable? ke.enable () : ke.disable ();
+    if (!err) {	
+	show_msg (dlg, 1500, _("Key status changed."));
+	k->update = 1;
+    }
+    else
+	msg_box (dlg, gpgme_strerror (err), _("Key Manager"), MB_ERR);    
+}
+
+
+static void
+do_editkey_minimize (winpt_key_t k, HWND dlg)
+{
+    gpgme_error_t err;
+    GpgKeyEdit ke;
+
+    ke.setKeyID (k->keyid);
+    err = ke.minimizeKey ();
+    if (err)
+	msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
+    else {
+	msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
+	k->update = 1;
+    }
+}
+
+
+static void
+do_editkey_clean (winpt_key_t k, HWND dlg)
+{
+    gpgme_error_t err;
+    GpgKeyEdit ke;
+    
+    ke.setKeyID (k->keyid);
+    err = ke.cleanKey ();
+    if (err)
+	msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);   
+    else {
+	msg_box (dlg, _("Finished to compact key."), _("Key Edit"), MB_OK);
+	k->update = 1;
+    }
+}
+
+
+/* Start the dialog to list and display the status of all 
+   signatures for this key. */
+static void
+do_editkey_check (winpt_key_t k, HWND dlg)
+{
+    if (!k->ctx)
+	get_pubkey (k->keyid, &k->ctx);
+    if (!k->uid && k->ctx)
+	k->uid = k->ctx->uids->uid;
+    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYSIG_TREE, dlg,
+		    sigtree_dlg_proc, (LPARAM)k);
+}
+
+
+static int
+do_editkey_sign_userid (winpt_key_t k, HWND dlg, listview_ctrl_t lv, int mode)
+{
+    gpgme_error_t err;
+    winpt_key_s signer;
+    GpgKeyEdit ke;
+    char *pass = NULL;
+    char *defkey;
+    char email[64], name[128], valid[32];
+    int uid_index;
+    int cancel = 0;
+
+    uid_index = listview_get_curr_pos (lv);
+    if (uid_index == -1) {
+	msg_box (dlg, _("Please select a user ID."), _("Key Edit"), MB_ERR);
+	return FALSE;
+    }
+    listview_get_item_text (lv, uid_index, UID_COL_VALID, valid, DIM (valid)-1);
+    if (!strcmp (valid, _("Revoked")))
+	return TRUE;
+    if (mode == CMD_SIGN) {
+	cancel = msg_box (dlg, _("Do you really want to make this sig exportable?"),
+			  _("Key Edit"), MB_QUEST_ASK);
+	if (cancel == IDNO)
+	    return FALSE;
+    }
+    listview_get_item_text (lv, uid_index, UID_COL_EMAIL, email, DIM (email)-1);
+    listview_get_item_text (lv, uid_index, UID_COL_NAME, name, DIM (name)-1);
+    uid_index = do_find_userid (k->keyid, email, name, NULL);
+
+    defkey = get_gnupg_default_key ();
+    memset (&signer, 0, sizeof (signer));
+    if (winpt_get_seckey (defkey, &signer)) {
+	log_debug ("do_editkey_sign_userid: no default secret key.\r\n");
+	free_if_alloc (defkey);
+	return FALSE;
+    }
+    if (signer.is_protected) {
+	pass = request_key_passphrase (signer.ctx, _("Key Edit"), &cancel);
+	if (cancel)
+	    return FALSE;
+    }
+    ke.setKeyID (k->keyid);
+    if (signer.is_protected)
+	ke.setPassphrase (pass);
+    else
+	ke.setNoPassphrase (true);
+    ke.setLocalUser (signer.ctx);
+    err = ke.signUserid (uid_index, 
+			  mode == CMD_SIGN? GPG_EDITKEY_SIGN : GPG_EDITKEY_LSIGN,
+			  0, NULL);
+    if (!err) {
+	msg_box (dlg, _("Key successfully signed."), _("Key Edit"), MB_OK);
+	k->update = 1;
+    }
+    else
+	msg_box (dlg, gpgme_strerror (err), _("Key Edit"), MB_ERR);
+
+    sfree_if_alloc (pass);
+    return !err? TRUE : FALSE;
+}
+
+
+static int
+lookup_cmd (HWND dlg)
+{
+    char buf[64];
+    int i;
+
+    i = SendDlgItemMessage (dlg, IDC_KEYEDIT_CMD, CB_GETCURSEL, 0, 0);
+    if (i == LB_ERR)
+	return LB_ERR;
+    GetDlgItemText (dlg, IDC_KEYEDIT_CMD, buf, DIM (buf)-1);
+    for (i=0; cmdlist[i].name != NULL; i++) {
+	if (!strcmp (buf, cmdlist[i].name))
+	    return cmdlist[i].id;
+    }
+    return LB_ERR;
+}
+
+
+
+gpgme_error_t key_get_revokers (winpt_key_t key, int reload, 
+				gpg_desig_rev_t *r_rev);
+
+/* Check if the key supports designated revokers and if
+    secret keys exist to generate such a revoke cert. */
+static bool
+check_desig_rev (winpt_key_t key)
+{
+    gpg_desig_rev_t rev, u;
+    struct winpt_key_s sk;
+
+    if (!key->ext->gloflags.has_desig_rev)
+	return false;
+    key_get_revokers (key, 0, &rev);
+    for (u = rev; u; u = u->next) {
+	memset (&sk, 0, sizeof (sk));
+	if (!winpt_get_seckey (u->fpr+32, &sk))
+	    return true;
+    }
+    return false;
+}
+
+
+/* Use the gpg --desig-revoker command to create a revocation
+   cert for a key that lists our key as a designated revoker. */
+static void 
+gen_desig_revoke_cert (winpt_key_t key, HWND dlg)
+{
+    const char *warn;
+    char *inf, *p;
+    int id;
+
+    inf = km_key_get_info (key, 0);
+    warn = _("Your keys is listed as a designated revoker for the key\n\n"
+	     "%s\n\n"
+	     "Are you sure you want to create a revocation certificate\n"
+	     "which allows you to revoke the key listed above?");
+    p = new char[strlen (inf)+1+strlen (warn)+1];
+    sprintf (p, warn, inf);
+    free_if_alloc (inf);
+
+    id = msg_box (dlg, p, _("Key Edit"), MB_YESNO|MB_ICONWARNING);
+    free_if_alloc (p);
+    if (id == IDNO)
+	return;
+
+    key->internal = 1;
+    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKE, dlg,
+		    key_revoke_dlg_proc, (LPARAM)key);
+}
+
+
+/* Create tooltip control for the listview header. */
+static HWND
+create_header_tooltip (HWND dlg)
+{
+    TOOLINFO ti;
+    HWND tt;
+
+    tt = CreateWindow (TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP|TTS_BALLOON ,
+			CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
+			CW_USEDEFAULT, 
+			NULL, (HMENU) NULL, glob_hinst, NULL);
+    if (!tt)
+	BUG (NULL);
+    memset (&ti, 0, sizeof (ti));
+    ti.cbSize = sizeof (TOOLINFO); 
+    ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;     
+    ti.hwnd = dlg;     
+    ti.uId = (UINT) ListView_GetHeader (GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST));
+    ti.hinst = 0;
+    ti.lpszText = (char*)_("Capabilties: C = Certify, S = Sign, E = Encrypt, A = Authenticate");
+    SendMessage(tt, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
+    return tt;
+}
+
+
+#define TTM_POPUP (WM_USER+34)
+
+/* Dialog box procedure for the edit key dialog. */
+BOOL CALLBACK
+keyedit_main_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    static winpt_key_t k;
+    static listview_ctrl_t lvsub = NULL;
+    static listview_ctrl_t lvuid = NULL;
+    static HWND tt = NULL;
+    int cmd;
+    HWND item;
+
+    switch (msg) {
+    case WM_INITDIALOG:
+	k = (winpt_key_t)lparam;
+	if (!k)
+	    BUG (NULL);
+	do_init_cmdlist (dlg, k->key_pair);
+	lvsub = subkey_list_init (dlg, k);
+	lvuid = userid_list_init (dlg, k);
+	item = GetDlgItem (dlg, IDC_KEYEDIT_KEYLIST);
+	keyedit_subkey_proc.opaque = (void*)k;
+	keyedit_subkey_proc.dlg = dlg;
+	keyedit_subkey_proc.current = (WNDPROC)subkey_subclass_proc;
+	keyedit_subkey_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
+	if (keyedit_subkey_proc.old) {
+	    if (!SetWindowLong (item, GWL_WNDPROC, 
+				(LONG)keyedit_subkey_proc.current)) {
+		msg_box (dlg, "Could not set subkey window procedure.", 
+			 _("Key Edit"), MB_ERR);
+		BUG (NULL);
+	    }
+	}
+	tt = create_header_tooltip (dlg);
+	
+	item = GetDlgItem (dlg, IDC_KEYEDIT_UIDLIST);
+	keyedit_uid_proc.opaque = (void*)k;
+	keyedit_uid_proc.dlg = dlg;
+	keyedit_uid_proc.current = (WNDPROC)uid_subclass_proc;
+	keyedit_uid_proc.old = (WNDPROC)GetWindowLong (item, GWL_WNDPROC);
+	if (keyedit_uid_proc.old) {
+	    if (!SetWindowLong (item, GWL_WNDPROC, 
+			        (LONG)keyedit_uid_proc.current)) {
+		msg_box (dlg, "Could not set user ID window procedure.", 
+			 _("Key Edit"), MB_ERR);
+		BUG (NULL);
+	    }
+	}
+	if (k->ctx->revoked || k->ctx->expired) {
+	    EnableWindow (GetDlgItem (dlg, IDC_KEYEDIT_CMD), FALSE);
+	    EnableWindow (GetDlgItem (dlg, IDOK), FALSE);
+	}
+	SetDlgItemText (dlg, IDC_KEYEDIT_CMDINF, _("Command>"));
+	SetDlgItemText (dlg, IDCANCEL, _("&Close"));
+	SetDlgItemText (dlg, IDC_KEYEDIT_HELP, _("&Help"));
+	SetDlgItemText (dlg, IDC_KEYEDIT_REVOKE, _("&Revoke..."));
+	SetDlgItemText (dlg, IDOK, _("&OK"));
+	if (!check_desig_rev (k))
+	    ShowWindow (GetDlgItem (dlg, IDC_KEYEDIT_REVOKE), SW_HIDE);
+	if (k->is_v3)
+	    SetWindowText (dlg, _("Key Edit (PGP 2.6.x mode)"));
+	else
+	    SetWindowText (dlg, _("Key Edit"));
+	SetForegroundWindow (dlg);
+	center_window (dlg, NULL);
+	return TRUE;
+
+    case WM_DESTROY:
+	if (lvsub) {
+	    listview_release (lvsub);
+	    lvsub = NULL;
+	}
+	if (lvuid) {
+	    listview_release (lvuid);
+	    lvuid = NULL;
+	}
+	if (tt != NULL)
+	    DestroyWindow (tt);
+	
+	balloon_msg_disable ();
+	break;
+
+    case WM_NOTIFY:
+	NMHDR *notify;
+        notify = (NMHDR *)lparam;
+	if (!notify || notify->idFrom != IDC_KEYEDIT_UIDLIST)
+	    break;
+	if (notify->code == NM_DBLCLK)
+	    do_editkey_showpref (k, dlg, lvuid);
+	else if (notify->code == NM_RCLICK && k->key_pair) {
+	    if (listview_count_items (lvuid, 0) == 1)
+		break;
+	    HMENU hm = LoadMenu (glob_hinst, MAKEINTRESOURCE (IDR_WINPT_KEYEDIT));
+	    HMENU popup = GetSubMenu (hm, 0);
+	    POINT p;
+
+	    set_menu_text (popup, ID_KEYEDIT_UID_PRIM, _("Flag user ID as &primary"));
+	    set_menu_text (popup, ID_KEYEDIT_UID_DEL, _("&Delete user ID"));
+	    set_menu_text (popup, ID_KEYEDIT_UID_REV, _("&Revoke user ID"));
+	    GetCursorPos (&p);
+	    TrackPopupMenu (popup, TPM_RIGHTALIGN, p.x, p.y, 0, dlg, NULL);
+	    DestroyMenu (hm);
+	    DestroyMenu (popup);
+	}
+	break;
+
+    case WM_COMMAND:
+	switch (LOWORD (wparam)) {
+	case IDOK:
+	    cmd = lookup_cmd (dlg);
+	    if (cmd == LB_ERR) {
+		msg_box (dlg, _("Please select a command."), _("Key Edit"), MB_INFO);
+		return FALSE;
+	    }
+	    if (k->is_v3 && is_cmd_openpgp (cmd)) {
+		msg_box (dlg, _("This command cannot be used with PGP 2 (v3) keys.\n"),
+				_("Key Edit"), MB_ERR);
+		return FALSE;
+	    }
+	    switch (cmd) {
+	    case CMD_SHOWPREF: do_editkey_showpref (k, dlg, lvuid); break;
+	    case CMD_DELKEY: do_editkey_delkey (k, dlg, lvsub); break;
+	    case CMD_ADDKEY: keyedit_add_subkey (k, dlg, lvsub); break;
+	    case CMD_EXPIRE: do_editkey_expire (k, dlg, lvsub); break;
+	    case CMD_REVKEY: do_editkey_revoke (k, dlg, lvsub); break;
+	    case CMD_SETPREF:/*do_editkey_setpref (k, dlg, lvuid);*/ break;
+	    case CMD_ADDUID: keyedit_add_userid( k, dlg, lvuid ); break;
+	    case CMD_ADDREVOKER: keyedit_add_revoker( k, dlg ); break;
+	    case CMD_ADDPHOTO: keyedit_add_photo( k, dlg ); break;
+	    case CMD_REVUID: do_editkey_revuid( k, dlg, lvuid ); break;
+	    case CMD_DELUID: do_editkey_deluid( k, dlg, lvuid ); break;
+	    case CMD_PASSWD: keyedit_change_passwd (k, dlg); break;
+	    case CMD_PRIMARY: do_editkey_primary (k, dlg, lvuid); break;
+	    case CMD_ENABLE: do_editkey_enable_disable (k, dlg, lvsub, 1); break;
+	    case CMD_DISABLE: do_editkey_enable_disable (k, dlg, lvsub, 0); break;
+	    case CMD_CHECK: do_editkey_check (k, dlg); break;
+	    case CMD_TRUST: keyedit_change_ownertrust (k, dlg); break;
+	    case CMD_SIGN:
+	    case CMD_LSIGN: do_editkey_sign_userid (k, dlg, 
+						    lvuid, cmd);
+			    break;
+	    case CMD_CLEAN: do_editkey_clean (k, dlg); break;
+	    case CMD_MINIMIZE: do_editkey_minimize (k, dlg); break;
+	    }
+	    break;	    
+
+	case IDCANCEL:
+	    EndDialog (dlg, FALSE);
+	    break;
+
+	case IDC_KEYEDIT_HELP:
+	    do_show_help (dlg);
+	    break;
+
+	case IDC_KEYEDIT_REVOKE:
+	    gen_desig_revoke_cert (k, dlg);
+	    break;
+
+	case ID_KEYEDIT_UID_PRIM:
+	    do_editkey_primary (k, dlg, lvuid);
+	    break;
+
+	case ID_KEYEDIT_UID_DEL:
+	    do_editkey_deluid (k, dlg, lvuid);
+	    break;
+
+	case ID_KEYEDIT_UID_REV:
+	    do_editkey_revuid (k, dlg, lvuid);
+	    break;
+	}
+	break;
+    }
+    return FALSE;
+}

Modified: trunk/Src/wptKeyserver.cpp
===================================================================
--- trunk/Src/wptKeyserver.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptKeyserver.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -60,6 +60,36 @@
 static size_t default_socket_timeout = 6;
 
 
+/* Remove %AB sequences from the input buffer @in
+   and store the raw data in @out. */
+void
+unhexify_buffer (const char *in, char **r_out)
+{
+    char temp[3], *out;
+    size_t len, pos, i=0;
+
+    len = strlen (in);
+    out = new char[len+1];
+    if (!out)
+	BUG (0);
+    memset (out, 0, len+1);
+    for (pos = 0; pos < len; pos++) {
+	if (in[pos] == '%' && in[pos+1] == '%')
+	    out[i++] = '%';
+	else if (in[pos] == '%') {
+	    temp[0] = in[++pos];
+	    temp[1] = in[++pos];
+	    temp[2] = 0;
+	    out[i++] = (char)strtoul (temp, NULL, 16);
+	}
+	else
+	    out[i++] = in[pos];
+    }
+    out[i] = 0;
+    *r_out = out;
+}
+
+
 /* Wrapper for safe memory allocation. */
 static char*
 safe_alloc (DWORD n)

Modified: trunk/Src/wptMAPI.cpp
===================================================================
--- trunk/Src/wptMAPI.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptMAPI.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -211,7 +211,7 @@
 	  "exchange encrypted mails with the key holder and to be able\n"
 	  "to verify its signatures.\n"
 	  "\n"
-	  "If you don't have WinPT, you can download it at http://winpt.gnupt.de");
+	  "If you do not have WinPT, you can download it at http://winpt.gnupt.de");
     kinf = km_key_get_info (key, 0);
     p = (char*)malloc (strlen (s) + strlen (kinf) + 2);
     sprintf (p, s, kinf);

Deleted: trunk/Src/wptMDSumDlg.cpp
===================================================================
--- trunk/Src/wptMDSumDlg.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptMDSumDlg.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -1,285 +0,0 @@
-#if 0 /*UNUSED*/
-/* wptMDSumDlg.cpp - Dialog to show hash values for files
- *	Copyright (C) 2003, 2005, 2006, 2008 Timo Schulz
- *
- * This file is part of WinPT.
- *
- * WinPT is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * WinPT 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.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <windows.h>
-#include <stdio.h>
-
-#include "resource.h"
-#include "wptTypes.h"
-#include "wptW32API.h"
-#include "wptGPG.h"
-#include "wptCommonCtl.h"
-#include "wptContext.h"
-#include "wptNLS.h"
-#include "wptErrors.h"
-
-
-/* maximum hash size in octets (sha512=64) */
-#define MAX_HASHSIZE 64
-
-/* Symbolic column IDs. */
-enum md_col_t {COL_MD=0, COL_NAME};
-
-
-/* A model which represents the contents of the list view. */
-struct hashlist_model_s {
-    struct hashlist_model_s *next;
-    char *name;
-    BYTE *md;
-    DWORD mdlen;
-};
-typedef struct hashlist_model_s *hashlist_model_t;
-
-
-/* Release the file list @hm. */
-static void
-hashmodel_release (hashlist_model_t hm)
-{
-    hashlist_model_t t;
-
-    while (hm) {
-	t = hm->next;
-	free_if_alloc (hm->name);
-	free_if_alloc (hm->md);
-	free_if_alloc (hm);
-	hm = t;
-    }
-}
-
-
-/* Add a new file with the name @name to the list @hm. */
-static hashlist_model_t
-hashmodel_add_file (hashlist_model_t *hm, const char *name, 
-		    const BYTE *mdbuf, size_t mdlen)
-{
-    hashlist_model_t t, n;
-
-    t = new hashlist_model_s;
-    memset (t, 0, sizeof *t);
-    t->name = m_strdup (name);
-    t->mdlen = mdlen;
-    t->md = new BYTE[mdlen];
-    memcpy (t->md, mdbuf, mdlen);
-    if (!*hm)
-	*hm = t;
-    else {
-	for (n = *hm; n->next; n=n->next)
-	    ;
-	n->next = t;
-    }
-    return t;
-}
-
-
-/* Return a printable digest of the buffer @mdbuf. */
-static const char*
-printable_digest (BYTE *mdbuf, size_t n, char *mdasc, size_t maxlen)
-{
-    if (n*4 > maxlen)
-	return NULL;
-    for (size_t i = 0; i < n; i++)
-	sprintf (mdasc+2*i, "%02X", mdbuf[i]);
-    return mdasc;
-}
-
-
-static const char*
-id2algo (gpgme_hash_algo_t mdalgo)
-{
-    switch (mdalgo) {
-    case GPGME_MD_MD5:	    return "MD5";
-    case GPGME_MD_SHA1:	    return "SHA1";
-    case GPGME_MD_RMD160:   return "RMD160";
-    case GPGME_MD_SHA256:   return "SHA256";
-    case GPGME_MD_SHA384:   return "SHA384";
-    case GPGME_MD_SHA512:   return "SHA512";
-    default:		    break;
-    }
-    return "";
-}
-
-
-/* Hash the selected file from the FM listview control in @md.
-   Add the results to the listview @lv. */
-static void
-hash_selected_files (md_file_s *md, listview_ctrl_t lv, hashlist_model_t *r_fl)
-{
-    hashlist_model_t item;
-    BYTE mdbuf[MAX_HASHSIZE];
-    char fname[MAX_PATH+1];
-    char mdasc[4*MAX_HASHSIZE+1];
-    size_t n;
-    int i;
-
-    for (i = 0; i < listview_count_items (md->lv, 0); i++) {
-	if (!listview_get_item_state (md->lv, i))
-	    continue;
-	listview_get_item_text (md->lv, i, 1, fname, DIM (fname)-1);
-	if (!gpg_md_hash_file (md->mdalgo, fname, mdbuf, &n)) {
-	    const char *pmd = printable_digest(mdbuf, n, mdasc, DIM(mdasc)-1);
-	    item = hashmodel_add_file (r_fl, fname, mdbuf, n);
-	    listview_add_item2 (lv, "", (void*)item);
-	    listview_add_sub_item (lv, 0, COL_MD, pmd);
-	    listview_add_sub_item (lv, 0, COL_NAME, fname);
-	}	
-    }
-}
-
-
-/* Return 1 if there is a tool available to check the file.
-   (sha1sum, md5sum). */
-static int
-tool_avail (gpgme_hash_algo_t mdalgo)
-{
-    if (mdalgo == GPGME_MD_SHA1 || mdalgo == GPGME_MD_MD5)
-	return 1;
-    return 0;
-}
-
-
-/* Sorting callback. */
-static int CALLBACK
-sort_cb (LPARAM first, LPARAM second, LPARAM param)
-{
-    hashlist_model_t a, b;
-    int sortby = (int)param;
-    int cmpres = 0;
-
-    a = (hashlist_model_t)first;
-    b = (hashlist_model_t)second;
-    if (sortby == COL_NAME)
-	cmpres = stricmp (a->name, b->name);
-    else
-	cmpres = memcmp (a->md, b->md, a->mdlen);
-    return cmpres;
-}
-
-
-/* Dialog box procedure to show and calculate file digests. */
-BOOL CALLBACK
-mdsum_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
-    static listview_ctrl_t lv;
-    static struct md_file_s *md;
-    static hashlist_model_t hm = NULL;
-    struct listview_column_s cols[] = {
-        {0, 264, (char *)_("Digest")},
-        {1, 160, (char *)_("Name")},
-        {0, 0, 0}
-    };
-    gpgme_data_t sumlist = NULL;
-    const char *name, *algname;
-    char fname[MAX_PATH+64], mdasc[MAX_HASHSIZE*4];
-    int i;
-
-    switch (msg) {
-    case WM_INITDIALOG:
-	md = (md_file_s *)lparam;
-	if (!md)
-	    BUG (NULL);
-	listview_new (&lv, GetDlgItem (dlg, IDC_MDSUM_LIST));
-	for (i = 0; i < cols[i].width; i++)
-	    listview_add_column (lv, &cols[i]);
-	hash_selected_files (md, lv, &hm);
-	SetDlgItemText (dlg, IDC_MDSUM_COPY, _("&Save..."));
-	SetDlgItemText (dlg, IDOK, _("&Close"));
-	SetDlgItemText (dlg, IDC_MDSUM_TOCLIP, _("Save to clipboard"));
-	SetWindowText (dlg, _("Print Message Digest"));
-	SetForegroundWindow (dlg);
-	break;
-
-    case WM_DESTROY:
-	if (lv) {
-	    listview_release (lv);
-	    lv = NULL;
-	}
-	if (hm) {
-	    hashmodel_release (hm);
-	    hm = NULL;
-	}
-	break;
-
-    case WM_NOTIFY:
-	if (((NMHDR *)lparam)->code == LVN_COLUMNCLICK) {
-	    NMLISTVIEW *nft = (LPNMLISTVIEW) lparam;
-	    ListView_SortItems (lv->ctrl, sort_cb, nft->iSubItem);
-	}
-	break;
-
-    case WM_COMMAND:
-	switch (LOWORD (wparam)) {
-	case IDOK:
-	    EndDialog (dlg, TRUE);
-	    break;
-
-	case IDCANCEL:
-	    EndDialog (dlg, FALSE);
-	    break;
-
-	case IDC_MDSUM_COPY:
-	    algname = id2algo ((gpgme_hash_algo_t)md->mdalgo);
-	    if (gpgme_data_new (&sumlist))
-		BUG(0);
-	    if (!tool_avail ((gpgme_hash_algo_t)md->mdalgo)) {
-		const char *s;
-
-		s = "#warning '";
-		gpgme_data_write (sumlist, s, strlen (s));
-		gpgme_data_write (sumlist, algname, strlen (algname));
-		s = " ' sum is not yet available\r\n";
-		gpgme_data_write (sumlist, s, strlen (s));
-	    }
-	    for (i = 0; i < listview_count_items (lv, 0); i++) {
-		listview_get_item_text (lv, i, COL_MD, mdasc, DIM (mdasc)-1);
-		listview_get_item_text (lv, i, COL_NAME, fname, DIM (fname)-1);
-		
-		gpgme_data_write (sumlist, mdasc, strlen (mdasc));
-		gpgme_data_write (sumlist, " ", 1);
-		gpgme_data_write (sumlist, fname, strlen (fname));
-		gpgme_data_write (sumlist, "\r\n", 2);
-	    }
-	    if (IsDlgButtonChecked (dlg, IDC_MDSUM_TOCLIP)) {
-		gpg_data_release_to_clipboard (sumlist, 0);
-		break;
-	    }
-	    _snprintf (fname, DIM (fname)-1, "%s_sums.txt", algname);
-	    name = get_filesave_dlg (dlg, _("Select File to Save Checksums"), 
-				     NULL, fname);
-	    if (name && *name) {
-		gpgme_error_t err;
-
-		err = gpg_data_release_and_set_file (sumlist, name);
-		if (!err) {
-		    log_box (_("File Manager"), MB_OK, 
-			     _("Checksums successfully saved in '%s'"), name);
-		    sumlist = NULL;
-		}
-		else
-		    msg_box (dlg, gpgme_strerror (err), _("File Manager"), MB_ERR);
-	    }
-	    if (sumlist)
-		gpgme_data_release (sumlist);
-	    break;
-	}
-	break;
-    }
-    return FALSE;
-}
-#endif

Modified: trunk/Src/wptPassphraseCB.cpp
===================================================================
--- trunk/Src/wptPassphraseCB.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptPassphraseCB.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -194,10 +194,7 @@
 		else {
 		    char *p = new char[n+2];
 		    SafeGetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), p, n+1);
-		    if (emulate_utf8_bug)
-			c->pwd = native_to_utf8 (p);
-		    else
-			c->pwd = m_strdup (p);
+		    c->pwd = m_strdup (p);
 		    sfree_if_alloc (p);
 		}
 		if (c->gpg != NULL) {

Modified: trunk/Src/wptPassphraseDlg.cpp
===================================================================
--- trunk/Src/wptPassphraseDlg.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptPassphraseDlg.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -238,10 +238,8 @@
 	*ret_cancel = 1;
 	return NULL;
     }
-    if (emulate_utf8_bug)
-	p = native_to_utf8 (pass.pwd);
-    else
-	p = m_strdup (pass.pwd);
+
+    p = m_strdup (pass.pwd);
     wipememory (pass.pwd, sizeof (pass.pwd));
     return p;
 }
@@ -271,10 +269,7 @@
 	*ret_cancel = 1;
 	return NULL;
     }
-    if (emulate_utf8_bug)
-	p = native_to_utf8 (pass.pwd);
-    else
-	p = m_strdup (pass.pwd);
+    p = m_strdup (pass.pwd);
     wipememory (pass.pwd, sizeof (pass.pwd));
     return p;
 }

Modified: trunk/Src/wptUtil.cpp
===================================================================
--- trunk/Src/wptUtil.cpp	2011-11-27 12:45:44 UTC (rev 339)
+++ trunk/Src/wptUtil.cpp	2011-11-27 13:15:07 UTC (rev 340)
@@ -153,36 +153,8 @@
 }
 
 
-/* Remove %AB sequences from the input buffer @in
-   and store the raw data in @out. */
-void
-unhexify_buffer (const char *in, char **r_out)
-{
-    char temp[3], *out;
-    size_t len, pos, i=0;
 
-    len = strlen (in);
-    out = new char[len+1];
-    if (!out)
-	BUG (0);
-    memset (out, 0, len+1);
-    for (pos = 0; pos < len; pos++) {
-	if (in[pos] == '%' && in[pos+1] == '%')
-	    out[i++] = '%';
-	else if (in[pos] == '%') {
-	    temp[0] = in[++pos];
-	    temp[1] = in[++pos];
-	    temp[2] = 0;
-	    out[i++] = (char)strtoul (temp, NULL, 16);
-	}
-	else
-	    out[i++] = in[pos];
-    }
-    out[i] = 0;
-    *r_out = out;
-}
 
-
 /* Safe strdup version (C++ version). */
 char*
 m_strdup (const char *str)



More information about the Winpt-commits mailing list