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

Contents of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 234 - (show annotations)
Tue Jun 27 10:16:41 2006 UTC (18 years, 8 months ago) by twoaday
File size: 48564 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26