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

Contents of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 328 - (show annotations)
Fri Sep 25 16:07:38 2009 UTC (15 years, 5 months ago) by twoaday
File size: 47241 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_ENCRYPT_DIR:
733 case FM_SIGNENCRYPT:
734 if (strcmp (status, "ENCRYPTED")
735 && strcmp (status, "SYMKEYENC"))
736 rc = 1;
737 break;
738
739 case FM_DECRYPT:
740 if (!strcmp (status, "DATA") ||
741 !strcmp (status, "ENCRYPTED") ||
742 !strcmp (status, "SYMKEYENC") ||
743 !strcmp (status, "ARMORED"))
744 rc = 1;
745 break;
746
747 case FM_SIGN:
748 if (strncmp( status, "SIGNED", 6))
749 rc = 1;
750 break;
751
752 case FM_VERIFY:
753 if(!strncmp (status, "SIGNED", 6) ||
754 !strcmp (status, "COMPRESSED"))
755 rc = 1;
756 break;
757
758 case FM_SYMENC:
759 if (strcmp (status, "SYMKEYENC"))
760 rc = 1;
761 break;
762
763 case FM_IMPORT:
764 if (!strcmp (status, "PUBKEY") ||
765 !strcmp (status, "SECKEY"))
766 rc = 1;
767 break;
768
769 case FM_LIST:
770 rc = 1;
771 break;
772 }
773
774 return rc;
775 }
776
777
778 /* Set the file status of the given command @fm_cmd.
779 @success is 0 on success. */
780 static void
781 fm_set_status (listview_ctrl_t lv, int pos, int fm_cmd,
782 gpgme_sig_mode_t sigmode, int success, const char *output)
783 {
784 char status[128], operat[128];
785 int update = 1;
786 const char *s;
787
788 if (fm_cmd == FM_LIST)
789 return;
790 success ? s = "SUCCESS" : s = "FAILED";
791 strcpy (operat, s);
792
793 switch (fm_cmd) {
794 case FM_ENCRYPT:
795 case FM_ENCRYPT_DIR:
796 case FM_SIGNENCRYPT:
797 strcpy (status, "ENCRYPTED");
798 break;
799
800 case FM_DECRYPT:
801 strcpy (status, "UNKNOWN");
802 break;
803
804 case FM_SIGN:
805 if (sigmode == GPGME_SIG_MODE_DETACH)
806 strcpy (status, "SIGNED-DETACH");
807 else if (sigmode == GPGME_SIG_MODE_CLEAR)
808 strcpy (status, "SIGNED-CLEAR");
809 else
810 strcpy (status, "SIGNED");
811 break;
812 case FM_VERIFY:
813 update = 0;
814 break;
815
816 case FM_SYMENC:
817 strcpy (status, "SYMKEYENC");
818 break;
819
820 case FM_IMPORT:
821 update = 0;
822 break;
823
824 default:
825 strcpy (status, "UNKNOWN");
826 break;
827 }
828
829 if (success && update) {
830 listview_add_sub_item (lv, pos, FM_COL_STAT, status);
831 listview_add_sub_item (lv, pos, FM_COL_NAME, output);
832 }
833 listview_add_sub_item (lv, pos, FM_COL_OP, operat);
834 }
835
836
837 int
838 fm_clearsign_8bit (listview_ctrl_t lv, fm_state_s *ctx)
839 {
840 FILE *f;
841 BYTE buf[32];
842 char name[MAX_PATH+1];
843 int i, n, cnt=0;
844
845 if (ctx->sigmode != GPGME_SIG_MODE_CLEAR)
846 return 0;
847 listview_get_item_text (lv, -1, FM_COL_NAME, name, DIM (name)-1);
848 if (stristr (name, ".txt"))
849 return 0;
850 f = fopen (name, "rb");
851 if (!f)
852 return -1; /* should never happen */
853 n = fread (buf, 1, 32, f);
854 fclose (f);
855 for (i = 0; i < n; i++) {
856 if (buf[i] == 0x00 || buf[i] > 170)
857 cnt++;
858 }
859 if (!cnt)
860 return 0;
861 n = -1;
862 i = log_box (_("File Manager"), MB_WARN|MB_YESNO,
863 _("\"%s\" does not seems to be a text file.\n"
864 "Do you really want to clearsign it?"), name);
865 if (i == IDYES)
866 n = 0;
867 return n;
868 }
869
870 int
871 fm_parse_files (listview_ctrl_t lv, HWND dlg, int cmd)
872 {
873 struct progress_filter_s pfx/*, pfx2*/;
874 fm_state_s * ctx;
875 int fm_cmd, sig_detached = 0;
876 int rc = 0, i, n;
877 char fname[2*MAX_PATH+1], status[128];
878
879 switch (cmd) {
880 case ID_FILEMISC_ENCRYPT: fm_cmd = FM_ENCRYPT; break;
881 case ID_FILEMISC_DECRYPT: fm_cmd = FM_DECRYPT; break;
882 case ID_FILEMISC_SYMENC: fm_cmd = FM_SYMENC; break;
883 case ID_FILEMISC_SIGN: fm_cmd = FM_SIGN; break;
884 case ID_FILEMISC_VERIFY: fm_cmd = FM_VERIFY; break;
885 case ID_FILEMISC_IMPORT: fm_cmd = FM_IMPORT; break;
886 case ID_FILEMISC_LIST: fm_cmd = FM_LIST; break;
887 case ID_FILEMISC_SIGNENC: fm_cmd = FM_SIGNENCRYPT; break;
888 default: return 1; /* unknown command */
889 }
890
891 if (fm_get_current_pos (lv) == -1)
892 return WPTERR_GENERAL;
893 rc = fm_state_new (&ctx);
894 if (rc)
895 BUG (0);
896 ctx->dlg = dlg;
897
898 // TODO: for file operations the progress dialog will be
899 // reloaded somewhere and thus a 'dummy' dialog remains
900
901 /* we use it here to make sure that pfx_cleanup will not use
902 any weird values. */
903 memset (&pfx, 0, sizeof (pfx));
904 ctx->prog_cb = NULL;
905 if (cmd != FM_VERIFY && cmd != FM_SIGN /*&& reg_prefs.fm.progress > 0*/) {
906 pfx.hwnd = dlg;
907 /*gpgme_set_progress_cb (ctx->ctx, progress_callback, &pfx);*/
908 /*ctx->prog_cb = &pfx;*/
909 }
910
911 /* Commands we need before we can perform the main command */
912 switch (fm_cmd) {
913 case FM_ENCRYPT_ZIP:
914 case FM_ENCRYPT:
915 case FM_SIGNENCRYPT:
916 if (fm_cmd == FM_SIGNENCRYPT)
917 ctx->req_signer = 1;
918 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_FILE_ENCRYPT,
919 ctx->dlg, file_encrypt_dlg_proc, (LPARAM)ctx);
920 if (ctx->cancel == 1) {
921 rc = WPTERR_GENERAL;
922 goto leave;
923 }
924 break;
925
926 case FM_SIGN:
927 DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_FILE_SIGN, dlg,
928 file_sign_dlg_proc, (LPARAM) ctx);
929 if (ctx->cancel == 1 || fm_clearsign_8bit (lv, ctx)) {
930 rc = WPTERR_GENERAL;
931 goto leave;
932 }
933 break;
934 }
935
936 for (i = 0, n = 0; i < listview_count_items (lv, 0); i++) {
937 if (!listview_get_item_state (lv, i))
938 continue;
939 listview_get_item_text (lv, i, FM_COL_STAT, status, DIM (status) -1);
940 if (!strcmp (status, "ENCRYPTED") && fm_cmd == FM_DECRYPT)
941 n++;
942 if (!strcmp (status, "UNKNOWN") && fm_cmd == FM_SIGN)
943 n++;
944 }
945
946 if (n > 1 && fm_cmd != FM_SYMENC)
947 ctx->cache_cb = 1;
948
949 for (i = 0; i < listview_count_items (lv, 0); i++) {
950 if (!listview_get_item_state (lv, i))
951 continue;
952 listview_get_item_text (lv, i, FM_COL_NAME, fname, DIM (fname) - 1);
953 if (file_exist_check (fname) && !is_directory (fname)) {
954 log_box (_("File Manager"), MB_ERR,
955 _("\"%s\" does not exist"), fname);
956 continue;
957 }
958 if (is_directory (fname))
959 fm_cmd = FM_ENCRYPT_DIR;
960 if (!fm_check_file_type (lv, i, fm_cmd))
961 continue;
962 sig_detached = fm_check_detached_sig (lv, i);
963 switch (fm_cmd) {
964 case FM_LIST: fm_list( fname, dlg ); break;
965 case FM_ENCRYPT: rc = fm_encrypt( ctx, fname, 0 ); break;
966 case FM_SIGNENCRYPT: rc = fm_encrypt( ctx, fname, 1 ); break;
967 case FM_DECRYPT: rc = fm_decrypt( ctx, fname ); break;
968 case FM_SIGN: rc = fm_sign( ctx, fname ); break;
969 case FM_SYMENC: rc = fm_sym_encrypt (ctx, fname); break;
970 case FM_VERIFY: rc = fm_verify (ctx, sig_detached, fname);break;
971 case FM_IMPORT:
972 free_if_alloc (ctx->opaque);
973 ctx->opaque = m_strdup (fname);
974 DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_IMPORT, dlg,
975 file_import_dlg_proc, (LPARAM)ctx);
976 if (ctx->cancel == 1)
977 continue;
978 rc = fm_import (ctx, fname);
979 break;
980 }
981 if (ctx->cancel == 1) {
982 ctx->cancel = 0;
983 continue;
984 }
985 fm_set_status (lv, i, fm_cmd, ctx->sigmode, !rc, ctx->output);
986 free_if_alloc (ctx->output);
987 progress_cleanup (&pfx);
988 }
989
990 if (ctx->cache_cb) {
991 release_gpg_passphrase_cb (&ctx->pass_cb);
992 ctx->cache_cb = 0; /* make sure it's only used for this session! */
993 }
994
995 leave:
996 if (!rc)
997 fm_state_release (ctx);
998 progress_cleanup (&pfx);
999 return rc;
1000 }
1001
1002
1003 /* Dump out the given PGP packets from file @name in a dialog. */
1004 void
1005 fm_list (const char *name, HWND dlg)
1006 {
1007 dialog_box_param (glob_hinst, (LPCTSTR)IDD_WINPT_FILE_STAT, dlg,
1008 file_stat_dlg_proc, (LPARAM)name, _("File Status"),
1009 IDS_WINPT_FILE_STAT);
1010 }
1011
1012
1013 static int
1014 ask_filename (fm_state_t c, const char *msg, const char *oldfile, char **dst)
1015 {
1016 const char *s;
1017
1018 s = get_filesave_dlg (c->dlg, msg, NULL, oldfile);
1019 if (!s)
1020 return WPTERR_GENERAL;
1021
1022 if (dst != NULL)
1023 free_if_alloc (*dst);
1024 free_if_alloc (c->output);
1025 c->output = m_strdup (s);
1026 if (dst != NULL)
1027 *dst = fm_quote_file (s);
1028 return 0;
1029 }
1030
1031
1032 int
1033 fm_encrypt (fm_state_t c, const char *name, int sign)
1034 {
1035 gpgme_error_t err;
1036 gpgme_key_t key = NULL;
1037 gpgme_ctx_t ctx = c->ctx;
1038 file_data_t in=NULL, out=NULL;
1039 char *keyid = NULL, ext[5];
1040 int rc = 0;
1041
1042 c->output = new char[strlen (name) + 5 + 1];
1043 if (!c->output)
1044 BUG (0);
1045 strcpy (ext, file_get_extension (ctx, c->sigmode));
1046 strcpy (c->output, name);
1047 strcat (c->output, ext);
1048
1049 if (!overwrite_file (c->output)) {
1050 rc = ask_filename (c, _("Enter Filename for Encrypted File"), c->output, NULL);
1051 if (rc)
1052 goto leave;
1053 }
1054
1055 err = gpg_file_data_new (name, F_DATA_READ, &in);
1056 if (err)
1057 goto leave;
1058 remove_crit_file_attrs (c->output, 0);
1059 err = gpg_file_data_new (c->output, F_DATA_WRITE, &out);
1060 if (err)
1061 goto leave;
1062
1063 /*
1064 int no_compr = 0;
1065 if (c->prog_cb) {
1066 c->prog_cb->what = name;
1067 gpg_file_data_set_cb (in, c->prog_cb);
1068 }
1069 */
1070
1071 // TODO: disable compression for multi-media files.
1072
1073 if (sign) {
1074 if (gpgme_signers_enum (ctx, 0) == NULL) {
1075 keyid = get_gnupg_default_key ();
1076 if (!keyid) {
1077 msg_box (c->dlg, _("Could not get default secret key."),
1078 _("Signing"), MB_ERR);
1079 rc = WPTERR_GENERAL;
1080 goto leave;
1081 }
1082 if (get_seckey (keyid, &key))
1083 BUG (0);
1084 gpgme_signers_add (ctx, key);
1085 }
1086 else {
1087 gpgme_key_t sigkey = gpgme_signers_enum (ctx, 0);
1088 if (sigkey && sigkey->subkeys) {
1089 keyid = m_strdup (sigkey->subkeys->keyid);
1090 }
1091 }
1092 if (!c->init_cb || !c->cache_cb) {
1093 set_gpg_passphrase_cb (&c->pass_cb, c->ctx, GPG_CMD_SIGN,
1094 c->dlg, _("Signing"));
1095 c->init_cb = 1;
1096 }
1097 op_begin ();
1098 err = gpgme_op_encrypt_sign (ctx, c->recp, GPGME_ENCRYPT_ALWAYS_TRUST,
1099 in->dat, out->dat);
1100 op_end ();
1101 if (!c->cache_cb)
1102 release_gpg_passphrase_cb (&c->pass_cb);
1103 if (c->pass_cb.cancel) {
1104 rc = WPTERR_GENERAL;
1105 goto leave;
1106 }
1107 if (err) {
1108 msg_box (c->dlg, gpgme_strerror (err), _("Sign"), MB_ERR);
1109 if (gpgme_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
1110 agent_del_cache (keyid);
1111 rc = WPTERR_GENERAL;
1112 goto leave;
1113 }
1114 }
1115 else {
1116 op_begin ();
1117 err = gpgme_op_encrypt (ctx, c->recp, GPGME_ENCRYPT_ALWAYS_TRUST,
1118 in->dat, out->dat);
1119 op_end ();
1120 if (err) {
1121 msg_box (c->dlg, gpgme_strerror (err), _("Encrypt"), MB_ERR);
1122 rc = WPTERR_GENERAL;
1123 goto leave;
1124 }
1125 }
1126
1127 leave:
1128 if (in)
1129 gpg_file_data_release (in);
1130 if (out)
1131 gpg_file_data_release (out);
1132 free_if_alloc (keyid);
1133 return rc;
1134 }
1135
1136
1137 int
1138 fm_sym_encrypt (fm_state_t c, const char * name)
1139 {
1140 gpgme_ctx_t ctx = c->ctx;
1141 gpgme_error_t err;
1142 file_data_t in=NULL, out=NULL;
1143 int rc = 0, cancel = 0;
1144 char ext[5], *pass;
1145
1146 pass = request_passphrase2 (_("Symmetric Encryption"), 0, &cancel);
1147 if (cancel) {
1148 c->cancel = 1;
1149 return 0;
1150 }
1151
1152 /* XXX: a convenient feature could be to select the preferred
1153 symmetric algorithm. */
1154 c->output = new char[strlen (name) + 5 + 1];
1155 if (!c->output)
1156 BUG (0);
1157 strcpy (ext, file_get_extension (ctx, c->sigmode));
1158 strcpy (c->output, name);
1159 strcat (c->output, ext);
1160
1161 if (overwrite_file (c->output) == 0) {
1162 rc = WPTERR_GENERAL;
1163 goto leave;
1164 }
1165
1166 gpgme_set_passphrase_cb (ctx, sym_passphrase_cb, pass);
1167 err = gpg_file_data_new (name, 1, &in);
1168 if (err)
1169 goto leave;
1170 err = gpg_file_data_new (c->output, 0, &out);
1171 if (err)
1172 goto leave;
1173
1174 op_begin ();
1175 err = gpgme_op_encrypt (ctx, NULL, GPGME_ENCRYPT_ALWAYS_TRUST,
1176 in->dat, out->dat);
1177 op_end ();
1178 if (err) {
1179 msg_box (c->dlg, gpgme_strerror (err), _("Symmetric"), MB_ERR);
1180 rc = WPTERR_GENERAL;
1181 goto leave;
1182 }
1183 if (file_exist_check (c->output)) {
1184 msg_box (c->dlg, _("Encryption failed."), _("Symmetric"), MB_ERR);
1185 rc = WPTERR_GENERAL;
1186 }
1187
1188 leave:
1189 if (in)
1190 gpg_file_data_release (in);
1191 if (out)
1192 gpg_file_data_release (out);
1193 sfree_if_alloc (pass);
1194 return rc;
1195 }
1196
1197
1198 /* Check the recipients if we have at least one secret key. */
1199 bool
1200 is_seckey_available (gpgme_recipient_t rset)
1201 {
1202 gpgme_recipient_t r;
1203 winpt_key_s key;
1204
1205 for (r=rset; r; r = r->next) {
1206 if (gpgme_err_code (r->status) == GPG_ERR_NO_SECKEY)
1207 continue;
1208 else {
1209 memset (&key, 0, sizeof (key));
1210 /* extra check to make sure the key is available right now. */
1211 if (!winpt_get_seckey (r->keyid, &key)) {
1212 winpt_release_pubkey (&key);
1213 return true;
1214 }
1215 winpt_release_pubkey (&key);
1216 }
1217 }
1218 return false;
1219 }
1220
1221
1222 /* If the decrypt result contains the original file name,
1223 we use it instead of the artificial "output - .gpg" string. */
1224 static int
1225 restore_original_name (const char *output, const char *file_name)
1226 {
1227 char *dir;
1228 char *orig;
1229 int rc = 0;
1230
1231 dir = strrchr (output, '\\');
1232 if (!dir)
1233 orig = strdup (file_name);
1234 else {
1235 orig = (char*)calloc (1, strlen (file_name)+ 1 +
1236 strlen (output)+1);
1237 if (!orig)
1238 BUG (0);
1239 memcpy (orig, output, (dir-output)+1);
1240 strcat (orig, file_name);
1241 }
1242 /* XXX: we need to find out if the string needs to be utf8 decoded. */
1243 if (overwrite_file (orig)) {
1244 DeleteFile (orig);
1245 if (!MoveFile (output, orig))
1246 rc = -1;
1247 }
1248 safe_free (orig);
1249 return rc;
1250 }
1251
1252
1253 /* Decrypt the file @name. */
1254 int
1255 fm_decrypt (fm_state_t c, const char *name)
1256 {
1257 gpgme_error_t err;
1258 gpgme_ctx_t ctx = c->ctx;
1259 gpgme_decrypt_result_t res;
1260 gpgme_verify_result_t sigres;
1261 file_data_t in = NULL, out = NULL;
1262 int rc = 0;
1263
1264 if (!c->init_cb || !c->cache_cb) {
1265 set_gpg_passphrase_cb (&c->pass_cb, c->ctx, GPG_CMD_DECRYPT,
1266 c->dlg, _("Decryption"));
1267 c->init_cb = 1;
1268 }
1269
1270 c->output = m_strdup (name);
1271 if (is_openpgp_ext (c->output))
1272 c->output[strlen (c->output)-4] = '\0';
1273 else {
1274 const char *s;
1275 s = get_filesave_dlg (c->dlg, _("Choose Filename for Output"),
1276 NULL, NULL);
1277 if (s) {
1278 free_if_alloc (c->output);
1279 c->output = m_strdup (s);
1280 }
1281 }
1282
1283 if (overwrite_file (c->output) == 0) {
1284 rc = ask_filename (c, _("Enter Filename for Plaintext File"), c->output, NULL);
1285 if (rc)
1286 goto leave;
1287 }
1288
1289 /* we fetch all recipients here to make sure they list is complete. */
1290 release_gpg_recipients (&c->pass_cb.recipients);
1291 gpg_get_recipients (name, &c->pass_cb.recipients);
1292
1293 err = gpg_file_data_new (name, F_DATA_READ, &in);
1294 if (err)
1295 goto leave;
1296 remove_crit_file_attrs (c->output, 0);
1297 err = gpg_file_data_new (c->output, F_DATA_WRITE, &out);
1298 if (err)
1299 goto leave;
1300
1301 op_begin ();
1302 err = gpgme_op_decrypt_verify (ctx, in->dat, out->dat);
1303 op_end ();
1304 if (!c->cache_cb)
1305 release_gpg_passphrase_cb (&c->pass_cb);
1306 if (c->pass_cb.cancel) {
1307 rc = WPTERR_GENERAL;
1308 goto leave;
1309 }
1310
1311 res = gpgme_op_decrypt_result (ctx);
1312 if (res && res->recipients && !is_seckey_available (res->recipients)) {
1313 const char *keyid = get_keyid_from_fpr (res->recipients->keyid);
1314 char *p = get_key_userid (keyid);
1315 gpgme_pubkey_algo_t pkalgo = res->recipients->pubkey_algo;
1316
1317 log_box (_("Decryption"), MB_ERR,
1318 _("Encrypted with %s key, ID 0x%s.%s\n"
1319 "Decryption failed: secret key not available."),
1320 get_key_pubalgo (pkalgo), keyid, p);
1321 rc = WPTERR_GENERAL;
1322 free_if_alloc (p);
1323 goto leave;
1324 }
1325 else if (err) {
1326 msg_box (c->dlg, gpgme_strerror (err), _("Decrypt"), MB_ERR);
1327 rc = WPTERR_GENERAL;
1328 goto leave;
1329 }
1330 if (file_exist_check (c->output)) {
1331 log_box ("Decrypt", MB_ERR,
1332 _("Decryption failed.\n%s: does not exist."), c->output);
1333 rc = WPTERR_GENERAL;
1334 goto leave;
1335 }
1336 else if (res && res->file_name) {
1337 char *file;
1338 int id = IDNO;
1339
1340 file = strrchr (c->output, '\\');
1341 if (!file)
1342 file = c->output;
1343 else
1344 file++;
1345 if (strcmp (res->file_name, file))
1346 id = log_box (_("Decrypt"), MB_QUEST_ASK,
1347 _("The original file name is '%s'.\n\n"
1348 "Do you want to use this instead of '%s'?"),
1349 res->file_name, file);
1350 if (id == IDYES) {
1351 /* before we can move the file, it needs to be closed first. */
1352 gpg_file_data_release (out);
1353 out = NULL;
1354 restore_original_name (c->output, res->file_name);
1355 }
1356 }
1357 sigres = gpgme_op_verify_result (ctx);
1358 if (sigres && sigres->signatures)
1359 verify_show_signature_state (sigres->signatures);
1360
1361 leave:
1362 if (in)
1363 gpg_file_data_release (in);
1364 if (out)
1365 gpg_file_data_release (out);
1366
1367 return rc;
1368 }
1369
1370
1371 int
1372 fm_sign (fm_state_t c, const char * name)
1373 {
1374 gpgme_ctx_t ctx = c->ctx;
1375 gpgme_error_t err;
1376 file_data_t in=NULL, out=NULL;
1377 char ext[5];
1378 int rc = 0;
1379
1380 if (!c->init_cb || !c->cache_cb) {
1381 set_gpg_passphrase_cb (&c->pass_cb, c->ctx,
1382 GPG_CMD_SIGN, c->dlg, _("Signing"));
1383 c->init_cb = 1;
1384 }
1385
1386 free_if_alloc (c->output);
1387 c->output = new char[strlen (name) + 5 + 1];
1388 if (!c->output)
1389 BUG (NULL);
1390 strcpy (ext, file_get_extension (ctx, c->sigmode));
1391 strcpy (c->output, name);
1392 strcat (c->output, ext);
1393
1394 if (!overwrite_file (c->output)) {
1395 rc = ask_filename (c, _("Enter Filename for Signed File"), c->output, NULL);
1396 if (rc)
1397 goto leave;
1398 }
1399
1400 err = gpg_file_data_new (name, F_DATA_READ, &in);
1401 if (err)
1402 goto leave;
1403 remove_crit_file_attrs (c->output, 0);
1404 err = gpg_file_data_new (c->output, F_DATA_WRITE, &out);
1405 if (err)
1406 goto leave;
1407
1408 op_begin ();
1409 err = gpgme_op_sign (ctx, in->dat, out->dat, c->sigmode);
1410 op_end ();
1411 if (!c->cache_cb)
1412 release_gpg_passphrase_cb (&c->pass_cb);
1413 if (c->pass_cb.cancel) {
1414 rc = WPTERR_GENERAL;
1415 goto leave;
1416 }
1417 if (err) {
1418 msg_box (c->dlg, gpgme_strerror (err), _("Sign"), MB_ERR);
1419 rc = WPTERR_GENERAL;
1420 goto leave;
1421 }
1422
1423 leave:
1424 if (in)
1425 gpg_file_data_release (in);
1426 if (out)
1427 gpg_file_data_release (out);
1428 return rc;
1429 }
1430
1431
1432 static void
1433 fm_add_sig_stat (file_sig_ctx_t log)
1434 {
1435 struct winpt_key_s key;
1436 const char *kid;
1437
1438 memset (&key, 0, sizeof (key));
1439 kid = get_keyid_from_fpr (log->sig->fpr);
1440 log->use_uid = 0;
1441 if (!winpt_get_pubkey (kid, &key)) {
1442 log->user_id = key.ext->uids->uid;
1443 log->use_uid = 1;
1444 }
1445 file_verify_add_state (log);
1446 winpt_release_pubkey (&key);
1447 }
1448
1449
1450 /* Verify a detached signature from the clipboard. */
1451 static int
1452 verify_pasted (listview_ctrl_t lv, fm_state_t ctx,
1453 const char *dat, int pos, HWND dlg)
1454 {
1455 FILE *fp;
1456 char stat[32];
1457 char file[MAX_PATH+1], *fname = NULL;
1458 int del_end = 0;
1459
1460 listview_get_item_text (lv, pos, FM_COL_STAT, stat, DIM (stat)-1);
1461 listview_get_item_text (lv, pos, FM_COL_NAME, file, DIM (file)-1);
1462 if (strcmp (stat, "UNKNOWN"))
1463 return 0;
1464 fname = make_filename (NULL, file, "asc");
1465 if (file_exist_check (fname) != 0) {
1466 fp = fopen (fname, "wb");
1467 if (fp == NULL) {
1468 log_box (_("File Manager"), MB_ERR, "Could not create '%s'", fname);
1469 free_if_alloc (fname);
1470 return WPTERR_GENERAL;
1471 }
1472 fwrite (dat, 1, strlen (dat), fp);
1473 fclose (fp);
1474 del_end = 1;
1475 }
1476 fm_verify (ctx, 1, fname);
1477 if (del_end)
1478 DeleteFile (fname);
1479 free_if_alloc (fname);
1480 return 0;
1481 }
1482
1483
1484 /* Figure out if the clipboard contains a detached signature. */
1485 int
1486 fm_verify_pasted_detsig (listview_ctrl_t lv, HWND dlg)
1487 {
1488 fm_state_t ctx = NULL;
1489 char * dat=NULL;
1490 int i, fnd = 0;
1491
1492 dat = get_clip_text (NULL);
1493 if (!dat || !strstr (dat, "BEGIN PGP SIGNATURE")) {
1494 msg_box (dlg, _("Could not find detached signature in the clipboard."),
1495 _("File Manager"), MB_ERR);
1496 free_if_alloc (dat);
1497 return WPTERR_GENERAL;
1498 }
1499 /* XXX find a way to filter out bad signatures or just ignore all in
1500 this case */
1501 fm_state_new (&ctx);
1502 i = listview_get_curr_pos (lv);
1503 if (i == -1) {
1504 verify_pasted (lv, ctx, dat, i, dlg);
1505 fnd = 1;
1506 }
1507 else {
1508 for (i=0; i < listview_count_items (lv, 0); i++) {
1509 verify_pasted (lv, ctx, dat, i, dlg);
1510 fnd = 1;
1511 }
1512 }
1513 if (!fnd)
1514 msg_box (dlg, _("No files to check."), _("File Manager"), MB_INFO);
1515 free_if_alloc (dat);
1516 fm_state_release (ctx);
1517 return 0;
1518 }
1519
1520
1521 /* Extract automatically the output file name from @name.
1522 If @detached is 1, a detached sig is assumed. */
1523 static int
1524 get_output_file (fm_state_t c, const char *name, int detached)
1525 {
1526 const char *file = NULL;
1527 const char *title;
1528 char fname[384];
1529
1530 if (detached)
1531 title = _("Select Data File");
1532 else
1533 title = _("Selected Output File");
1534
1535 if (is_openpgp_ext (name)) {
1536 _snprintf (fname, DIM (fname) - 1, "%s", name);
1537 fname[strlen (fname) - 4] = '\0';
1538 if (file_exist_check (fname) == 0 && detached)
1539 file = fname;
1540 else if (!detached) {
1541 /* If the signature is clear or normal, make sure we do not
1542 overwrite the original file if it exists. */
1543 if (file_exist_check (fname) == 0 && !overwrite_file (fname)) {
1544 file = get_filesave_dlg (c->dlg, title, NULL, NULL);
1545 if (!file)
1546 return WPTERR_GENERAL;
1547 }
1548 else
1549 file = fname;
1550 }
1551 }
1552 if (!file)
1553 file = get_fileopen_dlg (c->dlg, title, NULL, NULL);
1554 if (file) {
1555 free_if_alloc (c->output);
1556 c->output = m_strdup (file);
1557 }
1558 else {
1559 msg_box (c->dlg, _("Invalid file name. Exit"), _("Verify"), MB_ERR);
1560 return WPTERR_GENERAL;
1561 }
1562 if (detached)
1563 c->sigmode = GPGME_SIG_MODE_DETACH;
1564 else {
1565 if (stristr (name, ".asc"))
1566 c->sigmode = GPGME_SIG_MODE_CLEAR;
1567 else
1568 c->sigmode = GPGME_SIG_MODE_NORMAL;
1569 }
1570 return 0;
1571 }
1572
1573
1574 /* Handy function to kick of the gpg verify process. */
1575 static gpgme_error_t
1576 fm_gpg_verify (gpgme_sig_mode_t sigmode, gpgme_ctx_t ctx,
1577 file_data_t in, file_data_t out)
1578 {
1579 gpgme_error_t err;
1580
1581 op_begin ();
1582 if (sigmode == GPGME_SIG_MODE_DETACH)
1583 err = gpgme_op_verify (ctx, in->dat, out->dat, NULL);
1584 else
1585 err = gpgme_op_verify (ctx, in->dat, in->dat, out->dat);
1586 op_end ();
1587 return err;
1588 }
1589
1590
1591 /* Verify the signature from the file @name. If @detached 1,
1592 it is assumed that a detached signature should be checked. */
1593 int
1594 fm_verify (fm_state_t c, int detached, const char *name)
1595 {
1596 gpgme_error_t err;
1597 gpgme_signature_t s;
1598 gpgme_verify_result_t res;
1599 struct file_sig_ctx_s log;
1600 file_data_t in=NULL, out=NULL;
1601 int rc = 0;
1602
1603 if (stristr (name, ".sig"))
1604 detached = 1;
1605
1606 if (get_output_file (c, name, detached))
1607 return WPTERR_GENERAL;
1608
1609 file_verify_create_dlg ();
1610
1611 memset (&log, 0, sizeof (log));
1612 log.file = m_strdup (name);
1613
1614 err = gpg_file_data_new (name, F_DATA_READ, &in);
1615 if (err)
1616 goto leave;
1617 err = gpg_file_data_new (c->output,
1618 detached? F_DATA_READ : F_DATA_WRITE, &out);
1619 if (err)
1620 goto leave;
1621
1622 err = fm_gpg_verify (c->sigmode, c->ctx, in, out);
1623 if (err) {
1624 msg_box (c->dlg, gpgme_strerror (err), _("Verify"), MB_ERR);
1625 rc = WPTERR_GENERAL;
1626 goto leave;
1627 }
1628
1629 res = gpgme_op_verify_result (c->ctx);
1630 if (!res)
1631 goto leave;
1632 if (res->signatures != NULL &&
1633 gpgme_err_code (res->signatures->status) == GPG_ERR_NO_PUBKEY) {
1634 /* We need to call gpg again to get the actual sig state
1635 and the data files must be rewinded also. */
1636 if (fetch_key_from_keyserver (c->dlg, res->signatures)) {
1637 rc = WPTERR_GENERAL;
1638 goto leave;
1639 }
1640 gpg_file_data_rewind (in);
1641 gpg_file_data_rewind (out);
1642 err = fm_gpg_verify (c->sigmode, c->ctx, in, out);
1643 if (err) {
1644 msg_box (c->dlg, gpgme_strerror (err), _("Verify"), MB_ERR);
1645 rc = WPTERR_GENERAL;
1646 goto leave;
1647 }
1648 /* Refresh the pointer because a new GPG instance has been
1649 created for the new verify operation. */
1650 res = gpgme_op_verify_result (c->ctx);
1651 }
1652
1653 for (s=res->signatures; s; s=s->next) {
1654 log.sig = s;
1655 fm_add_sig_stat (&log);
1656 }
1657 if (!c->output)
1658 c->output = m_strdup (name); /* for later use */
1659
1660 leave:
1661 if (in)
1662 gpg_file_data_release (in);
1663 if (out)
1664 gpg_file_data_release (out);
1665 free_if_alloc (log.file);
1666 return rc;
1667 }
1668
1669
1670 /* Import the keys from the file @name.
1671 Return value: 0 on success. */
1672 int
1673 fm_import (fm_state_t c, const char *name)
1674 {
1675 gpgme_ctx_t ctx = c->ctx;
1676 gpgme_error_t err;
1677 gpgme_import_result_t res;
1678 file_data_t keydata = NULL;
1679 int rc = 0;
1680
1681 free_if_alloc (c->output);
1682 c->output = m_strdup (name);
1683
1684 err = gpg_file_data_new (name, F_DATA_READ, &keydata);
1685 if (err)
1686 goto leave;
1687
1688 op_begin ();
1689 err = gpgme_op_import (ctx, keydata->dat);
1690 op_end ();
1691 if (err) {
1692 msg_box (c->dlg, gpgme_strerror (err), _("Import"), MB_ERR);
1693 rc = WPTERR_GENERAL;
1694 goto leave;
1695 }
1696
1697 res = gpgme_op_import_result (ctx);
1698 print_import_status (res);
1699 if (res->no_user_id > 0) {
1700 msg_box (c->dlg, _("Key without a self signature was dectected!\n"
1701 "(This key is NOT usable for encryption, etc)\n"
1702 "\n"
1703 "Cannot import these key(s)!"), _("Import"), MB_INFO);
1704 }
1705
1706 leave:
1707 if (keydata)
1708 gpg_file_data_release (keydata);
1709 return rc;
1710 }
1711
1712
1713 /* Parse the command line and process the given file. */
1714 int
1715 fm_parse_command_line (char *cmdl)
1716 {
1717 fm_state_t ctx;
1718 const char *s;
1719 char *p, *fn = NULL;
1720 int count = 0, detached = 0;
1721 int type;
1722
1723 if (!cmdl || !*cmdl)
1724 return 0;
1725
1726 fm_state_new (&ctx);
1727 ctx->dlg = GetActiveWindow ();
1728 ctx->cache_cb = 1;
1729
1730 p = cmdl;
1731 if (p && *p > 32 && !stristr (p, "winpt.exe")
1732 && !strstr (p, "--" )) {
1733 count++;
1734 if (*p == '"') { /* need to remove quotes */
1735 fn = new char[strlen (p)];
1736 if (!fn)
1737 BUG (NULL);
1738 memcpy (fn, p+1, strlen (p) - 2);
1739 fn[strlen (p) -2] = '\0';
1740 }
1741 else
1742 fn = m_strdup (p);
1743 s = fm_get_file_type (fn, &type);
1744 if (!s || !strcmp (s, "UNKNOWN"))
1745 s = gnupg_check_file_ext (fn, &type);
1746 if (type == PGP_NONE) {
1747 log_box (_("File Manager"), MB_ERR,
1748 _("%s: no valid OpenPGP data found."), p);
1749 free_if_alloc (fn);
1750 return count;
1751 }
1752 switch (type) {
1753 case PGP_MESSAGE:
1754 fm_decrypt (ctx, fn);
1755 break;
1756
1757 case PGP_PUBKEY:
1758 case PGP_SECKEY:
1759 fm_import (ctx, fn);
1760 break;
1761
1762 case PGP_SIG:
1763 case PGP_CLEARSIG:
1764 if (type == PGP_SIG)
1765 detached = 1;
1766 fm_verify (ctx, detached, fn);
1767 file_verify_wait ();
1768 break;
1769
1770 default:
1771 break;
1772 }
1773 }
1774
1775 wipememory (&ctx->pass_cb, sizeof (ctx->pass_cb));
1776 free_if_alloc (fn);
1777 fm_state_release (ctx);
1778 return count;
1779 }
1780
1781
1782 /* Extract the last folder name from @name. */
1783 const char*
1784 default_dirname (const char *name)
1785 {
1786 char *p = strrchr (name, '\\');
1787 if (!p)
1788 return NULL;
1789 return p+1;
1790 }
1791
1792 #if 0
1793 /* Store all selected files from @lv in a zip archive
1794 and encrypt the zip archive then.
1795 Return value: 0 on success. */
1796 int
1797 fm_encrypt_into_zip (fm_state_t ctx, listview_ctrl_t lv)
1798 {
1799 PK_FILE_LIST list=NULL;
1800 const char *outfile, *ext;
1801 char *out_enc;
1802 int nitems;
1803 int i, idx = -1;
1804 int rc;
1805
1806 nitems = listview_count_items (lv, 0);
1807 if (!nitems) {
1808 msg_box (NULL, _("Encrypting into a ZIP archive makes sense with multiple files"),
1809 _("File Manager"), MB_ERR);
1810 return WPTERR_GENERAL;
1811 }
1812
1813 outfile = get_filesave_dlg (ctx->dlg, _("Choose File Name for Output"),
1814 NULL, "Encrypted_Files.zip");
1815 if (!outfile)
1816 return WPTERR_GENERAL;
1817
1818 for (i=0; i < nitems; i++) {
1819 char name[MAX_PATH+32];
1820
1821 if (!listview_get_item_state (lv, i))
1822 continue;
1823 if (idx == -1)
1824 idx = i;
1825 listview_get_item_text (lv, i, 1, name, DIM (name)-1);
1826 pk_list_add (&list, name);
1827 }
1828
1829 pk_archiv_create (list, outfile);
1830 pk_list_free (list);
1831
1832 rc = fm_encrypt (ctx, outfile, 0);
1833 DeleteFile (outfile);
1834 if (rc)
1835 return rc;
1836
1837 ext = file_get_extension (ctx->ctx, ctx->sigmode)+1;
1838 out_enc = make_filename (NULL, outfile, ext);
1839 fm_set_status (lv, idx, FM_ENCRYPT, (gpgme_sig_mode_t)0, 1, out_enc);
1840 free_if_alloc (out_enc);
1841
1842 for (i=nitems; i > -1; i--) {
1843 if (i != idx && listview_get_item_state (lv, i))
1844 listview_del_item (lv, i);
1845 }
1846 return 0;
1847 }
1848
1849 int
1850 fm_encrypt_directory (fm_state_t c, const char *name)
1851 {
1852 WIN32_FIND_DATA findbuf;
1853 HANDLE hd;
1854 PK_FILE_LIST list = NULL;
1855 const char *s;
1856 char *patt = NULL, *p;
1857 int rc = 0;
1858
1859 if (!is_directory (name))
1860 return -1;
1861 patt = new char[strlen (name) + 4];
1862 if (!patt)
1863 BUG (NULL);
1864 strcpy (patt, name);
1865 strcat (patt, "\\*");
1866 hd = FindFirstFile (patt, &findbuf);
1867 if (!hd) {
1868 free_if_alloc (patt);
1869 return WPTERR_GENERAL;
1870 }
1871 if (strcmp (findbuf.cFileName, ".") && strcmp (findbuf.cFileName, "..")) {
1872 p = make_filename (name, findbuf.cFileName, NULL);
1873 pk_list_add (&list, p);
1874 free_if_alloc (p);
1875 }
1876 /* XXX: support to scan sub directories also. */
1877 while (FindNextFile (hd, &findbuf)) {
1878 if (strcmp (findbuf.cFileName, ".") && strcmp (findbuf.cFileName, "..")) {
1879 p = make_filename (name, findbuf.cFileName, NULL);
1880 pk_list_add (&list, p);
1881 free_if_alloc (p);
1882 }
1883 }
1884 s = get_filesave_dlg (c->dlg, _("Choose a Name for the Archive"),
1885 NULL, default_dirname (name));
1886 if (!s) {
1887 msg_box (c->dlg, _("Invalid archive name. Exit."),
1888 _("Encrypt Directory"), MB_ERR);
1889 rc = -1;
1890 goto leave;
1891 }
1892
1893 rc = pk_archiv_create (list, s);
1894 if (rc)
1895 msg_box (c->dlg, _("Could not create zip archive."),
1896 _("Encrypt Directory"), MB_ERR);
1897 else {
1898 fm_encrypt (c, s, 0);
1899 DeleteFile (s);
1900 }
1901 leave:
1902 FindClose (hd);
1903 pk_list_free (list);
1904 free_if_alloc (patt);
1905 return rc;
1906 }
1907 #endif
1908
1909 static int CALLBACK
1910 fm_cmp_cb (LPARAM first, LPARAM second, LPARAM sortby)
1911 {
1912 fm_model_t a, b;
1913 int cmpres = 0;
1914
1915 a = (fm_model_t)first;
1916 b = (fm_model_t)second;
1917 if (!a || !b)
1918 return 0;
1919
1920 switch ((int)sortby) {
1921 case FM_COL_STAT:
1922 cmpres = stricmp (a->status, b->status);
1923 break;
1924
1925 case FM_COL_NAME:
1926 cmpres = stricmp (a->name, b->name);
1927 break;
1928
1929 case FM_COL_OP:
1930 if (a->op && b->op)
1931 cmpres = stricmp (a->op, b->op);
1932 break;
1933 }
1934 return cmpres;
1935 }
1936
1937
1938 /* Sort the list items from @lv with the mode given by @sortby. */
1939 int
1940 fm_sort (listview_ctrl_t lv, int sortby)
1941 {
1942 return ListView_SortItems (lv->ctrl, fm_cmp_cb, (LPARAM)sortby);
1943 }
1944
1945
1946
1947 /* Send the selected file in @lv via MAPI to a mail recipient. */
1948 int
1949 fm_send_file (listview_ctrl_t lv)
1950 {
1951 char name[MAX_PATH+1];
1952 int rc;
1953
1954 rc = listview_get_item_text (lv, -1, FM_COL_NAME, name, DIM (name)-1);
1955 if (rc != -1)
1956 mapi_send_ascfile (name);
1957 return 0;
1958 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26