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

Annotation of /trunk/Src/wptFileManager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 119 - (hide annotations)
Fri Dec 9 08:04:51 2005 UTC (19 years, 2 months ago) by twoaday
File size: 48343 byte(s)
2005-12-08  Timo Schulz  <ts@g10code.com>
 
        * wptKeyserverDlg.cpp (show_imported_keys): Enhanced.
        (hkp_recv_key2): Show user-id of the imported key instead
        of just the pattern.
        * wptFileCBS.cpp (read_cb): Changed to W32 API.
        (write_cb): Likewise. Create output file on demand.
        (gpg_file_data_new): Adjusted code for new API.
        * wptKeyEdit.cpp (cleanKey): New.
        * wptKeyEditCB.cpp (cmd_clean_handler): New.
        (editkey_command_handler): Call clean handler.
        * wptKeyManagerDlg.cpp (keymanager_dlg_proc): Sort
        keylist after inserting items.
        * wptFileManager.cpp (fm_set_status): Take care of
        cleartext sigs.
         


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26