1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: smime.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2013-2016 Eduardo Chappa
8 * Copyright 2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
20 * This is based on a contribution from Jonathan Paisley
23 * Author: paisleyj@dcs.gla.ac.uk
32 #include "../pith/charconv/utf8.h"
33 #include "../pith/status.h"
34 #include "../pith/store.h"
35 #include "../pith/conf.h"
36 #include "../pith/list.h"
37 #include "../pith/mailcmd.h"
38 #include "../pith/tempfile.h"
43 #include "confscroll.h"
47 /* internal prototypes */
48 void format_smime_info(int pass
, BODY
*body
, long msgno
, gf_io_t pc
);
49 void print_separator_line(int percent
, int ch
, gf_io_t pc
);
50 void output_cert_info(X509
*cert
, gf_io_t pc
);
51 void output_X509_NAME(X509_NAME
*name
, gf_io_t pc
);
52 void side_by_side(STORE_S
*left
, STORE_S
*right
, gf_io_t pc
);
53 STORE_S
*wrap_store(STORE_S
*in
, int width
);
54 void smime_config_init_display(struct pine
*, CONF_S
**, CONF_S
**);
55 void revert_to_saved_smime_config(struct pine
*ps
, SAVED_CONFIG_S
*vsave
);
56 SAVED_CONFIG_S
*save_smime_config_vars(struct pine
*ps
);
57 void free_saved_smime_config(struct pine
*ps
, SAVED_CONFIG_S
**vsavep
);
58 int smime_helper_tool(struct pine
*, int, CONF_S
**, unsigned);
59 //int smime_public_certs_tool(struct pine *, int, CONF_S **, unsigned);
60 void manage_certificates(struct pine
*, WhichCerts
);
61 void smime_manage_certs_init (struct pine
*, CONF_S
**, CONF_S
**, WhichCerts
, int);
62 void display_certificate_information(struct pine
*, X509
*, char *, WhichCerts
, int num
);
63 int manage_certs_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned flags
);
64 int manage_certificate_info_tool(int, MSGNO_S
*, SCROLL_S
*);
65 void smime_setup_size(char **, size_t, size_t);
69 * prompt the user for their passphrase
70 * (possibly prompting with the email address in s_passphrase_emailaddr)
73 smime_get_passphrase(void)
78 HelpType help
= NO_HELP
;
80 assert(ps_global
->smime
!= NULL
);
81 snprintf(prompt
, sizeof(prompt
),
82 _("Enter passphrase for <%s>: "), (ps_global
->smime
&& ps_global
->smime
->passphrase_emailaddr
) ? ps_global
->smime
->passphrase_emailaddr
[0] : "unknown");
85 flags
= OE_PASSWD
| OE_DISALLOW_HELP
;
86 ((char *) ps_global
->smime
->passphrase
)[0] = '\0';
87 rc
= optionally_enter((char *) ps_global
->smime
->passphrase
,
88 -FOOTER_ROWS(ps_global
), 0,
89 sizeof(ps_global
->smime
->passphrase
),
90 prompt
, NULL
, help
, &flags
);
91 } while (rc
!=0 && rc
!=1 && rc
>0);
95 ps_global
->smime
->entered_passphrase
= 1;
98 return rc
; /* better return rc and make the caller check its return value */
102 smime_check(BODY
*body
)
107 if(body
->type
== TYPEMULTIPART
){
110 for(p
=body
->nested
.part
; p
&& rv
== 0; p
=p
->next
)
111 rv
+= smime_check(&p
->body
);
113 if(rv
> 0) return rv
;
115 p7
= get_smime_sparep_type(body
->sparep
) == P7Type
116 ? (PKCS7
*)get_smime_sparep_data(body
->sparep
)
118 if(p7
&& (PKCS7_type_is_signed(p7
) || PKCS7_type_is_enveloped(p7
)))
125 display_smime_info(struct pine
*ps
, ENVELOPE
*env
, BODY
*body
)
127 OtherMenu what
= FirstMenu
;
128 HANDLE_S
*handles
= NULL
;
130 STORE_S
*store
= NULL
;
134 msgno
= mn_m2raw(ps
->msgmap
, mn_get_cur(ps
->msgmap
));
135 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
137 while(ps
->next_screen
== SCREEN_FUN_NULL
){
141 so_truncate(store
, 0);
143 view_writec_init(store
, &handles
, HEADER_ROWS(ps
),
145 ps
->ttyo
->screen_rows
- (HEADER_ROWS(ps
)
148 gf_puts_uline("Overview", view_writec
);
149 gf_puts(NEWLINE
, view_writec
);
151 format_smime_info(1, body
, msgno
, view_writec
);
152 gf_puts(NEWLINE
, view_writec
);
153 format_smime_info(2, body
, msgno
, view_writec
);
155 view_writec_destroy();
157 ps
->next_screen
= SCREEN_FUN_NULL
;
159 memset(&scrollargs
, 0, sizeof(SCROLL_S
));
160 scrollargs
.text
.text
= so_text(store
);
161 scrollargs
.text
.src
= CharStar
;
162 scrollargs
.text
.desc
= "S/MIME information";
163 scrollargs
.body_valid
= 1;
165 if(offset
){ /* resize? preserve paging! */
166 scrollargs
.start
.on
= Offset
;
167 scrollargs
.start
.loc
.offset
= offset
;
171 scrollargs
.bar
.title
= "S/MIME INFORMATION";
172 /* scrollargs.end_scroll = view_end_scroll; */
173 scrollargs
.resize_exit
= 1;
174 scrollargs
.help
.text
= NULL
;
175 scrollargs
.help
.title
= "HELP FOR S/MIME INFORMATION VIEW";
176 scrollargs
.keys
.menu
= &smime_info_keymenu
;
177 scrollargs
.keys
.what
= what
;
178 setbitmap(scrollargs
.keys
.bitmap
);
180 if(scrolltool(&scrollargs
) == MC_RESIZE
)
181 offset
= scrollargs
.start
.loc
.offset
;
188 smime_info_screen(struct pine
*ps
)
194 /* ps->prev_screen = smime_info_screen;
195 ps->next_screen = SCREEN_FUN_NULL; */
197 msgno
= mn_m2raw(ps
->msgmap
, mn_get_cur(ps
->msgmap
));
199 env
= mail_fetch_structure(ps
->mail_stream
, msgno
, &body
, 0);
202 q_status_message(SM_ORDER
, 0, 3,
203 _("Can't fetch body of message."));
207 if(smime_check(body
) == 0){
208 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
209 _("Not a signed or encrypted message"));
213 if(mn_total_cur(ps
->msgmap
) > 1L){
214 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
215 _("Can only view one message's information at a time."));
219 display_smime_info(ps
, env
, body
);
224 format_smime_info(int pass
, BODY
*body
, long msgno
, gf_io_t pc
)
229 if(body
->type
== TYPEMULTIPART
){
232 for(p
=body
->nested
.part
; p
; p
=p
->next
)
233 format_smime_info(pass
, &p
->body
, msgno
, pc
);
236 p7
= get_smime_sparep_type(body
->sparep
) == P7Type
237 ? (PKCS7
*)get_smime_sparep_data(body
->sparep
)
241 if(PKCS7_type_is_signed(p7
)){
242 STACK_OF(X509
) *signers
;
246 gf_puts(_("This message was cryptographically signed."), pc
);
247 gf_puts(NEWLINE
, pc
);
251 signers
= PKCS7_get0_signers(p7
, NULL
, 0);
255 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("Certificate%s used for signing"),
256 plural(sk_X509_num(signers
)));
257 gf_puts_uline(tmp_20k_buf
, pc
);
258 gf_puts(NEWLINE
, pc
);
259 print_separator_line(100, '-', pc
);
261 for(i
=0; i
<sk_X509_num(signers
); i
++){
262 X509
*x
= sk_X509_value(signers
, i
);
265 output_cert_info(x
, pc
);
266 gf_puts(NEWLINE
, pc
);
271 sk_X509_free(signers
);
276 else if(PKCS7_type_is_enveloped(p7
)){
280 gf_puts(_("This message was encrypted."), pc
);
281 gf_puts(NEWLINE
, pc
);
285 if(p7
->d
.enveloped
&& p7
->d
.enveloped
->enc_data
){
286 X509_ALGOR
*alg
= p7
->d
.enveloped
->enc_data
->algorithm
;
287 STACK_OF(PKCS7_RECIP_INFO
) *ris
= p7
->d
.enveloped
->recipientinfo
;
290 gf_puts(_("The algorithm used to encrypt was "), pc
);
293 char *n
= (char *) OBJ_nid2sn( OBJ_obj2nid(alg
->algorithm
));
295 gf_puts(n
? n
: "<unknown>", pc
);
299 gf_puts("<unknown>", pc
);
301 gf_puts("." NEWLINE NEWLINE
, pc
);
303 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("Certificate%s for decrypting"),
304 plural(sk_PKCS7_RECIP_INFO_num(ris
)));
305 gf_puts_uline(tmp_20k_buf
, pc
);
306 gf_puts(NEWLINE
, pc
);
307 print_separator_line(100, '-', pc
);
309 for(i
=0; i
<sk_PKCS7_RECIP_INFO_num(ris
); i
++){
310 PKCS7_RECIP_INFO
*ri
;
311 PERSONAL_CERT
*pcert
;
313 ri
= sk_PKCS7_RECIP_INFO_value(ris
, i
);
317 pcert
= find_certificate_matching_recip_info(ri
);
321 print_separator_line(25, '*', pc
);
322 gf_puts(NEWLINE
, pc
);
327 output_cert_info(pcert
->cert
, pc
);
328 gf_puts(NEWLINE
, pc
);
334 gf_puts(_("No certificate capable of decrypting could be found."), pc
);
335 gf_puts(NEWLINE
, pc
);
336 gf_puts(NEWLINE
, pc
);
348 print_separator_line(int percent
, int ch
, gf_io_t pc
)
352 len
= ps_global
->ttyo
->screen_cols
* percent
/ 100;
353 start
= (ps_global
->ttyo
->screen_cols
- len
)/2;
355 for(i
=0; i
<start
; i
++)
358 for(i
=start
; i
<start
+len
; i
++)
361 gf_puts(NEWLINE
, pc
);
366 output_cert_info(X509
*cert
, gf_io_t pc
)
369 STORE_S
*left
,*right
;
372 STACK_OF(X509
) *chain
;
374 left
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
375 right
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
379 gf_set_so_writec(&spc
, left
);
381 if(!cert
->cert_info
){
382 gf_puts("Couldn't find certificate info.", spc
);
383 gf_puts(NEWLINE
, spc
);
386 gf_puts_uline("Certificate Owner", spc
);
387 gf_puts(NEWLINE
, spc
);
389 output_X509_NAME(cert
->cert_info
->subject
, spc
);
390 gf_puts(NEWLINE
, spc
);
392 gf_puts_uline("Serial Number", spc
);
393 gf_puts(NEWLINE
, spc
);
401 bs
= X509_get_serialNumber(cert
);
402 if (bs
->length
<= (int)sizeof(long)){
403 l
= ASN1_INTEGER_get(bs
);
404 if (bs
->type
== V_ASN1_NEG_INTEGER
){
410 snprintf(buf
, sizeof(buf
), " %s%lu (%s0x%lx)", neg
, l
, neg
, l
);
412 snprintf(buf
, sizeof(buf
), "%s", bs
->type
== V_ASN1_NEG_INTEGER
? "(Negative)" : "");
413 for (i
= 0; i
< bs
->length
; i
++)
414 snprintf(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
), "%02x%s", bs
->data
[i
],
415 i
+1 == bs
->length
? "" : ":");
419 gf_puts(NEWLINE
, spc
);
420 gf_puts(NEWLINE
, spc
);
422 gf_puts_uline("Validity", spc
);
423 gf_puts(NEWLINE
, spc
);
425 BIO
*mb
= BIO_new(BIO_s_mem());
428 gf_puts("Not Before: ", spc
);
430 (void) BIO_reset(mb
);
431 ASN1_UTCTIME_print(mb
, cert
->cert_info
->validity
->notBefore
);
432 (void) BIO_flush(mb
);
433 while((len
= BIO_read(mb
, iobuf
, sizeof(iobuf
))) > 0)
434 gf_nputs(iobuf
, len
, spc
);
436 gf_puts(NEWLINE
, spc
);
438 gf_puts("Not After: ", spc
);
440 (void) BIO_reset(mb
);
441 ASN1_UTCTIME_print(mb
, cert
->cert_info
->validity
->notAfter
);
442 (void) BIO_flush(mb
);
443 while((len
= BIO_read(mb
, iobuf
, sizeof(iobuf
))) > 0)
444 gf_nputs(iobuf
, len
, spc
);
446 gf_puts(NEWLINE
, spc
);
447 gf_puts(NEWLINE
, spc
);
453 gf_clear_so_writec(left
);
455 gf_set_so_writec(&spc
, right
);
457 if(!cert
->cert_info
){
458 gf_puts(_("Couldn't find certificate info."), spc
);
459 gf_puts(NEWLINE
, spc
);
462 gf_puts_uline("Issuer", spc
);
463 gf_puts(NEWLINE
, spc
);
465 output_X509_NAME(cert
->cert_info
->issuer
, spc
);
466 gf_puts(NEWLINE
, spc
);
469 gf_clear_so_writec(right
);
471 side_by_side(left
, right
, pc
);
473 gf_puts_uline("SHA1 Fingerprint", pc
);
474 gf_puts(NEWLINE
, pc
);
475 get_fingerprint(cert
, EVP_sha1(), buf
, sizeof(buf
), ":");
477 gf_puts(NEWLINE
, pc
);
479 gf_puts_uline("MD5 Fingerprint", pc
);
480 gf_puts(NEWLINE
, pc
);
481 get_fingerprint(cert
, EVP_md5(), buf
, sizeof(buf
), ":");
483 gf_puts(NEWLINE
, pc
);
484 gf_puts(NEWLINE
, pc
);
486 gf_puts_uline("Certificate Chain Information", pc
);
487 gf_puts(NEWLINE
, pc
);
489 if((chain
= get_chain_for_cert(cert
, &error
, &len
)) != NULL
){
495 for(i
= 0; i
< offset
; i
++) space
[i
] = ' ';
497 for(i
= -1; i
< sk_X509_num(chain
); i
++){
500 x
= i
== -1 ? cert
: sk_X509_value(chain
, i
);
502 if(x
&& x
->cert_info
){
504 space
[offset
+ i
+ 0] = ' ';
505 space
[offset
+ i
+ 1] = '\\';
506 space
[offset
+ i
+ 2] = '-';
507 space
[offset
+ i
+ 3] = ' ';
508 space
[offset
+ i
+ 4] = '\0';
512 space
[offset
] = '\0';
516 gf_puts_uline("Signed by: ", pc
);
518 gf_puts_uline("Issued to: ", pc
);
520 e
= X509_NAME_get_entry(x
->cert_info
->subject
,
521 X509_NAME_entry_count(x
->cert_info
->subject
)-1);
524 X509_NAME_get_text_by_OBJ(x
->cert_info
->subject
, e
->object
, buf
, sizeof(buf
));
526 gf_puts(NEWLINE
, pc
);
530 gf_puts("No certificate info found", pc
);
531 gf_puts(NEWLINE
, pc
);
535 e
= X509_NAME_get_entry(x
->cert_info
->issuer
,
536 X509_NAME_entry_count(x
->cert_info
->issuer
)-1);
538 X509_NAME_get_text_by_OBJ(x
->cert_info
->issuer
, e
->object
, buf
, sizeof(buf
));
539 space
[offset
+ i
+ 0] = ' ';
540 space
[offset
+ i
+ 1] = '\\';
541 space
[offset
+ i
+ 2] = '-';
542 space
[offset
+ i
+ 3] = ' ';
543 space
[offset
+ i
+ 4] = '\0';
545 gf_puts_uline("Signed by: ", pc
);
547 gf_puts(NEWLINE
, pc
);
549 sk_X509_pop_free(chain
, X509_free
);
551 gf_puts(NEWLINE
, pc
);
559 output_X509_NAME(X509_NAME
*name
, gf_io_t pc
)
564 c
= X509_NAME_entry_count(name
);
566 for(i
=c
-1; i
>=0; i
--){
569 e
= X509_NAME_get_entry(name
,i
);
573 X509_NAME_get_text_by_OBJ(name
, e
->object
, buf
, sizeof(buf
));
576 gf_puts(NEWLINE
, pc
);
582 * Output the contents of the given stores (left and right)
583 * to the given gf_io_t.
584 * The width of the terminal is inspected and two columns
585 * are created to fit the stores into. They are then wrapped
589 side_by_side(STORE_S
*left
, STORE_S
*right
, gf_io_t pc
)
591 STORE_S
*left_wrapped
;
592 STORE_S
*right_wrapped
;
598 int w
= ps_global
->ttyo
->screen_cols
/2 - 1;
601 so_seek(right
, 0, 0);
603 left_wrapped
= wrap_store(left
, w
);
604 right_wrapped
= wrap_store(right
, w
);
606 so_seek(left_wrapped
, 0, 0);
607 so_seek(right_wrapped
, 0, 0);
611 l
= so_fgets(left_wrapped
, buf_l
, sizeof(buf_l
));
612 r
= so_fgets(right_wrapped
, buf_r
, sizeof(buf_r
));
613 if(l
== NULL
&& r
== NULL
)
616 for(i
=0, b
=buf_l
; i
<w
&& *b
&& *b
!='\r' && *b
!='\n'; i
++,b
++){
618 /* reduce accumulated width if an embed tag is discovered */
630 for(i
=0, b
=buf_r
; i
<w
&& *b
&& *b
!='\r' && *b
!='\n'; i
++,b
++)
634 gf_puts(NEWLINE
, pc
);
637 so_give(&left_wrapped
);
638 so_give(&right_wrapped
);
642 * Wrap the text in the given store to the given width.
643 * A new store is created for the result.
646 wrap_store(STORE_S
*in
, int width
)
655 result
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
656 ws
= gf_wrap_filter_opt(width
, width
, NULL
, 0, 0);
659 gf_link_filter(gf_wrap
, ws
);
661 gf_set_so_writec(&opc
, result
);
662 gf_set_so_readc(&ipc
, in
);
666 gf_clear_so_readc(in
);
667 gf_clear_so_writec(result
);
674 smime_config_screen(struct pine
*ps
, int edit_exceptions
)
676 CONF_S
*ctmp
= NULL
, *first_line
= NULL
;
677 SAVED_CONFIG_S
*vsave
;
679 int ew
, readonly_warning
= 0;
681 dprint((9, "smime_config_screen()"));
682 ps
->next_screen
= SCREEN_FUN_NULL
;
685 * this is necessary because we need to know the correct paths
686 * to configure certificates and keys, and we could get here
687 * without having done that before we reach this place.
691 if(ps
->fix_fixed_warning
)
692 offer_to_fix_pinerc(ps
);
694 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
697 readonly_warning
= 1;
699 PINERC_S
*prc
= NULL
;
712 readonly_warning
= prc
? prc
->readonly
: 1;
713 if(prc
&& prc
->quit_to_edit
){
714 quit_to_edit_msg(prc
);
719 smime_config_init_display(ps
, &ctmp
, &first_line
);
721 vsave
= save_smime_config_vars(ps
);
723 memset(&screen
, 0, sizeof(screen
));
724 screen
.deferred_ro_warning
= readonly_warning
;
725 switch(conf_scroll_screen(ps
, &screen
, first_line
,
726 edit_exceptions
? _("SETUP S/MIME EXCEPTIONS")
728 /* TRANSLATORS: Print something1 using something2.
729 configuration is something1 */
730 _("configuration"), 0, NULL
)){
735 write_pinerc(ps
, ew
, WRP_NONE
);
739 revert_to_saved_smime_config(ps
, vsave
);
743 q_status_message(SM_ORDER
, 7, 10,
744 _("conf_scroll_screen bad ret in smime_config"));
748 free_saved_smime_config(ps
, &vsave
);
754 smime_related_var(struct pine
*ps
, struct variable
*var
)
756 return(var
== &ps
->vars
[V_PUBLICCERT_DIR
] ||
757 var
== &ps
->vars
[V_PUBLICCERT_CONTAINER
] ||
758 var
== &ps
->vars
[V_PRIVATEKEY_DIR
] ||
759 var
== &ps
->vars
[V_PRIVATEKEY_CONTAINER
] ||
760 var
== &ps
->vars
[V_CACERT_DIR
] ||
761 var
== &ps
->vars
[V_CACERT_CONTAINER
]);
765 smime_config_init_display(struct pine
*ps
, CONF_S
**ctmp
, CONF_S
**first_line
)
769 struct variable
*vtmp
;
773 /* find longest variable name */
774 for(vtmp
= ps
->vars
; vtmp
->name
; vtmp
++){
775 if(!(smime_related_var(ps
, vtmp
)))
778 if((i
= utf8_width(pretty_var_name(vtmp
->name
))) > ln
)
782 for(vtmp
= ps
->vars
; vtmp
->name
; vtmp
++){
783 if(!(smime_related_var(ps
, vtmp
)))
786 new_confline(ctmp
)->var
= vtmp
;
787 if(first_line
&& !*first_line
)
790 (*ctmp
)->valoffset
= ln
+3;
791 (*ctmp
)->keymenu
= &config_text_keymenu
;
792 (*ctmp
)->help
= config_help(vtmp
- ps
->vars
, 0);
793 (*ctmp
)->tool
= text_tool
;
795 utf8_snprintf(tmp
, sizeof(tmp
), "%-*.100w =", ln
, pretty_var_name(vtmp
->name
));
796 tmp
[sizeof(tmp
)-1] = '\0';
798 (*ctmp
)->varname
= cpystr(tmp
);
799 (*ctmp
)->varnamep
= (*ctmp
);
800 (*ctmp
)->flags
= CF_STARTITEM
;
801 (*ctmp
)->value
= pretty_value(ps
, *ctmp
);
805 vtmp
= &ps
->vars
[V_FEATURE_LIST
];
809 (*ctmp
)->flags
|= CF_NOSELECT
| CF_STARTITEM
;
810 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
811 (*ctmp
)->tool
= NULL
;
813 /* put a nice delimiter before list */
814 new_confline(ctmp
)->var
= NULL
;
815 (*ctmp
)->varnamep
= ctmpb
;
816 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
817 (*ctmp
)->help
= NO_HELP
;
818 (*ctmp
)->tool
= checkbox_tool
;
819 (*ctmp
)->valoffset
= feature_indent();
820 (*ctmp
)->flags
|= CF_NOSELECT
;
821 (*ctmp
)->value
= cpystr("Set Feature Name");
823 new_confline(ctmp
)->var
= NULL
;
824 (*ctmp
)->varnamep
= ctmpb
;
825 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
826 (*ctmp
)->help
= NO_HELP
;
827 (*ctmp
)->tool
= checkbox_tool
;
828 (*ctmp
)->valoffset
= feature_indent();
829 (*ctmp
)->flags
|= CF_NOSELECT
;
830 (*ctmp
)->value
= cpystr("--- ----------------------");
832 ind
= feature_list_index(F_DONT_DO_SMIME
);
833 feature
= feature_list(ind
);
834 new_confline(ctmp
)->var
= vtmp
;
835 (*ctmp
)->varnamep
= ctmpb
;
836 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
837 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
838 (*ctmp
)->tool
= checkbox_tool
;
839 (*ctmp
)->valoffset
= feature_indent();
840 (*ctmp
)->varmem
= ind
;
841 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
843 ind
= feature_list_index(F_ENCRYPT_DEFAULT_ON
);
844 feature
= feature_list(ind
);
845 new_confline(ctmp
)->var
= vtmp
;
846 (*ctmp
)->varnamep
= ctmpb
;
847 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
848 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
849 (*ctmp
)->tool
= checkbox_tool
;
850 (*ctmp
)->valoffset
= feature_indent();
851 (*ctmp
)->varmem
= ind
;
852 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
854 ind
= feature_list_index(F_REMEMBER_SMIME_PASSPHRASE
);
855 feature
= feature_list(ind
);
856 new_confline(ctmp
)->var
= vtmp
;
857 (*ctmp
)->varnamep
= ctmpb
;
858 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
859 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
860 (*ctmp
)->tool
= checkbox_tool
;
861 (*ctmp
)->valoffset
= feature_indent();
862 (*ctmp
)->varmem
= ind
;
863 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
865 ind
= feature_list_index(F_SIGN_DEFAULT_ON
);
866 feature
= feature_list(ind
);
867 new_confline(ctmp
)->var
= vtmp
;
868 (*ctmp
)->varnamep
= ctmpb
;
869 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
870 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
871 (*ctmp
)->tool
= checkbox_tool
;
872 (*ctmp
)->valoffset
= feature_indent();
873 (*ctmp
)->varmem
= ind
;
874 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
876 ind
= feature_list_index(F_USE_CERT_STORE_ONLY
);
877 feature
= feature_list(ind
);
878 new_confline(ctmp
)->var
= vtmp
;
879 (*ctmp
)->varnamep
= ctmpb
;
880 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
881 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
882 (*ctmp
)->tool
= checkbox_tool
;
883 (*ctmp
)->valoffset
= feature_indent();
884 (*ctmp
)->varmem
= ind
;
885 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
889 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
892 (*ctmp
)->flags
|= CF_NOSELECT
;
893 (*ctmp
)->value
= cpystr(_("Mac OS X specific features"));
895 ind
= feature_list_index(F_PUBLICCERTS_IN_KEYCHAIN
);
896 feature
= feature_list(ind
);
897 new_confline(ctmp
)->var
= vtmp
;
898 (*ctmp
)->varnamep
= ctmpb
;
899 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
900 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
901 (*ctmp
)->tool
= checkbox_tool
;
902 (*ctmp
)->valoffset
= feature_indent();
903 (*ctmp
)->varmem
= ind
;
904 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
905 #endif /* APPLEKEYCHAIN */
908 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
910 for(i
= 0; i
< sizeof(tmp
) && i
< (ps
->ttyo
? ps
->ttyo
->screen_cols
: sizeof(tmp
)); i
++)
913 (*ctmp
)->flags
|= CF_NOSELECT
;
914 (*ctmp
)->value
= cpystr(tmp
);
917 (*ctmp
)->flags
|= CF_NOSELECT
;
918 (*ctmp
)->value
= cpystr(_("Be careful with the following commands, they REPLACE contents in the target"));
921 (*ctmp
)->flags
|= CF_NOSELECT
;
922 (*ctmp
)->value
= cpystr(tmp
);
925 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
927 /* copy public directory to container */
929 (*ctmp
)->tool
= smime_helper_tool
;
930 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
931 (*ctmp
)->help
= h_config_smime_transfer_pub_to_con
;
932 (*ctmp
)->value
= cpystr(_("Transfer public certs FROM directory TO container"));
935 /* copy private directory to container */
937 (*ctmp
)->tool
= smime_helper_tool
;
938 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
939 (*ctmp
)->help
= h_config_smime_transfer_priv_to_con
;
940 (*ctmp
)->value
= cpystr(_("Transfer private keys FROM directory TO container"));
943 /* copy cacert directory to container */
945 (*ctmp
)->tool
= smime_helper_tool
;
946 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
947 (*ctmp
)->help
= h_config_smime_transfer_cacert_to_con
;
948 (*ctmp
)->value
= cpystr(_("Transfer CA certs FROM directory TO container"));
951 new_confline(ctmp
)->var
= vtmp
;
952 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
954 /* copy public container to directory */
956 (*ctmp
)->tool
= smime_helper_tool
;
957 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
958 (*ctmp
)->help
= h_config_smime_transfer_pub_to_dir
;
959 (*ctmp
)->value
= cpystr(_("Transfer public certs FROM container TO directory"));
962 /* copy private container to directory */
964 (*ctmp
)->tool
= smime_helper_tool
;
965 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
966 (*ctmp
)->help
= h_config_smime_transfer_priv_to_dir
;
967 (*ctmp
)->value
= cpystr(_("Transfer private keys FROM container TO directory"));
970 /* copy cacert container to directory */
972 (*ctmp
)->tool
= smime_helper_tool
;
973 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
974 (*ctmp
)->help
= h_config_smime_transfer_cacert_to_dir
;
975 (*ctmp
)->value
= cpystr(_("Transfer CA certs FROM container TO directory"));
980 new_confline(ctmp
)->var
= vtmp
;
981 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
983 /* copy public container to keychain */
985 (*ctmp
)->tool
= smime_helper_tool
;
986 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
987 (*ctmp
)->help
= h_config_smime_transfer_pubcon_to_key
;
988 (*ctmp
)->value
= cpystr(_("Transfer public certs FROM container TO keychain"));
991 /* copy public keychain to container */
993 (*ctmp
)->tool
= smime_helper_tool
;
994 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
995 (*ctmp
)->help
= h_config_smime_transfer_pubkey_to_con
;
996 (*ctmp
)->value
= cpystr(_("Transfer public certs FROM keychain TO container"));
999 #endif /* APPLEKEYCHAIN */
1001 if(SMHOLDERTYPE(Private
) == Keychain
1002 && SMHOLDERTYPE(Public
) == Keychain
1003 && SMHOLDERTYPE(CACert
) == Keychain
)
1006 new_confline(ctmp
)->var
= vtmp
;
1007 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1010 (*ctmp
)->flags
|= CF_NOSELECT
;
1011 (*ctmp
)->value
= cpystr(tmp
);
1014 (*ctmp
)->flags
|= CF_NOSELECT
;
1015 (*ctmp
)->value
= cpystr(_("Manage your own certificates"));
1018 (*ctmp
)->flags
|= CF_NOSELECT
;
1019 (*ctmp
)->value
= cpystr(tmp
);
1021 new_confline(ctmp
)->var
= vtmp
;
1022 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1024 /* manage public certificates */
1026 (*ctmp
)->tool
= smime_helper_tool
;
1027 (*ctmp
)->keymenu
= &config_smime_manage_certs_menu_keymenu
;
1028 (*ctmp
)->help
= h_config_smime_public_certificates
;
1029 (*ctmp
)->value
= cpystr(_("Manage Public Certificates"));
1030 (*ctmp
)->varmem
= 9;
1032 /* manage private keys */
1034 (*ctmp
)->tool
= smime_helper_tool
;
1035 (*ctmp
)->keymenu
= &config_smime_manage_certs_menu_keymenu
;
1036 (*ctmp
)->help
= h_config_smime_private_keys
;
1037 (*ctmp
)->value
= cpystr(_("Manage Private Keys"));
1038 (*ctmp
)->varmem
= 10;
1040 /* manage Certificate Authorities */
1042 (*ctmp
)->tool
= smime_helper_tool
;
1043 (*ctmp
)->keymenu
= &config_smime_manage_certs_menu_keymenu
;
1044 (*ctmp
)->help
= h_config_smime_certificate_authorities
;
1045 (*ctmp
)->value
= cpystr(_("Manage Certificate Authorities"));
1046 (*ctmp
)->varmem
= 11;
1048 (*ctmp
)->next
= NULL
;
1051 void display_certificate_information(struct pine
*ps
, X509
*cert
, char *email
, WhichCerts ctype
, int num
)
1054 SCROLL_S scrollargs
;
1056 int pub_cert
, priv_cert
, new_store
;
1060 cmd
= offset
= pub_cert
= priv_cert
= 0;
1062 ps
->next_screen
= SCREEN_FUN_NULL
;
1064 /* MC_PRIVATE and MC_PUBLIC cancel each other,
1065 * they can not be active at the same time
1070 priv_cert
= 1 - priv_cert
;
1071 smime_certificate_info_keymenu
.keys
[PUBLIC_KEY
].label
= N_("Public Key");
1072 smime_certificate_info_keymenu
.keys
[PRIVATE_KEY
].label
= priv_cert
? N_("No Priv Key") : N_("Pivate Key");
1077 pub_cert
= 1 - pub_cert
;
1078 smime_certificate_info_keymenu
.keys
[PRIVATE_KEY
].label
= priv_cert
? N_("No Priv Key") : N_("Pivate Key");
1079 smime_certificate_info_keymenu
.keys
[PUBLIC_KEY
].label
= N_("Public Key");
1083 if(SMHOLDERTYPE(CACert
) == Directory
)
1084 save_cert_for(email
, cert
, CACert
);
1085 else{ /* if(SMHOLDERTYPE(CACert) == Container) */
1087 char *upath
= PATHCERTDIR(ctype
);
1088 char *tempfile
= tempfile_in_same_dir(path
, "az", NULL
);
1091 if(IS_REMOTE(upath
))
1092 strncpy(path
, temp_nam(NULL
, "a6"), sizeof(path
)-1);
1094 strncpy(path
, upath
, sizeof(path
)-1);
1095 path
[sizeof(path
)-1] = '\0';
1097 add_to_end_of_certlist(&ps_global
->smime
->cacertlist
, email
, X509_dup(cert
));
1098 for(clist
=ps_global
->smime
->cacertlist
; clist
&& clist
->next
; clist
= clist
->next
);
1099 certlist_to_file(tempfile
, clist
);
1100 add_file_to_container(CACert
, tempfile
, email
);
1108 if (get_cert_deleted(ctype
, num
) != 0)
1109 q_status_message(SM_ORDER
, 1, 3, _("Certificate already deleted"));
1111 mark_cert_deleted(ctype
, num
, 1);
1112 q_status_message(SM_ORDER
, 1, 3, _("Certificate marked deleted"));
1117 if (get_cert_deleted(ctype
, num
) != 0){
1118 mark_cert_deleted(ctype
, num
, 0);
1119 q_status_message(SM_ORDER
, 1, 3, _("Certificate marked UNdeleted"));
1122 q_status_message(SM_ORDER
, 1, 3, _("Certificate not marked deleted"));
1128 if((pub_cert
|| priv_cert
)
1129 && (out
= print_private_key_information(email
, priv_cert
)) == NULL
)
1130 q_status_message(SM_ORDER
, 1, 3, _("Problem Reading Private Certificate Information"));
1133 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
1134 view_writec_init(store
, NULL
, HEADER_ROWS(ps
),
1135 HEADER_ROWS(ps
) + ps
->ttyo
->screen_rows
- (HEADER_ROWS(ps
)+ FOOTER_ROWS(ps
)));
1137 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,"%s", _("Certificate Information"));
1138 gf_puts_uline(tmp_20k_buf
, view_writec
);
1139 gf_puts(NEWLINE
, view_writec
);
1140 print_separator_line(100, '-', view_writec
);
1142 output_cert_info(cert
, view_writec
);
1143 gf_puts(NEWLINE
, view_writec
);
1145 if(smime_validate_cert(cert
, &error
) < 0){
1146 const char *errorp
= X509_verify_cert_error_string(error
);
1147 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,_("Error validating certificate: %s"), errorp
);
1149 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s", _("Certificate validated without errors"));
1151 gf_puts_uline(tmp_20k_buf
, view_writec
);
1152 gf_puts(NEWLINE
, view_writec
);
1154 if(out
!= NULL
){ /* print private key information */
1155 unsigned char ch
[2];
1157 gf_puts(NEWLINE
, view_writec
);
1159 while(BIO_read(out
, ch
, 1) >= 1)
1160 gf_puts((char *)ch
, view_writec
);
1161 gf_puts(NEWLINE
, view_writec
);
1162 q_status_message1(SM_ORDER
, 1, 3, _("%s information shown at bottom of certificate information"), pub_cert
? _("Public") : _("Private"));
1166 view_writec_destroy();
1170 memset(&scrollargs
, 0, sizeof(SCROLL_S
));
1172 scrollargs
.text
.text
= so_text(store
);
1173 scrollargs
.text
.src
= CharStar
;
1174 scrollargs
.text
.desc
= "certificate information";
1175 scrollargs
.body_valid
= 1;
1177 if(offset
){ /* resize? preserve paging! */
1178 scrollargs
.start
.on
= Offset
;
1179 scrollargs
.start
.loc
.offset
= offset
;
1180 scrollargs
.body_valid
= 0;
1184 scrollargs
.use_indexline_color
= 1;
1186 scrollargs
.bar
.title
= _("CERTIFICATE INFORMATION");
1187 scrollargs
.proc
.tool
= manage_certificate_info_tool
;
1188 scrollargs
.resize_exit
= 1;
1189 scrollargs
.help
.text
= h_certificate_information
;
1190 scrollargs
.help
.title
= _("HELP FOR MESSAGE TEXT VIEW");
1191 scrollargs
.keys
.what
= FirstMenu
;
1192 scrollargs
.keys
.menu
= &smime_certificate_info_keymenu
;
1193 setbitmap(scrollargs
.keys
.bitmap
);
1194 if(ctype
!= Public
|| error
!= X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
)
1195 /*error != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)*/
1196 clrbitn(TRUST_KEY
, scrollargs
.keys
.bitmap
);
1197 if(ctype
!= Private
){
1198 clrbitn(PUBLIC_KEY
, scrollargs
.keys
.bitmap
);
1199 clrbitn(PRIVATE_KEY
, scrollargs
.keys
.bitmap
);
1202 cmd
= scrolltool(&scrollargs
);
1207 case MC_PUBLIC
: if(scrollargs
.start
.on
== Offset
)
1208 offset
= scrollargs
.start
.loc
.offset
;
1214 } while (cmd
!= MC_EXIT
);
1215 ps
->mangled_screen
= 1;
1219 * This is silly, we just need this function so that we can tell scrolltool
1220 * that some commands are recognized. We use scrolltool because we do not
1221 * want to rewrite output_cert_info.
1224 manage_certificate_info_tool(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
1232 case MC_TRUST
: rv
= 1; break;
1233 default: rv
= 0; break;
1240 manage_certs_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned flags
)
1244 WhichCerts ctype
= (*cl
)->d
.s
.ctype
;
1248 if(PATHCERTDIR(ctype
) == NULL
)
1251 if((cert
= get_cert_for((*cl
)->d
.s
.address
, ctype
, 0)) == NULL
){
1252 q_status_message(SM_ORDER
, 1, 3, _("Problem Reading Certificate"));
1256 display_certificate_information(ps
, cert
, (*cl
)->d
.s
.address
, ctype
, (*cl
)->varmem
);
1257 rv
= 10 + (*cl
)->varmem
;
1262 if ((*cl
)->d
.s
.deleted
!= 0)
1263 q_status_message(SM_ORDER
, 1, 3, _("Certificate already deleted"));
1265 (*cl
)->d
.s
.deleted
= 1;
1266 rv
= 10 + (*cl
)->varmem
; /* forces redraw */
1267 mark_cert_deleted(ctype
, (*cl
)->varmem
, 1);
1268 q_status_message(SM_ORDER
, 1, 3, _("Certificate marked deleted"));
1273 if ((*cl
)->d
.s
.deleted
== 0)
1274 q_status_message(SM_ORDER
, 1, 3, _("Certificate not marked deleted"));
1276 (*cl
)->d
.s
.deleted
= 0;
1277 mark_cert_deleted(ctype
, (*cl
)->varmem
, 0);
1278 rv
= 10 + (*cl
)->varmem
; /* forces redraw */
1279 q_status_message(SM_ORDER
, 1, 3, _("Certificate marked UNdeleted"));
1286 for(cl
= DATACERT(ctype
); cl
!= NULL
&& DELETEDCERT(cl
) == 0; cl
= cl
->next
);
1287 if(cl
!= NULL
&& DELETEDCERT(cl
) != 0){
1288 smime_expunge_cert(ctype
);
1289 rv
= 10; /* forces redraw */
1292 q_status_message(SM_ORDER
, 3, 3, _("No certificates marked deleted"));
1298 rv
= import_certificate(ctype
);
1303 cmd_cancelled("Import certificate");
1307 q_status_message1(SM_ORDER
, 0, 2, _("Can't import certificate outside of %s"),
1308 ps_global
->VAR_OPER_DIR
);
1312 rv
= 10; /* forces redraw */
1316 rv
= config_exit_cmd(flags
);
1329 smime_setup_size(char **s
, size_t buflen
, size_t n
)
1335 snprintf(t
, buflen
-3, "%zu.%zu", n
, n
);
1341 void smime_manage_certs_init(struct pine
*ps
, CONF_S
**ctmp
, CONF_S
**first_line
, WhichCerts ctype
, int fline
)
1350 data
= DATACERT(ctype
);
1351 ext
= EXTCERT(ctype
);
1353 if(data
== NULL
|| RENEWCERT(data
))
1354 renew_cert_data(&data
, ctype
);
1356 for(i
= 0; i
< sizeof(tmp
) && i
< (ps
->ttyo
? ps
->ttyo
->screen_cols
: sizeof(tmp
)); i
++)
1359 (*ctmp
)->flags
|= CF_NOSELECT
;
1360 (*ctmp
)->value
= cpystr(tmp
);
1362 (*ctmp
)->keymenu
= &config_text_keymenu
;
1365 (*ctmp
)->flags
|= CF_NOSELECT
;
1366 sprintf(tmp
, _("List of %s certificates"), ctype
== Public
? _("public")
1367 : (ctype
== Private
? _("private")
1368 : (ctype
== CACert
? _("certificate authority") : "unknown (?)")));
1369 (*ctmp
)->value
= cpystr(tmp
);
1371 for(i
= 0; i
< sizeof(tmp
) && i
< (ps
->ttyo
? ps
->ttyo
->screen_cols
: sizeof(tmp
)); i
++)
1374 (*ctmp
)->flags
|= CF_NOSELECT
;
1375 (*ctmp
)->value
= cpystr(tmp
);
1378 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1381 CertList
*cl
; int i
;
1382 int s
, e
, df
, dt
, md5
; /* sizes of certain fields */
1383 int nf
; /* number of fields */
1384 char u
[MAILTMPLEN
], *t
;
1386 for(cl
= data
, e
= 0; cl
; cl
= cl
->next
)
1387 if(cl
->name
&& strlen(cl
->name
) > e
)
1388 e
= strlen(cl
->name
);
1390 if(ctype
!= Private
&& SMHOLDERTYPE(ctype
) == Directory
)
1391 e
-= 4; /* remove extension length */
1392 e
= MIN(e
, ps
->ttyo
->screen_cols
/3); /* do not use too much screen */
1393 nf
= 5; /* there are 5 fields */
1394 s
= 3; /* status has fixed size */
1395 df
= dt
= 10; /* date from and date to have fixed size */
1396 md5
= ps
->ttyo
->screen_cols
- s
- df
- dt
- e
- (nf
- 1);
1399 smime_setup_size(&t
, sizeof(u
), s
);
1400 smime_setup_size(&t
, sizeof(u
) - strlen(t
), e
);
1401 smime_setup_size(&t
, sizeof(u
) - strlen(t
), df
);
1402 *t
++ = ' '; /* leave an extra space between dates */
1403 smime_setup_size(&t
, sizeof(u
) - strlen(t
), dt
);
1404 *t
++ = ' '; /* and another space between date and md5 sum */
1405 smime_setup_size(&t
, sizeof(u
) - strlen(t
), md5
);
1406 *t
= '\0'; /* tie off */
1408 for(cl
= data
, i
= 0; cl
; cl
= cl
->next
)
1413 (*ctmp
)->d
.s
.ctype
= ctype
;
1414 (*ctmp
)->d
.s
.deleted
= get_cert_deleted(ctype
, i
);
1415 (*ctmp
)->tool
= manage_certs_tool
;
1416 (*ctmp
)->keymenu
= &config_smime_manage_certs_work_keymenu
;
1417 (*ctmp
)->varmem
= i
++;
1418 (*ctmp
)->help
= ctype
== Public
? h_config_smime_manage_public_menu
1419 : (ctype
== Private
? h_config_smime_manage_private_menu
1420 : h_config_smime_manage_cacerts_menu
);
1421 if(ctype
!= Private
&& SMHOLDERTYPE(ctype
) == Directory
)
1422 cl
->name
[strlen(cl
->name
) - 4] = '\0'; /* FIX FIX FIX */
1423 strncpy((*ctmp
)->d
.s
.address
, cl
->name
, sizeof((*ctmp
)->d
.s
.address
));
1424 (*ctmp
)->d
.s
.address
[sizeof((*ctmp
)->d
.s
.address
) - 1] = '\0';
1425 snprintf(tmp
, sizeof(tmp
), u
,
1426 (*ctmp
)->d
.s
.deleted
? "D" : " ",
1427 ctype
== CACert
? cl
->cn
: cl
->name
,
1428 DATEFROMCERT(cl
), DATETOCERT(cl
), MD5CERT(cl
));
1429 if(ctype
!= Private
&& SMHOLDERTYPE(ctype
) == Directory
)
1430 cl
->name
[strlen(cl
->name
)] = '.';
1431 (*ctmp
)->value
= cpystr(tmp
);
1432 if(i
== fline
+1 && first_line
&& !*first_line
)
1433 *first_line
= *ctmp
;
1438 (*ctmp
)->d
.s
.ctype
= ctype
;
1439 (*ctmp
)->tool
= manage_certs_tool
;
1440 (*ctmp
)->keymenu
= &config_smime_add_certs_keymenu
;
1441 (*ctmp
)->value
= cpystr(_(" \tNo certificates found, press \"RETURN\" to add one."));
1442 if(first_line
&& !*first_line
)
1443 *first_line
= *ctmp
;
1447 void manage_certificates(struct pine
*ps
, WhichCerts ctype
)
1449 OPT_SCREEN_S screen
;
1450 int readonly_warning
= 0, rv
= 10, fline
;
1452 dprint((9, "manage_certificates(ps, %s)", ctype
== Public
? _("Public") : (ctype
== Private
? _("Private") : (ctype
== CACert
? _("certificate authority") : _("unknown")))));
1453 ps
->next_screen
= SCREEN_FUN_NULL
;
1456 CONF_S
*ctmp
= NULL
, *first_line
= NULL
;
1458 fline
= rv
>= 10 ? rv
- 10 : 0;
1462 smime_manage_certs_init(ps
, &ctmp
, &first_line
, ctype
, fline
);
1465 ps
->mangled_screen
= 1;
1470 memset(&screen
, 0, sizeof(screen
));
1471 screen
.deferred_ro_warning
= readonly_warning
;
1472 rv
= conf_scroll_screen(ps
, &screen
, first_line
,
1473 _("MANAGE CERTIFICATES"),
1474 /* TRANSLATORS: Print something1 using something2.
1475 configuration is something1 */
1476 _("configuration"), 0, NULL
);
1479 ps
->mangled_screen
= 1;
1484 smime_helper_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned flags
)
1490 switch((*cl
)->varmem
){
1492 rv
= copy_publiccert_dir_to_container();
1494 q_status_message(SM_ORDER
, 1, 3, _("Public certs transferred to container"));
1496 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1503 rv
= copy_publiccert_container_to_dir();
1505 q_status_message(SM_ORDER
, 1, 3, _("Public certs transferred to directory, delete Container config to use"));
1507 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1514 rv
= copy_privatecert_dir_to_container();
1516 q_status_message(SM_ORDER
, 1, 3, _("Private keys transferred to container"));
1518 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1525 rv
= copy_privatecert_container_to_dir();
1527 q_status_message(SM_ORDER
, 1, 3, _("Private keys transferred to directory, delete Container config to use"));
1529 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1536 rv
= copy_cacert_dir_to_container();
1538 q_status_message(SM_ORDER
, 1, 3, _("CA certs transferred to container"));
1540 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1547 rv
= copy_cacert_container_to_dir();
1549 q_status_message(SM_ORDER
, 1, 3, _("CA certs transferred to directory, delete Container config to use"));
1551 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1557 #ifdef APPLEKEYCHAIN
1559 rv
= copy_publiccert_container_to_keychain();
1561 q_status_message(SM_ORDER
, 1, 3, _("Public certs transferred to keychain"));
1563 q_status_message(SM_ORDER
, 3, 3, _("Command not implemented yet"));
1570 rv
= copy_publiccert_keychain_to_container();
1572 q_status_message(SM_ORDER
, 1, 3, _("Public certs transferred to container"));
1574 q_status_message(SM_ORDER
, 3, 3, _("Command not implemented yet"));
1579 #endif /* APPLEKEYCHAIN */
1581 case 9: manage_certificates(ps
, Public
) ; break;
1582 case 10: manage_certificates(ps
, Private
); break;
1583 case 11: manage_certificates(ps
, CACert
) ; break;
1593 rv
= config_exit_cmd(flags
);
1598 /* keep this selection consistent with the codes above */
1599 ctype
= (*cl
)->varmem
== 9 ? Public
1600 : ((*cl
)->varmem
== 10 ? Private
: CACert
);
1601 rv
= import_certificate(ctype
);
1615 * Compare saved user_val with current user_val to see if it changed.
1616 * If any have changed, change it back and take the appropriate action.
1619 revert_to_saved_smime_config(struct pine
*ps
, SAVED_CONFIG_S
*vsave
)
1621 struct variable
*vreal
;
1625 char *pval
, **apval
, **lval
, ***alval
;
1628 for(vreal
= ps
->vars
; vreal
->name
; vreal
++,v
++){
1629 if(!(smime_related_var(ps
, vreal
) || vreal
==&ps
->vars
[V_FEATURE_LIST
]))
1633 lval
= LVAL(vreal
, ew
);
1634 alval
= ALVAL(vreal
, ew
);
1636 if((v
->saved_user_val
.l
&& !lval
)
1637 || (!v
->saved_user_val
.l
&& lval
))
1639 else if(!v
->saved_user_val
.l
&& !lval
)
1640 ;/* no change, nothing to do */
1642 for(i
= 0; v
->saved_user_val
.l
[i
] || lval
[i
]; i
++)
1643 if((v
->saved_user_val
.l
[i
]
1645 || strcmp(v
->saved_user_val
.l
[i
], lval
[i
])))
1647 (!v
->saved_user_val
.l
[i
] && lval
[i
])){
1657 free_list_array(alval
);
1659 /* copy back the original one */
1660 if(v
->saved_user_val
.l
){
1661 list
= v
->saved_user_val
.l
;
1663 /* count how many */
1667 *alval
= (char **)fs_get((n
+1) * sizeof(char *));
1669 for(i
= 0; i
< n
; i
++)
1670 (*alval
)[i
] = cpystr(v
->saved_user_val
.l
[i
]);
1678 pval
= PVAL(vreal
, ew
);
1679 apval
= APVAL(vreal
, ew
);
1681 if((v
->saved_user_val
.p
&&
1682 (!pval
|| strcmp(v
->saved_user_val
.p
, pval
))) ||
1683 (!v
->saved_user_val
.p
&& pval
)){
1684 /* It changed, fix it */
1687 /* free the changed value */
1689 fs_give((void **)apval
);
1691 if(v
->saved_user_val
.p
)
1692 *apval
= cpystr(v
->saved_user_val
.p
);
1698 if(vreal
== &ps
->vars
[V_FEATURE_LIST
])
1699 set_feature_list_current_val(vreal
);
1701 set_current_val(vreal
, TRUE
, FALSE
);
1703 fix_side_effects(ps
, vreal
, 1);
1710 save_smime_config_vars(struct pine
*ps
)
1712 struct variable
*vreal
;
1713 SAVED_CONFIG_S
*vsave
, *v
;
1715 vsave
= (SAVED_CONFIG_S
*)fs_get((V_LAST_VAR
+1)*sizeof(SAVED_CONFIG_S
));
1716 memset((void *)vsave
, 0, (V_LAST_VAR
+1)*sizeof(SAVED_CONFIG_S
));
1718 for(vreal
= ps
->vars
; vreal
->name
; vreal
++,v
++){
1719 if(!(smime_related_var(ps
, vreal
) || vreal
==&ps
->vars
[V_FEATURE_LIST
]))
1726 if(LVAL(vreal
, ew
)){
1727 /* count how many */
1729 list
= LVAL(vreal
, ew
);
1733 v
->saved_user_val
.l
= (char **)fs_get((n
+1) * sizeof(char *));
1734 memset((void *)v
->saved_user_val
.l
, 0, (n
+1)*sizeof(char *));
1735 for(i
= 0; i
< n
; i
++)
1736 v
->saved_user_val
.l
[i
] = cpystr(list
[i
]);
1738 v
->saved_user_val
.l
[n
] = NULL
;
1743 v
->saved_user_val
.p
= cpystr(PVAL(vreal
, ew
));
1752 free_saved_smime_config(struct pine
*ps
, SAVED_CONFIG_S
**vsavep
)
1754 struct variable
*vreal
;
1757 if(vsavep
&& *vsavep
){
1758 for(v
= *vsavep
, vreal
= ps
->vars
; vreal
->name
; vreal
++,v
++){
1759 if(!(smime_related_var(ps
, vreal
)))
1762 if(vreal
->is_list
){ /* free saved_user_val.l */
1763 if(v
&& v
->saved_user_val
.l
)
1764 free_list_array(&v
->saved_user_val
.l
);
1766 else if(v
&& v
->saved_user_val
.p
)
1767 fs_give((void **)&v
->saved_user_val
.p
);
1770 fs_give((void **)vsavep
);