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

Legend:
Removed from v.28  
changed lines
  Added in v.295

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26