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

Contents of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 205 - (show annotations)
Thu Apr 27 12:46:03 2006 UTC (18 years, 10 months ago) by twoaday
File size: 48900 byte(s)
2006-04-27  Timo Schulz  <ts@g10code.de>
                                                                                
        * wptKeyManager.cpp (km_get_key_ptr): New.
        * wptListview.cpp (listview_get_item_text): Drop utf8 support.
        * wptKeyCache.cpp (keycache_decode_uids): New.
        (free_native_uids): New.
        * wptKeyEdit.cpp (uid_inf_colon_handler): Do utf8 decodig here.
                                                                                
2006-04-26  Timo Schulz  <ts@g10code.de>
                                                                                
        * wptKeylist.cpp (get_keyid_from_fpr): New.
        * wptDecryptClipDlg.cpp (clip_decrypt_dlg): Use it here.
        * wptVerifyList.cpp (verlist_add_sig): Likewise.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26