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

Annotation of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 195 - (hide annotations)
Mon Apr 3 17:10:47 2006 UTC (18 years, 10 months ago) by twoaday
File size: 48753 byte(s)
Prepare new release.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26