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

Contents of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26