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

Contents of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 333 - (show annotations)
Tue Oct 13 10:51:21 2009 UTC (15 years, 4 months ago) by twoaday
File size: 47106 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26