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

Contents of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 463 - (show annotations)
Tue Oct 9 09:07:28 2012 UTC (12 years, 4 months ago) by twoaday
File size: 44224 byte(s)
2012-10-09  Timo Schulz  <twoaday@gmx.net>

        * wptFileManager.cpp (fm_check_armor_type): Check more than
	        one line to determine the message type.
		

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26