* Update configure script according to previous change to configure.ac
[alpine.git] / alpine / smime.c
blob552438a3cfb60e02057f7117c6b9035fae73278b
1 /*
2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
16 * This is based on a contribution from Jonathan Paisley
18 * File: smime.c
19 * Author: paisleyj@dcs.gla.ac.uk
20 * Date: 01/2001
24 #include "headers.h"
26 #ifdef SMIME
28 #include "../pith/charconv/utf8.h"
29 #include "../pith/status.h"
30 #include "../pith/store.h"
31 #include "../pith/conf.h"
32 #include "../pith/list.h"
33 #include "../pith/mailcmd.h"
34 #include "../pith/tempfile.h"
35 #include "../pith/body.h"
36 #include "radio.h"
37 #include "keymenu.h"
38 #include "mailcmd.h"
39 #include "mailview.h"
40 #include "conftype.h"
41 #include "confscroll.h"
42 #include "setup.h"
43 #include "smime.h"
45 /* internal prototypes */
46 void format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc);
47 void print_separator_line(int percent, int ch, gf_io_t pc);
48 void output_cert_info(X509 *cert, gf_io_t pc);
49 void output_X509_NAME(X509_NAME *name, gf_io_t pc);
50 void side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc);
51 STORE_S *wrap_store(STORE_S *in, int width);
52 void smime_config_init_display(struct pine *, CONF_S **, CONF_S **);
53 void revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave);
54 SAVED_CONFIG_S *save_smime_config_vars(struct pine *ps);
55 void free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep);
56 int smime_helper_tool(struct pine *, int, CONF_S **, unsigned);
57 void manage_certificates(struct pine *, WhichCerts);
58 #ifdef PASSFILE
59 void manage_password_file_certificates(struct pine *);
60 #endif /* PASSFILE */
61 void smime_manage_certs_init (struct pine *, CONF_S **, CONF_S **, WhichCerts, int);
62 void smime_manage_password_file_certs_init(struct pine *, CONF_S **, CONF_S **, int, int *);
63 void display_certificate_information(struct pine *, X509 *, char *, WhichCerts, int num);
64 int manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags);
65 int manage_certificate_info_tool(int, MSGNO_S *, SCROLL_S *);
66 void smime_setup_size(char **, size_t, size_t);
70 * prompt the user for their passphrase
71 * (possibly prompting with the email address in s_passphrase_emailaddr)
73 int
74 smime_get_passphrase(void)
76 int rc;
77 int flags;
78 char prompt[500];
79 HelpType help = NO_HELP;
81 assert(ps_global->smime != NULL);
82 snprintf(prompt, sizeof(prompt),
83 _("Enter passphrase for <%s>: "), (ps_global->smime && ps_global->smime->passphrase_emailaddr) ? ps_global->smime->passphrase_emailaddr[0] : "unknown");
85 do {
86 flags = F_ON(F_QUELL_ASTERISKS, ps_global) ? OE_PASSWD_NOAST : OE_PASSWD;
87 flags |= OE_DISALLOW_HELP;
88 ((char *) ps_global->smime->passphrase)[0] = '\0';
89 rc = optionally_enter((char *) ps_global->smime->passphrase,
90 -FOOTER_ROWS(ps_global), 0,
91 sizeof(ps_global->smime->passphrase),
92 prompt, NULL, help, &flags);
93 } while (rc!=0 && rc!=1 && rc>0);
95 if(rc==0){
96 if(ps_global->smime)
97 ps_global->smime->entered_passphrase = 1;
100 return rc; /* better return rc and make the caller check its return value */
104 smime_check(BODY *body)
106 int rv = 0;
107 PKCS7 *p7 = NULL;
109 if(body->type == TYPEMULTIPART){
110 PART *p;
112 for(p=body->nested.part; p && rv == 0; p=p->next)
113 rv += smime_check(&p->body);
115 if(rv > 0) return rv;
116 if(body->sparep)
117 p7 = get_body_sparep_type(body->sparep) == P7Type
118 ? (PKCS7 *)get_body_sparep_data(body->sparep)
119 : NULL;
120 if(p7 && (PKCS7_type_is_signed(p7) || PKCS7_type_is_enveloped(p7)))
121 rv += 1;
122 return rv;
126 void
127 display_smime_info(struct pine *ps, ENVELOPE *env, BODY *body)
129 OtherMenu what = FirstMenu;
130 HANDLE_S *handles = NULL;
131 SCROLL_S scrollargs;
132 STORE_S *store = NULL;
133 long msgno;
134 int offset = 0;
136 msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
137 store = so_get(CharStar, NULL, EDIT_ACCESS);
139 while(ps->next_screen == SCREEN_FUN_NULL){
141 ClearLine(1);
143 so_truncate(store, 0);
145 view_writec_init(store, &handles, HEADER_ROWS(ps),
146 HEADER_ROWS(ps) +
147 ps->ttyo->screen_rows - (HEADER_ROWS(ps)
148 + HEADER_ROWS(ps)));
150 gf_puts_uline("Overview", view_writec);
151 gf_puts(NEWLINE, view_writec);
153 format_smime_info(1, body, msgno, view_writec);
154 gf_puts(NEWLINE, view_writec);
155 format_smime_info(2, body, msgno, view_writec);
157 view_writec_destroy();
159 ps->next_screen = SCREEN_FUN_NULL;
161 memset(&scrollargs, 0, sizeof(SCROLL_S));
162 scrollargs.text.text = so_text(store);
163 scrollargs.text.src = CharStar;
164 scrollargs.text.desc = "S/MIME information";
165 scrollargs.body_valid = 1;
167 if(offset){ /* resize? preserve paging! */
168 scrollargs.start.on = Offset;
169 scrollargs.start.loc.offset = offset;
170 offset = 0L;
173 scrollargs.bar.title = "S/MIME INFORMATION";
174 /* scrollargs.end_scroll = view_end_scroll; */
175 scrollargs.resize_exit = 1;
176 scrollargs.help.text = NULL;
177 scrollargs.help.title = "HELP FOR S/MIME INFORMATION VIEW";
178 scrollargs.keys.menu = &smime_info_keymenu;
179 scrollargs.keys.what = what;
180 setbitmap(scrollargs.keys.bitmap);
182 if(scrolltool(&scrollargs) == MC_RESIZE)
183 offset = scrollargs.start.loc.offset;
186 so_give(&store);
189 void
190 smime_info_screen(struct pine *ps)
192 long msgno;
193 BODY *body;
194 ENVELOPE *env;
196 /* ps->prev_screen = smime_info_screen;
197 ps->next_screen = SCREEN_FUN_NULL; */
199 msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
201 env = mail_fetch_structure(ps->mail_stream, msgno, &body, 0);
203 if(!env || !body){
204 q_status_message(SM_ORDER, 0, 3,
205 _("Can't fetch body of message."));
206 return;
209 if(smime_check(body) == 0){
210 q_status_message(SM_ORDER | SM_DING, 0, 3,
211 _("Not a signed or encrypted message"));
212 return;
215 if(mn_total_cur(ps->msgmap) > 1L){
216 q_status_message(SM_ORDER | SM_DING, 0, 3,
217 _("Can only view one message's information at a time."));
218 return;
221 display_smime_info(ps, env, body);
225 void
226 format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc)
228 PKCS7 *p7 = NULL;
229 int i;
231 if(body->type == TYPEMULTIPART){
232 PART *p;
234 for(p=body->nested.part; p; p=p->next)
235 format_smime_info(pass, &p->body, msgno, pc);
237 if(body->sparep)
238 p7 = get_body_sparep_type(body->sparep) == P7Type
239 ? (PKCS7 *)get_body_sparep_data(body->sparep)
240 : NULL;
241 if(p7){
243 if(PKCS7_type_is_signed(p7)){
244 STACK_OF(X509) *signers;
246 switch(pass){
247 case 1:
248 gf_puts(_("This message was cryptographically signed."), pc);
249 gf_puts(NEWLINE, pc);
250 break;
252 case 2:
253 signers = PKCS7_get0_signers(p7, NULL, 0);
255 if(signers){
257 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s used for signing"),
258 plural(sk_X509_num(signers)));
259 gf_puts_uline(tmp_20k_buf, pc);
260 gf_puts(NEWLINE, pc);
261 print_separator_line(100, '-', pc);
263 for(i=0; i<sk_X509_num(signers); i++){
264 X509 *x = sk_X509_value(signers, i);
266 if(x){
267 output_cert_info(x, pc);
268 gf_puts(NEWLINE, pc);
273 sk_X509_free(signers);
274 break;
278 else if(PKCS7_type_is_enveloped(p7)){
280 switch(pass){
281 case 1:
282 gf_puts(_("This message was encrypted."), pc);
283 gf_puts(NEWLINE, pc);
284 break;
286 case 2:
287 if(p7->d.enveloped && p7->d.enveloped->enc_data){
288 X509_ALGOR *alg = p7->d.enveloped->enc_data->algorithm;
289 STACK_OF(PKCS7_RECIP_INFO) *ris = p7->d.enveloped->recipientinfo;
290 int found = 0;
292 gf_puts(_("The algorithm used to encrypt was "), pc);
294 if(alg){
295 char *n = (char *) OBJ_nid2sn( OBJ_obj2nid(alg->algorithm));
297 gf_puts(n ? n : "<unknown>", pc);
300 else
301 gf_puts("<unknown>", pc);
303 gf_puts("." NEWLINE NEWLINE, pc);
305 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s for decrypting"),
306 plural(sk_PKCS7_RECIP_INFO_num(ris)));
307 gf_puts_uline(tmp_20k_buf, pc);
308 gf_puts(NEWLINE, pc);
309 print_separator_line(100, '-', pc);
311 for(i=0; i<sk_PKCS7_RECIP_INFO_num(ris); i++){
312 PKCS7_RECIP_INFO *ri;
313 PERSONAL_CERT *pcert;
315 ri = sk_PKCS7_RECIP_INFO_value(ris, i);
316 if(!ri)
317 continue;
319 pcert = find_certificate_matching_recip_info(ri);
321 if(pcert){
322 if(found){
323 print_separator_line(25, '*', pc);
324 gf_puts(NEWLINE, pc);
327 found = 1;
329 output_cert_info(pcert->cert, pc);
330 gf_puts(NEWLINE, pc);
335 if(!found){
336 gf_puts(_("No certificate capable of decrypting could be found."), pc);
337 gf_puts(NEWLINE, pc);
338 gf_puts(NEWLINE, pc);
342 break;
349 void
350 print_separator_line(int percent, int ch, gf_io_t pc)
352 int i, start, len;
354 len = ps_global->ttyo->screen_cols * percent / 100;
355 start = (ps_global->ttyo->screen_cols - len)/2;
357 for(i=0; i<start; i++)
358 pc(' ');
360 for(i=start; i<start+len; i++)
361 pc(ch);
363 gf_puts(NEWLINE, pc);
367 void
368 output_cert_info(X509 *cert, gf_io_t pc)
370 char buf[256];
371 STORE_S *left,*right;
372 gf_io_t spc;
373 int len, error;
374 STACK_OF(X509) *chain;
376 left = so_get(CharStar, NULL, EDIT_ACCESS);
377 right = so_get(CharStar, NULL, EDIT_ACCESS);
378 if(!(left && right))
379 return;
381 gf_set_so_writec(&spc, left);
383 gf_puts_uline("Certificate Owner", spc);
384 gf_puts(NEWLINE, spc);
386 output_X509_NAME(X509_get_subject_name(cert), spc);
387 gf_puts(NEWLINE, spc);
389 gf_puts_uline("Serial Number", spc);
390 gf_puts(NEWLINE, spc);
392 { ASN1_INTEGER *bs;
393 long l;
394 const char *neg;
395 int i;
397 bs = X509_get_serialNumber(cert);
398 if (bs->length <= (int)sizeof(long)){
399 l = ASN1_INTEGER_get(bs);
400 if (bs->type == V_ASN1_NEG_INTEGER){
401 l = -l;
402 neg="-";
404 else
405 neg="";
406 snprintf(buf, sizeof(buf), " %s%lu (%s0x%lx)", neg, l, neg, l);
407 } else {
408 snprintf(buf, sizeof(buf), "%s", bs->type == V_ASN1_NEG_INTEGER ? "(Negative)" : "");
409 for (i = 0; i < bs->length; i++)
410 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%02x%s", bs->data[i],
411 i+1 == bs->length ? "" : ":");
414 gf_puts(buf, spc);
415 gf_puts(NEWLINE, spc);
416 gf_puts(NEWLINE, spc);
418 gf_puts_uline("Validity", spc);
419 gf_puts(NEWLINE, spc);
420 { BIO *mb = BIO_new(BIO_s_mem());
421 char iobuf[4096];
423 gf_puts("Not Before: ", spc);
425 (void) BIO_reset(mb);
426 ASN1_UTCTIME_print(mb, X509_get0_notBefore(cert));
427 (void) BIO_flush(mb);
428 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
429 gf_nputs(iobuf, len, spc);
431 gf_puts(NEWLINE, spc);
433 gf_puts("Not After: ", spc);
435 (void) BIO_reset(mb);
436 ASN1_UTCTIME_print(mb, X509_get0_notAfter(cert));
437 (void) BIO_flush(mb);
438 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
439 gf_nputs(iobuf, len, spc);
441 gf_puts(NEWLINE, spc);
442 gf_puts(NEWLINE, spc);
444 BIO_free(mb);
447 gf_clear_so_writec(left);
449 gf_set_so_writec(&spc, right);
451 gf_puts_uline("Issuer", spc);
452 gf_puts(NEWLINE, spc);
454 output_X509_NAME(X509_get_issuer_name(cert), spc);
455 gf_puts(NEWLINE, spc);
457 gf_clear_so_writec(right);
459 side_by_side(left, right, pc);
461 gf_puts_uline("SHA1 Fingerprint", pc);
462 gf_puts(NEWLINE, pc);
463 get_fingerprint(cert, EVP_sha1(), buf, sizeof(buf), ":");
464 gf_puts(buf, pc);
465 gf_puts(NEWLINE, pc);
467 gf_puts_uline("MD5 Fingerprint", pc);
468 gf_puts(NEWLINE, pc);
469 get_fingerprint(cert, EVP_md5(), buf, sizeof(buf), ":");
470 gf_puts(buf, pc);
471 gf_puts(NEWLINE, pc);
472 gf_puts(NEWLINE, pc);
474 gf_puts_uline("Certificate Chain Information", pc);
475 gf_puts(NEWLINE, pc);
477 if((chain = get_chain_for_cert(cert, &error, &len)) != NULL){
478 X509 *x = NULL;
479 X509_NAME_ENTRY *e;
480 int i, offset = 2;
481 char space[256];
482 X509_NAME *subject;
484 for(i = 0; i < offset; i++) space[i] = ' ';
486 for(i = -1; i < sk_X509_num(chain); i++){
487 char buf[256];
489 x = i == -1 ? cert : sk_X509_value(chain, i);
491 if(x){
492 if(i>=0){
493 space[offset + i + 0] = ' ';
494 space[offset + i + 1] = '\\';
495 space[offset + i + 2] = '-';
496 space[offset + i + 3] = ' ';
497 space[offset + i + 4] = '\0';
498 gf_puts(space, pc);
500 else{
501 space[offset] = '\0';
502 gf_puts(space, pc);
504 if(i >= 0)
505 gf_puts_uline("Signed by: ", pc);
506 else
507 gf_puts_uline("Issued to: ", pc);
509 subject = X509_get_subject_name(x);
511 if((e = X509_NAME_get_entry(subject, X509_NAME_entry_count(subject)-1)) != NULL){
512 X509_NAME_get_text_by_OBJ(subject, X509_NAME_ENTRY_get_object(e), buf, sizeof(buf));
513 gf_puts(buf, pc);
514 gf_puts(NEWLINE, pc);
517 else{
518 gf_puts("No certificate info found", pc);
519 gf_puts(NEWLINE, pc);
520 break;
523 e = X509_NAME_get_entry(X509_get_issuer_name(x),
524 X509_NAME_entry_count(X509_get_issuer_name(x))-1);
525 if(e){
526 X509_NAME_get_text_by_OBJ(X509_get_issuer_name(x), X509_NAME_ENTRY_get_object(e), buf, sizeof(buf));
527 space[offset + i + 0] = ' ';
528 space[offset + i + 1] = '\\';
529 space[offset + i + 2] = '-';
530 space[offset + i + 3] = ' ';
531 space[offset + i + 4] = '\0';
532 gf_puts(space, pc);
533 gf_puts_uline("Signed by: ", pc);
534 gf_puts(buf, pc);
535 gf_puts(NEWLINE, pc);
537 sk_X509_pop_free(chain, X509_free);
539 gf_puts(NEWLINE, pc);
541 so_give(&left);
542 so_give(&right);
546 void
547 output_X509_NAME(X509_NAME *name, gf_io_t pc)
549 int i, c;
550 char buf[256];
552 c = X509_NAME_entry_count(name);
554 for(i=c-1; i>=0; i--){
555 X509_NAME_ENTRY *e;
557 e = X509_NAME_get_entry(name,i);
558 if(!e)
559 continue;
561 X509_NAME_get_text_by_OBJ(name, X509_NAME_ENTRY_get_object(e), buf, sizeof(buf));
563 gf_puts(buf, pc);
564 gf_puts(NEWLINE, pc);
570 * Output the contents of the given stores (left and right)
571 * to the given gf_io_t.
572 * The width of the terminal is inspected and two columns
573 * are created to fit the stores into. They are then wrapped
574 * and merged.
576 void
577 side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc)
579 STORE_S *left_wrapped;
580 STORE_S *right_wrapped;
581 char buf_l[256];
582 char buf_r[256];
583 char *l, *r;
584 char *b;
585 int i;
586 int w = ps_global->ttyo->screen_cols/2 - 1;
588 so_seek(left, 0, 0);
589 so_seek(right, 0, 0);
591 left_wrapped = wrap_store(left, w);
592 right_wrapped = wrap_store(right, w);
594 so_seek(left_wrapped, 0, 0);
595 so_seek(right_wrapped, 0, 0);
597 for(;;){
599 l = so_fgets(left_wrapped, buf_l, sizeof(buf_l));
600 r = so_fgets(right_wrapped, buf_r, sizeof(buf_r));
601 if(l == NULL && r == NULL)
602 break;
604 for(i=0, b=buf_l; i<w && *b && *b!='\r' && *b!='\n'; i++,b++){
605 pc(*b);
606 /* reduce accumulated width if an embed tag is discovered */
607 if(*b==TAG_EMBED)
608 i-=2;
611 if(buf_r[0]){
612 while(i<w){
613 pc(' ');
614 i++;
616 pc(' ');
618 for(i=0, b=buf_r; i<w && *b && *b!='\r' && *b!='\n'; i++,b++)
619 pc(*b);
622 gf_puts(NEWLINE, pc);
625 so_give(&left_wrapped);
626 so_give(&right_wrapped);
630 * Wrap the text in the given store to the given width.
631 * A new store is created for the result.
633 STORE_S *
634 wrap_store(STORE_S *in, int width)
636 STORE_S *result;
637 void *ws;
638 gf_io_t ipc,opc;
640 if(width<10)
641 width = 10;
643 result = so_get(CharStar, NULL, EDIT_ACCESS);
644 ws = gf_wrap_filter_opt(width, width, NULL, 0, 0);
646 gf_filter_init();
647 gf_link_filter(gf_wrap, ws);
649 gf_set_so_writec(&opc, result);
650 gf_set_so_readc(&ipc, in);
652 gf_pipe(ipc, opc);
654 gf_clear_so_readc(in);
655 gf_clear_so_writec(result);
657 return result;
661 void
662 smime_config_screen(struct pine *ps, int edit_exceptions)
664 CONF_S *ctmp = NULL, *first_line = NULL;
665 SAVED_CONFIG_S *vsave;
666 OPT_SCREEN_S screen;
667 int ew, readonly_warning = 0;
669 dprint((9, "smime_config_screen()"));
670 ps->next_screen = SCREEN_FUN_NULL;
673 * this is necessary because we need to know the correct paths
674 * to configure certificates and keys, and we could get here
675 * without having done that before we reach this place.
677 smime_reinit();
679 if(ps->fix_fixed_warning)
680 offer_to_fix_pinerc(ps);
682 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
684 if(ps->restricted)
685 readonly_warning = 1;
686 else{
687 PINERC_S *prc = NULL;
689 switch(ew){
690 case Main:
691 prc = ps->prc;
692 break;
693 case Post:
694 prc = ps->post_prc;
695 break;
696 default:
697 break;
700 readonly_warning = prc ? prc->readonly : 1;
701 if(prc && prc->quit_to_edit){
702 quit_to_edit_msg(prc);
703 return;
707 smime_config_init_display(ps, &ctmp, &first_line);
709 vsave = save_smime_config_vars(ps);
711 memset(&screen, 0, sizeof(screen));
712 screen.deferred_ro_warning = readonly_warning;
713 switch(conf_scroll_screen(ps, &screen, first_line,
714 edit_exceptions ? _("SETUP S/MIME EXCEPTIONS")
715 : _("SETUP S/MIME"),
716 /* TRANSLATORS: Print something1 using something2.
717 configuration is something1 */
718 _("configuration"), 0, NULL)){
719 case 0:
720 break;
722 case 1:
723 write_pinerc(ps, ew, WRP_NONE);
724 break;
726 case 10:
727 revert_to_saved_smime_config(ps, vsave);
728 break;
730 default:
731 q_status_message(SM_ORDER, 7, 10,
732 _("conf_scroll_screen bad ret in smime_config"));
733 break;
736 free_saved_smime_config(ps, &vsave);
737 smime_reinit();
742 smime_related_var(struct pine *ps, struct variable *var)
744 return(var == &ps->vars[V_PUBLICCERT_DIR] ||
745 var == &ps->vars[V_PUBLICCERT_CONTAINER] ||
746 var == &ps->vars[V_PRIVATEKEY_DIR] ||
747 var == &ps->vars[V_PRIVATEKEY_CONTAINER] ||
748 var == &ps->vars[V_CACERT_DIR] ||
749 var == &ps->vars[V_CACERT_CONTAINER]);
752 void
753 smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
755 char tmp[200];
756 int i, ind, ln = 0;
757 struct variable *vtmp;
758 CONF_S *ctmpb;
759 FEATURE_S *feature;
761 /* find longest variable name */
762 for(vtmp = ps->vars; vtmp->name; vtmp++){
763 if(!(smime_related_var(ps, vtmp)))
764 continue;
766 if((i = utf8_width(pretty_var_name(vtmp->name))) > ln)
767 ln = i;
770 for(vtmp = ps->vars; vtmp->name; vtmp++){
771 if(!(smime_related_var(ps, vtmp)))
772 continue;
774 new_confline(ctmp)->var = vtmp;
775 if(first_line && !*first_line)
776 *first_line = *ctmp;
778 (*ctmp)->valoffset = ln+3;
779 (*ctmp)->keymenu = &config_text_keymenu;
780 (*ctmp)->help = config_help(vtmp - ps->vars, 0);
781 (*ctmp)->tool = text_tool;
783 utf8_snprintf(tmp, sizeof(tmp), "%-*.100w =", ln, pretty_var_name(vtmp->name));
784 tmp[sizeof(tmp)-1] = '\0';
786 (*ctmp)->varname = cpystr(tmp);
787 (*ctmp)->varnamep = (*ctmp);
788 (*ctmp)->flags = CF_STARTITEM;
789 (*ctmp)->value = pretty_value(ps, *ctmp);
793 vtmp = &ps->vars[V_FEATURE_LIST];
795 new_confline(ctmp);
796 ctmpb = (*ctmp);
797 (*ctmp)->flags |= CF_NOSELECT | CF_STARTITEM;
798 (*ctmp)->keymenu = &config_checkbox_keymenu;
799 (*ctmp)->tool = NULL;
801 /* put a nice delimiter before list */
802 new_confline(ctmp)->var = NULL;
803 (*ctmp)->varnamep = ctmpb;
804 (*ctmp)->keymenu = &config_checkbox_keymenu;
805 (*ctmp)->help = NO_HELP;
806 (*ctmp)->tool = checkbox_tool;
807 (*ctmp)->valoffset = feature_indent();
808 (*ctmp)->flags |= CF_NOSELECT;
809 (*ctmp)->value = cpystr("Set Feature Name");
811 new_confline(ctmp)->var = NULL;
812 (*ctmp)->varnamep = ctmpb;
813 (*ctmp)->keymenu = &config_checkbox_keymenu;
814 (*ctmp)->help = NO_HELP;
815 (*ctmp)->tool = checkbox_tool;
816 (*ctmp)->valoffset = feature_indent();
817 (*ctmp)->flags |= CF_NOSELECT;
818 (*ctmp)->value = cpystr("--- ----------------------");
820 ind = feature_list_index(F_DONT_DO_SMIME);
821 feature = feature_list(ind);
822 new_confline(ctmp)->var = vtmp;
823 (*ctmp)->varnamep = ctmpb;
824 (*ctmp)->keymenu = &config_checkbox_keymenu;
825 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
826 (*ctmp)->tool = checkbox_tool;
827 (*ctmp)->valoffset = feature_indent();
828 (*ctmp)->varmem = ind;
829 (*ctmp)->value = pretty_value(ps, (*ctmp));
831 ind = feature_list_index(F_ENCRYPT_DEFAULT_ON);
832 feature = feature_list(ind);
833 new_confline(ctmp)->var = vtmp;
834 (*ctmp)->varnamep = ctmpb;
835 (*ctmp)->keymenu = &config_checkbox_keymenu;
836 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
837 (*ctmp)->tool = checkbox_tool;
838 (*ctmp)->valoffset = feature_indent();
839 (*ctmp)->varmem = ind;
840 (*ctmp)->value = pretty_value(ps, (*ctmp));
842 ind = feature_list_index(F_REMEMBER_SMIME_PASSPHRASE);
843 feature = feature_list(ind);
844 new_confline(ctmp)->var = vtmp;
845 (*ctmp)->varnamep = ctmpb;
846 (*ctmp)->keymenu = &config_checkbox_keymenu;
847 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
848 (*ctmp)->tool = checkbox_tool;
849 (*ctmp)->valoffset = feature_indent();
850 (*ctmp)->varmem = ind;
851 (*ctmp)->value = pretty_value(ps, (*ctmp));
853 ind = feature_list_index(F_SIGN_DEFAULT_ON);
854 feature = feature_list(ind);
855 new_confline(ctmp)->var = vtmp;
856 (*ctmp)->varnamep = ctmpb;
857 (*ctmp)->keymenu = &config_checkbox_keymenu;
858 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
859 (*ctmp)->tool = checkbox_tool;
860 (*ctmp)->valoffset = feature_indent();
861 (*ctmp)->varmem = ind;
862 (*ctmp)->value = pretty_value(ps, (*ctmp));
864 ind = feature_list_index(F_USE_CERT_STORE_ONLY);
865 feature = feature_list(ind);
866 new_confline(ctmp)->var = vtmp;
867 (*ctmp)->varnamep = ctmpb;
868 (*ctmp)->keymenu = &config_checkbox_keymenu;
869 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
870 (*ctmp)->tool = checkbox_tool;
871 (*ctmp)->valoffset = feature_indent();
872 (*ctmp)->varmem = ind;
873 (*ctmp)->value = pretty_value(ps, (*ctmp));
875 #ifdef APPLEKEYCHAIN
876 new_confline(ctmp);
877 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
879 new_confline(ctmp);
880 (*ctmp)->flags |= CF_NOSELECT;
881 (*ctmp)->value = cpystr(_("Mac OS X specific features"));
883 ind = feature_list_index(F_PUBLICCERTS_IN_KEYCHAIN);
884 feature = feature_list(ind);
885 new_confline(ctmp)->var = vtmp;
886 (*ctmp)->varnamep = ctmpb;
887 (*ctmp)->keymenu = &config_checkbox_keymenu;
888 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
889 (*ctmp)->tool = checkbox_tool;
890 (*ctmp)->valoffset = feature_indent();
891 (*ctmp)->varmem = ind;
892 (*ctmp)->value = pretty_value(ps, (*ctmp));
893 #endif /* APPLEKEYCHAIN */
895 new_confline(ctmp);
896 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
898 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
899 tmp[i] = '-';
900 tmp[i] = '\0';
901 new_confline(ctmp);
902 (*ctmp)->flags |= CF_NOSELECT;
903 (*ctmp)->value = cpystr(tmp);
905 new_confline(ctmp);
906 (*ctmp)->flags |= CF_NOSELECT;
907 (*ctmp)->value = cpystr(_("Be careful with the following commands, they REPLACE contents in the target"));
909 new_confline(ctmp);
910 (*ctmp)->flags |= CF_NOSELECT;
911 (*ctmp)->value = cpystr(tmp);
913 new_confline(ctmp);
914 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
916 /* copy public directory to container */
917 new_confline(ctmp);
918 (*ctmp)->tool = smime_helper_tool;
919 (*ctmp)->keymenu = &config_smime_helper_keymenu;
920 (*ctmp)->help = h_config_smime_transfer_pub_to_con;
921 (*ctmp)->value = cpystr(_("Transfer public certs FROM directory TO container"));
922 (*ctmp)->varmem = 1;
924 /* copy private directory to container */
925 new_confline(ctmp);
926 (*ctmp)->tool = smime_helper_tool;
927 (*ctmp)->keymenu = &config_smime_helper_keymenu;
928 (*ctmp)->help = h_config_smime_transfer_priv_to_con;
929 (*ctmp)->value = cpystr(_("Transfer private keys FROM directory TO container"));
930 (*ctmp)->varmem = 3;
932 /* copy cacert directory to container */
933 new_confline(ctmp);
934 (*ctmp)->tool = smime_helper_tool;
935 (*ctmp)->keymenu = &config_smime_helper_keymenu;
936 (*ctmp)->help = h_config_smime_transfer_cacert_to_con;
937 (*ctmp)->value = cpystr(_("Transfer CA certs FROM directory TO container"));
938 (*ctmp)->varmem = 5;
940 new_confline(ctmp)->var = vtmp;
941 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
943 /* copy public container to directory */
944 new_confline(ctmp);
945 (*ctmp)->tool = smime_helper_tool;
946 (*ctmp)->keymenu = &config_smime_helper_keymenu;
947 (*ctmp)->help = h_config_smime_transfer_pub_to_dir;
948 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO directory"));
949 (*ctmp)->varmem = 2;
951 /* copy private container to directory */
952 new_confline(ctmp);
953 (*ctmp)->tool = smime_helper_tool;
954 (*ctmp)->keymenu = &config_smime_helper_keymenu;
955 (*ctmp)->help = h_config_smime_transfer_priv_to_dir;
956 (*ctmp)->value = cpystr(_("Transfer private keys FROM container TO directory"));
957 (*ctmp)->varmem = 4;
959 /* copy cacert container to directory */
960 new_confline(ctmp);
961 (*ctmp)->tool = smime_helper_tool;
962 (*ctmp)->keymenu = &config_smime_helper_keymenu;
963 (*ctmp)->help = h_config_smime_transfer_cacert_to_dir;
964 (*ctmp)->value = cpystr(_("Transfer CA certs FROM container TO directory"));
965 (*ctmp)->varmem = 6;
967 #ifdef APPLEKEYCHAIN
969 new_confline(ctmp)->var = vtmp;
970 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
972 /* copy public container to keychain */
973 new_confline(ctmp);
974 (*ctmp)->tool = smime_helper_tool;
975 (*ctmp)->keymenu = &config_smime_helper_keymenu;
976 (*ctmp)->help = h_config_smime_transfer_pubcon_to_key;
977 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO keychain"));
978 (*ctmp)->varmem = 7;
980 /* copy public keychain to container */
981 new_confline(ctmp);
982 (*ctmp)->tool = smime_helper_tool;
983 (*ctmp)->keymenu = &config_smime_helper_keymenu;
984 (*ctmp)->help = h_config_smime_transfer_pubkey_to_con;
985 (*ctmp)->value = cpystr(_("Transfer public certs FROM keychain TO container"));
986 (*ctmp)->varmem = 8;
988 #endif /* APPLEKEYCHAIN */
990 if(ps_global->smime
991 && SMHOLDERTYPE(Private) == Keychain
992 && SMHOLDERTYPE(Public) == Keychain
993 && SMHOLDERTYPE(CACert) == Keychain)
994 return;
996 new_confline(ctmp)->var = vtmp;
997 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
999 new_confline(ctmp);
1000 (*ctmp)->flags |= CF_NOSELECT;
1001 (*ctmp)->value = cpystr(tmp);
1003 new_confline(ctmp);
1004 (*ctmp)->flags |= CF_NOSELECT;
1005 (*ctmp)->value = cpystr(_("Manage your own certificates"));
1007 new_confline(ctmp);
1008 (*ctmp)->flags |= CF_NOSELECT;
1009 (*ctmp)->value = cpystr(tmp);
1011 new_confline(ctmp)->var = vtmp;
1012 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1014 /* manage public certificates */
1015 new_confline(ctmp);
1016 (*ctmp)->tool = smime_helper_tool;
1017 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1018 (*ctmp)->help = h_config_smime_public_certificates;
1019 (*ctmp)->value = cpystr(_("Manage Public Certificates"));
1020 (*ctmp)->varmem = 9;
1021 (*ctmp)->d.s.ctype = Public;
1023 /* manage private keys */
1024 new_confline(ctmp);
1025 (*ctmp)->tool = smime_helper_tool;
1026 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1027 (*ctmp)->help = h_config_smime_private_keys;
1028 (*ctmp)->value = cpystr(_("Manage Private Keys"));
1029 (*ctmp)->varmem = 10;
1030 (*ctmp)->d.s.ctype = Private;
1032 /* manage Certificate Authorities */
1033 new_confline(ctmp);
1034 (*ctmp)->tool = smime_helper_tool;
1035 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1036 (*ctmp)->help = h_config_smime_certificate_authorities;
1037 (*ctmp)->value = cpystr(_("Manage Certificate Authorities"));
1038 (*ctmp)->varmem = 11;
1039 (*ctmp)->d.s.ctype = CACert;
1041 #ifdef PASSFILE
1042 new_confline(ctmp)->var = vtmp;
1043 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1045 new_confline(ctmp);
1046 (*ctmp)->flags |= CF_NOSELECT;
1047 (*ctmp)->value = cpystr(tmp);
1049 new_confline(ctmp);
1050 (*ctmp)->flags |= CF_NOSELECT;
1051 (*ctmp)->value = cpystr(_("Manage Key and Certificate for Password File"));
1053 new_confline(ctmp);
1054 (*ctmp)->flags |= CF_NOSELECT;
1055 (*ctmp)->value = cpystr(tmp);
1057 new_confline(ctmp)->var = vtmp;
1058 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1060 /* manage password file certificates */
1061 new_confline(ctmp);
1062 (*ctmp)->tool = smime_helper_tool;
1063 (*ctmp)->keymenu = &config_smime_manage_password_file_menu_keymenu;
1064 (*ctmp)->help = h_config_smime_password_file_certificates;
1065 (*ctmp)->value = cpystr(_("Manage Password File Key and Certificate"));
1066 (*ctmp)->varmem = 12;
1067 (*ctmp)->d.s.ctype = Password;
1068 #endif /* PASSFILE */
1070 (*ctmp)->next = NULL;
1073 void
1074 display_certificate_information(struct pine *ps, X509 *cert, char *email, WhichCerts ctype, int num)
1076 STORE_S *store;
1077 SCROLL_S scrollargs;
1078 int cmd, offset;
1079 int pub_cert, priv_cert, new_store;
1080 long error;
1081 BIO *out = NULL;
1083 cmd = offset = pub_cert = priv_cert = 0;
1084 new_store = 1;
1085 ps->next_screen = SCREEN_FUN_NULL;
1086 do {
1087 /* MC_PRIVATE and MC_PUBLIC cancel each other,
1088 * they can not be active at the same time
1090 switch(cmd){
1091 case MC_PRIVATE:
1092 pub_cert = 0;
1093 priv_cert = 1 - priv_cert;
1094 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
1095 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
1096 break;
1098 case MC_PUBLIC:
1099 priv_cert = 0;
1100 pub_cert = 1 - pub_cert;
1101 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
1102 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
1103 break;
1105 case MC_TRUST:
1106 if(SMHOLDERTYPE(CACert) == Directory)
1107 save_cert_for(email, cert, CACert);
1108 else{ /* if(SMHOLDERTYPE(CACert) == Container) */
1109 char path[MAXPATH];
1110 char *upath = PATHCERTDIR(ctype);
1111 char *tempfile = tempfile_in_same_dir(path, "az", NULL);
1112 CertList *clist;
1114 if(IS_REMOTE(upath))
1115 strncpy(path, temp_nam(NULL, "a6"), sizeof(path)-1);
1116 else
1117 strncpy(path, upath, sizeof(path)-1);
1118 path[sizeof(path)-1] = '\0';
1120 add_to_end_of_certlist(&ps_global->smime->cacertlist, email, X509_dup(cert));
1121 for(clist=ps_global->smime->cacertlist; clist && clist->next; clist = clist->next);
1122 certlist_to_file(tempfile, clist);
1123 add_file_to_container(CACert, tempfile, email);
1124 unlink(tempfile);
1126 renew_store();
1127 new_store = 1;
1128 break;
1130 case MC_DELETE:
1131 if (get_cert_deleted(ctype, num) != 0)
1132 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
1133 else{
1134 mark_cert_deleted(ctype, num, 1);
1135 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
1137 break;
1139 case MC_UNDELETE:
1140 if (get_cert_deleted(ctype, num) != 0){
1141 mark_cert_deleted(ctype, num, 0);
1142 q_status_message(SM_ORDER, 1, 3, _("Certificate marked UNdeleted"));
1144 else
1145 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
1146 break;
1148 default: break;
1151 if((pub_cert || priv_cert)
1152 && (out = print_private_key_information(email, priv_cert)) == NULL)
1153 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Private Certificate Information"));
1155 if(new_store){
1156 store = so_get(CharStar, NULL, EDIT_ACCESS);
1157 view_writec_init(store, NULL, HEADER_ROWS(ps),
1158 HEADER_ROWS(ps) + ps->ttyo->screen_rows - (HEADER_ROWS(ps)+ FOOTER_ROWS(ps)));
1160 snprintf(tmp_20k_buf, SIZEOF_20KBUF,"%s", _("Certificate Information"));
1161 gf_puts_uline(tmp_20k_buf, view_writec);
1162 gf_puts(NEWLINE, view_writec);
1163 print_separator_line(100, '-', view_writec);
1165 output_cert_info(cert, view_writec);
1166 gf_puts(NEWLINE, view_writec);
1168 if(smime_validate_cert(cert, &error) < 0){
1169 const char *errorp = X509_verify_cert_error_string(error);
1170 snprintf(tmp_20k_buf, SIZEOF_20KBUF,_("Error validating certificate: %s"), errorp);
1171 } else
1172 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s", _("Certificate validated without errors"));
1174 gf_puts_uline(tmp_20k_buf, view_writec);
1175 gf_puts(NEWLINE, view_writec);
1177 if(out != NULL){ /* print private key information */
1178 unsigned char ch[2];
1180 gf_puts(NEWLINE, view_writec);
1181 ch[1] = '\0';
1182 while(BIO_read(out, ch, 1) >= 1)
1183 gf_puts((char *)ch, view_writec);
1184 gf_puts(NEWLINE, view_writec);
1185 q_status_message1(SM_ORDER, 1, 3, _("%s information shown at bottom of certificate information"), pub_cert ? _("Public") : _("Private"));
1186 BIO_free_all(out);
1187 out = NULL;
1189 view_writec_destroy();
1190 new_store = 0;
1193 memset(&scrollargs, 0, sizeof(SCROLL_S));
1195 scrollargs.text.text = so_text(store);
1196 scrollargs.text.src = CharStar;
1197 scrollargs.text.desc = "certificate information";
1198 scrollargs.body_valid = 1;
1200 if(offset){ /* resize? preserve paging! */
1201 scrollargs.start.on = Offset;
1202 scrollargs.start.loc.offset = offset;
1203 scrollargs.body_valid = 0;
1204 offset = 0L;
1207 scrollargs.use_indexline_color = 1;
1209 scrollargs.bar.title = _("CERTIFICATE INFORMATION");
1210 scrollargs.proc.tool = manage_certificate_info_tool;
1211 scrollargs.resize_exit = 1;
1212 scrollargs.help.text = h_certificate_information;
1213 scrollargs.help.title = _("HELP FOR MESSAGE TEXT VIEW");
1214 scrollargs.keys.what = FirstMenu;
1215 scrollargs.keys.menu = &smime_certificate_info_keymenu;
1216 setbitmap(scrollargs.keys.bitmap);
1217 if(ctype != Public || error != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
1218 /*error != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)*/
1219 clrbitn(TRUST_KEY, scrollargs.keys.bitmap);
1220 if(ctype != Private){
1221 clrbitn(PUBLIC_KEY, scrollargs.keys.bitmap);
1222 clrbitn(PRIVATE_KEY, scrollargs.keys.bitmap);
1224 if(ctype == Password){
1225 clrbitn(DELETE_CERT_KEY, scrollargs.keys.bitmap);
1226 clrbitn(UNDELETE_CERT_KEY, scrollargs.keys.bitmap);
1229 cmd = scrolltool(&scrollargs);
1231 switch(cmd){
1232 case MC_RESIZE :
1233 case MC_PRIVATE:
1234 case MC_PUBLIC : if(scrollargs.start.on == Offset)
1235 offset = scrollargs.start.loc.offset;
1236 new_store = 1;
1237 default: break;
1239 if(new_store)
1240 so_give(&store);
1241 } while (cmd != MC_EXIT);
1242 ps->mangled_screen = 1;
1246 * This is silly, we just need this function so that we can tell scrolltool
1247 * that some commands are recognized. We use scrolltool because we do not
1248 * want to rewrite output_cert_info.
1251 manage_certificate_info_tool(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
1253 int rv;
1254 switch(cmd){
1255 case MC_DELETE:
1256 case MC_UNDELETE:
1257 case MC_PRIVATE:
1258 case MC_PUBLIC:
1259 case MC_TRUST: rv = 1; break;
1260 default: rv = 0; break;
1262 return rv;
1267 manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1269 int rv = 0;
1270 X509 *cert = NULL;
1271 WhichCerts ctype = (*cl)->d.s.ctype;
1273 switch(cmd){
1274 case MC_ADD: /* create a self signed certificate and import it */
1275 if(ctype == Password){
1276 PERSONAL_CERT *pc;
1277 char pathdir[MAXPATH+1], filename[MAXPATH+1];
1278 struct stat sbuf;
1279 int st;
1280 smime_path(DF_SMIMETMPDIR, pathdir, sizeof(pathdir));
1281 if(((st = our_stat(pathdir, &sbuf)) == 0
1282 && (sbuf.st_mode & S_IFMT) == S_IFDIR)
1283 || (st != 0
1284 && can_access(pathdir, ACCESS_EXISTS) != 0
1285 && our_mkpath(pathdir, 0700) == 0)){
1286 pc = ALPINE_self_signed_certificate(NULL, 0, pathdir, MASTERNAME);
1287 if(strlen(pathdir) + strlen(MASTERNAME) + 5 + 1 > sizeof(filename)){
1288 q_status_message(SM_ORDER, 0, 2,
1289 _("pathdir for key too long"));
1291 else{
1292 snprintf(filename, sizeof(filename), "%.*s/%.*s.key",
1293 (int) strlen(pathdir), pathdir,
1294 (int) (sizeof(filename) - strlen(MASTERNAME) - 5 - 1), MASTERNAME);
1295 filename[sizeof(filename)-1] = '\0';
1296 rv = import_certificate(ctype, pc, filename);
1297 if(rv == 1){
1298 ps->keyemptypwd = 0;
1299 if(our_stat(pathdir, &sbuf) == 0){
1300 if(unlink(filename) < 0)
1301 q_status_message1(SM_ORDER, 0, 2,
1302 _("Could not remove private key %s.key"), MASTERNAME);
1303 filename[strlen(filename)-4] = '\0';
1304 strcat(filename, ".crt");
1305 if(unlink(filename) < 0)
1306 q_status_message1(SM_ORDER, 0, 2,
1307 _("Could not remove public certificate %s.crt"), MASTERNAME);
1308 if(rmdir(pathdir) < 0)
1309 q_status_message1(SM_ORDER, 0, 2,
1310 _("Could not remove temporary directory %s"), pathdir);
1315 rv = 10; /* forces redraw */
1317 break;
1319 case MC_CHOICE:
1320 if(PATHCERTDIR(ctype) == NULL)
1321 return 0;
1323 if((cert = get_cert_for((*cl)->d.s.address, ctype, 0)) == NULL){
1324 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Certificate"));
1325 rv = 0;
1327 else{
1328 display_certificate_information(ps, cert, (*cl)->d.s.address, ctype, (*cl)->varmem);
1329 rv = 10 + (*cl)->varmem;
1331 break;
1333 case MC_DELETE:
1334 if(ctype == Password){
1335 EVP_PKEY *key = NULL;
1336 PERSONAL_CERT *pc = (PERSONAL_CERT *) ps->pwdcert;
1337 RSA *rsa = NULL;
1338 const EVP_CIPHER *enc = NULL;
1339 BIO *out = NULL;
1340 BIO *in = NULL;
1341 char filename[MAXPATH+1];
1342 char passwd[MAILTMPLEN];
1343 char prompt[MAILTMPLEN];
1345 if (pc != NULL && pc->key != NULL){
1346 strncpy(prompt, _("Enter password to unlock key: "), sizeof(prompt));
1347 prompt[sizeof(prompt)-1] = '\0';
1348 passwd[0] = '\0';
1350 rv = alpine_get_password(prompt, passwd, sizeof(passwd));
1352 if(rv == 1)
1353 q_status_message(SM_ORDER, 1, 3, _("Password deletion cancelled"));
1354 else if(rv == 0){
1355 snprintf(filename, sizeof(filename), "%s/%s.key", ps->pwdcertdir, pc->name);
1356 filename[sizeof(filename)-1] = '\0';
1357 if((in = BIO_new_file(filename, "r")) != NULL){
1358 key = PEM_read_bio_PrivateKey(in, NULL, NULL, passwd);
1359 if(key != NULL){
1360 if((rsa = EVP_PKEY_get1_RSA(key)) != NULL
1361 && (out = BIO_new(BIO_s_file())) != NULL
1362 && BIO_write_filename(out, filename) > 0
1363 && PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, NULL, passwd) > 0){
1364 q_status_message(SM_ORDER, 1, 3, _("Password Removed from private key"));
1365 ps->keyemptypwd = 1;
1367 else
1368 rv = 1;
1370 else{
1371 rv = 1;
1372 q_status_message(SM_ORDER, 1, 3, _("Failed to unlock private key"));
1374 BIO_free(in);
1376 else
1377 rv = 1;
1379 if(rv == 1)
1380 q_status_message(SM_ORDER, 1, 3, _("Failed to remove password from private key"));
1381 rv += 10; /* forces redraw */
1382 if(out != NULL)
1383 BIO_free_all(out);
1384 if(rsa != NULL)
1385 RSA_free(rsa);
1386 if(key != NULL)
1387 EVP_PKEY_free(key);
1390 else {
1391 if ((*cl)->d.s.deleted != 0)
1392 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
1393 else{
1394 (*cl)->d.s.deleted = 1;
1395 rv = 10 + (*cl)->varmem; /* forces redraw */
1396 mark_cert_deleted(ctype, (*cl)->varmem, 1);
1397 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
1400 break;
1402 case MC_UNDELETE:
1403 if ((*cl)->d.s.deleted == 0)
1404 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
1405 else{
1406 (*cl)->d.s.deleted = 0;
1407 mark_cert_deleted(ctype, (*cl)->varmem, 0);
1408 rv = 10 + (*cl)->varmem; /* forces redraw */
1409 q_status_message(SM_ORDER, 1, 3, _("Certificate marked UNdeleted"));
1411 break;
1413 case MC_EXPUNGE:
1414 { CertList *cl;
1416 for(cl = DATACERT(ctype); cl != NULL && DELETEDCERT(cl) == 0; cl = cl->next);
1417 if(cl != NULL && DELETEDCERT(cl) != 0){
1418 smime_expunge_cert(ctype);
1419 rv = 10; /* forces redraw */
1421 else{
1422 q_status_message(SM_ORDER, 3, 3, _("No certificates marked deleted"));
1423 rv = 0;
1425 break;
1427 case MC_IMPORT:
1428 rv = import_certificate(ctype, NULL, NULL);
1429 if(rv < 0){
1430 switch(rv){
1431 default:
1432 case -1:
1433 cmd_cancelled("Import certificate");
1434 break;
1436 case -2:
1437 q_status_message1(SM_ORDER, 0, 2, _("Can't import certificate outside of %s"),
1438 ps_global->VAR_OPER_DIR);
1439 break;
1442 rv = 10; /* forces redraw */
1443 break;
1445 case MC_EXIT:
1446 rv = config_exit_cmd(flags);
1447 break;
1449 default:
1450 rv = -1;
1451 break;
1454 X509_free(cert);
1455 return rv;
1458 void
1459 smime_setup_size(char **s, size_t buflen, size_t n)
1461 char *t = *s;
1462 *t++ = ' ';
1463 *t++ = '%';
1464 *t++ = '-';
1465 snprintf(t, buflen-3, "%zu.%zu", n, n);
1466 t += strlen(t);
1467 *t++ = 's';
1468 *t = '\0';
1469 *s = t;
1472 #ifdef PASSFILE
1473 void
1474 manage_password_file_certificates(struct pine *ps)
1476 OPT_SCREEN_S screen;
1477 int readonly_warning = 0, rv = 10, fline, state = 0;
1479 dprint((9, "manage_password_file_certificates"));
1480 ps->next_screen = SCREEN_FUN_NULL;
1481 ps->keyemptypwd = 0; /* just in case */
1483 do {
1484 CONF_S *ctmp = NULL, *first_line = NULL;
1486 fline = rv >= 10 ? rv - 10 : 0;
1488 smime_manage_password_file_certs_init(ps, &ctmp, &first_line, fline, &state);
1490 if(ctmp == NULL){
1491 ps->mangled_screen = 1;
1492 q_status_message(SM_ORDER, 1, 3, _("Failed to initialize password management screen (no key)"));
1493 return;
1496 memset(&screen, 0, sizeof(screen));
1497 screen.deferred_ro_warning = readonly_warning;
1499 rv = conf_scroll_screen(ps, &screen, first_line,
1500 _("MANAGE PASSWORD FILE CERTS"),
1501 /* TRANSLATORS: Print something1 using something2.
1502 configuration is something1 */
1503 _("configuration"), 0, NULL);
1504 } while (rv != 0);
1506 ps->mangled_screen = 1;
1507 ps->keyemptypwd = 0; /* reset this so it will not confuse other routines */
1508 smime_reinit();
1511 /* state: 0 = first time,
1512 * 1 = second or another time
1514 void
1515 smime_manage_password_file_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, int fline, int *state)
1517 char tmp[200];
1518 CertList *cl;
1519 int i;
1520 void *pwdcert = NULL; /* this is our current password file */
1521 char filename[MAXPATH+1];
1522 BIO *in = NULL;
1523 EVP_PKEY *key = NULL;
1524 PERSONAL_CERT *pc;
1526 if(*state == 0){ /* first time around? */
1527 setup_pwdcert(&pwdcert);
1528 if(pwdcert == NULL) return;
1529 if(ps->pwdcert == NULL)
1530 ps->pwdcert = pwdcert;
1531 else
1532 free_personal_certs((PERSONAL_CERT **) &pwdcert);
1533 (*state)++;
1536 pc = (PERSONAL_CERT *) ps_global->pwdcert;
1537 snprintf(filename, sizeof(filename), "%s/%s.key", ps->pwdcertdir, pc->name);
1538 filename[sizeof(filename)-1] = '\0';
1539 if((in = BIO_new_file(filename, "r")) != NULL
1540 && (key = PEM_read_bio_PrivateKey(in, NULL, NULL, "")) != NULL)
1541 ps->keyemptypwd = 1;
1542 if(in != NULL)
1543 BIO_free(in);
1544 if(key != NULL)
1545 EVP_PKEY_free(key);
1547 ps->pwdcertlist = cl = smime_X509_to_cert_info(X509_dup(pc->cert), pc->name);
1549 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1550 tmp[i] = '-';
1551 tmp[i] = '\0';
1553 new_confline(ctmp);
1554 (*ctmp)->flags |= CF_NOSELECT;
1555 (*ctmp)->value = cpystr(tmp);
1557 new_confline(ctmp);
1558 (*ctmp)->flags |= CF_NOSELECT;
1559 (*ctmp)->value = cpystr(_("Manage Certificates and Keys Used to Encrypt your Password File"));
1561 new_confline(ctmp);
1562 (*ctmp)->flags |= CF_NOSELECT;
1563 (*ctmp)->value = cpystr(tmp);
1565 new_confline(ctmp);
1566 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1568 if(cl){
1569 int s, e, df, dt, md5; /* sizes of certain fields */
1570 int nf; /* number of fields */
1571 char u[MAILTMPLEN], *t;
1573 e = MIN(strlen(cl->name), ps->ttyo->screen_cols/3); /* do not use too much screen */
1574 nf = 5; /* there are 5 fields */
1575 s = 3; /* status has fixed size */
1576 df = dt = 10; /* date from and date to have fixed size */
1577 md5 = ps->ttyo->screen_cols - s - df - dt - e - (nf - 1);
1579 t = u;
1580 smime_setup_size(&t, sizeof(u), s);
1581 smime_setup_size(&t, sizeof(u) - strlen(t), e);
1582 smime_setup_size(&t, sizeof(u) - strlen(t), df);
1583 *t++ = ' '; /* leave an extra space between dates */
1584 *t = '\0'; /* make valgrind happy */
1585 smime_setup_size(&t, sizeof(u) - strlen(t), dt);
1586 *t++ = ' '; /* and another space between date and md5 sum */
1587 *t = '\0'; /* make valgrind happy again */
1588 smime_setup_size(&t, sizeof(u) - strlen(t), md5);
1589 *t = '\0'; /* tie off */
1591 new_confline(ctmp);
1592 (*ctmp)->flags |= CF_NOSELECT;
1593 (*ctmp)->value = cpystr(_("New Public Certificate and Key:"));
1595 new_confline(ctmp);
1596 (*ctmp)->d.s.ctype = Password;
1597 (*ctmp)->help = h_config_smime_password_file_certificates;
1598 (*ctmp)->tool = manage_certs_tool;
1599 (*ctmp)->keymenu = &config_smime_add_new_key_keymenu;
1600 s += 2;
1601 for(i = 0; i < s; i++) tmp[i] = ' ';
1602 tmp[i] = '\0';
1603 strncpy(tmp+s, _("Press \"RETURN\" to add new personal key"), sizeof(tmp)-s-1);
1604 for(i = strlen(tmp); i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp) - 1); i++)
1605 tmp[i] = ' ';
1606 tmp[i] = '\0';
1607 (*ctmp)->value = cpystr(tmp);
1608 *first_line = *ctmp;
1610 new_confline(ctmp);
1611 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1613 new_confline(ctmp);
1614 (*ctmp)->flags |= CF_NOSELECT;
1615 (*ctmp)->value = cpystr(_("Current Public Certificate and Key:"));
1617 new_confline(ctmp);
1618 (*ctmp)->d.s.ctype = Password;
1619 (*ctmp)->d.s.deleted = 0;
1620 (*ctmp)->help = h_config_smime_password_file_certificates;
1621 (*ctmp)->tool = manage_certs_tool;
1622 (*ctmp)->keymenu = ps->keyemptypwd == 0
1623 ? &config_smime_manage_view_cert_keymenu
1624 : &config_smime_manage_view_cert_keymenu_no_delete;
1625 (*ctmp)->varmem = 0;
1626 strncpy((*ctmp)->d.s.address, cl->name, sizeof((*ctmp)->d.s.address));
1627 (*ctmp)->d.s.address[sizeof((*ctmp)->d.s.address) - 1] = '\0';
1628 snprintf(tmp, sizeof(tmp), u,
1629 (*ctmp)->d.s.deleted ? "D" : " ",
1630 cl->name,
1631 DATEFROMCERT(cl), DATETOCERT(cl), MD5CERT(cl));
1632 (*ctmp)->value = cpystr(tmp);
1635 #endif /* PASSFILE */
1638 void
1639 smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, WhichCerts ctype, int fline)
1641 char tmp[200];
1642 CertList *data;
1643 int i;
1645 smime_init();
1647 data = DATACERT(ctype);
1648 // ext = EXTCERT(ctype);
1650 if(data == NULL || RENEWCERT(data))
1651 renew_cert_data(&data, ctype);
1653 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1654 tmp[i] = '-';
1655 tmp[i] = '\0';
1657 new_confline(ctmp);
1658 (*ctmp)->flags |= CF_NOSELECT;
1659 (*ctmp)->value = cpystr(tmp);
1661 (*ctmp)->keymenu = &config_text_keymenu;
1663 new_confline(ctmp);
1664 (*ctmp)->flags |= CF_NOSELECT;
1665 sprintf(tmp, _("List of %s certificates"), ctype == Public ? _("public")
1666 : (ctype == Private ? _("private")
1667 : (ctype == CACert ? _("certificate authority") : "unknown (?)")));
1668 (*ctmp)->value = cpystr(tmp);
1670 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1671 tmp[i] = '-';
1672 tmp[i] = '\0';
1674 new_confline(ctmp);
1675 (*ctmp)->flags |= CF_NOSELECT;
1676 (*ctmp)->value = cpystr(tmp);
1678 new_confline(ctmp);
1679 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1681 if(data){
1682 CertList *cl; int i;
1683 int s, e, df, dt, md5; /* sizes of certain fields */
1684 int nf; /* number of fields */
1685 char u[MAILTMPLEN], *t;
1687 for(cl = data, e = 0; cl; cl = cl->next)
1688 if(cl->name && strlen(cl->name) > e)
1689 e = strlen(cl->name);
1691 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1692 e -= 4; /* remove extension length */
1693 e = MIN(e, ps->ttyo->screen_cols/3); /* do not use too much screen */
1694 nf = 5; /* there are 5 fields */
1695 s = 3; /* status has fixed size */
1696 df = dt = 10; /* date from and date to have fixed size */
1697 md5 = ps->ttyo->screen_cols - s - df - dt - e - (nf - 1);
1699 t = u;
1700 smime_setup_size(&t, sizeof(u), s);
1701 smime_setup_size(&t, sizeof(u) - strlen(t), e);
1702 smime_setup_size(&t, sizeof(u) - strlen(t), df);
1703 *t++ = ' '; /* leave an extra space between dates */
1704 *t = '\0'; /* make valgrind happy */
1705 smime_setup_size(&t, sizeof(u) - strlen(t), dt);
1706 *t++ = ' '; /* and another space between date and md5 sum */
1707 *t = '\0'; /* make valgrind happy again */
1708 smime_setup_size(&t, sizeof(u) - strlen(t), md5);
1709 *t = '\0'; /* tie off */
1711 for(cl = data, i = 0; cl; cl = cl->next)
1712 if(cl->name){
1713 new_confline(ctmp);
1714 (*ctmp)->d.s.ctype = ctype;
1715 (*ctmp)->d.s.deleted = get_cert_deleted(ctype, i);
1716 (*ctmp)->tool = manage_certs_tool;
1717 (*ctmp)->keymenu = &config_smime_manage_certs_work_keymenu;
1718 (*ctmp)->varmem = i++;
1719 (*ctmp)->help = ctype == Public ? h_config_smime_manage_public_menu
1720 : (ctype == Private ? h_config_smime_manage_private_menu
1721 : h_config_smime_manage_cacerts_menu);
1722 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1723 cl->name[strlen(cl->name) - 4] = '\0'; /* FIX FIX FIX */
1724 strncpy((*ctmp)->d.s.address, cl->name, sizeof((*ctmp)->d.s.address));
1725 (*ctmp)->d.s.address[sizeof((*ctmp)->d.s.address) - 1] = '\0';
1726 snprintf(tmp, sizeof(tmp), u,
1727 (*ctmp)->d.s.deleted ? "D" : " ",
1728 ctype == CACert ? cl->cn : cl->name,
1729 DATEFROMCERT(cl), DATETOCERT(cl), MD5CERT(cl));
1730 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1731 cl->name[strlen(cl->name)] = '.';
1732 (*ctmp)->value = cpystr(tmp);
1733 if(i == fline+1 && first_line && !*first_line)
1734 *first_line = *ctmp;
1737 else {
1738 new_confline(ctmp);
1739 (*ctmp)->d.s.ctype = ctype;
1740 (*ctmp)->tool = manage_certs_tool;
1741 (*ctmp)->keymenu = &config_smime_add_certs_keymenu;
1742 (*ctmp)->value = cpystr(_(" \tNo certificates found, press \"RETURN\" to add one."));
1743 if(first_line && !*first_line)
1744 *first_line = *ctmp;
1748 void
1749 manage_certificates(struct pine *ps, WhichCerts ctype)
1751 OPT_SCREEN_S screen;
1752 int readonly_warning = 0, rv = 10, fline;
1754 dprint((9, "manage_certificates(ps, %s)", ctype == Public ? _("Public") : (ctype == Private ? _("Private") : (ctype == CACert ? _("certificate authority") : _("unknown")))));
1755 ps->next_screen = SCREEN_FUN_NULL;
1757 do {
1758 CONF_S *ctmp = NULL, *first_line = NULL;
1760 fline = rv >= 10 ? rv - 10 : 0;
1762 smime_init();
1764 smime_manage_certs_init(ps, &ctmp, &first_line, ctype, fline);
1766 if(ctmp == NULL){
1767 ps->mangled_screen = 1;
1768 smime_reinit();
1769 return;
1772 memset(&screen, 0, sizeof(screen));
1773 screen.deferred_ro_warning = readonly_warning;
1774 rv = conf_scroll_screen(ps, &screen, first_line,
1775 _("MANAGE CERTIFICATES"),
1776 /* TRANSLATORS: Print something1 using something2.
1777 configuration is something1 */
1778 _("configuration"), 0, NULL);
1779 } while (rv != 0);
1781 ps->mangled_screen = 1;
1782 smime_reinit();
1786 smime_helper_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1788 int rv = 0;
1790 switch(cmd){
1791 case MC_CHOICE:
1792 switch((*cl)->varmem){
1793 case 1:
1794 rv = copy_publiccert_dir_to_container();
1795 if(rv == 0)
1796 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1797 else{
1798 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1799 rv = 0;
1802 break;
1804 case 2:
1805 rv = copy_publiccert_container_to_dir();
1806 if(rv == 0)
1807 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to directory, delete Container config to use"));
1808 else{
1809 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1810 rv = 0;
1813 break;
1815 case 3:
1816 rv = copy_privatecert_dir_to_container();
1817 if(rv == 0)
1818 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to container"));
1819 else{
1820 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1821 rv = 0;
1824 break;
1826 case 4:
1827 rv = copy_privatecert_container_to_dir();
1828 if(rv == 0)
1829 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to directory, delete Container config to use"));
1830 else{
1831 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1832 rv = 0;
1835 break;
1837 case 5:
1838 rv = copy_cacert_dir_to_container();
1839 if(rv == 0)
1840 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to container"));
1841 else{
1842 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1843 rv = 0;
1846 break;
1848 case 6:
1849 rv = copy_cacert_container_to_dir();
1850 if(rv == 0)
1851 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to directory, delete Container config to use"));
1852 else{
1853 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1854 rv = 0;
1857 break;
1859 #ifdef APPLEKEYCHAIN
1860 case 7:
1861 rv = copy_publiccert_container_to_keychain();
1862 if(rv == 0)
1863 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to keychain"));
1864 else{
1865 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1866 rv = 0;
1869 break;
1871 case 8:
1872 rv = copy_publiccert_keychain_to_container();
1873 if(rv == 0)
1874 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1875 else{
1876 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1877 rv = 0;
1880 break;
1881 #endif /* APPLEKEYCHAIN */
1883 case 9: manage_certificates(ps, Public) ; break;
1884 case 10: manage_certificates(ps, Private); break;
1885 case 11: manage_certificates(ps, CACert) ; break;
1887 #ifdef PASSFILE
1888 case 12: manage_password_file_certificates(ps); break;
1889 #endif /* PASSFILE */
1891 default:
1892 rv = -1;
1893 break;
1896 break;
1898 case MC_EXIT:
1899 rv = config_exit_cmd(flags);
1900 break;
1902 case MC_IMPORT:
1903 rv = import_certificate((*cl)->d.s.ctype, NULL, NULL);
1904 break;
1906 default:
1907 rv = -1;
1908 break;
1911 return rv;
1916 * Compare saved user_val with current user_val to see if it changed.
1917 * If any have changed, change it back and take the appropriate action.
1919 void
1920 revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave)
1922 struct variable *vreal;
1923 SAVED_CONFIG_S *v;
1924 int i, n;
1925 int changed = 0;
1926 char *pval, **apval, **lval, ***alval;
1928 v = vsave;
1929 for(vreal = ps->vars; vreal->name; vreal++,v++){
1930 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
1931 continue;
1933 if(vreal->is_list){
1934 lval = LVAL(vreal, ew);
1935 alval = ALVAL(vreal, ew);
1937 if((v->saved_user_val.l && !lval)
1938 || (!v->saved_user_val.l && lval))
1939 changed++;
1940 else if(!v->saved_user_val.l && !lval)
1941 ;/* no change, nothing to do */
1942 else
1943 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
1944 if((v->saved_user_val.l[i]
1945 && (!lval[i]
1946 || strcmp(v->saved_user_val.l[i], lval[i])))
1948 (!v->saved_user_val.l[i] && lval[i])){
1949 changed++;
1950 break;
1953 if(changed){
1954 char **list;
1956 if(alval){
1957 if(*alval)
1958 free_list_array(alval);
1960 /* copy back the original one */
1961 if(v->saved_user_val.l){
1962 list = v->saved_user_val.l;
1963 n = 0;
1964 /* count how many */
1965 while(list[n])
1966 n++;
1968 *alval = (char **)fs_get((n+1) * sizeof(char *));
1970 for(i = 0; i < n; i++)
1971 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
1973 (*alval)[n] = NULL;
1978 else{
1979 pval = PVAL(vreal, ew);
1980 apval = APVAL(vreal, ew);
1982 if((v->saved_user_val.p &&
1983 (!pval || strcmp(v->saved_user_val.p, pval))) ||
1984 (!v->saved_user_val.p && pval)){
1985 /* It changed, fix it */
1986 changed++;
1987 if(apval){
1988 /* free the changed value */
1989 if(*apval)
1990 fs_give((void **)apval);
1992 if(v->saved_user_val.p)
1993 *apval = cpystr(v->saved_user_val.p);
1998 if(changed){
1999 if(vreal == &ps->vars[V_FEATURE_LIST])
2000 set_feature_list_current_val(vreal);
2001 else
2002 set_current_val(vreal, TRUE, FALSE);
2004 fix_side_effects(ps, vreal, 1);
2010 SAVED_CONFIG_S *
2011 save_smime_config_vars(struct pine *ps)
2013 struct variable *vreal;
2014 SAVED_CONFIG_S *vsave, *v;
2016 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
2017 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
2018 for(v = vsave, vreal = ps->vars; vreal->name; vreal++,v++){
2019 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
2020 continue;
2022 if(vreal->is_list){
2023 int n, i;
2024 char **list;
2026 if(LVAL(vreal, ew)){
2027 /* count how many */
2028 n = 0;
2029 list = LVAL(vreal, ew);
2030 while(list[n])
2031 n++;
2033 v->saved_user_val.l = (char **)fs_get((n+1)*sizeof(char *));
2034 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
2035 for(i = 0; i < n; i++)
2036 v->saved_user_val.l[i] = cpystr(list[i]);
2038 v->saved_user_val.l[n] = NULL;
2041 else{
2042 if(PVAL(vreal, ew))
2043 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
2047 return(vsave);
2051 void
2052 free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep)
2054 struct variable *vreal;
2055 SAVED_CONFIG_S *v;
2057 if(vsavep && *vsavep){
2058 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
2059 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
2060 continue;
2062 if(vreal->is_list){ /* free saved_user_val.l */
2063 if(v && v->saved_user_val.l)
2064 free_list_array(&v->saved_user_val.l);
2066 else if(v && v->saved_user_val.p)
2067 fs_give((void **)&v->saved_user_val.p);
2070 fs_give((void **)vsavep);
2074 #endif /* SMIME */