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

Contents of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 218 - (show annotations)
Wed May 24 07:53:24 2006 UTC (18 years, 9 months ago) by twoaday
File size: 49399 byte(s)
2006-05-23  Timo Schulz  <ts@g10code.de>
                                                                                
        * wptKeyEditDlgs.cpp (do_add_new_userid): Fix re-introduced
        problem.
        (keyedit_main_dlg_proc): Popup menu for the user ID list
        with common commands.
        * wptKeyserverDlg.cpp (keyserver_dlg_proc): Automatically
        disable search for ldap servers.
        Use subkeys.pgp.net by default when no server was selected.
                                                                                


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26