/[winpt]/trunk/Src/wptFileManager.cpp
ViewVC logotype

Diff of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 32 by twoaday, Mon Oct 24 08:03:48 2005 UTC revision 256 by twoaday, Sat Aug 5 10:31:06 2006 UTC
# Line 1  Line 1 
1  /* wptFileManager.cpp - File Manager routines  /* wptFileManager.cpp - File Manager routines
2   *      Copyright (C) 2001-2005 Timo Schulz   *      Copyright (C) 2001-2006 Timo Schulz
3   *      Copyright (C) 2005 g10 Code GmbH   *      Copyright (C) 2005 g10 Code GmbH
4   *   *
5   * This file is part of WinPT.   * This file is part of WinPT.
6   *   *
7   * WinPT is free software; you can redistribute it and/or   * WinPT is free software; you can redistribute it and/or
8   * modify it under the terms of the GNU General Public License   * modify it under the terms of the GNU General Public License
9   * as published by the Free Software Foundation; either version 2   * as published by the Free Software Foundation; either version 2
10   * of the License, or (at your option) any later version.   * of the License, or (at your option) any later version.
11   *     *  
12   * WinPT is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * General Public License for more details.   * General Public License for more details.
16   *   *
17   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
18   * along with WinPT; if not, write to the Free Software Foundation,   * along with WinPT; if not, write to the Free Software Foundation,
19   * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20   */   */
21  /* TODO:  
22   *    check_armor_type: we should check the whole file and not only the first line!  #ifdef HAVE_CONFIG_H
23   */  #include <config.h>
24    #endif
25  #include <sys/types.h>  
26  #include <windows.h>  #include <sys/types.h>
27  #include <commdlg.h>  #include <windows.h>
28  #include <io.h>  #include <commdlg.h>
29    #include <io.h>
30  #include "../resource.h"  #include <stdio.h>
31  #include "wptTypes.h"  
32  #include "wptGPG.h"  #include "resource.h"
33  #include "wptAgent.h"  #include "wptTypes.h"
34  #include "wptCommonCtl.h"  #include "wptGPG.h"
35  #include "wptContext.h"  #include "wptAgent.h"
36  #include "wptErrors.h"  #include "wptCommonCtl.h"
37  #include "wptKeylist.h"  #include "wptContext.h"
38  #include "wptFileManager.h"  #include "wptErrors.h"
39  #include "wptNLS.h"  #include "wptKeylist.h"
40  #include "wptW32API.h"  #include "wptFileManager.h"
41  #include "wptVersion.h"  #include "wptNLS.h"
42  #include "wptDlgs.h"  #include "wptW32API.h"
43  #include "wptGPGZIP.h"  #include "wptVersion.h"
44  #include "wptUTF8.h"  #include "wptDlgs.h"
45  #include "wptRegistry.h"  #include "wptZIP.h"
46  #include "wptImport.h"  #include "wptUTF8.h"
47    #include "wptRegistry.h"
48  #include "openpgp.h"  #include "wptImport.h"
49    #include "wptCrypto.h"
50  void progress_cleanup (progress_filter_s *pfx);  #include "wptKeyManager.h"
51  BOOL CALLBACK file_secdel_confirm_dlg_proc (HWND dlg, UINT msg,  #include "openpgp.h"
52                                              WPARAM wparam, LPARAM lparam);  
53  char* gpg_keylist_to_pattern (gpgme_key_t *rset, int n);  
54  gpgme_error_t sym_passphrase_cb (void *hook, const char *hint, const char *pass_inf,  void progress_cleanup (progress_filter_s *pfx);
55                                   int prev_was_bad, int fd);  BOOL CALLBACK file_secdel_confirm_dlg_proc (HWND dlg, UINT msg,
56                                                WPARAM wparam, LPARAM lparam);
57  /*-- wptFileVerifyDlg.cpp --*/  char* gpg_keylist_to_pattern (gpgme_key_t *rset, int n);
58  void file_verify_add_state (file_sig_ctx_t c);  gpgme_error_t sym_passphrase_cb (void *hook, const char *hint, const char *pass_inf,
59  void file_verify_use_event (void);                                   int prev_was_bad, int fd);
60  void file_verify_wait (void);  void verify_show_signature_state (gpgme_signature_t sig);
61    
62  static const char * mm_files[] = {".mov", ".avi", ".mpg", ".mpeg",  
63                                    ".mp3", ".wav", ".mid", ".wma",  static const char *mm_files[] = {".mov", ".avi", ".mpg", ".mpeg",
64                                    ".gif", ".jpg", ".png", ".jpeg", ".dib", 0};                                    ".mp3", ".wav", ".mid", ".wma",
65                                      ".gif", ".jpg", ".png", ".jpeg", ".dib", 0};
66    
67  /* Check if the drive given by @fname is a floppy disc.  
68     Return value: 1 for success. */  /* Add a new file to the model @fm. */
69  static int  static void
70  is_floppy_disc (const char * fname)  fm_model_add_file (fm_model_t *fm, fm_model_t file)
71  {  {
72      char drv[32] = {0};      fm_model_t m;
73      int i=0;  
74        if (!*fm) {
75      if (!strstr (fname, ":\\"))          *fm = file;
76          return 0;          return;
77        }
78      while (fname && *fname && *fname != '\\')      for (m = *fm; m->next; m = m->next)
79          drv[i++] = *fname++;          ;
80      drv[i++] = '\\';      m->next = file;
81      drv[i++] = '\0';  }
82      i = GetDriveType (drv);  
83      if (i == DRIVE_REMOVABLE)  
84          return -1;  /* Search for a file model based on the name @name. */
85      return 0;  static fm_model_t
86  }  fm_model_find_file (fm_model_t fm, const char *name)
87    {
88        fm_model_t m;
89  /* Ask the user to overwrite file @fname.  
90     Return value: 0 for cancel. */      for (m=fm; m; m=m->next) {
91  int          if (!stricmp (m->name, name))
92  overwrite_file (const char *fname)              return m;
93  {      }
94      int id;      return NULL;
95    }
96      if (file_exist_check (fname))  
97          return -1;  
98      id = log_box (_("File Manager"), MB_YESNO,  /* Check if the drive given by @fname is a floppy disc.
99                    _("\"%s\" already exists.\n"     Return value: -1 for success. */
100                      "Replace existing file?"), fname);  static int
101      return id == IDNO ? 0 : -1;  is_floppy_disc (const char *fname)
102  }  {
103        char drv[32] = {0};    
104        int max = sizeof (drv)-1;
105  /* Removes 'critical' attributes from the file @fname.      int i=0;
106     If @force is 1, the user is not asked for permission. */  
107  static void      if (!strstr (fname, ":\\"))
108  remove_crit_file_attrs (const char *fname, int force)          return 0;
109  {  
110      u32 f_attr;      while (fname && *fname && *fname != '\\' && i < max)
111      int id;          drv[i++] = *fname++;
112        drv[i++] = '\\';
113      if (file_exist_check (fname))      drv[i++] = '\0';
114          return; /* Does not exist */      i = GetDriveType (drv);
115                if (i == DRIVE_REMOVABLE)
116      f_attr = GetFileAttributes (fname);          return -1;
117      if ((f_attr & FILE_ATTRIBUTE_READONLY) && force)      return 0;
118          SetFileAttributes (fname, FILE_ATTRIBUTE_NORMAL);  }
119      else if (f_attr & FILE_ATTRIBUTE_READONLY) {  
120          id = log_box (_("File Manager"), MB_YESNO,            
121                        _("\"%s\" has read-only attribute.\n"  /* Ask the user to overwrite file @fname.
122                          "Set attribute to normal?"), fname);     Return value: 0 for cancel. */
123          if (id == IDYES)  static int
124              SetFileAttributes (fname, FILE_ATTRIBUTE_NORMAL);  overwrite_file (const char *fname)
125      }  {
126  }      int id;
127    
128        if (file_exist_check (fname))
129  static int inline          return -1;
130  is_directory (const char *fname)      id = log_box (_("File Manager"), MB_YESNO,
131  {                        _("\"%s\" already exists.\n"
132      return GetFileAttributes (fname) & FILE_ATTRIBUTE_DIRECTORY? 1 : 0;                      "Replace existing file?"), fname);
133  }      return id == IDNO ? 0 : -1;
134    }
135    
136  static int inline  
137  is_openpgp_ext (const char *name)  /* Removes 'critical' attributes from the file @fname.
138  {     If @force is 1, the user is not asked for permission. */
139      if (strstr (name, ".gpg") || strstr (name, ".asc")  void
140          || strstr (name, ".sig") || strstr (name, ".pgp"))  remove_crit_file_attrs (const char *fname, int force)
141          return -1;  {
142      return 0;      DWORD fattr;
143  }      int id = 0;
144    
145        if (file_exist_check (fname))
146  static int          return; /* Does not exist */
147  is_multi_media (const char * name)          
148  {          fattr = GetFileAttributes (fname);
149      const char * val;      if ((fattr & FILE_ATTRIBUTE_READONLY) && force)
150      char * p;          id = IDYES;
151      int i;      else if (fattr & FILE_ATTRIBUTE_READONLY)
152      int ans=0;          id = log_box (_("File Manager"), MB_YESNO,          
153                          _("\"%s\" has read-only attribute.\n"
154      i = get_reg_winpt_single (CFG_NOZIP_MMEDIA);                          "Set attribute to normal?"), fname);
155      if (i == -1)      if (id == IDYES) {
156      {          if (!SetFileAttributes (fname, FILE_ATTRIBUTE_NORMAL))
157          ans = msg_box (NULL, _("Multi-Media files are already compressed, GPG would compress\n"              msg_box (NULL, _("Could not reset file attribute to normal."),
158                                 "them anyway and this costs a lot of time.\n"                       _("File Manager"), MB_ERR);
159                                 "It is possible to disable compression for these files.\n"      }
160                                 "Do you want to disable it?"),  }
161                                 _("File Manager"), MB_YESNO|MB_INFO);  
162          set_reg_winpt_single (CFG_NOZIP_MMEDIA, ans == IDYES? 1 : 0);  
163          if (ans == IDNO)  /* Return 1 if the given path @fname is a directory, 0 otherwise. */
164              return 0;  static int
165      }  is_directory (const char *fname)
166      else if (i == 0)  {
167          return 0;      return GetFileAttributes (fname) & FILE_ATTRIBUTE_DIRECTORY? 1 : 0;
168    }
169      p = strrchr (name, '.');  
170      if (!p)  
171          return 0;  /* Return -1 if the given name @name is a valid GPG extension. */
172      for (i=0; (val = mm_files[i]); i++)  int
173      {  is_openpgp_ext (const char *name)
174          if (!stricmp (p, val))  {
175              return -1;      if (stristr (name, ".gpg") ||
176      }          stristr (name, ".asc") ||
177      return 0;          stristr (name, ".sig") ||
178  }          stristr (name, ".pgp"))
179            return -1;
180        return 0;
181  const char*  }
182  file_get_extension (gpgme_ctx_t ctx, gpgme_sig_mode_t sigmode)  
183  {  
184      int use_armor = gpgme_get_armor (ctx);  static int
185    is_multi_media (const char * name)
186      if (use_armor || sigmode == GPGME_SIG_MODE_CLEAR)  {    
187          return ".asc";      const char * val;
188      if (!use_armor && sigmode == GPGME_SIG_MODE_DETACH)      char * p;
189          return ".sig";      int i;
190      return ".gpg";      int ans=0;
191  }  
192        i = get_reg_winpt_single (CFG_NOZIP_MMEDIA);
193        if (i == -1)
194  char*      {
195  fm_quote_file (const char * name)          ans = msg_box (NULL, _("Multi-Media files are already compressed, GPG would compress\n"
196  {                                 "them anyway and this takes a lot of time.\n"
197      char * p;                                 "It is possible to disable compression for these files.\n"
198      size_t len = strlen (name) + 8;                                 "Do you want to disable it?"),
199                                   _("File Manager"), MB_YESNO|MB_INFO);
200      if (*name == '"')          set_reg_winpt_single (CFG_NOZIP_MMEDIA, ans == IDYES? 1 : 0);
201          return m_strdup (name); /* avoid double quotes */          if (ans == IDNO)
202      p = new char[len + 1];              return 0;
203      if (!p)      }
204          BUG (0);      else if (i == 0)
205      _snprintf (p, len, "\"%s\"", name);          return 0;
206    
207      return p;      p = strrchr (name, '.');
208  } /* fm_quote_file */      if (!p)
209            return 0;
210        for (i=0; (val = mm_files[i]); i++) {
211            if (!stricmp (p, val))
212  /* Check the armor type of the file @fname and return              return -1;
213     a string representation of it. */      }
214  static const char *      return 0;
215  fm_check_armor_type (const char *fname, int *r_type)  }
216  {  
217      FILE * fp;  
218      char header[768], * p;  /* Return a GPG file extension which depends on the operation
219           mode in @ctx and the sig mode @sigmode. */
220      if (r_type)  const char*
221          *r_type = PGP_NONE;  file_get_extension (gpgme_ctx_t ctx, gpgme_sig_mode_t sigmode)
222      fp = fopen (fname, "rb");  {
223      if (!fp)      int use_armor = gpgme_get_armor (ctx);
224          return "UNKNOWN";  
225      p = fgets (header, sizeof (header) - 1, fp);      if (use_armor || sigmode == GPGME_SIG_MODE_CLEAR)
226      fclose (fp);          return ".asc";
227      if (!p)      if (!use_armor && sigmode == GPGME_SIG_MODE_DETACH)
228          return "UNKNOWN";          return ".sig";
229        return reg_prefs.default_ext == 1? ".pgp" : ".gpg";
230      if (strncmp (header, "-----", 5))  }
231          goto leave;  
232      if (strstr( header, "BEGIN PGP PUBLIC KEY" )) {  
233          if (r_type) *r_type = PGP_PUBKEY;  /* Quote a file to avoid shell problems with spaces in the files. */
234          return "PUBKEY";  char*
235      }  fm_quote_file (const char * name)
236      else if (strstr (header, "BEGIN PGP PRIVATE KEY") ||  {
237               strstr (header, "BEGIN PGP SECRET KEY")) {      char * p;
238          if (r_type) *r_type = PGP_SECKEY;      size_t len = strlen (name) + 8;
239          return "SECKEY";  
240      }      if (*name == '"')
241      else if (strstr (header, "BEGIN PGP MESSAGE")) {          return m_strdup (name); /* avoid double quotes */
242          if (r_type) *r_type = PGP_MESSAGE;      p = new char[len + 1];
243          return "ENCRYPTED";      if (!p)
244      }          BUG (0);
245      else if (strstr( header, "BEGIN PGP SIGNED MESSAGE")) {      _snprintf (p, len, "\"%s\"", name);
246          if (r_type) *r_type = PGP_CLEARSIG;  
247          return "SIGNED-CLEAR";      return p;
248      }  }
249      else if (strstr(header, "BEGIN PGP SIGNATURE")) {  
250          if (r_type) *r_type = PGP_SIG;  
251          return "SIGNED-DETACH";  
252      }  /* Check the armor type of the file @fname and return
253       a string representation of it. */
254  leave:  static const char*
255      return "UNKNOWN";  fm_check_armor_type (const char *fname, int *r_type)
256  }  {
257        FILE *fp;
258        char header[768], *p;
259  /* Extract file type from @fname. If @r_type is valid,      
260     it contains the PGP type on success. */      if (r_type)
261  static const char *          *r_type = PGP_NONE;
262  fm_get_file_type (const char *fname, int *r_type)      fp = fopen (fname, "rb");
263  {              if (!fp)
264      gpg_iobuf_t inp;          return "UNKNOWN";
265      armor_filter_context_t afx;      p = fgets (header, sizeof (header) - 1, fp);
266      PACKET * pkt = (PACKET *)calloc (1, sizeof *pkt);      fclose (fp);
267      int i = 0, rc = 0;      if (!p)
268      const char *s = NULL;          return "UNKNOWN";
269    
270      if (r_type)      if (strncmp (header, "-----", 5))
271          *r_type = PGP_NONE;          goto leave;
272      if (!fname) {      if (strstr( header, "BEGIN PGP PUBLIC KEY" )) {
273          safe_free (pkt);          if (r_type) *r_type = PGP_PUBKEY;
274          return NULL;          return "PUBKEY";
275      }      }
276        else if (strstr (header, "BEGIN PGP PRIVATE KEY") ||
277      if (is_floppy_disc (fname))               strstr (header, "BEGIN PGP SECRET KEY")) {
278          return fm_check_armor_type (fname, r_type);          if (r_type) *r_type = PGP_SECKEY;
279            return "SECKEY";
280      inp = gpg_iobuf_open (fname);      }
281      if (!inp) {      else if (strstr (header, "BEGIN PGP MESSAGE")) {
282          const char *s = winpt_strerror (WPTERR_FILE_OPEN);          if (r_type) *r_type = PGP_MESSAGE;
283          log_box( _("File Manager"), MB_ERR, "\"%s\": %s", fname, s );          return "ENCRYPTED";
284          safe_free( pkt );      }
285          return NULL;      else if (strstr( header, "BEGIN PGP SIGNED MESSAGE")) {
286      }          if (r_type) *r_type = PGP_CLEARSIG;
287      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */          return "SIGNED-CLEAR";
288      if (gpg_iobuf_get_filelength (inp) > 32000000 /* 32MB */      }
289          && !is_openpgp_ext (fname)) {      else if (strstr(header, "BEGIN PGP SIGNATURE")) {
290          gpg_iobuf_close (inp);          if (r_type) *r_type = PGP_SIG;
291          return "UNKNOWN";          return "SIGNED-DETACH";
292      }      }
293    
294      if (gpg_use_armor_filter(inp)) {  leave:
295          memset (&afx, 0, sizeof (afx));      return "UNKNOWN";
296          gpg_iobuf_push_filter (inp, gpg_armor_filter, &afx);  }
297      }  
298        
299      gpg_init_packet (pkt);  /* Extract file type from @fname. If @r_type is valid,
300      while (!(rc = gpg_parse_packet (inp, pkt))) {     it contains the PGP type on success. */
301          switch (pkt->pkttype) {  static const char*
302          case PKT_PUBKEY_ENC:  fm_get_file_type (const char *fname, int *r_type)
303              s = "ENCRYPTED";rc = -2;  {        
304              if (r_type) *r_type = PGP_MESSAGE;      gpg_iobuf_t inp;
305              break;      armor_filter_context_t afx;
306          case PKT_SYMKEY_ENC:      PACKET *pkt;
307          case PKT_ENCRYPTED:      const char *s = NULL;
308              s = "SYMKEYENC";rc = -2;      size_t count = 0, compr = 0;
309              if (r_type) *r_type = PGP_MESSAGE;      int rc = 0;
310              break;  
311          case PKT_SIGNATURE:      if (r_type)
312          case PKT_ONEPASS_SIG:          *r_type = PGP_NONE;
313              s = "SIGNED";   rc = -2;      if (!fname) {
314              if (r_type) *r_type = PGP_SIG;          log_debug ("fm_get_file_type: !fname\r\n");
315              break;          return NULL;
316          case PKT_PUBLIC_KEY:      }
317              s = "PUBKEY";   rc = -2;  
318              if (r_type) *r_type = PGP_PUBKEY;      if (is_floppy_disc (fname))
319              break;          return fm_check_armor_type (fname, r_type);
320          case PKT_SECRET_KEY:  
321              s = "SECKEY";   rc = -2;      inp = gpg_iobuf_open (fname);
322              if (r_type) *r_type = PGP_SECKEY;      if (!inp) {
323              break;          const char *err = winpt_strerror (WPTERR_FILE_OPEN);
324          }          log_box (_("File Manager"), MB_ERR, "\"%s\": %s", fname, err);
325          gpg_free_packet (pkt);          return NULL;
326          gpg_init_packet (pkt);      }
327          if (rc == -2)      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
328              break; /* found */      if (gpg_iobuf_get_filelength (inp) > 32000000 /* 32MB */
329      }          && !is_openpgp_ext (fname)) {
330      safe_free (pkt);          gpg_iobuf_close (inp);
331      gpg_iobuf_close (inp);          return "UNKNOWN";
332      if (!s)      }
333          s = fm_check_armor_type (fname, r_type);  
334      if (!s)      if (gpg_use_armor_filter(inp)) {
335          s = "UNKNOWN";          memset (&afx, 0, sizeof (afx));
336      if (!strcmp (s, "SIGNED")          gpg_iobuf_push_filter (inp, gpg_armor_filter, &afx);
337          && strcmp (fm_check_armor_type (fname, r_type), "SIGNED-CLEAR ")) {      }
338          if (r_type) *r_type = PGP_SIG;      pkt = (PACKET *)calloc (1, sizeof *pkt);
339          s = "SIGNED-DETACH";      if (!pkt)
340      }          BUG (NULL);
341      return s;      gpg_init_packet (pkt);
342  }      while (!(rc = gpg_parse_packet (inp, pkt))) {
343            switch (pkt->pkttype) {
344            case PKT_PUBKEY_ENC:
345  int              s = "ENCRYPTED";rc = -2;
346  fm_build (listview_ctrl_t *lv, HWND ctrl)              if (r_type) *r_type = PGP_MESSAGE;
347  {              break;
348      int i, rc = 0;          case PKT_SYMKEY_ENC:
349      listview_ctrl_t c;          case PKT_ENCRYPTED:
350      struct listview_column_s col[] =              s = "SYMKEYENC";rc = -2;
351      {              if (r_type) *r_type = PGP_MESSAGE;
352          {0,  80, (char *)_("Status") },              break;
353          {1, 256, (char *)_("Name") },          case PKT_SIGNATURE:
354          {2, 128, (char *)_("Operation") },          case PKT_ONEPASS_SIG:
355          {0,   0, NULL }              s = "SIGNED";   rc = -2;
356      };              if (r_type) *r_type = PGP_SIG;
357                        break;
358      rc = listview_new( &c );          case PKT_PUBLIC_KEY:
359      if( rc )              s = "PUBKEY";   rc = -2;
360          BUG( NULL );              if (r_type) *r_type = PGP_PUBKEY;
361      c->ctrl = ctrl;              break;
362      for ( i = 0; col[i].width; i++ )          case PKT_SECRET_KEY:
363          listview_add_column( c, &col[i] );              s = "SECKEY";   rc = -2;
364      listview_set_ext_style( c );              if (r_type) *r_type = PGP_SECKEY;
365      if( lv )              break;
366          *lv = c;  
367      return 0;          case PKT_COMPRESSED:
368  } /* fm_build */              /* If we only find 1 packet and it is compressed,
369                   we assume a compress one-pass signature. */
370                if (count != 0)
371  void                  break;
372  fm_delete( listview_ctrl_t lv )              s = "SIGNED";   rc = -2;
373  {              compr = 1;
374      if( lv ) {              break;
375          listview_release( lv );  
376      }          default:
377  } /* fm_delete */              break;
378            }
379            count++;
380  int          gpg_free_packet (pkt);
381  fm_state_new (fm_state_t * ctx)          gpg_init_packet (pkt);
382  {          if (rc == -2)
383      gpgme_error_t rc;              break; /* found */
384      fm_state_s * c;      }
385        safe_free (pkt);
386      c = new fm_state_s;      gpg_iobuf_close (inp);
387      if (!c)      if (!s)
388          BUG (0);          s = fm_check_armor_type (fname, r_type);
389      memset (c, 0, sizeof * c);      if (!s)
390      rc = gpgme_new (&c->ctx);          s = "UNKNOWN";
391      if (rc)      if (!strcmp (s, "SIGNED") && !compr
392          BUG (0);          && strcmp (fm_check_armor_type (fname, r_type), "SIGNED-CLEAR ")) {
393      /* XXX rc = gpgme_recipients_new (&c->recp);*/          if (r_type) *r_type = PGP_SIG;
394      /* XXX gpgme_set_comment (c->ctx, "Generated by WinPT "PGM_VERSION); */          s = "SIGNED-DETACH";
395      *ctx = c;      }
396      return 0;      return s;
397  } /* fm_state_new */  }
398    
399    
400  /* Release the FM state handle @c. */  /* Build the File Manager dialog context. */
401  void  void
402  fm_state_release (fm_state_t c)  fm_build (fm_info_t *r_fm, HWND ctrl)
403  {  {
404      if (!c)      int i;
405          return;      fm_info_t fm;
406      if (c->recp)      struct listview_column_s col[] = {
407          free (c->recp);          {0,  80, (char *)_("Status") },
408      if (c->ctx) {          {1, 256, (char *)_("Name") },
409          gpgme_release (c->ctx);          {2, 128, (char *)_("Operation") },
410          c->ctx = NULL;            {0,   0, NULL}  
411      }      };
412      free_if_alloc (c->opaque);  
413      free_if_alloc (c->output);      fm = new fm_info_s;
414      delete c; c = NULL;          memset (fm, 0, sizeof *fm);
415  }      listview_new (&fm->lv, ctrl);
416        for (i = 0; col[i].width; i++)
417  static int          listview_add_column (fm->lv, &col[i]);
418  fm_check_for_entry( listview_ctrl_t lv, const char *file )      listview_set_ext_style (fm->lv);
419  {      fm->model = NULL; /*init*/
420      char name[512];      *r_fm = fm;
421      int i;  }
422    
423      memset (name, 0, sizeof (name));  
424      for( i = 0; i < listview_count_items( lv, 0 ); i++ )  /* Release the file model. */
425      {  static void
426          listview_get_item_text( lv, i, 1, name, sizeof (name) - 1 );  fm_model_release (fm_model_t mod)
427          if( !strcmp( name, file ) )  {
428              return 1; /* found */            fm_model_t m;
429      }  
430        while (mod) {
431      return 0;          m = mod->next;
432  } /* fm_check_for_entry */          free_if_alloc (mod->name);
433            free_if_alloc (mod->op);
434            free_if_alloc (mod->status);
435  static int          free_if_alloc (mod);
436  fm_set_ftype (listview_ctrl_t lv, const char *name)          mod = m;
437  {      }
438      const char *type;  }
439      int rc;  
440    
441      rc = fm_check_for_entry (lv, name);  /* Reset the File Manager info context. */
442      if (rc)  void
443          return 0;  fm_reset (fm_info_t fm)
444      type = fm_get_file_type (name, NULL);  {
445      if (!type || !strcmp (type, "UNKNOWN"))      listview_del_all_items (fm->lv);
446          type = gnupg_check_file_ext (name, NULL);      fm_model_release (fm->model);
447      rc = listview_add_item (lv, " ");      fm->model = NULL;
448      if (rc)  }
449          return -1;  
450      listview_add_sub_item (lv, 0, 0, type);  
451      listview_add_sub_item (lv, 0, 1, name);  /* Release the File Manager dialog context. */
452      return 0;  void
453  }  fm_delete (fm_info_t fm)
454    {
455        if (!fm)
456  static int          return;
457  fm_add_dir_files (listview_ctrl_t lv, char *path)      if (fm->menu)
458  {          DestroyMenu (fm->menu);
459      struct _finddata_t fd;      listview_release (fm->lv);
460      char * p;      fm_model_release (fm->model);
461      long hd;      free_if_alloc (fm);  
462    }
463      strcat (path, "\\*");  
464      hd = _findfirst (path, &fd);  
465      do {  int
466          p = new char [(strlen (path) + strlen (fd.name))+1];  fm_state_new (fm_state_t * ctx)
467          if (!p)  {
468              BUG (0);      fm_state_s *c;
469          memcpy (p, path, strlen (path)-1);  
470          p[strlen (path)-1] = 0;      c = new fm_state_s;
471          strcat (p, fd.name);      if (!c)
472          if (!is_directory (p))          BUG (0);
473              fm_set_ftype (lv, p);      memset (c, 0, sizeof *c);
474          free_if_alloc (p);      if (gpgme_new (&c->ctx))
475                    BUG (0);
476      } while (_findnext (hd, &fd) == 0);      *ctx = c;
477      _findclose (hd);      return 0;
478      return 0;  }
479  }  
480    
481    /* Release the FM state handle @c. */
482  /* Add the drag & drop files from @dd_files to the  void
483     list view control @lv. */  fm_state_release (fm_state_t c)
484  int  {
485  fm_add_dropped_files (listview_ctrl_t lv, HDROP dd_files)      if (!c)
486  {          return;
487      char name[384+4];      if (c->ctx) {
488      int nfiles, rc, i;          gpgme_release (c->ctx);
489                c->ctx = NULL;  
490      memset (name, 0, sizeof (name));      }
491      nfiles = DragQueryFile (dd_files, 0xFFFFFFFF, NULL, 0);      safe_free (c->recp);
492      for (i = 0;  i < nfiles; i++) {      free_if_alloc (c->opaque);
493          DragQueryFile (dd_files, i, name, sizeof (name) -1);      free_if_alloc (c->output);
494          if (is_directory (name))      delete c;
495              rc = fm_add_dir_files (lv, name);  }
496          else  
497              rc = fm_set_ftype (lv, name);  
498          if (rc == -1)  /* Check if file @file is already in the list (view). */
499              break;  static int
500      }  fm_check_for_entry (listview_ctrl_t lv, const char *file)
501      return rc;  {
502  }      char name[MAX_PATH+128];
503        int i;
504    
505  int      memset (name, 0, sizeof (name));
506  fm_add_opened_files (listview_ctrl_t lv, HWND dlg)      for (i = 0; i < listview_count_items (lv, 0); i++) {
507  {          listview_get_item_text (lv, i, FM_COL_NAME, name, sizeof (name) - 1);
508      OPENFILENAME open;          if (!strcmp (name, file))
509      const char *type;                return 1; /* found */      
510      char file[512] = "";      }
511      int rc;  
512            return 0;
513      /* XXX: support to add multiple files. */  }
514      memset (&open, 0, sizeof (open));  
515      open.lStructSize = sizeof (OPENFILENAME);  
516      open.hInstance = glob_hinst;  static int
517      open.lpstrTitle = _("File Open");  fm_set_ftype (listview_ctrl_t lv, fm_model_t *fm, const char *name)
518      open.lpstrFilter = _("All Files (*.*)\0*.*\0\0");  {
519      open.hwndOwner = dlg;      fm_model_t m;
520      open.lpstrFile = file;      const char *type;
521      open.nMaxFile = sizeof (file) - 1;      int rc;
522      open.Flags = 0;  
523            rc = fm_check_for_entry (lv, name);
524      if (GetOpenFileName (&open)) {      if (rc)
525          type = fm_get_file_type (open.lpstrFile, NULL);          return 0;
526          if (!type)      m = new fm_model_s;
527              return WPTERR_FILE_OPEN;      memset (m, 0, sizeof *m);
528          if (!strcmp (type, "UNKNOWN"))      type = fm_get_file_type (name, NULL);
529              type = gnupg_check_file_ext (open.lpstrFile, NULL);      if (!type || !strcmp (type, "UNKNOWN"))
530          rc = listview_add_item (lv, "");          type = gnupg_check_file_ext (name, NULL);
531          if (!rc) {      listview_add_item2 (lv, " ", (void*)m);
532              listview_add_sub_item (lv, 0, 0, type);      listview_add_sub_item (lv, 0, FM_COL_STAT, type);
533              listview_add_sub_item (lv, 0, 1, open.lpstrFile);      listview_add_sub_item (lv, 0, FM_COL_NAME, name);
534          }      m->name = m_strdup (name);
535      }      m->status = m_strdup (type);
536            m->op = NULL;
537      return rc;      fm_model_add_file (fm, m);
538  }      return 0;
539    }
540    
541  int  
542  fm_assume_onepass_sig (const char * fname)  /* Add all files from the directory @path to the list view @lv. */
543  {  static int
544      gpgme_data_t dat;  fm_add_dir_files (listview_ctrl_t lv, fm_model_t *fm, char *path)
545      armor_filter_context_t afx;  {
546      gpg_iobuf_t fp;      struct _finddata_t fd;
547      PACKET * pkt = (PACKET *)calloc (1, sizeof *pkt);      char *p;
548      int check = 0;      long hd;
549    
550      if (!fname) {      strcat (path, "\\*");
551          gpg_data_new_from_clipboard (&dat, 0);      hd = _findfirst (path, &fd);
552          gpg_data_release_and_set_file (dat, "gpgme.tmp");      do {
553            p = new char [strlen (path) + strlen (fd.name)+1];
554          fp = gpg_iobuf_open ("gpgme.tmp");          if (!p)
555          if (!fp)              BUG (0);
556              return 0;          memcpy (p, path, strlen (path)-1);
557          gpg_iobuf_ioctl (fp, 3, 1, NULL);          p[strlen (path)-1] = 0;
558          if (gpg_use_armor_filter(fp)) {          strcat (p, fd.name);
559              memset (&afx, 0, sizeof (afx));          if (!is_directory (p))
560              gpg_iobuf_push_filter (fp, gpg_armor_filter, &afx);              fm_set_ftype (lv, fm, p);
561          }          free_if_alloc (p);
562          gpg_init_packet (pkt);      } while (_findnext (hd, &fd) == 0);
563          if (!gpg_parse_packet (fp, pkt)      _findclose (hd);
564              && pkt->pkttype == PKT_COMPRESSED)      return 0;
565              check = 1;    }
566          gpg_free_packet (pkt);  
567          safe_free (pkt);  
568          gpg_iobuf_close (fp);  /* Add the drag & drop files from @dd_files to the
569          unlink ("gpgme.tmp");     list view control @lv. */
570      }  int
571      /* XXX: implement it for real files */  fm_add_dropped_files (fm_info_t fm, HDROP dd_files)
572      return check;  {
573  }      char name[384+4];
574        int nfiles;
575        int rc = 0;
576  int      int i;
577  fm_get_current_pos (listview_ctrl_t lv)      
578  {      memset (name, 0, sizeof (name));
579      int i = 0, items;      nfiles = DragQueryFile (dd_files, 0xFFFFFFFF, NULL, 0);
580        for (i = 0;  i < nfiles; i++) {
581      items = listview_count_items (lv, 0);          DragQueryFile (dd_files, i, name, sizeof (name) -1);
582      if (!items)          if (is_directory (name))
583          return -1;              rc = fm_add_dir_files (fm->lv, &fm->model, name);
584      else if (items == 1)          else
585      {              rc = fm_set_ftype (fm->lv, &fm->model, name);
586          listview_select_one (lv, 0);          if (rc == -1)
587          return 0;              break; /* XXX: fixme? */
588      }      }
589      else if (items > 1)      DragFinish (dd_files);
590      {      return rc;
591          i = listview_get_curr_pos (lv);  }
592          if (i == -1)  
593          {  
594              msg_box (lv->ctrl, _("Please select a file."), _("File Manager"), MB_ERR);  /* Add a single file @name to the list view and before
595              return -1;     figure out the type of it.
596          }     Return value: 0 on success. */
597          return i;  static int
598      }  add_single_file (listview_ctrl_t lv, fm_model_t *fm, const char *name)
599    {
600      return -1;      fm_model_t m;
601  } /* fm_get_current_pos */      const char *type;
602        int rc = 0;
603        
604  static int      type = fm_get_file_type (name, NULL);
605  fm_check_detached_sig( listview_ctrl_t lv, int pos )      if (!type)
606  {          return WPTERR_FILE_OPEN;
607      char type[128];      m = new fm_model_s;
608        memset (m, 0, sizeof *m);
609      listview_get_item_text( lv, pos, 0, type, 127 );      if (!strcmp (type, "UNKNOWN"))      
610      return !strcmp( type, "SIGNED-DETACH" )? 1 : 0;          type = gnupg_check_file_ext (name, NULL);
611  } /* fm_check_detached_sig */      rc = listview_add_item2 (lv, "", (void*)m);
612        if (!rc) {
613            listview_add_sub_item (lv, 0, FM_COL_STAT, type);
614  int          listview_add_sub_item (lv, 0, FM_COL_NAME, name);
615  fm_check_file_type (listview_ctrl_t lv, int pos, int fm_cmd)      }
616  {      m->status = m_strdup (type);
617      char status[128];      m->name = m_strdup (name);
618      int rc = 0;      m->op = NULL;
619            fm_model_add_file (fm, m);
620      listview_get_item_text (lv, pos, 0, status, sizeof (status) - 1);      return rc;
621        }
622      switch (fm_cmd) {  
623      case FM_ENCRYPT:  
624      case FM_ENCRYPT_DIR:  /* Use the common Open-File-Dialog to allow the user to
625      case FM_SIGNENCRYPT:       add one ore more selected files to the listview @lv. */
626          if (strcmp (status, "ENCRYPTED")  int
627              && strcmp (status, "SYMKEYENC"))  fm_add_opened_files (fm_info_t fm, HWND dlg)
628              rc = 1;  {
629          break;      OPENFILENAME open;
630                char file[512], name[MAX_PATH+1];
631      case FM_DECRYPT:      char *path = NULL;
632          if (!strcmp (status, "DATA")      const char *s;
633              || !strcmp (status, "ENCRYPTED")      int i, len=0, n=0;
634              || !strcmp (status, "SYMKEYENC")      int rc=0;
635              || !strcmp (status, "ARMORED"))  
636              rc = 1;      memset (&open, 0, sizeof (open));
637          break;      open.lStructSize = sizeof (OPENFILENAME);
638                open.hInstance = glob_hinst;
639      case FM_SIGN:      open.lpstrTitle = _("File Open");
640          if( strncmp( status, "SIGNED", 6 ) )      open.lpstrFilter = "All Files (*.*)\0*.*\0\0";
641              rc = 1;      open.hwndOwner = dlg;
642          break;      open.lpstrFile = file;
643                open.nMaxFile = sizeof (file) - 1;
644      case FM_VERIFY:      open.Flags = OFN_ALLOWMULTISELECT|OFN_EXPLORER ;
645          if( !strncmp( status, "SIGNED", 6 )      
646               || !strcmp( status, "COMPRESSED" ) )      memset (file, 0, sizeof file);
647              rc = 1;      if (!GetOpenFileName (&open))
648          break;          return 0;
649            
650      case FM_SYMENC:      /* It is possible that multiple files are returned
651          if( strcmp( status, "SYMKEYENC" ) )         and then they are separated by \0 chars. */
652              rc = 1;      s = file;
653          break;      len = sizeof (file)-1;
654                for (;;) {
655      case FM_IMPORT:          if (len < 2 || (*s == '\0' && *(s+1) == '\0'))
656          if( !strcmp( status, "PUBKEY" )              break;
657              || !strcmp( status, "SECKEY" ) )          memset (name, 0, sizeof (name));
658              rc = 1;          for (i=0; len > 0; len--, i++) {
659          break;              if (*s == '\0') {
660                            name[i] = *s++;
661      case FM_WIPE:                  break;
662      case FM_LIST:              }
663          rc = 1;              name[i] = *s++;
664          break;            }
665      }          if (n == 0)
666                    path = m_strdup (name);
667      return rc;          else {
668  } /* fm_check_file_type */              char *p = make_filename (path, name, NULL);
669                rc = add_single_file (fm->lv, &fm->model, p);
670                free_if_alloc (p);
671  static void          }
672  fm_set_status (listview_ctrl_t lv, int pos, int fm_cmd, int success,          n++;
673                 const char * output)      }
674  {      if (n == 1) /* single file selected. */
675      char status[128], operat[128];          rc = add_single_file (fm->lv, &fm->model, path);
676      int update = 1;      free_if_alloc (path);
677      const char *s;      return rc;
678    }
679      if ( fm_cmd == FM_LIST )  
680          return;  
681      success ? s = "SUCCESS" : s = "FAILED";  int
682      strcpy( operat, s );  fm_assume_onepass_sig (const char *fname)
683    {    
684      switch (fm_cmd) {      armor_filter_context_t afx;
685      case FM_ENCRYPT:      gpg_iobuf_t fp;
686      case FM_ENCRYPT_DIR:      gpgme_data_t dat;
687      case FM_SIGNENCRYPT: strcpy( status, "ENCRYPTED" ); break;      PACKET *pkt;
688      case FM_DECRYPT:     strcpy( status, "UNKNOWN" );   break;      char tmpfile[MAX_PATH+1];
689      case FM_SIGN:        strcpy( status, "SIGNED" );    break;      int check = 0;
690      case FM_VERIFY:      update = 0;                    break;  
691      case FM_SYMENC:      strcpy( status, "SYMKEYENC" ); break;      pkt = (PACKET *)calloc (1, sizeof *pkt);
692      case FM_IMPORT:      update = 0;                    break;      if (!fname) {
693      case FM_WIPE:        strcpy( status, "WIPED" );     break;          get_temp_name (tmpfile, sizeof (tmpfile)-1, "gpgme.tmp");
694      default:             strcpy( status, "UNKNOWN");    break;          gpg_data_new_from_clipboard (&dat, 0);
695      }          gpg_data_release_and_set_file (dat, tmpfile);
696    
697      if (success) {          fp = gpg_iobuf_open (tmpfile);
698          if (update) {          if (!fp)
699              listview_add_sub_item (lv, pos, 0, status);              return 0;
700              listview_add_sub_item (lv, pos, 1, output);          gpg_iobuf_ioctl (fp, 3, 1, NULL);
701          }          if (gpg_use_armor_filter(fp)) {
702      }              memset (&afx, 0, sizeof (afx));
703      listview_add_sub_item( lv, pos, 2, operat );              gpg_iobuf_push_filter (fp, gpg_armor_filter, &afx);
704  } /* fm_set_status */          }
705            gpg_init_packet (pkt);
706            if (!gpg_parse_packet (fp, pkt)
707  int              && pkt->pkttype == PKT_COMPRESSED)
708  fm_clearsign_8bit (listview_ctrl_t lv, fm_state_s *ctx)              check = 1;  
709  {          gpg_free_packet (pkt);
710      FILE *f;          gpg_iobuf_close (fp);
711      byte buf[32];          DeleteFile (tmpfile);
712      char name[256];      }
713      int i, n, cnt=0;      /* XXX: implement it for real files */
714        safe_free (pkt);
715      if (ctx->sigmode != GPGME_SIG_MODE_CLEAR)      return check;
716          return 0;  }
717      listview_get_item_text (lv, -1, 1, name, sizeof (name)-1);  
718      if (stristr (name, ".TXT"))  
719          return 0;  int
720      f = fopen (name, "rb");  fm_get_current_pos (listview_ctrl_t lv)
721      if (!f)  {
722          return -1; /* should never happen */      int i = 0, items;
723      n = fread (buf, 1, 32, f);  
724      for (i = 0; i < n; i++) {      items = listview_count_items (lv, 0);
725          if (buf[i] == 0x00 || buf[i] > 170)      if (!items)
726              cnt++;          return -1;
727      }      else if (items == 1) {
728      fclose (f);          listview_select_one (lv, 0);
729      if (!cnt)          return 0;
730          return 0;      }
731      n = -1;      else if (items > 1) {
732      i = log_box (_("File Manager"), MB_WARN|MB_YESNO,          i = listview_get_curr_pos (lv);
733                   _("\"%s\" does not seems to be a text file.\n"          if (i == -1) {
734                     "Do you really want to clearsign it?"), name);              msg_box (lv->ctrl, _("Please select a file."),
735      if (i == IDYES)                       _("File Manager"), MB_ERR);
736          n = 0;              return -1;
737      return n;          }
738  }          return i;
739        }
740  int  
741  fm_parse_files (listview_ctrl_t lv, HWND dlg, int cmd)      return -1;
742  {  }
743      struct secdel_confirm_s confirm = {0};  
744      struct progress_filter_s pfx, pfx2;  
745      fm_state_s * ctx;  static int
746      int fm_cmd, sig_detached = 0;  fm_check_detached_sig (listview_ctrl_t lv, int pos)
747      int rc = 0, i, n, ndel = 0;  {
748      char fname[512], status[128];      char type[128];
749        
750      switch (cmd) {      listview_get_item_text (lv, pos, 0, type, sizeof (type)-1);
751      case ID_FILEMISC_ENCRYPT: fm_cmd = FM_ENCRYPT; break;      return !strcmp (type, "SIGNED-DETACH")? 1 : 0;
752      case ID_FILEMISC_DECRYPT: fm_cmd = FM_DECRYPT; break;  }
753      case ID_FILEMISC_SYMENC:  fm_cmd = FM_SYMENC;  break;  
754      case ID_FILEMISC_SIGN:    fm_cmd = FM_SIGN;    break;      
755      case ID_FILEMISC_VERIFY:  fm_cmd = FM_VERIFY;  break;  int
756      case ID_FILEMISC_IMPORT:  fm_cmd = FM_IMPORT;  break;  fm_check_file_type (listview_ctrl_t lv, int pos, int fm_cmd)
757      case ID_FILEMISC_WIPE:    fm_cmd = FM_WIPE;    break;  {
758      case ID_FILEMISC_LIST:    fm_cmd = FM_LIST;    break;      char status[128];
759      case ID_FILEMISC_SIGNENC: fm_cmd = FM_SIGNENCRYPT; break;      int rc = 0;
760      default: return 1; /* unknown command */      
761      }      listview_get_item_text (lv, pos, 0, status, sizeof (status) - 1);
762            
763      if (fm_get_current_pos (lv) == -1)      switch (fm_cmd) {
764          return WPTERR_GENERAL;          case FM_ENCRYPT:
765      rc = fm_state_new (&ctx);      case FM_ENCRYPT_DIR:
766      if (rc)      case FM_SIGNENCRYPT:  
767          BUG (0);          if (strcmp (status, "ENCRYPTED")
768      ctx->dlg = dlg;              && strcmp (status, "SYMKEYENC"))
769                rc = 1;
770      // XXX: for file operations the progress dialog will be          break;
771      //       reloaded somewhere and thus a 'dummy' dialog remains          
772        case FM_DECRYPT:
773      /* we use it here to make sure that pfx_cleanup will not use          if (!strcmp (status, "DATA") ||
774         any weird values. */              !strcmp (status, "ENCRYPTED") ||
775      memset (&pfx, 0, sizeof (pfx));              !strcmp (status, "SYMKEYENC") ||
776      ctx->prog_cb = NULL;              !strcmp (status, "ARMORED"))
777      if (cmd != FM_VERIFY && cmd != FM_SIGN /*&& reg_prefs.fm.progress > 0*/) {              rc = 1;
778          pfx.hwnd = dlg;          break;
779          /*gpgme_set_progress_cb (ctx->ctx, progress_callback, &pfx);*/          
780          /*ctx->prog_cb = &pfx;*/      case FM_SIGN:
781      }          if( strncmp( status, "SIGNED", 6 ) )
782                    rc = 1;
783      /* Commands we need before we can perform the main command */          break;
784      switch (fm_cmd) {          
785      case FM_ENCRYPT:      case FM_VERIFY:
786      case FM_SIGNENCRYPT:          if( !strncmp( status, "SIGNED", 6 )
787          if (fm_cmd == FM_SIGNENCRYPT)               || !strcmp( status, "COMPRESSED" ) )
788              ctx->req_signer = 1;              rc = 1;
789          DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_FILE_ENCRYPT, ctx->dlg,          break;
790                          file_encrypt_dlg_proc, (LPARAM)ctx);          
791          if (ctx->cancel == 1) {      case FM_SYMENC:
792              rc = WPTERR_GENERAL;          if( strcmp( status, "SYMKEYENC" ) )
793              goto leave;              rc = 1;
794          }          break;
795          break;          
796                case FM_IMPORT:
797      case FM_SIGN:          if( !strcmp( status, "PUBKEY" )
798          DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_FILE_SIGN, dlg,              || !strcmp( status, "SECKEY" ) )
799                          file_sign_dlg_proc, (LPARAM) ctx);              rc = 1;
800          if (ctx->cancel == 1 || fm_clearsign_8bit (lv, ctx)) {          break;
801              rc = WPTERR_GENERAL;          
802              goto leave;      case FM_WIPE:
803          }      case FM_LIST:
804          break;          rc = 1;
805            break;  
806      case FM_WIPE:      }
807          memset (&pfx2, 0, sizeof (pfx2));      
808          secure_unlink_set_cb (progress_callback, &pfx2);      return rc;
809          break;  }
810      }  
811        
812      for( i = 0, n = 0;  i < listview_count_items( lv, 0 ); i++ ) {  /* Set the file status of the given command @fm_cmd.
813          if( !listview_get_item_state( lv, i ) )     @success is 0 on success. */
814              continue;  static void
815          listview_get_item_text( lv, i, 0, status, sizeof (status) -1 );  fm_set_status (listview_ctrl_t lv, int pos, int fm_cmd,
816          if (!strcmp( status, "ENCRYPTED" ) && fm_cmd == FM_DECRYPT)                 gpgme_sig_mode_t sigmode, int success, const char *output)
817              n++;  {
818          if (!strcmp( status, "UNKNOWN" ) && fm_cmd == FM_SIGN)      char status[128], operat[128];
819              n++;      int update = 1;
820          if (fm_cmd == FM_WIPE)      const char *s;
821              ndel++;  
822      }      if (fm_cmd == FM_LIST)
823                return;
824      if (n > 1 && fm_cmd != FM_SYMENC)      success ? s = "SUCCESS" : s = "FAILED";
825          ctx->cache_cb = 1;      strcpy (operat, s);
826    
827      if (fm_cmd == FM_WIPE && ndel > 0) {      switch (fm_cmd) {
828          memset (&confirm, 0, sizeof confirm);      case FM_ENCRYPT:
829          confirm.lv_files = lv;      case FM_ENCRYPT_DIR:
830          DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_FILES_SECDEL, ctx->dlg,      case FM_SIGNENCRYPT: strcpy (status, "ENCRYPTED"); break;
831                              file_secdel_confirm_dlg_proc, (LPARAM)&confirm);      case FM_DECRYPT:     strcpy (status, "UNKNOWN");   break;
832          if (!confirm.yes)      case FM_SIGN:
833              goto leave;          if (sigmode == GPGME_SIG_MODE_DETACH)
834      }              strcpy (status, "SIGNED-DETACH");
835                else if (sigmode == GPGME_SIG_MODE_CLEAR)
836      for( i = 0; i < listview_count_items( lv, 0 ); i++ ) {              strcpy (status, "SIGNED-CLEAR");
837          if( !listview_get_item_state( lv, i ) )          else
838              continue;              strcpy (status, "SIGNED");
839          listview_get_item_text( lv, i, 1, fname, sizeof (fname) - 1 );          break;
840          if( file_exist_check( fname ) && !is_directory( fname ) ) {      case FM_VERIFY:      update = 0;                    break;
841              log_box( _("File Manager"), MB_ERR, _("\"%s\" does not exist"), fname );      case FM_SYMENC:      strcpy (status, "SYMKEYENC"); break;
842              continue;      case FM_IMPORT:      update = 0;                    break;
843          }      case FM_WIPE:        strcpy (status, "WIPED");     break;
844          if( is_directory( fname ) )      default:             strcpy (status, "UNKNOWN");    break;
845              fm_cmd = FM_ENCRYPT_DIR;              }
846          if( !fm_check_file_type( lv, i, fm_cmd ) )  
847              continue;      if (success && update) {
848          sig_detached = fm_check_detached_sig( lv, i );          listview_add_sub_item (lv, pos, 0, status);
849          switch( fm_cmd ) {          listview_add_sub_item (lv, pos, 1, output);
850          case FM_LIST:        rc = fm_list( fname, dlg );       break;      }
851          case FM_WIPE:        rc = fm_wipe( fname );            break;      listview_add_sub_item( lv, pos, 2, operat );
852          case FM_ENCRYPT:     rc = fm_encrypt( ctx, fname, 0 ); break;  }
853          case FM_ENCRYPT_DIR: rc = fm_encrypt_directory( ctx, fname ); break;  
854          case FM_SIGNENCRYPT: rc = fm_encrypt( ctx, fname, 1 ); break;  
855          case FM_DECRYPT:     rc = fm_decrypt( ctx, fname );    break;  int
856          case FM_SIGN:        rc = fm_sign( ctx, fname );       break;  fm_clearsign_8bit (listview_ctrl_t lv, fm_state_s *ctx)
857          case FM_SYMENC:      rc = fm_sym_encrypt( ctx, fname );break;  {
858          case FM_VERIFY:      rc = fm_verify (ctx, sig_detached, fname);break;      FILE *f;
859          case FM_IMPORT:      BYTE buf[32];
860              free_if_alloc (ctx->opaque);      char name[256];
861              ctx->opaque = m_strdup (fname);      int i, n, cnt=0;
862              if (!ctx->opaque)  
863                  BUG (0);      if (ctx->sigmode != GPGME_SIG_MODE_CLEAR)
864              DialogBoxParam( glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,          return 0;
865                             file_import_dlg_proc, (LPARAM)ctx );      listview_get_item_text (lv, -1, FM_COL_NAME, name, sizeof (name)-1);
866              if (ctx->cancel == 1)      if (stristr (name, ".TXT"))
867                  continue;          return 0;
868              rc = fm_import (ctx, fname);      f = fopen (name, "rb");
869              break;      if (!f)
870          }          return -1; /* should never happen */
871          fm_set_status (lv, i, fm_cmd, !rc, ctx->output);      n = fread (buf, 1, 32, f);
872          free_if_alloc (ctx->output);      fclose (f);
873          progress_cleanup (&pfx);      for (i = 0; i < n; i++) {
874      }          if (buf[i] == 0x00 || buf[i] > 170)
875      if (fm_cmd == FM_WIPE) {              cnt++;
876          secure_unlink_set_cb (NULL, NULL);      }
877          progress_cleanup (&pfx2);      if (!cnt)
878      }          return 0;
879      if (ctx->cache_cb) {      n = -1;
880          release_gpg_passphrase_cb (&ctx->pass_cb);      i = log_box (_("File Manager"), MB_WARN|MB_YESNO,
881          ctx->cache_cb = 0; /* make sure it's only used for this session! */                   _("\"%s\" does not seems to be a text file.\n"
882      }                     "Do you really want to clearsign it?"), name);
883            if (i == IDYES)
884      /* remove wipe files from the list */          n = 0;
885      n = listview_count_items (lv, 0);      return n;
886      while (n--) {  }
887          char status[128];  
888          listview_get_item_text (lv, n, 0, status, sizeof (status) - 1);  
889          if( !strcmp (status, "WIPED"))  int
890              listview_del_item (lv, n);  fm_parse_files (listview_ctrl_t lv, HWND dlg, int cmd)
891      }  {
892            struct secdel_confirm_s confirm = {0};
893  leave:      struct progress_filter_s pfx, pfx2;
894      if (!rc)      fm_state_s * ctx;
895          fm_state_release (ctx);      int fm_cmd, sig_detached = 0;
896      progress_cleanup (&pfx);      int rc = 0, i, n, ndel = 0;
897      return rc;      char fname[512], status[128];
898  } /* fm_parse_files */      
899        switch (cmd) {
900        case ID_FILEMISC_ENCRYPT: fm_cmd = FM_ENCRYPT; break;
901  /* Wipe the given file @name with the delete mode      case ID_FILEMISC_ENCRYPT_ZIP:fm_cmd = FM_ENCRYPT_ZIP; break;
902     from the configuration.      case ID_FILEMISC_DECRYPT: fm_cmd = FM_DECRYPT; break;
903     Return value: 0 on success. */      case ID_FILEMISC_SYMENC:  fm_cmd = FM_SYMENC;  break;
904  int      case ID_FILEMISC_SIGN:    fm_cmd = FM_SIGN;    break;    
905  fm_wipe (const char *name)      case ID_FILEMISC_VERIFY:  fm_cmd = FM_VERIFY;  break;
906  {      case ID_FILEMISC_IMPORT:  fm_cmd = FM_IMPORT;  break;
907      int rc;      case ID_FILEMISC_WIPE:    fm_cmd = FM_WIPE;    break;
908        case ID_FILEMISC_LIST:    fm_cmd = FM_LIST;    break;
909      SetCursor (LoadCursor (NULL, IDC_WAIT));      case ID_FILEMISC_SIGNENC: fm_cmd = FM_SIGNENCRYPT; break;
910      remove_crit_file_attrs (name, 1);      default: return 1; /* unknown command */
911      rc = secure_unlink (name, reg_prefs.wipe_mode);      }
912      SetCursor (LoadCursor (NULL, IDC_ARROW));      
913      return rc;      if (fm_get_current_pos (lv) == -1)
914  }          return WPTERR_GENERAL;
915        rc = fm_state_new (&ctx);
916        if (rc)
917  /* Dump out the given PGP packets from file @name in a dialog. */          BUG (0);
918  int      ctx->dlg = dlg;
919  fm_list (const char *name, HWND dlg)  
920  {      // XXX: for file operations the progress dialog will be
921      dialog_box_param( glob_hinst, (LPCTSTR)IDD_WINPT_FILE_STAT, dlg,      //       reloaded somewhere and thus a 'dummy' dialog remains
922                        file_stat_dlg_proc, (LPARAM)name, _("File Status"),  
923                        IDS_WINPT_FILE_STAT );      /* we use it here to make sure that pfx_cleanup will not use
924      return 0;         any weird values. */
925  }      memset (&pfx, 0, sizeof (pfx));
926        ctx->prog_cb = NULL;
927        if (cmd != FM_VERIFY && cmd != FM_SIGN /*&& reg_prefs.fm.progress > 0*/) {
928  static int          pfx.hwnd = dlg;
929  ask_filename (fm_state_t c, const char *msg, char **dst)          /*gpgme_set_progress_cb (ctx->ctx, progress_callback, &pfx);*/
930  {          /*ctx->prog_cb = &pfx;*/
931      const char * s;      }
932        
933      s = get_filename_dlg (c->dlg, FILE_SAVE, msg, NULL, NULL);      /* Commands we need before we can perform the main command */
934      if (!s)      switch (fm_cmd) {
935          return WPTERR_GENERAL;      case FM_ENCRYPT_ZIP:
936        case FM_ENCRYPT:
937      if (dst != NULL)      case FM_SIGNENCRYPT:
938          free_if_alloc (*dst);          if (fm_cmd == FM_SIGNENCRYPT)
939      free_if_alloc (c->output);              ctx->req_signer = 1;
940      c->output = m_strdup (s);          DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_FILE_ENCRYPT,
941      if (!c->output)                          ctx->dlg, file_encrypt_dlg_proc, (LPARAM)ctx);
942          BUG (0);          if (ctx->cancel == 1) {
943      if (dst)              rc = WPTERR_GENERAL;
944          *dst = fm_quote_file (s);              goto leave;
945      return 0;          }
946  }          break;
947            
948        case FM_SIGN:
949  int          DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_FILE_SIGN, dlg,
950  fm_encrypt (fm_state_t c, const char *name, int sign)                          file_sign_dlg_proc, (LPARAM) ctx);
951  {          if (ctx->cancel == 1 || fm_clearsign_8bit (lv, ctx)) {
952      gpgme_error_t err;              rc = WPTERR_GENERAL;
953      gpgme_key_t key = NULL;              goto leave;
954      gpgme_ctx_t ctx = c->ctx;          }
955      file_data_t in=NULL, out=NULL;          break;
956      char *keyid = NULL, ext[5];  
957      int no_compr = 0;      case FM_WIPE:
958      int rc = 0;          memset (&pfx2, 0, sizeof (pfx2));
959            secure_unlink_set_cb (progress_callback, &pfx2);
960      c->output = new char[strlen (name) + 5 + 1];          break;
961      if (!c->output)      }
962          BUG (0);      
963      strcpy (ext, file_get_extension (ctx, c->sigmode));      for( i = 0, n = 0;  i < listview_count_items( lv, 0 ); i++ ) {
964      strcpy (c->output, name);          if( !listview_get_item_state( lv, i ) )
965      strcat (c->output, ext);                      continue;
966                listview_get_item_text( lv, i, 0, status, sizeof (status) -1 );
967      if (!overwrite_file (c->output)) {          if (!strcmp( status, "ENCRYPTED" ) && fm_cmd == FM_DECRYPT)
968          rc = ask_filename (c, _("Enter filename for encrypted file"), NULL);              n++;
969          if (rc)          if (!strcmp( status, "UNKNOWN" ) && fm_cmd == FM_SIGN)
970              goto leave;              n++;
971      }          if (fm_cmd == FM_WIPE)
972                ndel++;
973      err = gpg_file_data_new (name, 1, &in);      }
974      if (err)      
975          goto leave;      if (n > 1 && fm_cmd != FM_SYMENC)
976      err = gpg_file_data_new (c->output, 0, &out);          ctx->cache_cb = 1;
977      if (err)  
978          goto leave;      if (fm_cmd == FM_WIPE && ndel > 0) {
979            memset (&confirm, 0, sizeof confirm);
980      /*          confirm.lv_files = lv;
981      if (c->prog_cb) {          DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_FILES_SECDEL, ctx->dlg,
982          c->prog_cb->what = name;                          file_secdel_confirm_dlg_proc, (LPARAM)&confirm);
983          gpg_file_data_set_cb (in, c->prog_cb);          if (!confirm.yes)
984      }              goto leave;
985      */      }
986        
987      /* XXX      if (fm_cmd == FM_ENCRYPT_ZIP)
988      no_compr = is_multi_media (name);          fm_encrypt_into_zip (ctx, lv);
989      gpgme_control (ctx, GPGME_CTRL_NO_COMPR, no_compr);  
990      */      for (i = 0; i < listview_count_items (lv, 0); i++) {
991            if (!listview_get_item_state (lv, i))
992      if (sign) {              continue;
993          if (gpgme_signers_enum (ctx, 0) == NULL) {          listview_get_item_text (lv, i, 1, fname, sizeof (fname) - 1);
994              keyid = get_gnupg_default_key ();          if( file_exist_check (fname) && !is_directory (fname)) {
995              if (!keyid) {              log_box (_("File Manager"), MB_ERR,
996                  msg_box (c->dlg, _("Could not get default secret key."),                       _("\"%s\" does not exist"), fname);
997                           _("Signing"), MB_ERR);              continue;
998                  rc = WPTERR_GENERAL;          }
999                  goto leave;          if (is_directory (fname))
1000              }              fm_cmd = FM_ENCRYPT_DIR;        
1001              if (get_seckey (keyid, &key))          if (!fm_check_file_type (lv, i, fm_cmd))
1002                  BUG (0);              continue;
1003              gpgme_signers_add (ctx, key);          sig_detached = fm_check_detached_sig (lv, i);
1004          }          switch (fm_cmd) {
1005          else {          case FM_LIST:        rc = fm_list( fname, dlg );       break;
1006              gpgme_key_t key = gpgme_signers_enum (ctx, 0);          case FM_WIPE:        rc = fm_wipe( fname );            break;
1007              if (key && key->subkeys) {          case FM_ENCRYPT:     rc = fm_encrypt( ctx, fname, 0 ); break;
1008                  keyid = m_strdup (key->subkeys->keyid);          case FM_ENCRYPT_DIR: rc = fm_encrypt_directory( ctx, fname ); break;
1009                  if (!keyid)          case FM_SIGNENCRYPT: rc = fm_encrypt( ctx, fname, 1 ); break;
1010                      BUG (NULL);          case FM_DECRYPT:     rc = fm_decrypt( ctx, fname );    break;
1011              }          case FM_SIGN:        rc = fm_sign( ctx, fname );       break;
1012          }          case FM_SYMENC:      rc = fm_sym_encrypt (ctx, fname); break;
1013          if (!c->init_cb || !c->cache_cb) {          case FM_VERIFY:      rc = fm_verify (ctx, sig_detached, fname);break;
1014              set_gpg_passphrase_cb (&c->pass_cb, c->ctx, GPG_CMD_SIGN,          case FM_IMPORT:
1015                                     c->dlg, _("Signing"));              free_if_alloc (ctx->opaque);
1016              c->init_cb = 1;              ctx->opaque = m_strdup (fname);
1017          }              DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,
1018          err = gpgme_op_encrypt_sign (ctx, c->recp, GPGME_ENCRYPT_ALWAYS_TRUST,                              file_import_dlg_proc, (LPARAM)ctx);
1019                                       in->dat, out->dat);              if (ctx->cancel == 1)
1020          if (!c->cache_cb)                  continue;
1021              release_gpg_passphrase_cb (&c->pass_cb);              rc = fm_import (ctx, fname);
1022          if (c->pass_cb.cancel) {              break;
1023              rc = WPTERR_GENERAL;          }
1024              goto leave;          if (ctx->cancel == 1) {
1025          }              ctx->cancel = 0;
1026          if (err) {              continue;
1027              msg_box (c->dlg, gpgme_strerror (err), _("Sign"), MB_ERR);          }
1028              if (gpgme_err_code (err) == GPG_ERR_BAD_PASSPHRASE)          fm_set_status (lv, i, fm_cmd, ctx->sigmode, !rc, ctx->output);
1029                  agent_del_cache (keyid);          free_if_alloc (ctx->output);
1030              rc = WPTERR_GENERAL;          progress_cleanup (&pfx);
1031              goto leave;      }
1032          }  
1033      }      if (fm_cmd == FM_WIPE) {
1034      else {          secure_unlink_set_cb (NULL, NULL);
1035          err = gpgme_op_encrypt (ctx, c->recp, GPGME_ENCRYPT_ALWAYS_TRUST,          progress_cleanup (&pfx2);
1036                                  in->dat, out->dat);      }
1037          if (err) {      if (ctx->cache_cb) {
1038              msg_box (c->dlg, gpgme_strerror (err), _("Encrypt"), MB_ERR);          release_gpg_passphrase_cb (&ctx->pass_cb);
1039              rc = WPTERR_GENERAL;          ctx->cache_cb = 0; /* make sure it's only used for this session! */
1040              goto leave;      }
1041          }      
1042      }      /* remove wipe files from the list */
1043      if (c->wipe)      n = listview_count_items (lv, 0);
1044          secure_unlink (name, WIPE_MODE_SIMPLE);      while (n--) {
1045                listview_get_item_text (lv, n, 0, status, sizeof (status) - 1);
1046  leave:          if (!strcmp (status, "WIPED"))
1047      if (in)              listview_del_item (lv, n);
1048          gpg_file_data_release (in);      }
1049      if (out)      
1050          gpg_file_data_release (out);  leave:
1051      free_if_alloc (keyid);      if (!rc)
1052      return rc;          fm_state_release (ctx);
1053  }      progress_cleanup (&pfx);
1054        return rc;
1055    } /* fm_parse_files */
1056  int  
1057  fm_sym_encrypt (fm_state_t c, const char * name)  
1058  {  /* Wipe the given file @name with the delete mode
1059      gpgme_ctx_t ctx = c->ctx;     from the configuration.
1060      gpgme_error_t err;         Return value: 0 on success. */
1061      file_data_t in=NULL, out=NULL;  int
1062      int rc = 0, cancel = 0;  fm_wipe (const char *name)
1063      char * src = NULL, * dst = NULL;  {
1064      char ext[5], * pass;          int rc;
1065        
1066      pass = request_passphrase2 (_("Symmetric"), 0, &cancel);      SetCursor (LoadCursor (NULL, IDC_WAIT));
1067      if (cancel)      remove_crit_file_attrs (name, 1);
1068          return 0;      rc = secure_unlink (name, reg_prefs.wipe_mode);
1069            SetCursor (LoadCursor (NULL, IDC_ARROW));
1070      /* XXX gpgme_control (ctx, GPGME_CTRL_CIPHER, -1);*/      return rc;
1071      c->output = new char[strlen (name) + 5 + 1];  }
1072      if (!c->output)  
1073          BUG (0);  
1074      strcpy (ext, file_get_extension (ctx, c->sigmode));  /* Dump out the given PGP packets from file @name in a dialog. */
1075      strcpy (c->output, name);  int
1076      strcat (c->output, ext);  fm_list (const char *name, HWND dlg)
1077    {
1078      if (overwrite_file (c->output) == 0) {      dialog_box_param( glob_hinst, (LPCTSTR)IDD_WINPT_FILE_STAT, dlg,
1079          rc = WPTERR_GENERAL;                        file_stat_dlg_proc, (LPARAM)name, _("File Status"),
1080          goto leave;                            IDS_WINPT_FILE_STAT );
1081      }      return 0;
1082    }
1083      gpgme_set_passphrase_cb (ctx, sym_passphrase_cb, pass);      
1084    
1085      err = gpg_file_data_new (name, 1, &in);  static int
1086      if (err)  ask_filename (fm_state_t c, const char *msg, char **dst)
1087          goto leave;  {
1088      err = gpg_file_data_new (c->output, 0, &out);      const char *s;
1089      if (err)  
1090          goto leave;      s = get_filesave_dlg (c->dlg, msg, NULL, NULL);
1091        if (!s)
1092      err = gpgme_op_encrypt (ctx, NULL, GPGME_ENCRYPT_ALWAYS_TRUST, in->dat, out->dat);          return WPTERR_GENERAL;
1093      if (err) {  
1094          msg_box (c->dlg, gpgme_strerror (err), _("Symmetric"), MB_ERR);      if (dst != NULL)
1095          rc = WPTERR_GENERAL;          free_if_alloc (*dst);
1096          goto leave;      free_if_alloc (c->output);
1097      }      c->output = m_strdup (s);
1098      if (file_exist_check (c->output)) {      if (dst)
1099          msg_box (c->dlg, _("Encryption failed."), _("Symmetric"), MB_ERR);          *dst = fm_quote_file (s);
1100          rc = WPTERR_GENERAL;      return 0;
1101      }  }
1102        
1103  leave:  
1104      if (in)  int
1105          gpg_file_data_release (in);  fm_encrypt (fm_state_t c, const char *name, int sign)
1106      if (out)  {
1107          gpg_file_data_release (out);      gpgme_error_t err;
1108      sfree_if_alloc (pass);      gpgme_key_t key = NULL;
1109      return rc;      gpgme_ctx_t ctx = c->ctx;
1110  } /* fm_sym_encrypt */      file_data_t in=NULL, out=NULL;
1111        char *keyid = NULL, ext[5];
1112        /*int no_compr = 0;*/
1113  /* Show the human readable verify result from @sigres. */      int rc = 0;
1114  static void  
1115  show_verify_result (gpgme_verify_result_t sigres)      c->output = new char[strlen (name) + 5 + 1];
1116  {      if (!c->output)
1117      gpgme_key_t key=NULL;          BUG (0);
1118      gpgme_signature_t sig=sigres->signatures;      strcpy (ext, file_get_extension (ctx, c->sigmode));
1119      const char *s, *keyid;      strcpy (c->output, name);
1120      int sigok = 0;      strcat (c->output, ext);
1121      int type;      
1122      char buf[384];      if (!overwrite_file (c->output)) {
1123            rc = ask_filename (c, _("Enter Filename for Encrypted File"), NULL);
1124      sig = sigres->signatures;          if (rc)
1125      sigok = sig->summary & GPGME_SIGSUM_GREEN;              goto leave;
1126      s = sigok? _("Good signature") : _("BAD signature");      }
1127      type = sigok? MB_OK: MB_ICONWARNING|MB_OK;  
1128      keyid = sig->fpr;        err = gpg_file_data_new (name, F_DATA_READ, &in);
1129      if (!keyid)      if (err)
1130          return;          goto leave;
1131        remove_crit_file_attrs (c->output, 0);
1132      keyid = strlen (sig->fpr) == 40? sig->fpr+32 : sig->fpr + 24;      err = gpg_file_data_new (c->output, F_DATA_WRITE, &out);
1133      get_pubkey (sig->fpr, &key);      if (err)
1134      _snprintf (buf, sizeof (buf)-1, "Signature made %s using %s key ID %s\n"          goto leave;
1135                                      "%s from \"%s\"",  
1136                  strtimestamp (sig->timestamp), get_key_pubalgo (sig->pubkey_algo),      /*
1137                  keyid, s, key? key->uids->uid : _("user ID not found"));      if (c->prog_cb) {
1138      msg_box (NULL, buf, _("Decrypt Verify"), type);          c->prog_cb->what = name;
1139  }          gpg_file_data_set_cb (in, c->prog_cb);
1140        }
1141        */
1142  /* Check the recipients if we have at least one secret key. */      
1143  bool      /* XXX: disable compression for multi-media files.
1144  secret_key_available (gpgme_recipient_t rset)      no_compr = is_multi_media (name);
1145  {      gpgme_control (ctx, GPGME_CTRL_NO_COMPR, no_compr);
1146      gpgme_recipient_t r;      */
1147      gpgme_key_t key;  
1148        if (sign) {
1149      for (r=rset; r; r = r->next) {                if (gpgme_signers_enum (ctx, 0) == NULL) {
1150          if (gpgme_err_code (r->status) == GPG_ERR_NO_SECKEY)              keyid = get_gnupg_default_key ();
1151              continue;              if (!keyid) {
1152          else {                  msg_box (c->dlg, _("Could not get default secret key."),
1153              /* extra check to make sure the key is available right now. */                           _("Signing"), MB_ERR);
1154              if (!get_seckey (r->keyid, &key))                  rc = WPTERR_GENERAL;
1155                  return true;                  goto leave;
1156          }              }
1157      }              if (get_seckey (keyid, &key))
1158      return false;                  BUG (0);
1159  }              gpgme_signers_add (ctx, key);
1160            }
1161            else {
1162  /* Decrypt the file @name. */              gpgme_key_t sigkey = gpgme_signers_enum (ctx, 0);
1163  int              if (sigkey && sigkey->subkeys) {
1164  fm_decrypt (fm_state_t c, const char *name)                  keyid = m_strdup (sigkey->subkeys->keyid);
1165  {              }
1166      gpgme_error_t err;          }
1167      gpgme_ctx_t ctx = c->ctx;              if (!c->init_cb || !c->cache_cb) {
1168      gpgme_decrypt_result_t res;              set_gpg_passphrase_cb (&c->pass_cb, c->ctx, GPG_CMD_SIGN,
1169      gpgme_verify_result_t sigres;                                     c->dlg, _("Signing"));
1170      file_data_t in =NULL, out=NULL;              c->init_cb = 1;
1171      int is_signed = 0;          }
1172      int rc = 0;          op_begin ();
1173                err = gpgme_op_encrypt_sign (ctx, c->recp, GPGME_ENCRYPT_ALWAYS_TRUST,
1174      if (!c->init_cb || !c->cache_cb) {                                       in->dat, out->dat);
1175          set_gpg_passphrase_cb (&c->pass_cb, c->ctx, GPG_CMD_DECRYPT,          op_end ();
1176                                 c->dlg, _("Decryption"));          if (!c->cache_cb)
1177          c->init_cb = 1;              release_gpg_passphrase_cb (&c->pass_cb);
1178      }              if (c->pass_cb.cancel) {
1179                    rc = WPTERR_GENERAL;
1180      c->output = m_strdup (name);              goto leave;
1181      if (!c->output)          }
1182          BUG (0);          if (err) {
1183      if (is_openpgp_ext (c->output))              msg_box (c->dlg, gpgme_strerror (err), _("Sign"), MB_ERR);
1184          c->output[strlen (c->output)-4] = '\0';              if (gpgme_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
1185      else {                  agent_del_cache (keyid);
1186          const char *s = get_filesave_dlg (c->dlg, _("Choose Filename for Output"),              rc = WPTERR_GENERAL;
1187                                            NULL, NULL);              goto leave;
1188          if (s) {          }
1189              free_if_alloc (c->output);      }
1190              c->output = m_strdup (s);      else {
1191              if (!c->output)          op_begin ();
1192                  BUG (NULL);          err = gpgme_op_encrypt (ctx, c->recp, GPGME_ENCRYPT_ALWAYS_TRUST,
1193          }                                  in->dat, out->dat);
1194      }          op_end ();
1195            if (err) {
1196      if (overwrite_file (c->output) == 0) {              msg_box (c->dlg, gpgme_strerror (err), _("Encrypt"), MB_ERR);
1197          rc = ask_filename (c, _("Please enter filename for plaintext file"), NULL);              rc = WPTERR_GENERAL;
1198          if (rc)              goto leave;
1199              goto leave;          }
1200      }          }
1201        
1202      remove_crit_file_attrs (c->output, 0);  leave:
1203        if (in)
1204      err = gpg_file_data_new (name, 1, &in);          gpg_file_data_release (in);
1205      if (err)      if (out)
1206          goto leave;          gpg_file_data_release (out);
1207      err = gpg_file_data_new (c->output, 0, &out);      free_if_alloc (keyid);
1208      if (err)      if (!rc && c->wipe)
1209          goto leave;          secure_unlink (name, WIPE_MODE_SIMPLE);
1210        return rc;
1211      err = gpgme_op_decrypt_verify (ctx, in->dat, out->dat);  }
1212      if (!c->cache_cb)  
1213          release_gpg_passphrase_cb (&c->pass_cb);  
1214      if (c->pass_cb.cancel) {  int
1215          rc = WPTERR_GENERAL;  fm_sym_encrypt (fm_state_t c, const char * name)
1216          goto leave;  {
1217      }      gpgme_ctx_t ctx = c->ctx;
1218        gpgme_error_t err;    
1219      res = gpgme_op_decrypt_result (ctx);      file_data_t in=NULL, out=NULL;
1220      if (res && res->recipients && !secret_key_available (res->recipients)) {      int rc = 0, cancel = 0;
1221          const char *keyid = res->recipients->keyid;      char ext[5], *pass;    
1222          char *p = get_key_userid (keyid+8);      
1223          gpgme_pubkey_algo_t pkalgo = res->recipients->pubkey_algo;      pass = request_passphrase2 (_("Symmetric Encryption"), 0, &cancel);
1224                if (cancel) {
1225          log_box( _("Decryption"), MB_ERR,          c->cancel = 1;
1226                   _("Encrypted with %s key, ID %s.%s\n"          return 0;
1227                     "Decryption failed: secret key not available."),      }
1228                     get_key_pubalgo (pkalgo), keyid+8, p);      
1229          rc = WPTERR_GENERAL;      /* XXX: a convenient feature could be to select the preferred
1230          free_if_alloc (p);              symmetric algorithm. */
1231          goto leave;      c->output = new char[strlen (name) + 5 + 1];
1232      }      if (!c->output)
1233      else if (err) {          BUG (0);
1234          msg_box (c->dlg, gpgme_strerror (err), _("Decrypt"), MB_ERR);      strcpy (ext, file_get_extension (ctx, c->sigmode));
1235          rc = WPTERR_GENERAL;      strcpy (c->output, name);
1236          goto leave;      strcat (c->output, ext);
1237      }  
1238      if (file_exist_check (c->output)) {      if (overwrite_file (c->output) == 0) {
1239          log_box ("Decrypt", MB_ERR, _("Decryption failed.\n%s: does not exist."), c->output);          rc = WPTERR_GENERAL;
1240          rc = WPTERR_GENERAL;          goto leave;    
1241      }      }
1242        
1243      sigres = gpgme_op_verify_result (ctx);      gpgme_set_passphrase_cb (ctx, sym_passphrase_cb, pass);
1244      if (sigres && sigres->signatures)      err = gpg_file_data_new (name, 1, &in);
1245          show_verify_result (sigres);      if (err)
1246            goto leave;
1247            err = gpg_file_data_new (c->output, 0, &out);
1248  leave:      if (err)
1249      if (in)          goto leave;
1250          gpg_file_data_release (in);  
1251      if (out)      op_begin ();
1252          gpg_file_data_release (out);      err = gpgme_op_encrypt (ctx, NULL, GPGME_ENCRYPT_ALWAYS_TRUST,
1253      return rc;                              in->dat, out->dat);
1254  }      op_end ();
1255        if (err) {
1256            msg_box (c->dlg, gpgme_strerror (err), _("Symmetric"), MB_ERR);
1257  int          rc = WPTERR_GENERAL;
1258  fm_sign (fm_state_t c, const char * name)          goto leave;
1259  {            }
1260      int rc = 0;      if (file_exist_check (c->output)) {
1261      gpgme_ctx_t ctx = c->ctx;          msg_box (c->dlg, _("Encryption failed."), _("Symmetric"), MB_ERR);
1262      gpgme_error_t err;          rc = WPTERR_GENERAL;
1263      file_data_t in=NULL, out=NULL;      }
1264      char ext[5];      
1265    leave:
1266      if (!c->init_cb || !c->cache_cb) {      if (in)
1267          set_gpg_passphrase_cb (&c->pass_cb, c->ctx, GPG_CMD_SIGN, c->dlg, _("Signing") );          gpg_file_data_release (in);
1268          c->init_cb = 1;      if (out)
1269      }          gpg_file_data_release (out);
1270            sfree_if_alloc (pass);
1271      free_if_alloc (c->output);      return rc;
1272      c->output = new char[strlen (name) + 5 + 1];  }
1273      if( !c->output)  
1274          BUG( NULL );  
1275      strcpy (ext, file_get_extension (ctx, c->sigmode));  /* Check the recipients if we have at least one secret key. */
1276      strcpy (c->output, name);  bool
1277      strcat (c->output, ext);  is_seckey_available (gpgme_recipient_t rset)
1278        {
1279      if (!overwrite_file (c->output)) {      gpgme_recipient_t r;
1280          rc = ask_filename (c, _("Enter filename for signed file"), NULL);      winpt_key_s key;
1281          if (rc)  
1282              goto leave;      for (r=rset; r; r = r->next) {
1283      }          if (gpgme_err_code (r->status) == GPG_ERR_NO_SECKEY)
1284      remove_crit_file_attrs (c->output, 0);              continue;
1285            else {
1286      err = gpg_file_data_new (name, 1, &in);              memset (&key, 0, sizeof (key));
1287      if (err)              /* extra check to make sure the key is available right now. */
1288          goto leave;              if (!winpt_get_seckey (r->keyid, &key)) {
1289      err = gpg_file_data_new (c->output, 0, &out);                  winpt_release_pubkey (&key);
1290      if (err)                  return true;
1291          goto leave;              }
1292                winpt_release_pubkey (&key);
1293      err = gpgme_op_sign (ctx, in->dat, out->dat, c->sigmode);          }
1294      if( !c->cache_cb )      }
1295          release_gpg_passphrase_cb (&c->pass_cb);      return false;
1296      if( c->pass_cb.cancel ) {  }
1297          rc = WPTERR_GENERAL;  
1298          goto leave;  
1299      }  /* If the decrypt result contains the original file name,
1300      if( err ) {     we use it instead of the artificial "output - .gpg" string. */
1301          msg_box( c->dlg, gpgme_strerror( err ), _("Sign"), MB_ERR );  static int
1302          rc = WPTERR_GENERAL;  restore_original_name (const char *output, const char *file_name)
1303          goto leave;      {
1304      }      char *dir;
1305        char *orig;
1306  leave:      int rc = 0;
1307      if (in)  
1308          gpg_file_data_release (in);      dir = strrchr (output, '\\');
1309      if (out)      if (!dir)
1310          gpg_file_data_release (out);          orig = strdup (file_name);
1311      return rc;      else {
1312  }          orig = (char*)calloc (1, strlen (file_name)+ 1 +
1313                                     strlen (output)+1);
1314            if (!orig)
1315  static int              BUG (0);
1316  fm_add_sig_stat (file_sig_ctx_t log)          memcpy (orig, output, (dir-output)+1);
1317  {          strcat (orig, file_name);
1318      gpgme_key_t key;          }
1319      const char *kid;      /* XXX: we need to find out if the string needs to be utf8 decoded. */
1320      int not_found = 0;      if (overwrite_file (orig)) {
1321            DeleteFile (orig);
1322      kid = log->sig->fpr;          if (!MoveFile (output, orig))
1323      if (!kid)              rc = -1;
1324          BUG (NULL);      }
1325      if (strlen (kid) == 40)      safe_free (orig);
1326          kid += 32;            return rc;
1327      else if (strlen (kid) == 32)  }
1328          kid += 24;  
1329      if (get_pubkey (kid, &key))  
1330          log->use_uid = 0;  /* Decrypt the file @name. */
1331      else {  int
1332          log->user_id = key->uids->uid;  fm_decrypt (fm_state_t c, const char *name)
1333          log->use_uid = 1;  {
1334      }      gpgme_error_t err;
1335      file_verify_add_state (log);      gpgme_ctx_t ctx = c->ctx;    
1336      return 0;      gpgme_decrypt_result_t res;
1337  }      gpgme_verify_result_t sigres;
1338        file_data_t in = NULL, out = NULL;
1339        int rc = 0;
1340  static int      
1341  verify_pasted (listview_ctrl_t lv, fm_state_t ctx, const char * dat,      if (!c->init_cb || !c->cache_cb) {
1342                 int i, HWND dlg)          set_gpg_passphrase_cb (&c->pass_cb, c->ctx, GPG_CMD_DECRYPT,
1343  {                                 c->dlg, _("Decryption"));
1344      FILE * fp;          c->init_cb = 1;
1345      char stat[32];      }
1346      char file[256], * fname = NULL;      
1347      int del_end=0;      c->output = m_strdup (name);
1348        if (is_openpgp_ext (c->output))
1349      listview_get_item_text (lv, i, 0, stat, sizeof (stat)-1);          c->output[strlen (c->output)-4] = '\0';
1350      listview_get_item_text (lv, i, 1, file, sizeof (file)-1);      else {
1351      if (strcmp (stat, "UNKNOWN"))          const char *s;
1352          return 0;          s = get_filesave_dlg (c->dlg, _("Choose Filename for Output"),
1353      fname = make_filename (NULL, file, "asc");                                NULL, NULL);
1354      if (file_exist_check (fname) != 0) {          if (s) {
1355          fp = fopen (fname, "wb");              free_if_alloc (c->output);
1356          if (fp == NULL) {              c->output = m_strdup (s);
1357              log_box (_("File Manager"), MB_ERR, "could not create '%s'", fname);          }
1358              free_if_alloc (fname);      }
1359              return WPTERR_GENERAL;        
1360          }            if (overwrite_file (c->output) == 0) {
1361          fwrite (dat, 1, strlen (dat), fp);          rc = ask_filename (c, _("Enter Filename for Plaintext File"), NULL);
1362          fclose (fp);          if (rc)
1363          del_end = 1;              goto leave;
1364      }      }
1365      fm_verify (ctx, 1, fname);  
1366      if (del_end)      /* we fetch all recipients here to make sure they list is complete. */
1367          unlink (fname);      release_gpg_recipients (&c->pass_cb.recipients);
1368      free_if_alloc (fname);      gpg_get_recipients (name, &c->pass_cb.recipients);
1369      return 0;  
1370  }      err = gpg_file_data_new (name, F_DATA_READ, &in);
1371        if (err)
1372            goto leave;
1373  int      remove_crit_file_attrs (c->output, 0);
1374  fm_verify_pasted_detsig (listview_ctrl_t lv, HWND dlg)      err = gpg_file_data_new (c->output, F_DATA_WRITE, &out);
1375  {      if (err)
1376      fm_state_t ctx = NULL;          goto leave;
1377      char * dat=NULL;      
1378      int i, fnd = 0;      op_begin ();
1379        err = gpgme_op_decrypt_verify (ctx, in->dat, out->dat);
1380      dat = get_clip_text (NULL);      op_end ();
1381      if (!dat || !strstr (dat, "BEGIN PGP SIGNATURE")) {      if (!c->cache_cb)
1382          msg_box (dlg, _("Could not find detached signature in the clipboard."),          release_gpg_passphrase_cb (&c->pass_cb);
1383                   _("File Manager"), MB_ERR);      if (c->pass_cb.cancel) {
1384          free_if_alloc (dat);          rc = WPTERR_GENERAL;
1385          return WPTERR_GENERAL;          goto leave;
1386      }      }
1387      /* XXX find a way to filter out bad signatures or just ignore all in  
1388             this case */      res = gpgme_op_decrypt_result (ctx);
1389      fm_state_new (&ctx);      if (res && res->recipients && !is_seckey_available (res->recipients)) {
1390      if ((i=listview_get_curr_pos (lv)) != -1) {          const char *keyid = get_keyid_from_fpr (res->recipients->keyid);
1391          verify_pasted (lv, ctx, dat, i, dlg);          char *p = get_key_userid (keyid);
1392          fnd = 1;          gpgme_pubkey_algo_t pkalgo = res->recipients->pubkey_algo;
1393      }          
1394      else {          log_box (_("Decryption"), MB_ERR,
1395          for (i=0; i < listview_count_items (lv, 0); i++) {                   _("Encrypted with %s key, ID 0x%s.%s\n"
1396              verify_pasted (lv, ctx, dat, i, dlg);                     "Decryption failed: secret key not available."),
1397              fnd = 1;                     get_key_pubalgo (pkalgo), keyid, p);
1398          }          rc = WPTERR_GENERAL;
1399      }          free_if_alloc (p);
1400      if (!fnd)          goto leave;
1401          msg_box (dlg, _("No files to check."), _("File Manager"), MB_INFO);      }
1402      free_if_alloc (dat);      else if (err) {
1403      fm_state_release (ctx);          msg_box (c->dlg, gpgme_strerror (err), _("Decrypt"), MB_ERR);
1404      return 0;          rc = WPTERR_GENERAL;
1405  }          goto leave;
1406        }
1407        if (file_exist_check (c->output)) {
1408  /* Extract automatically the output file name from @name.          log_box ("Decrypt", MB_ERR,
1409     If @detached is 1, a detached sig is assumed. */                   _("Decryption failed.\n%s: does not exist."), c->output);
1410  static int          rc = WPTERR_GENERAL;
1411  get_output_file (fm_state_t c, const char *name, int detached)          goto leave;
1412  {      }
1413      const char *file = NULL;      else if (res && res->file_name) {
1414      const char *title;          char *file;
1415      char fname[384];          int id = IDNO;
1416        
1417      if (detached)          file = strrchr (c->output, '\\');
1418          title = _("Select Data File");          if (!file)
1419      else              file = c->output;
1420          title = _("Selected Output File");          else
1421                file++;
1422      if (strstr (name, ".sig") || strstr (name, ".asc") || strstr (name, ".gpg")) {          if (strcmp (res->file_name, file))
1423          _snprintf (fname, sizeof (fname) - 1, "%s", name);              id = log_box (_("Decrypt"), MB_QUEST_ASK,
1424          fname[strlen (fname) - 4] = '\0';                            _("The original file name is '%s'.\n\n"
1425          if (file_exist_check (fname) == 0 && detached)                                "Do you want to use this instead of '%s'?"),
1426              file = fname;                        res->file_name, file);
1427          else if (!detached) {          if (id == IDYES) {
1428              /* If the signature is clear or normal, make sure we do not              /* before we can move the file, it needs to be closed first. */
1429                 overwrite the original file if it exists. */              gpg_file_data_release (out);
1430              if (file_exist_check (fname) == 0 && !overwrite_file (fname)) {              out = NULL;
1431                  file = get_filesave_dlg (c->dlg, title, NULL, NULL);              restore_original_name (c->output, res->file_name);
1432                  if (!file)          }
1433                      return WPTERR_GENERAL;      }
1434              }      sigres = gpgme_op_verify_result (ctx);
1435              else      if (sigres && sigres->signatures)
1436                  file = fname;          verify_show_signature_state (sigres->signatures);
1437          }      
1438      }  leave:
1439      if (!file)      if (in)
1440          file = get_fileopen_dlg (c->dlg, title, NULL, NULL);          gpg_file_data_release (in);
1441      if (file) {          if (out)
1442          free_if_alloc (c->output);              gpg_file_data_release (out);
1443          c->output = m_strdup (file);  
1444          if (!c->output)      return rc;
1445              BUG (NULL);  }
1446      }  
1447      else {  
1448          msg_box (c->dlg, _("Invalid file name. Exit"), _("Verify"), MB_ERR);  int
1449          return WPTERR_GENERAL;    fm_sign (fm_state_t c, const char * name)
1450      }  {
1451      if (detached)      gpgme_ctx_t ctx = c->ctx;
1452          c->sigmode = GPGME_SIG_MODE_DETACH;      gpgme_error_t err;
1453      else {      file_data_t in=NULL, out=NULL;
1454          if (strstr (name, ".asc"))      char ext[5];
1455              c->sigmode = GPGME_SIG_MODE_CLEAR;      int rc = 0;
1456          else  
1457              c->sigmode = GPGME_SIG_MODE_NORMAL;      if (!c->init_cb || !c->cache_cb) {
1458      }          set_gpg_passphrase_cb (&c->pass_cb, c->ctx,
1459      return 0;                                 GPG_CMD_SIGN, c->dlg, _("Signing"));
1460  }          c->init_cb = 1;
1461        }
1462        
1463  /* Verify the signature from the file @name. If @detached 1,      free_if_alloc (c->output);
1464     it is assumed that a detached signature should be checked. */      c->output = new char[strlen (name) + 5 + 1];
1465  int      if (!c->output)
1466  fm_verify (fm_state_t c, int detached, const char *name)          BUG (NULL);
1467  {      strcpy (ext, file_get_extension (ctx, c->sigmode));
1468      gpgme_ctx_t ctx = c->ctx;      strcpy (c->output, name);
1469      gpgme_error_t err;      strcat (c->output, ext);
1470      gpgme_signature_t s;      
1471      gpgme_verify_result_t res;      if (!overwrite_file (c->output)) {
1472      struct file_sig_ctx_s log;          rc = ask_filename (c, _("Enter Filename for Signed File"), NULL);
1473      file_data_t in=NULL, out=NULL;          if (rc)
1474      int rc = 0;              goto leave;
1475        }
1476      if (strstr (name, ".sig"))      
1477          detached = 1;      err = gpg_file_data_new (name, F_DATA_READ, &in);
1478        if (err)
1479      if (get_output_file (c, name, detached))          goto leave;
1480          return WPTERR_GENERAL;      remove_crit_file_attrs (c->output, 0);
1481        err = gpg_file_data_new (c->output, F_DATA_WRITE, &out);
1482      memset (&log, 0, sizeof (log));      if (err)
1483      log.file = m_strdup (name);          goto leave;
1484      if (!log.file)  
1485          BUG (NULL);      op_begin ();
1486      file_verify_create_dlg ();      err = gpgme_op_sign (ctx, in->dat, out->dat, c->sigmode);
1487        op_end ();
1488      err = gpg_file_data_new (name, 1, &in);      if (!c->cache_cb)
1489      if (err)          release_gpg_passphrase_cb (&c->pass_cb);
1490          goto leave;      if (c->pass_cb.cancel) {
1491      err = gpg_file_data_new (c->output, detached? 1 : 0, &out);          rc = WPTERR_GENERAL;
1492      if (err)          goto leave;
1493          goto leave;      }
1494        if (err) {
1495      if (c->sigmode == GPGME_SIG_MODE_DETACH)          msg_box (c->dlg, gpgme_strerror (err), _("Sign"), MB_ERR);
1496          err = gpgme_op_verify (ctx, in->dat, out->dat, NULL);          rc = WPTERR_GENERAL;
1497      else          goto leave;    
1498          err = gpgme_op_verify (ctx, in->dat, in->dat, out->dat);      }
1499      if (err) {  
1500          msg_box (c->dlg, gpgme_strerror (err), _("Verify"), MB_ERR);  leave:
1501          rc = WPTERR_GENERAL;      if (in)
1502          goto leave;          gpg_file_data_release (in);
1503      }          if (out)
1504            gpg_file_data_release (out);
1505      res = gpgme_op_verify_result (ctx);      return rc;
1506      for (s=res->signatures; s; s=s->next) {  }
1507          log.sig = s;  
1508          fm_add_sig_stat (&log);  
1509      }  static void
1510      if (!c->output)  fm_add_sig_stat (file_sig_ctx_t log)
1511          c->output = m_strdup (name); /* for later use */  {
1512        struct winpt_key_s key;
1513  leave:      const char *kid;
1514      if (in)  
1515          gpg_file_data_release (in);      memset (&key, 0, sizeof (key));
1516      if (out)      kid = get_keyid_from_fpr (log->sig->fpr);
1517          gpg_file_data_release (out);      log->use_uid = 0;
1518      if (log.file)      if (!winpt_get_pubkey (kid, &key)) {
1519          delete []log.file;          log->user_id = key.ext->uids->uid;
1520      return rc;          log->use_uid = 1;
1521  }      }
1522        file_verify_add_state (log);
1523        winpt_release_pubkey (&key);    
1524  int  }
1525  fm_import (fm_state_t c, const char *name)  
1526  {  
1527      gpgme_ctx_t ctx = c->ctx;  /* Verify a detached signature from the clipboard. */  
1528      gpgme_error_t err;  static int
1529      gpgme_import_result_t res;  verify_pasted (listview_ctrl_t lv, fm_state_t ctx,
1530      file_data_t keydata = NULL;                 const char *dat, int pos, HWND dlg)
1531      int rc = 0;  {
1532        FILE *fp;
1533      free_if_alloc (c->output);      char stat[32];
1534      c->output = m_strdup (name);      char file[256], *fname = NULL;
1535      if (!c->output)      int del_end = 0;
1536          BUG (NULL);  
1537        listview_get_item_text (lv, pos, FM_COL_STAT, stat, sizeof (stat)-1);
1538      err = gpg_file_data_new (name, 1, &keydata);      listview_get_item_text (lv, pos, FM_COL_NAME, file, sizeof (file)-1);
1539      if (err)      if (strcmp (stat, "UNKNOWN"))
1540          goto leave;          return 0;
1541        fname = make_filename (NULL, file, "asc");
1542      err = gpgme_op_import (ctx, keydata->dat);      if (file_exist_check (fname) != 0) {
1543      if (err) {          fp = fopen (fname, "wb");
1544          msg_box (c->dlg, gpgme_strerror (err), _("Import"), MB_ERR);          if (fp == NULL) {
1545          rc = WPTERR_GENERAL;              log_box (_("File Manager"), MB_ERR, "Could not create '%s'", fname);
1546          goto leave;              free_if_alloc (fname);
1547      }              return WPTERR_GENERAL;
1548            }
1549      res = gpgme_op_import_result (ctx);          fwrite (dat, 1, strlen (dat), fp);
1550      print_import_status (res);          fclose (fp);
1551      if (res->no_user_id > 0) {          del_end = 1;
1552          msg_box (c->dlg, _("Key without a self signature was dectected!\n"            }
1553                             "(This key is NOT usable for encryption, etc)\n"      fm_verify (ctx, 1, fname);
1554                             "\n"      if (del_end)
1555                             "Cannot import these key(s)!"), _("Import"), MB_INFO);          DeleteFile (fname);
1556      }      free_if_alloc (fname);
1557        return 0;
1558  leave:  }
1559      if (keydata)  
1560          gpg_file_data_release (keydata);  
1561      return rc;  /* Figure out if the clipboard contains a detached signature. */
1562  } /* fm_import */  int
1563    fm_verify_pasted_detsig (listview_ctrl_t lv, HWND dlg)
1564    {
1565  /* Export the selected keys from the File Manager to a file. */      fm_state_t ctx = NULL;
1566  int      char * dat=NULL;
1567  fm_export (fm_state_t c)      int i, fnd = 0;
1568  {  
1569      int rc = 0, id = 0;      dat = get_clip_text (NULL);
1570      gpgme_ctx_t ctx = c->ctx;      if (!dat || !strstr (dat, "BEGIN PGP SIGNATURE")) {
1571      gpgme_error_t err;          msg_box (dlg, _("Could not find detached signature in the clipboard."),
1572      gpgme_key_t *rset = c->recp;                   _("File Manager"), MB_ERR);
1573      file_data_t keydata = NULL;          free_if_alloc (dat);
1574      const char *name, *s = NULL;          return WPTERR_GENERAL;
1575      char *p = NULL, *patt = NULL;      }
1576        /* XXX find a way to filter out bad signatures or just ignore all in
1577      if (!rset || !rset[0]) {             this case */
1578          msg_box (c->dlg, _("No key was selected for export."), _("Export"), MB_ERR);      fm_state_new (&ctx);
1579          rc = WPTERR_GENERAL;      i = listview_get_curr_pos (lv);
1580          goto leave;      if (i= -1) {
1581      }          verify_pasted (lv, ctx, dat, i, dlg);
1582            fnd = 1;
1583      if (rset[1] == NULL) { /* count == 1*/      }
1584          gpgme_key_t k = rset[0];      else {
1585          const char *s = k->uids->name;          for (i=0; i < listview_count_items (lv, 0); i++) {
1586          p = new char[strlen (s)+1+8];              verify_pasted (lv, ctx, dat, i, dlg);
1587          if (!p)              fnd = 1;
1588              BUG (NULL);          }
1589          strcpy (p, s );      }
1590          strcat (p, ".asc");      if (!fnd)
1591      }          msg_box (dlg, _("No files to check."), _("File Manager"), MB_INFO);
1592        free_if_alloc (dat);
1593      name = get_filename_dlg (c->dlg, FILE_SAVE, _("Choose Name for Key File"),      fm_state_release (ctx);
1594                               NULL, p? p : NULL);      return 0;
1595                                }
1596      if (!name)  
1597          name = "keys.gpg";  
1598    /* Extract automatically the output file name from @name.
1599      patt = gpg_keylist_to_pattern (rset, c->n_recp);     If @detached is 1, a detached sig is assumed. */
1600    static int
1601      err = gpg_file_data_new (name, 0, &keydata);  get_output_file (fm_state_t c, const char *name, int detached)
1602      if (err)  {
1603          goto leave;      const char *file = NULL;
1604        const char *title;
1605      err = gpgme_op_export (ctx, patt, 0, keydata->dat);      char fname[384];
1606      if (err) {      
1607          msg_box (c->dlg, gpgme_strerror (err), _("Export"), MB_ERR);      if (detached)
1608          rc = WPTERR_GENERAL;          title = _("Select Data File");
1609          goto leave;          else
1610      }          title = _("Selected Output File");
1611      log_box (_("GnuPG status"), MB_OK, _("Finished (Output: %s)"),  name);  
1612        if (is_openpgp_ext (name)) {
1613  leave:          _snprintf (fname, sizeof (fname) - 1, "%s", name);
1614      if (keydata)          fname[strlen (fname) - 4] = '\0';
1615          gpg_file_data_release (keydata);          if (file_exist_check (fname) == 0 && detached)  
1616      if (patt)              file = fname;
1617          free (patt);          else if (!detached) {
1618      free_if_alloc (p);              /* If the signature is clear or normal, make sure we do not
1619                           overwrite the original file if it exists. */
1620      return rc;              if (file_exist_check (fname) == 0 && !overwrite_file (fname)) {
1621  }                  file = get_filesave_dlg (c->dlg, title, NULL, NULL);
1622                    if (!file)
1623                        return WPTERR_GENERAL;
1624  /* Parse the command line and process the given file. */                }
1625  int              else
1626  fm_parse_command_line (char *cmdl)                  file = fname;
1627  {          }
1628      fm_state_t ctx;      }
1629      const char *s;      if (!file)
1630      char *p, *fn = NULL;          file = get_fileopen_dlg (c->dlg, title, NULL, NULL);
1631      int count = 0, detached = 0;      if (file) {    
1632      int type;          free_if_alloc (c->output);    
1633                c->output = m_strdup (file);
1634      if (!cmdl || !*cmdl)      }
1635          return 0;      else {
1636            msg_box (c->dlg, _("Invalid file name. Exit"), _("Verify"), MB_ERR);
1637      fm_state_new (&ctx);              return WPTERR_GENERAL;  
1638      ctx->dlg = GetActiveWindow ();      }
1639      ctx->cache_cb = 1;      if (detached)
1640                c->sigmode = GPGME_SIG_MODE_DETACH;
1641      p = cmdl;      else {
1642      if (p && *p > 32 && !stristr (p, "winpt.exe")          if (stristr (name, ".asc"))
1643                       && !strstr (p, "--" )) {              c->sigmode = GPGME_SIG_MODE_CLEAR;
1644          count++;          else
1645          if (*p == '"') { /* need to remove quotes */              c->sigmode = GPGME_SIG_MODE_NORMAL;
1646              fn = new char[strlen (p)];      }
1647              if (!fn)      return 0;
1648                  BUG (NULL);  }
1649              memcpy (fn, p+1, strlen (p) - 2);  
1650              fn[strlen (p) -2] = '\0';  
1651          }  /* Verify the signature from the file @name. If @detached 1,
1652          else     it is assumed that a detached signature should be checked. */
1653              fn = m_strdup (p);  int
1654          s = fm_get_file_type (fn, &type);  fm_verify (fm_state_t c, int detached, const char *name)
1655          log_box ("debug", MB_OK, "%s %d", s, type);  {
1656          if (!s || !strcmp (s, "UNKNOWN"))      gpgme_ctx_t ctx = c->ctx;
1657              s = gnupg_check_file_ext (fn, &type);      gpgme_error_t err;
1658          if (type == PGP_NONE) {      gpgme_signature_t s;
1659              log_box (_("File Manager"), MB_ERR,      gpgme_verify_result_t res;
1660                       _("%s: no valid OpenPGP data found."), p);      struct file_sig_ctx_s log;
1661              free_if_alloc (fn);      file_data_t in=NULL, out=NULL;
1662              return count;      int rc = 0;
1663          }  
1664                if (stristr (name, ".sig"))
1665          log_box ("debug", MB_OK, "type=%d", type); /*XXX: debug*/          detached = 1;
1666          switch (type) {  
1667          case PGP_MESSAGE:      if (get_output_file (c, name, detached))
1668              fm_decrypt (ctx, fn);          return WPTERR_GENERAL;
1669              break;  
1670        memset (&log, 0, sizeof (log));
1671          case PGP_PUBKEY:      log.file = m_strdup (name);
1672          case PGP_SECKEY:      file_verify_create_dlg ();
1673              fm_import (ctx, fn);  
1674              break;      err = gpg_file_data_new (name, F_DATA_READ, &in);
1675        if (err)
1676          case PGP_SIG:          goto leave;
1677          case PGP_CLEARSIG:      err = gpg_file_data_new (c->output,
1678              file_verify_use_event ();                               detached? F_DATA_READ : F_DATA_WRITE, &out);
1679              if (type == PGP_SIG)          if (err)
1680                  detached = 1;          goto leave;
1681              fm_verify (ctx, detached, fn);  
1682              file_verify_wait ();      op_begin ();
1683              break;      if (c->sigmode == GPGME_SIG_MODE_DETACH)
1684          }          err = gpgme_op_verify (ctx, in->dat, out->dat, NULL);
1685      }      else
1686            err = gpgme_op_verify (ctx, in->dat, in->dat, out->dat);
1687      wipememory (&ctx->pass_cb, sizeof (ctx->pass_cb));      op_end ();
1688      free_if_alloc (fn);      if (err) {
1689      fm_state_release (ctx);          msg_box (c->dlg, gpgme_strerror (err), _("Verify"), MB_ERR);
1690      return count;          rc = WPTERR_GENERAL;
1691  }          goto leave;
1692        }    
1693    
1694  const char*      res = gpgme_op_verify_result (ctx);
1695  default_dirname (const char *name)      for (s=res->signatures; s; s=s->next) {
1696  {          log.sig = s;
1697      char * p = strrchr( name, '\\' );          fm_add_sig_stat (&log);
1698      if( !p )      }
1699          return NULL;      if (!c->output)
1700      return p+1;          c->output = m_strdup (name); /* for later use */
1701  } /* default_dirname */  
1702    leave:
1703        if (in)
1704  int          gpg_file_data_release (in);
1705  fm_encrypt_directory( fm_state_t c, const char * name )      if (out)
1706  {          gpg_file_data_release (out);
1707      PK_FILE_LIST list = NULL;      free_if_alloc (log.file);
1708      WIN32_FIND_DATA findbuf;      return rc;
1709      HANDLE hd;  }
1710      const char * s;  
1711      char * patt = NULL, * p;  
1712      int rc = 0;  /* Import the keys from the file @name.
1713           Return value: 0 on success. */
1714      if( !is_directory( name ) )      int
1715          return -1;  fm_import (fm_state_t c, const char *name)
1716      patt = new char[strlen( name ) + 4];  {
1717      if( !patt )      gpgme_ctx_t ctx = c->ctx;
1718          BUG( NULL );      gpgme_error_t err;
1719      strcpy( patt, name );      gpgme_import_result_t res;
1720      strcat( patt, "\\*" );      file_data_t keydata = NULL;
1721      hd = FindFirstFile( patt, &findbuf );          int rc = 0;
1722      if( !hd ) {  
1723          free_if_alloc( patt );        free_if_alloc (c->output);
1724          return -1;            c->output = m_strdup (name);
1725      }  
1726      if( strcmp( findbuf.cFileName, "." ) && strcmp( findbuf.cFileName, ".." ) ) {      err = gpg_file_data_new (name, F_DATA_READ, &keydata);
1727          p = make_filename( name, findbuf.cFileName, NULL );      if (err)
1728          pk_list_add( &list, p );          goto leave;
1729          free_if_alloc( p );  
1730      }      op_begin ();
1731      while( FindNextFile( hd, &findbuf ) ) {      err = gpgme_op_import (ctx, keydata->dat);
1732          if( strcmp( findbuf.cFileName, "." ) && strcmp( findbuf.cFileName, ".." ) ) {      op_end ();
1733              p = make_filename( name, findbuf.cFileName, NULL );      if (err) {
1734              pk_list_add( &list, p );          msg_box (c->dlg, gpgme_strerror (err), _("Import"), MB_ERR);
1735              free_if_alloc( p );          rc = WPTERR_GENERAL;
1736          }          goto leave;
1737      }      }
1738      s = get_filename_dlg( c->dlg, FILE_SAVE, _("Choose a Name for the Archive"),  
1739                            NULL, default_dirname( name ) );      res = gpgme_op_import_result (ctx);
1740      if( !s ) {      print_import_status (res);
1741          msg_box( c->dlg, _("Invalid archive name. Exit."), _("Encrypt Directory"), MB_ERR );      if (res->no_user_id > 0) {
1742          rc = -1;          msg_box (c->dlg, _("Key without a self signature was dectected!\n"
1743          goto leave;                             "(This key is NOT usable for encryption, etc)\n"
1744      }                             "\n"
1745                               "Cannot import these key(s)!"), _("Import"), MB_INFO);
1746      rc = pk_archiv_create( list, s );      }
1747      if( rc )  
1748          msg_box( c->dlg, _("Could not create zip archive."), _("Encrypt Directory"), MB_ERR );  leave:
1749      else {      if (keydata)
1750          fm_encrypt( c, s, 0 );          gpg_file_data_release (keydata);
1751          unlink( s );      return rc;
1752      }  }
1753  leave:  
1754      FindClose (hd);  
1755      pk_list_free( list );  /* Export the selected keys from the File Manager to a file. */
1756      free_if_alloc( patt );  int
1757      return rc;  fm_export (fm_state_t c)
1758  } /* fm_encrypt_directory */  {    
1759        gpgme_ctx_t ctx = c->ctx;
1760        gpgme_error_t err;
1761  static int CALLBACK      gpgme_key_t *rset = c->recp;
1762  fm_cmp_cb( LPARAM first, LPARAM second, LPARAM sortby )      file_data_t keydata = NULL;
1763  {      const char *name;
1764      const char * a = 0, * b = 0;      char *p = NULL, *patt = NULL;
1765        int rc = 0;
1766      switch( (int)sortby ) {  
1767      case FM_SORT_STAT:      if (!rset || !rset[0]) {
1768          break;          msg_box (c->dlg, _("No key was selected for export."),
1769      case FM_SORT_NAME:                   _("Export"), MB_ERR);
1770          break;          rc = WPTERR_GENERAL;
1771      case FM_SORT_OP:          goto leave;
1772          break;      }
1773      }  
1774      return stricmp( a, b );      if (rset[1] == NULL) /* count == 1*/
1775  } /* fm_cmp_cb */          p = km_gen_export_filename (rset[0]->subkeys->keyid+8, 0);
1776            
1777        name = get_filesave_dlg (c->dlg, _("Choose Name for Key File"),
1778  int                               NULL, p? p : NULL);
1779  fm_sort( listview_ctrl_t lv, int sortby )      if (!name)
1780  {          name = reg_prefs.default_ext? "keys.pgp" : "keys.gpg";
1781      return listview_sort_items( lv, sortby, fm_cmp_cb );  
1782  } /* fm_sort */      patt = gpg_keylist_to_pattern (rset, c->n_recp);
1783    
1784        err = gpg_file_data_new (name, F_DATA_WRITE, &keydata);
1785  void      if (err)
1786  fm_print_md( listview_ctrl_t lv, HWND dlg, int mdalgo )          goto leave;
1787  {  
1788      struct md_file_s mdctx;      op_begin ();
1789        err = gpgme_op_export (ctx, patt, 0, keydata->dat);
1790      if( listview_count_items( lv, 0 ) == 0 )      op_end ();
1791          return;      if (err) {
1792      memset (&mdctx, 0, sizeof (mdctx));          msg_box (c->dlg, gpgme_strerror (err), _("Export"), MB_ERR);
1793      mdctx.lv = lv;          rc = WPTERR_GENERAL;
1794      mdctx.mdalgo = mdalgo;          goto leave;    
1795      DialogBoxParam( glob_hinst, (LPCTSTR)IDD_WINPT_FILE_MDSUM, dlg,      }
1796                      mdsum_dlg_proc, (LPARAM)&mdctx );      log_box (_("GnuPG status"), MB_OK, _("Finished (Output: %s)"),  name);
1797  } /* fm_print_md */  
1798    leave:
1799        if (keydata)
1800  int          gpg_file_data_release (keydata);
1801  fm_send_file (listview_ctrl_t lv)      safe_free (patt);
1802  {      free_if_alloc (p);
1803      char buf[128];      return rc;
1804      int rc;  }
1805    
1806      rc = listview_get_item_text (lv, -1, 1, buf, sizeof (buf)-1);  
1807      if (rc == -1)  /* Parse the command line and process the given file. */  
1808          return 0;  int
1809      /*mapi_send_ascfile (buf); XXX */  fm_parse_command_line (char *cmdl)
1810      return 0;  {
1811  }      fm_state_t ctx;
1812        const char *s;
1813        char *p, *fn = NULL;
1814        int count = 0, detached = 0;
1815        int type;
1816        
1817        if (!cmdl || !*cmdl)
1818            return 0;
1819    
1820        fm_state_new (&ctx);    
1821        ctx->dlg = GetActiveWindow ();
1822        ctx->cache_cb = 1;
1823        
1824        p = cmdl;
1825        if (p && *p > 32 && !stristr (p, "winpt.exe")
1826                         && !strstr (p, "--" )) {
1827            count++;
1828            if (*p == '"') { /* need to remove quotes */
1829                fn = new char[strlen (p)];
1830                if (!fn)
1831                    BUG (NULL);
1832                memcpy (fn, p+1, strlen (p) - 2);
1833                fn[strlen (p) -2] = '\0';
1834            }
1835            else
1836                fn = m_strdup (p);
1837            s = fm_get_file_type (fn, &type);
1838            if (!s || !strcmp (s, "UNKNOWN"))
1839                s = gnupg_check_file_ext (fn, &type);
1840            if (type == PGP_NONE) {
1841                log_box (_("File Manager"), MB_ERR,
1842                         _("%s: no valid OpenPGP data found."), p);
1843                free_if_alloc (fn);
1844                return count;
1845            }
1846            switch (type) {
1847            case PGP_MESSAGE:
1848                fm_decrypt (ctx, fn);
1849                break;
1850    
1851            case PGP_PUBKEY:
1852            case PGP_SECKEY:
1853                fm_import (ctx, fn);
1854                break;
1855    
1856            case PGP_SIG:
1857            case PGP_CLEARSIG:
1858                if (type == PGP_SIG)    
1859                    detached = 1;
1860                fm_verify (ctx, detached, fn);
1861                file_verify_wait ();
1862                break;
1863    
1864            default:
1865                break;
1866            }
1867        }
1868    
1869        wipememory (&ctx->pass_cb, sizeof (ctx->pass_cb));
1870        free_if_alloc (fn);
1871        fm_state_release (ctx);
1872        return count;
1873    }
1874    
1875    
1876    /* Extract the last folder name from @name. */
1877    const char*
1878    default_dirname (const char *name)
1879    {
1880        char *p = strrchr (name, '\\');
1881        if (!p)
1882            return NULL;
1883        return p+1;
1884    }
1885    
1886    
1887    /* Store all selected files from @lv in a zip archive
1888       and encrypt the zip archive then.
1889       Return value: 0 on success. */
1890    int
1891    fm_encrypt_into_zip (fm_state_t ctx, listview_ctrl_t lv)
1892    {
1893        PK_FILE_LIST list=NULL;
1894        const char *outfile, *ext;
1895        char *out_enc;
1896        int nitems;
1897        int i, idx = -1;
1898        int rc;
1899    
1900        nitems = listview_count_items (lv, 0);
1901        if (!nitems) {
1902            msg_box (NULL, _("Encrypting into a ZIP archive makes sense with multiple files"),
1903                     _("File Manager"), MB_ERR);
1904            return WPTERR_GENERAL;
1905        }
1906    
1907        outfile = get_filesave_dlg (ctx->dlg, _("Choose File Name for Output"),
1908                                    NULL, "Encrypted_Files.zip");
1909        if (!outfile)
1910            return WPTERR_GENERAL;
1911    
1912        for (i=0; i < nitems; i++) {
1913            char name[MAX_PATH+32];
1914    
1915            if (!listview_get_item_state (lv, i))
1916                continue;
1917            if (idx == -1)
1918                idx = i;
1919            listview_get_item_text (lv, i, 1, name, sizeof (name)-1);
1920            pk_list_add (&list, name);
1921        }    
1922    
1923        pk_archiv_create (list, outfile);
1924        pk_list_free (list);
1925    
1926        rc = fm_encrypt (ctx, outfile, 0);
1927        DeleteFile (outfile);
1928        if (rc)
1929            return rc;
1930    
1931        ext = file_get_extension (ctx->ctx, ctx->sigmode)+1;
1932        out_enc = make_filename (NULL, outfile, ext);
1933        fm_set_status (lv, idx, FM_ENCRYPT, (gpgme_sig_mode_t)0, 1, out_enc);
1934        free_if_alloc (out_enc);
1935    
1936        for (i=nitems; i > -1; i--) {
1937            if (i != idx && listview_get_item_state (lv, i))
1938                listview_del_item (lv, i);
1939        }
1940        return 0;
1941    }
1942    
1943    
1944    int
1945    fm_encrypt_directory (fm_state_t c, const char *name)
1946    {    
1947        WIN32_FIND_DATA findbuf;
1948        HANDLE hd;
1949        PK_FILE_LIST list = NULL;
1950        const char *s;
1951        char *patt = NULL, *p;
1952        int rc = 0;
1953        
1954        if (!is_directory (name))
1955            return -1;
1956        patt = new char[strlen (name) + 4];
1957        if (!patt)
1958            BUG (NULL);
1959        strcpy (patt, name);
1960        strcat (patt, "\\*");
1961        hd = FindFirstFile (patt, &findbuf);
1962        if (!hd) {
1963            free_if_alloc (patt);
1964            return WPTERR_GENERAL;
1965        }
1966        if (strcmp (findbuf.cFileName, ".") && strcmp (findbuf.cFileName, "..")) {
1967            p = make_filename (name, findbuf.cFileName, NULL);
1968            pk_list_add (&list, p);
1969            free_if_alloc (p);
1970        }
1971        while (FindNextFile (hd, &findbuf)) {
1972            if (strcmp (findbuf.cFileName, ".") && strcmp (findbuf.cFileName, "..")) {
1973                p = make_filename (name, findbuf.cFileName, NULL);
1974                pk_list_add (&list, p);
1975                free_if_alloc (p);
1976            }
1977        }
1978        s = get_filesave_dlg (c->dlg, _("Choose a Name for the Archive"),
1979                              NULL, default_dirname (name));
1980        if (!s) {
1981            msg_box (c->dlg, _("Invalid archive name. Exit."),
1982                     _("Encrypt Directory"), MB_ERR);
1983            rc = -1;
1984            goto leave;
1985        }
1986    
1987        rc = pk_archiv_create (list, s);
1988        if (rc)
1989            msg_box (c->dlg, _("Could not create zip archive."),
1990                     _("Encrypt Directory"), MB_ERR);
1991        else {
1992            fm_encrypt (c, s, 0);
1993            DeleteFile (s);
1994        }
1995    leave:
1996        FindClose (hd);
1997        pk_list_free (list);
1998        free_if_alloc (patt);
1999        return rc;
2000    }
2001    
2002    
2003    static int CALLBACK
2004    fm_cmp_cb (LPARAM first, LPARAM second, LPARAM sortby)
2005    {
2006        fm_model_t a, b;
2007        int cmpres = 0;
2008    
2009        a = (fm_model_t)first;
2010        b = (fm_model_t)second;
2011        if (!a || !b)
2012            return 0;
2013    
2014        switch ((int)sortby) {
2015        case FM_COL_STAT:
2016            cmpres = stricmp (a->status, b->status);
2017            break;
2018    
2019        case FM_COL_NAME:
2020            cmpres = stricmp (a->name, b->name);
2021            break;
2022    
2023        case FM_COL_OP:
2024            if (a->op && b->op)
2025                cmpres = stricmp (a->op, b->op);
2026            break;
2027        }
2028        return cmpres;
2029    }
2030    
2031    
2032    /* Sort the list items from @lv with the mode given by @sortby. */
2033    int
2034    fm_sort (listview_ctrl_t lv, int sortby)
2035    {
2036        return ListView_SortItems (lv->ctrl, fm_cmp_cb, (LPARAM)sortby);
2037    }
2038    
2039    
2040    /* Start the 'print md' dialog. Pass over the listview control
2041       @lv and the digest algo @mdalgo. */
2042    void
2043    fm_print_md (listview_ctrl_t lv, HWND dlg, int mdalgo)
2044    {
2045        struct md_file_s mdctx;
2046    
2047        if (listview_count_items (lv, 0) == 0)
2048            return;
2049        memset (&mdctx, 0, sizeof (mdctx));
2050        mdctx.lv = lv;
2051        mdctx.mdalgo = mdalgo;
2052        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_FILE_MDSUM, dlg,
2053                        mdsum_dlg_proc, (LPARAM)&mdctx);
2054    }
2055    
2056    
2057    /* Send the selected file in @lv via MAPI to a mail recipient. */
2058    int
2059    fm_send_file (listview_ctrl_t lv)
2060    {
2061        char name[128];
2062        int rc;
2063    
2064        rc = listview_get_item_text (lv, -1, FM_COL_NAME, name, sizeof (name)-1);
2065        if (rc != -1)
2066            mapi_send_ascfile (name);
2067        return 0;
2068    }

Legend:
Removed from v.32  
changed lines
  Added in v.256

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26