* Fixes bug in 2.19.8 that would make Alpine fail to build in Windows.
[alpine.git] / alpine / smime.c
blobb8fc9791145a390a3430b44dd2f19ba38accdc65
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: smime.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2014 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
22 * File: smime.c
23 * Author: paisleyj@dcs.gla.ac.uk
24 * Date: 01/2001
28 #include "headers.h"
30 #ifdef SMIME
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 "radio.h"
39 #include "keymenu.h"
40 #include "mailview.h"
41 #include "conftype.h"
42 #include "confscroll.h"
43 #include "setup.h"
44 #include "smime.h"
46 /* internal prototypes */
47 void format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc);
48 void print_separator_line(int percent, int ch, gf_io_t pc);
49 void output_cert_info(X509 *cert, gf_io_t pc);
50 void output_X509_NAME(X509_NAME *name, gf_io_t pc);
51 void side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc);
52 STORE_S *wrap_store(STORE_S *in, int width);
53 void smime_config_init_display(struct pine *, CONF_S **, CONF_S **);
54 void revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave);
55 SAVED_CONFIG_S *save_smime_config_vars(struct pine *ps);
56 void free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep);
57 int smime_helper_tool(struct pine *, int, CONF_S **, unsigned);
58 int smime_public_certs_tool(struct pine *, int, CONF_S **, unsigned);
59 void manage_certificates(struct pine *, WhichCerts);
60 void smime_manage_certs_init (struct pine *, CONF_S **, CONF_S **, WhichCerts, int);
61 void display_certificate_information(struct pine *, X509 *, char *, WhichCerts);
62 int manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags);
63 int manage_certificate_info_tool(int, MSGNO_S *, SCROLL_S *);
67 * prompt the user for their passphrase
68 * (possibly prompting with the email address in s_passphrase_emailaddr)
70 int
71 smime_get_passphrase(void)
73 int rc;
74 int flags;
75 char prompt[500];
76 HelpType help = NO_HELP;
78 assert(ps_global->smime != NULL);
79 snprintf(prompt, sizeof(prompt),
80 _("Enter passphrase for <%s>: "), (ps_global->smime && ps_global->smime->passphrase_emailaddr) ? ps_global->smime->passphrase_emailaddr[0] : "unknown");
82 do {
83 flags = OE_PASSWD | OE_DISALLOW_HELP;
84 ((char *) ps_global->smime->passphrase)[0] = '\0';
85 rc = optionally_enter((char *) ps_global->smime->passphrase,
86 -FOOTER_ROWS(ps_global), 0,
87 sizeof(ps_global->smime->passphrase),
88 prompt, NULL, help, &flags);
89 } while (rc!=0 && rc!=1 && rc>0);
91 if(rc==0){
92 if(ps_global->smime)
93 ps_global->smime->entered_passphrase = 1;
96 return rc; /* better return rc and make the caller check its return value */
100 void
101 smime_info_screen(struct pine *ps)
103 long msgno;
104 OtherMenu what;
105 int offset = 0;
106 BODY *body;
107 ENVELOPE *env;
108 HANDLE_S *handles = NULL;
109 SCROLL_S scrollargs;
110 STORE_S *store = NULL;
112 ps->prev_screen = smime_info_screen;
113 ps->next_screen = SCREEN_FUN_NULL;
115 if(mn_total_cur(ps->msgmap) > 1L){
116 q_status_message(SM_ORDER | SM_DING, 0, 3,
117 _("Can only view one message's information at a time."));
118 return;
120 /* else check for existence of smime bits */
122 msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
124 env = mail_fetch_structure(ps->mail_stream, msgno, &body, 0);
125 if(!env || !body){
126 q_status_message(SM_ORDER, 0, 3,
127 _("Can't fetch body of message."));
128 return;
131 what = FirstMenu;
133 store = so_get(CharStar, NULL, EDIT_ACCESS);
135 while(ps->next_screen == SCREEN_FUN_NULL){
137 ClearLine(1);
139 so_truncate(store, 0);
141 view_writec_init(store, &handles, HEADER_ROWS(ps),
142 HEADER_ROWS(ps) +
143 ps->ttyo->screen_rows - (HEADER_ROWS(ps)
144 + HEADER_ROWS(ps)));
146 gf_puts_uline("Overview", view_writec);
147 gf_puts(NEWLINE, view_writec);
149 format_smime_info(1, body, msgno, view_writec);
150 gf_puts(NEWLINE, view_writec);
151 format_smime_info(2, body, msgno, view_writec);
153 view_writec_destroy();
155 ps->next_screen = SCREEN_FUN_NULL;
157 memset(&scrollargs, 0, sizeof(SCROLL_S));
158 scrollargs.text.text = so_text(store);
159 scrollargs.text.src = CharStar;
160 scrollargs.text.desc = "S/MIME information";
161 scrollargs.body_valid = 1;
163 if(offset){ /* resize? preserve paging! */
164 scrollargs.start.on = Offset;
165 scrollargs.start.loc.offset = offset;
166 offset = 0L;
169 scrollargs.bar.title = "S/MIME INFORMATION";
170 /* scrollargs.end_scroll = view_end_scroll; */
171 scrollargs.resize_exit = 1;
172 scrollargs.help.text = NULL;
173 scrollargs.help.title = "HELP FOR S/MIME INFORMATION VIEW";
174 scrollargs.keys.menu = &smime_info_keymenu;
175 scrollargs.keys.what = what;
176 setbitmap(scrollargs.keys.bitmap);
178 if(scrolltool(&scrollargs) == MC_RESIZE)
179 offset = scrollargs.start.loc.offset;
182 so_give(&store);
186 void
187 format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc)
189 PKCS7 *p7;
190 int i;
192 if(body->type == TYPEMULTIPART){
193 PART *p;
195 for(p=body->nested.part; p; p=p->next)
196 format_smime_info(pass, &p->body, msgno, pc);
199 p7 = body->sparep;
200 if(p7){
202 if(PKCS7_type_is_signed(p7)){
203 STACK_OF(X509) *signers;
205 switch(pass){
206 case 1:
207 gf_puts(_("This message was cryptographically signed."), pc);
208 gf_puts(NEWLINE, pc);
209 break;
211 case 2:
212 signers = PKCS7_get0_signers(p7, NULL, 0);
214 if(signers){
216 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s used for signing"),
217 plural(sk_X509_num(signers)));
218 gf_puts_uline(tmp_20k_buf, pc);
219 gf_puts(NEWLINE, pc);
220 print_separator_line(100, '-', pc);
222 for(i=0; i<sk_X509_num(signers); i++){
223 X509 *x = sk_X509_value(signers, i);
225 if(x){
226 output_cert_info(x, pc);
227 gf_puts(NEWLINE, pc);
232 sk_X509_free(signers);
233 break;
237 else if(PKCS7_type_is_enveloped(p7)){
239 switch(pass){
240 case 1:
241 gf_puts(_("This message was encrypted."), pc);
242 gf_puts(NEWLINE, pc);
243 break;
245 case 2:
246 if(p7->d.enveloped && p7->d.enveloped->enc_data){
247 X509_ALGOR *alg = p7->d.enveloped->enc_data->algorithm;
248 STACK_OF(PKCS7_RECIP_INFO) *ris = p7->d.enveloped->recipientinfo;
249 int found = 0;
251 gf_puts(_("The algorithm used to encrypt was "), pc);
253 if(alg){
254 char *n = (char *) OBJ_nid2sn( OBJ_obj2nid(alg->algorithm));
256 gf_puts(n ? n : "<unknown>", pc);
259 else
260 gf_puts("<unknown>", pc);
262 gf_puts("." NEWLINE NEWLINE, pc);
264 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s for decrypting"),
265 plural(sk_PKCS7_RECIP_INFO_num(ris)));
266 gf_puts_uline(tmp_20k_buf, pc);
267 gf_puts(NEWLINE, pc);
268 print_separator_line(100, '-', pc);
270 for(i=0; i<sk_PKCS7_RECIP_INFO_num(ris); i++){
271 PKCS7_RECIP_INFO *ri;
272 PERSONAL_CERT *pcert;
274 ri = sk_PKCS7_RECIP_INFO_value(ris, i);
275 if(!ri)
276 continue;
278 pcert = find_certificate_matching_recip_info(ri);
280 if(pcert){
281 if(found){
282 print_separator_line(25, '*', pc);
283 gf_puts(NEWLINE, pc);
286 found = 1;
288 output_cert_info(pcert->cert, pc);
289 gf_puts(NEWLINE, pc);
294 if(!found){
295 gf_puts(_("No certificate capable of decrypting could be found."), pc);
296 gf_puts(NEWLINE, pc);
297 gf_puts(NEWLINE, pc);
301 break;
308 void
309 print_separator_line(int percent, int ch, gf_io_t pc)
311 int i, start, len;
313 len = ps_global->ttyo->screen_cols * percent / 100;
314 start = (ps_global->ttyo->screen_cols - len)/2;
316 for(i=0; i<start; i++)
317 pc(' ');
319 for(i=start; i<start+len; i++)
320 pc(ch);
322 gf_puts(NEWLINE, pc);
326 void
327 output_cert_info(X509 *cert, gf_io_t pc)
329 char buf[256];
330 STORE_S *left,*right;
331 gf_io_t spc;
332 int len;
334 left = so_get(CharStar, NULL, EDIT_ACCESS);
335 right = so_get(CharStar, NULL, EDIT_ACCESS);
336 if(!(left && right))
337 return;
339 gf_set_so_writec(&spc, left);
341 if(!cert->cert_info){
342 gf_puts("Couldn't find certificate info.", spc);
343 gf_puts(NEWLINE, spc);
345 else{
346 gf_puts_uline("Subject (whose certificate it is)", spc);
347 gf_puts(NEWLINE, spc);
349 output_X509_NAME(cert->cert_info->subject, spc);
350 gf_puts(NEWLINE, spc);
352 gf_puts_uline("Serial Number", spc);
353 gf_puts(NEWLINE, spc);
356 ASN1_INTEGER *bs;
357 long l;
358 const char *neg;
359 int i;
361 bs = X509_get_serialNumber(cert);
362 if (bs->length <= (int)sizeof(long)){
363 l = ASN1_INTEGER_get(bs);
364 if (bs->type == V_ASN1_NEG_INTEGER){
365 l = -l;
366 neg="-";
368 else
369 neg="";
370 snprintf(buf, sizeof(buf), " %s%lu (%s0x%lx)", neg, l, neg, l);
371 } else {
372 snprintf(buf, sizeof(buf), "%s", bs->type == V_ASN1_NEG_INTEGER ? "(Negative)" : "");
373 for (i = 0; i < bs->length; i++)
374 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%02x%s", bs->data[i],
375 i+1 == bs->length ? "" : ":");
378 gf_puts(buf, spc);
379 gf_puts(NEWLINE, spc);
380 gf_puts(NEWLINE, spc);
382 gf_puts_uline("Validity", spc);
383 gf_puts(NEWLINE, spc);
385 BIO *mb = BIO_new(BIO_s_mem());
386 char iobuf[4096];
388 gf_puts("Not Before: ", spc);
390 (void) BIO_reset(mb);
391 ASN1_UTCTIME_print(mb, cert->cert_info->validity->notBefore);
392 (void) BIO_flush(mb);
393 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
394 gf_nputs(iobuf, len, spc);
396 gf_puts(NEWLINE, spc);
398 gf_puts("Not After: ", spc);
400 (void) BIO_reset(mb);
401 ASN1_UTCTIME_print(mb, cert->cert_info->validity->notAfter);
402 (void) BIO_flush(mb);
403 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
404 gf_nputs(iobuf, len, spc);
406 gf_puts(NEWLINE, spc);
407 gf_puts(NEWLINE, spc);
409 BIO_free(mb);
413 gf_clear_so_writec(left);
415 gf_set_so_writec(&spc, right);
417 if(!cert->cert_info){
418 gf_puts(_("Couldn't find certificate info."), spc);
419 gf_puts(NEWLINE, spc);
421 else{
422 gf_puts_uline("Issuer", spc);
423 gf_puts(NEWLINE, spc);
425 output_X509_NAME(cert->cert_info->issuer, spc);
426 gf_puts(NEWLINE, spc);
429 gf_clear_so_writec(right);
431 side_by_side(left, right, pc);
433 gf_puts_uline("SHA1 Fingerprint", pc);
434 gf_puts(NEWLINE, pc);
435 get_fingerprint(cert, EVP_sha1(), buf, sizeof(buf));
436 gf_puts(buf, pc);
437 gf_puts(NEWLINE, pc);
439 gf_puts_uline("MD5 Fingerprint", pc);
440 gf_puts(NEWLINE, pc);
441 get_fingerprint(cert, EVP_md5(), buf, sizeof(buf));
442 gf_puts(buf, pc);
443 gf_puts(NEWLINE, pc);
445 so_give(&left);
446 so_give(&right);
450 void
451 output_X509_NAME(X509_NAME *name, gf_io_t pc)
453 int i, c;
454 char buf[256];
456 c = X509_NAME_entry_count(name);
458 for(i=c-1; i>=0; i--){
459 X509_NAME_ENTRY *e;
461 e = X509_NAME_get_entry(name,i);
462 if(!e)
463 continue;
465 X509_NAME_get_text_by_OBJ(name, e->object, buf, sizeof(buf));
467 gf_puts(buf, pc);
468 gf_puts(NEWLINE, pc);
474 * Output the contents of the given stores (left and right)
475 * to the given gf_io_t.
476 * The width of the terminal is inspected and two columns
477 * are created to fit the stores into. They are then wrapped
478 * and merged.
480 void
481 side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc)
483 STORE_S *left_wrapped;
484 STORE_S *right_wrapped;
485 char buf_l[256];
486 char buf_r[256];
487 char *l, *r;
488 char *b;
489 int i;
490 int w = ps_global->ttyo->screen_cols/2 - 1;
492 so_seek(left, 0, 0);
493 so_seek(right, 0, 0);
495 left_wrapped = wrap_store(left, w);
496 right_wrapped = wrap_store(right, w);
498 so_seek(left_wrapped, 0, 0);
499 so_seek(right_wrapped, 0, 0);
501 for(;;){
503 l = so_fgets(left_wrapped, buf_l, sizeof(buf_l));
504 r = so_fgets(right_wrapped, buf_r, sizeof(buf_r));
505 if(l == NULL && r == NULL)
506 break;
508 for(i=0, b=buf_l; i<w && *b && *b!='\r' && *b!='\n'; i++,b++){
509 pc(*b);
510 /* reduce accumulated width if an embed tag is discovered */
511 if(*b==TAG_EMBED)
512 i-=2;
515 if(buf_r[0]){
516 while(i<w){
517 pc(' ');
518 i++;
520 pc(' ');
522 for(i=0, b=buf_r; i<w && *b && *b!='\r' && *b!='\n'; i++,b++)
523 pc(*b);
526 gf_puts(NEWLINE, pc);
529 so_give(&left_wrapped);
530 so_give(&right_wrapped);
534 * Wrap the text in the given store to the given width.
535 * A new store is created for the result.
537 STORE_S *
538 wrap_store(STORE_S *in, int width)
540 STORE_S *result;
541 void *ws;
542 gf_io_t ipc,opc;
544 if(width<10)
545 width = 10;
547 result = so_get(CharStar, NULL, EDIT_ACCESS);
548 ws = gf_wrap_filter_opt(width, width, NULL, 0, 0);
550 gf_filter_init();
551 gf_link_filter(gf_wrap, ws);
553 gf_set_so_writec(&opc, result);
554 gf_set_so_readc(&ipc, in);
556 gf_pipe(ipc, opc);
558 gf_clear_so_readc(in);
559 gf_clear_so_writec(result);
561 return result;
565 void
566 smime_config_screen(struct pine *ps, int edit_exceptions)
568 CONF_S *ctmp = NULL, *first_line = NULL;
569 SAVED_CONFIG_S *vsave;
570 OPT_SCREEN_S screen;
571 int ew, readonly_warning = 0;
573 dprint((9, "smime_config_screen()"));
574 ps->next_screen = SCREEN_FUN_NULL;
577 * this is necessary because we need to know the correct paths
578 * to configure certificates and keys, and we could get here
579 * without having done that before we reach this place.
581 smime_reinit();
583 if(ps->fix_fixed_warning)
584 offer_to_fix_pinerc(ps);
586 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
588 if(ps->restricted)
589 readonly_warning = 1;
590 else{
591 PINERC_S *prc = NULL;
593 switch(ew){
594 case Main:
595 prc = ps->prc;
596 break;
597 case Post:
598 prc = ps->post_prc;
599 break;
600 default:
601 break;
604 readonly_warning = prc ? prc->readonly : 1;
605 if(prc && prc->quit_to_edit){
606 quit_to_edit_msg(prc);
607 return;
611 smime_config_init_display(ps, &ctmp, &first_line);
613 vsave = save_smime_config_vars(ps);
615 memset(&screen, 0, sizeof(screen));
616 screen.deferred_ro_warning = readonly_warning;
617 switch(conf_scroll_screen(ps, &screen, first_line,
618 edit_exceptions ? _("SETUP S/MIME EXCEPTIONS")
619 : _("SETUP S/MIME"),
620 /* TRANSLATORS: Print something1 using something2.
621 configuration is something1 */
622 _("configuration"), 0)){
623 case 0:
624 break;
626 case 1:
627 write_pinerc(ps, ew, WRP_NONE);
628 break;
630 case 10:
631 revert_to_saved_smime_config(ps, vsave);
632 break;
634 default:
635 q_status_message(SM_ORDER, 7, 10,
636 _("conf_scroll_screen bad ret in smime_config"));
637 break;
640 free_saved_smime_config(ps, &vsave);
641 smime_reinit();
646 smime_related_var(struct pine *ps, struct variable *var)
648 return(var == &ps->vars[V_PUBLICCERT_DIR] ||
649 var == &ps->vars[V_PUBLICCERT_CONTAINER] ||
650 var == &ps->vars[V_PRIVATEKEY_DIR] ||
651 var == &ps->vars[V_PRIVATEKEY_CONTAINER] ||
652 var == &ps->vars[V_CACERT_DIR] ||
653 var == &ps->vars[V_CACERT_CONTAINER]);
656 void
657 smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
659 char tmp[200];
660 int i, ind, ln = 0;
661 struct variable *vtmp;
662 CONF_S *ctmpb;
663 FEATURE_S *feature;
665 /* find longest variable name */
666 for(vtmp = ps->vars; vtmp->name; vtmp++){
667 if(!(smime_related_var(ps, vtmp)))
668 continue;
670 if((i = utf8_width(pretty_var_name(vtmp->name))) > ln)
671 ln = i;
674 for(vtmp = ps->vars; vtmp->name; vtmp++){
675 if(!(smime_related_var(ps, vtmp)))
676 continue;
678 new_confline(ctmp)->var = vtmp;
679 if(first_line && !*first_line)
680 *first_line = *ctmp;
682 (*ctmp)->valoffset = ln+3;
683 (*ctmp)->keymenu = &config_text_keymenu;
684 (*ctmp)->help = config_help(vtmp - ps->vars, 0);
685 (*ctmp)->tool = text_tool;
687 utf8_snprintf(tmp, sizeof(tmp), "%-*.100w =", ln, pretty_var_name(vtmp->name));
688 tmp[sizeof(tmp)-1] = '\0';
690 (*ctmp)->varname = cpystr(tmp);
691 (*ctmp)->varnamep = (*ctmp);
692 (*ctmp)->flags = CF_STARTITEM;
693 (*ctmp)->value = pretty_value(ps, *ctmp);
697 vtmp = &ps->vars[V_FEATURE_LIST];
699 new_confline(ctmp);
700 ctmpb = (*ctmp);
701 (*ctmp)->flags |= CF_NOSELECT | CF_STARTITEM;
702 (*ctmp)->keymenu = &config_checkbox_keymenu;
703 (*ctmp)->tool = NULL;
705 /* put a nice delimiter before list */
706 new_confline(ctmp)->var = NULL;
707 (*ctmp)->varnamep = ctmpb;
708 (*ctmp)->keymenu = &config_checkbox_keymenu;
709 (*ctmp)->help = NO_HELP;
710 (*ctmp)->tool = checkbox_tool;
711 (*ctmp)->valoffset = feature_indent();
712 (*ctmp)->flags |= CF_NOSELECT;
713 (*ctmp)->value = cpystr("Set Feature Name");
715 new_confline(ctmp)->var = NULL;
716 (*ctmp)->varnamep = ctmpb;
717 (*ctmp)->keymenu = &config_checkbox_keymenu;
718 (*ctmp)->help = NO_HELP;
719 (*ctmp)->tool = checkbox_tool;
720 (*ctmp)->valoffset = feature_indent();
721 (*ctmp)->flags |= CF_NOSELECT;
722 (*ctmp)->value = cpystr("--- ----------------------");
724 ind = feature_list_index(F_DONT_DO_SMIME);
725 feature = feature_list(ind);
726 new_confline(ctmp)->var = vtmp;
727 (*ctmp)->varnamep = ctmpb;
728 (*ctmp)->keymenu = &config_checkbox_keymenu;
729 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
730 (*ctmp)->tool = checkbox_tool;
731 (*ctmp)->valoffset = feature_indent();
732 (*ctmp)->varmem = ind;
733 (*ctmp)->value = pretty_value(ps, (*ctmp));
735 ind = feature_list_index(F_ENCRYPT_DEFAULT_ON);
736 feature = feature_list(ind);
737 new_confline(ctmp)->var = vtmp;
738 (*ctmp)->varnamep = ctmpb;
739 (*ctmp)->keymenu = &config_checkbox_keymenu;
740 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
741 (*ctmp)->tool = checkbox_tool;
742 (*ctmp)->valoffset = feature_indent();
743 (*ctmp)->varmem = ind;
744 (*ctmp)->value = pretty_value(ps, (*ctmp));
746 ind = feature_list_index(F_REMEMBER_SMIME_PASSPHRASE);
747 feature = feature_list(ind);
748 new_confline(ctmp)->var = vtmp;
749 (*ctmp)->varnamep = ctmpb;
750 (*ctmp)->keymenu = &config_checkbox_keymenu;
751 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
752 (*ctmp)->tool = checkbox_tool;
753 (*ctmp)->valoffset = feature_indent();
754 (*ctmp)->varmem = ind;
755 (*ctmp)->value = pretty_value(ps, (*ctmp));
757 ind = feature_list_index(F_SIGN_DEFAULT_ON);
758 feature = feature_list(ind);
759 new_confline(ctmp)->var = vtmp;
760 (*ctmp)->varnamep = ctmpb;
761 (*ctmp)->keymenu = &config_checkbox_keymenu;
762 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
763 (*ctmp)->tool = checkbox_tool;
764 (*ctmp)->valoffset = feature_indent();
765 (*ctmp)->varmem = ind;
766 (*ctmp)->value = pretty_value(ps, (*ctmp));
768 #ifdef APPLEKEYCHAIN
769 new_confline(ctmp);
770 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
772 new_confline(ctmp);
773 (*ctmp)->flags |= CF_NOSELECT;
774 (*ctmp)->value = cpystr(_("Mac OS X specific features"));
776 ind = feature_list_index(F_PUBLICCERTS_IN_KEYCHAIN);
777 feature = feature_list(ind);
778 new_confline(ctmp)->var = vtmp;
779 (*ctmp)->varnamep = ctmpb;
780 (*ctmp)->keymenu = &config_checkbox_keymenu;
781 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
782 (*ctmp)->tool = checkbox_tool;
783 (*ctmp)->valoffset = feature_indent();
784 (*ctmp)->varmem = ind;
785 (*ctmp)->value = pretty_value(ps, (*ctmp));
786 #endif /* APPLEKEYCHAIN */
788 new_confline(ctmp);
789 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
791 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
792 tmp[i] = '-';
793 new_confline(ctmp);
794 (*ctmp)->flags |= CF_NOSELECT;
795 (*ctmp)->value = cpystr(tmp);
797 new_confline(ctmp);
798 (*ctmp)->flags |= CF_NOSELECT;
799 (*ctmp)->value = cpystr(_("Be careful with the following commands, they REPLACE contents in the target"));
801 new_confline(ctmp);
802 (*ctmp)->flags |= CF_NOSELECT;
803 (*ctmp)->value = cpystr(tmp);
805 new_confline(ctmp);
806 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
808 /* copy public directory to container */
809 new_confline(ctmp);
810 (*ctmp)->tool = smime_helper_tool;
811 (*ctmp)->keymenu = &config_smime_helper_keymenu;
812 (*ctmp)->help = h_config_smime_transfer_pub_to_con;
813 (*ctmp)->value = cpystr(_("Transfer public certs FROM directory TO container"));
814 (*ctmp)->varmem = 1;
816 /* copy private directory to container */
817 new_confline(ctmp);
818 (*ctmp)->tool = smime_helper_tool;
819 (*ctmp)->keymenu = &config_smime_helper_keymenu;
820 (*ctmp)->help = h_config_smime_transfer_priv_to_con;
821 (*ctmp)->value = cpystr(_("Transfer private keys FROM directory TO container"));
822 (*ctmp)->varmem = 3;
824 /* copy cacert directory to container */
825 new_confline(ctmp);
826 (*ctmp)->tool = smime_helper_tool;
827 (*ctmp)->keymenu = &config_smime_helper_keymenu;
828 (*ctmp)->help = h_config_smime_transfer_cacert_to_con;
829 (*ctmp)->value = cpystr(_("Transfer CA certs FROM directory TO container"));
830 (*ctmp)->varmem = 5;
832 new_confline(ctmp)->var = vtmp;
833 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
835 /* copy public container to directory */
836 new_confline(ctmp);
837 (*ctmp)->tool = smime_helper_tool;
838 (*ctmp)->keymenu = &config_smime_helper_keymenu;
839 (*ctmp)->help = h_config_smime_transfer_pub_to_dir;
840 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO directory"));
841 (*ctmp)->varmem = 2;
843 /* copy private container to directory */
844 new_confline(ctmp);
845 (*ctmp)->tool = smime_helper_tool;
846 (*ctmp)->keymenu = &config_smime_helper_keymenu;
847 (*ctmp)->help = h_config_smime_transfer_priv_to_dir;
848 (*ctmp)->value = cpystr(_("Transfer private keys FROM container TO directory"));
849 (*ctmp)->varmem = 4;
851 /* copy cacert container to directory */
852 new_confline(ctmp);
853 (*ctmp)->tool = smime_helper_tool;
854 (*ctmp)->keymenu = &config_smime_helper_keymenu;
855 (*ctmp)->help = h_config_smime_transfer_cacert_to_dir;
856 (*ctmp)->value = cpystr(_("Transfer CA certs FROM container TO directory"));
857 (*ctmp)->varmem = 6;
859 #ifdef APPLEKEYCHAIN
861 new_confline(ctmp)->var = vtmp;
862 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
864 /* copy public container to keychain */
865 new_confline(ctmp);
866 (*ctmp)->tool = smime_helper_tool;
867 (*ctmp)->keymenu = &config_smime_helper_keymenu;
868 (*ctmp)->help = h_config_smime_transfer_pubcon_to_key;
869 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO keychain"));
870 (*ctmp)->varmem = 7;
872 /* copy public keychain to container */
873 new_confline(ctmp);
874 (*ctmp)->tool = smime_helper_tool;
875 (*ctmp)->keymenu = &config_smime_helper_keymenu;
876 (*ctmp)->help = h_config_smime_transfer_pubkey_to_con;
877 (*ctmp)->value = cpystr(_("Transfer public certs FROM keychain TO container"));
878 (*ctmp)->varmem = 8;
880 #endif /* APPLEKEYCHAIN */
882 new_confline(ctmp)->var = vtmp;
883 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
885 new_confline(ctmp);
886 (*ctmp)->flags |= CF_NOSELECT;
887 (*ctmp)->value = cpystr(tmp);
889 new_confline(ctmp);
890 (*ctmp)->flags |= CF_NOSELECT;
891 (*ctmp)->value = cpystr(_("Manage your own certificates"));
893 new_confline(ctmp);
894 (*ctmp)->flags |= CF_NOSELECT;
895 (*ctmp)->value = cpystr(tmp);
897 new_confline(ctmp)->var = vtmp;
898 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
900 /* manage public certificates */
901 new_confline(ctmp);
902 (*ctmp)->tool = smime_helper_tool;
903 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
904 (*ctmp)->help = h_config_smime_public_certificates;
905 (*ctmp)->value = cpystr(_("Manage Public Certificates"));
906 (*ctmp)->varmem = 9;
908 /* manage private keys */
909 new_confline(ctmp);
910 (*ctmp)->tool = smime_helper_tool;
911 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
912 (*ctmp)->help = h_config_smime_private_keys;
913 (*ctmp)->value = cpystr(_("Manage Private Keys"));
914 (*ctmp)->varmem = 10;
916 /* manage Certificate Authorities */
917 new_confline(ctmp);
918 (*ctmp)->tool = smime_helper_tool;
919 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
920 (*ctmp)->help = h_config_smime_certificate_authorities;
921 (*ctmp)->value = cpystr(_("Manage Certificate Authorities"));
922 (*ctmp)->varmem = 11;
925 void display_certificate_information(struct pine *ps, X509 *cert, char *email, WhichCerts ctype)
927 STORE_S *store;
928 SCROLL_S scrollargs;
929 int cmd, offset, i;
930 int pub_cert, priv_cert, new_store;
931 long error;
932 BIO *out = NULL;
934 cmd = offset = pub_cert = priv_cert = 0;
935 new_store = 1;
936 ps->next_screen = SCREEN_FUN_NULL;
937 do {
938 /* MC_PRIVATE and MC_PUBLIC cancel each other,
939 * they can not be active at the same time
941 switch(cmd){
942 case MC_PRIVATE:
943 pub_cert = 0;
944 priv_cert = ++priv_cert % 2;
945 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
946 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
947 break;
949 case MC_PUBLIC:
950 priv_cert = 0;
951 pub_cert = ++pub_cert % 2;
952 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
953 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
954 break;
956 case MC_TRUST:
957 save_cert_for(email, cert, CACert);
958 renew_store();
959 new_store = 1;
960 break;
962 case MC_DELETE:
963 if (get_cert_deleted(ctype, email) != 0)
964 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
965 else{
966 mark_cert_deleted(ctype, email, 1);
967 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
969 break;
971 case MC_UNDELETE:
972 if (get_cert_deleted(ctype, email) != 0)
973 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
974 else{
975 mark_cert_deleted(ctype, email, 0);
976 q_status_message(SM_ORDER, 1, 3, _("Certificate will not be deleted"));
978 break;
980 default: break;
983 if((pub_cert || priv_cert)
984 && (out = print_private_key_information(email, priv_cert)) == NULL)
985 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Private Certificate Information"));
987 if(new_store){
988 store = so_get(CharStar, NULL, EDIT_ACCESS);
989 view_writec_init(store, NULL, HEADER_ROWS(ps),
990 HEADER_ROWS(ps) + ps->ttyo->screen_rows - (HEADER_ROWS(ps)+ FOOTER_ROWS(ps)));
992 snprintf(tmp_20k_buf, SIZEOF_20KBUF,"%s", _("Certificate Information"));
993 gf_puts_uline(tmp_20k_buf, view_writec);
994 gf_puts(NEWLINE, view_writec);
995 print_separator_line(100, '-', view_writec);
997 output_cert_info(cert, view_writec);
998 gf_puts(NEWLINE, view_writec);
1000 if(smime_validate_cert(cert, &error) < 0){
1001 const char *errorp = X509_verify_cert_error_string(error);
1002 snprintf(tmp_20k_buf, SIZEOF_20KBUF,_("Error validating certificate: %s"), errorp);
1003 } else
1004 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s", _("Certificate validated without errors"));
1006 gf_puts_uline(tmp_20k_buf, view_writec);
1007 gf_puts(NEWLINE, view_writec);
1009 if(out != NULL){ /* print private key information */
1010 unsigned char ch[2];
1012 gf_puts(NEWLINE, view_writec);
1013 ch[1] = '\0';
1014 while(BIO_read(out, ch, 1) >= 1)
1015 gf_puts(ch, view_writec);
1016 gf_puts(NEWLINE, view_writec);
1017 q_status_message1(SM_ORDER, 1, 3, _("%s information shown at bottom of certificate information"), pub_cert ? _("Public") : _("Private"));
1018 BIO_free_all(out);
1019 out = NULL;
1021 view_writec_destroy();
1022 new_store = 0;
1025 memset(&scrollargs, 0, sizeof(SCROLL_S));
1027 scrollargs.text.text = so_text(store);
1028 scrollargs.text.src = CharStar;
1029 scrollargs.text.desc = "certificate information";
1030 scrollargs.body_valid = 1;
1032 if(offset){ /* resize? preserve paging! */
1033 scrollargs.start.on = Offset;
1034 scrollargs.start.loc.offset = offset;
1035 scrollargs.body_valid = 0;
1036 offset = 0L;
1039 scrollargs.use_indexline_color = 1;
1041 scrollargs.bar.title = _("CERTIFICATE INFORMATION");
1042 scrollargs.proc.tool = manage_certificate_info_tool;
1043 scrollargs.resize_exit = 1;
1044 scrollargs.help.text = h_certificate_information;
1045 scrollargs.help.title = _("HELP FOR MESSAGE TEXT VIEW");
1046 scrollargs.keys.what = FirstMenu;
1047 scrollargs.keys.menu = &smime_certificate_info_keymenu;
1048 setbitmap(scrollargs.keys.bitmap);
1049 if(ctype != Public || error != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
1050 clrbitn(TRUST_KEY, scrollargs.keys.bitmap);
1051 if(ctype != Private){
1052 clrbitn(PUBLIC_KEY, scrollargs.keys.bitmap);
1053 clrbitn(PRIVATE_KEY, scrollargs.keys.bitmap);
1056 cmd = scrolltool(&scrollargs);
1058 switch(cmd){
1059 case MC_RESIZE :
1060 case MC_PRIVATE:
1061 case MC_PUBLIC : if(scrollargs.start.on == Offset)
1062 offset = scrollargs.start.loc.offset;
1063 new_store = 1;
1064 default: break;
1066 if(new_store)
1067 so_give(&store);
1068 } while (cmd != MC_EXIT);
1069 ps->mangled_screen = 1;
1073 * This is silly, we just need this function so that we can tell scrolltool
1074 * that some commands are recognized. We use scrolltool because we do not
1075 * want to rewrite output_cert_info.
1078 manage_certificate_info_tool(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
1080 int rv;
1081 switch(cmd){
1082 case MC_DELETE:
1083 case MC_UNDELETE:
1084 case MC_PRIVATE:
1085 case MC_PUBLIC:
1086 case MC_TRUST: rv = 1; break;
1087 default: rv = 0; break;
1089 return rv;
1094 manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1096 int rv = 0;
1097 X509 *cert = NULL;
1098 WhichCerts ctype = (*cl)->d.s.ctype;
1100 switch(cmd){
1101 case MC_CHOICE:
1102 if(PATHCERTDIR(ctype) == NULL)
1103 return 0;
1105 if((cert = get_cert_for((*cl)->value+3, ctype)) == NULL){
1106 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Certificate"));
1107 rv = 0;
1109 else{
1110 display_certificate_information(ps, cert, (*cl)->value+3, ctype);
1111 rv = 10 + (*cl)->varmem;
1113 break;
1115 case MC_DELETE:
1116 if ((*cl)->d.s.deleted != 0)
1117 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
1118 else{
1119 (*cl)->d.s.deleted = 1;
1120 rv = 10 + (*cl)->varmem; /* forces redraw */
1121 mark_cert_deleted(ctype, (*cl)->value+3, 1);
1122 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
1124 break;
1126 case MC_UNDELETE:
1127 if ((*cl)->d.s.deleted == 0)
1128 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
1129 else{
1130 (*cl)->d.s.deleted = 0;
1131 mark_cert_deleted(ctype, (*cl)->value+3, 0);
1132 rv = 10 + (*cl)->varmem; /* forces redraw */
1133 q_status_message(SM_ORDER, 1, 3, _("Certificate will not be deleted"));
1135 break;
1137 case MC_EXPUNGE:
1138 { CertList *cl;
1140 for(cl = DATACERT(ctype); cl != NULL && DELETEDCERT(cl) == 0; cl = cl->next);
1141 if(cl != NULL && DELETEDCERT(cl) != 0){
1142 smime_expunge_cert(ctype);
1143 rv = 10; /* forces redraw */
1145 else{
1146 q_status_message(SM_ORDER, 3, 3, _("No certificates marked deleted"));
1147 rv = 0;
1149 break;
1151 case MC_IMPORT:
1152 rv = import_certificate(ctype);
1153 if(rv < 0){
1154 switch(rv){
1155 default:
1156 case -1:
1157 cmd_cancelled("Import certificate");
1158 break;
1160 case -2:
1161 q_status_message1(SM_ORDER, 0, 2, _("Can't import certificate outside of %s"),
1162 ps_global->VAR_OPER_DIR);
1163 break;
1166 rv = 10; /* forces redraw */
1167 break;
1169 case MC_EXIT:
1170 rv = config_exit_cmd(flags);
1171 break;
1173 default:
1174 rv = -1;
1175 break;
1178 X509_free(cert);
1179 return rv;
1182 void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, WhichCerts ctype, int fline)
1184 char tmp[200];
1185 char *ext;
1186 CertList *data;
1187 int i;
1189 smime_init();
1191 data = DATACERT(ctype);
1192 ext = EXTCERT(ctype);
1194 if(data == NULL || RENEWCERT(data))
1195 renew_cert_data(&data, ctype);
1197 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1198 tmp[i] = '-';
1199 new_confline(ctmp);
1200 (*ctmp)->flags |= CF_NOSELECT;
1201 (*ctmp)->value = cpystr(tmp);
1203 (*ctmp)->keymenu = &config_text_keymenu;
1205 new_confline(ctmp);
1206 (*ctmp)->flags |= CF_NOSELECT;
1207 sprintf(tmp, _("List of %scertificates"), ctype == Public ? _("public ")
1208 : (ctype == Private ? _("private ")
1209 : (ctype == CACert ? _("certificate authority ") : "unknown (?) ")));
1210 (*ctmp)->value = cpystr(tmp);
1212 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1213 tmp[i] = '-';
1214 new_confline(ctmp);
1215 (*ctmp)->flags |= CF_NOSELECT;
1216 (*ctmp)->value = cpystr(tmp);
1218 new_confline(ctmp);
1219 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1221 if(data){
1222 CertList *cl; int i;
1223 PERSONAL_CERT *pc;
1225 for(cl = data, i = 0; cl; cl = cl->next)
1226 if(cl->name){
1227 char *s, *t;
1229 new_confline(ctmp);
1230 (*ctmp)->d.s.ctype = ctype;
1231 (*ctmp)->d.s.deleted = get_cert_deleted(ctype, cl->name);
1232 (*ctmp)->tool = manage_certs_tool;
1233 (*ctmp)->keymenu = &config_smime_manage_certs_work_keymenu;
1234 (*ctmp)->varmem = i++;
1235 (*ctmp)->help = ctype == Public ? h_config_smime_manage_public_menu
1236 : (ctype == Private ? h_config_smime_manage_private_menu
1237 : h_config_smime_manage_cacerts_menu);
1238 snprintf(tmp, sizeof(tmp), " %s\t%s", (*ctmp)->d.s.deleted ? "D" : " ", cl->name);
1239 (*ctmp)->value = cpystr(tmp);
1240 for(s = (*ctmp)->value; s && (t = strstr(s, ext)) != NULL; s = t+1);
1241 if(s) *(s-1) = '\0';
1242 if(i == fline+1 && first_line && !*first_line)
1243 *first_line = *ctmp;
1246 else {
1247 new_confline(ctmp);
1248 (*ctmp)->d.s.ctype = ctype;
1249 (*ctmp)->tool = manage_certs_tool;
1250 (*ctmp)->keymenu = &config_smime_add_certs_keymenu;
1251 (*ctmp)->value = cpystr(_(" \tNo certificates found, press \"RETURN\" to add one."));
1252 if(first_line && !*first_line)
1253 *first_line = *ctmp;
1257 void manage_certificates(struct pine *ps, WhichCerts ctype)
1259 OPT_SCREEN_S screen;
1260 int ew, readonly_warning = 0, rv = 10, fline;
1262 dprint((9, "manage_certificates(ps, %s)", ctype == Public ? _("Public") : (ctype == Private ? _("Private") : (ctype == CACert ? _("certificate authority") : _("unknown")))));
1263 ps->next_screen = SCREEN_FUN_NULL;
1265 do {
1266 CONF_S *ctmp = NULL, *first_line = NULL;
1268 fline = rv >= 10 ? rv - 10 : 0;
1270 smime_init();
1272 smime_manage_certs_init(ps, &ctmp, &first_line, ctype, fline);
1274 if(ctmp == NULL){
1275 ps->mangled_screen = 1;
1276 smime_reinit();
1277 return;
1280 memset(&screen, 0, sizeof(screen));
1281 screen.deferred_ro_warning = readonly_warning;
1282 rv = conf_scroll_screen(ps, &screen, first_line,
1283 _("MANAGE CERTIFICATES"),
1284 /* TRANSLATORS: Print something1 using something2.
1285 configuration is something1 */
1286 _("configuration"), 0);
1287 } while (rv != 0);
1289 ps->mangled_screen = 1;
1290 smime_reinit();
1294 smime_helper_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1296 int rv = 0;
1298 switch(cmd){
1299 case MC_CHOICE:
1300 switch((*cl)->varmem){
1301 case 1:
1302 rv = copy_publiccert_dir_to_container();
1303 if(rv == 0)
1304 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1305 else{
1306 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1307 rv = 0;
1310 break;
1312 case 2:
1313 rv = copy_publiccert_container_to_dir();
1314 if(rv == 0)
1315 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to directory, delete Container config to use"));
1316 else{
1317 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1318 rv = 0;
1321 break;
1323 case 3:
1324 rv = copy_privatecert_dir_to_container();
1325 if(rv == 0)
1326 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to container"));
1327 else{
1328 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1329 rv = 0;
1332 break;
1334 case 4:
1335 rv = copy_privatecert_container_to_dir();
1336 if(rv == 0)
1337 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to directory, delete Container config to use"));
1338 else{
1339 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1340 rv = 0;
1343 break;
1345 case 5:
1346 rv = copy_cacert_dir_to_container();
1347 if(rv == 0)
1348 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to container"));
1349 else{
1350 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1351 rv = 0;
1354 break;
1356 case 6:
1357 rv = copy_cacert_container_to_dir();
1358 if(rv == 0)
1359 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to directory, delete Container config to use"));
1360 else{
1361 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1362 rv = 0;
1365 break;
1367 #ifdef APPLEKEYCHAIN
1368 case 7:
1369 rv = copy_publiccert_container_to_keychain();
1370 if(rv == 0)
1371 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to keychain"));
1372 else{
1373 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1374 rv = 0;
1377 break;
1379 case 8:
1380 rv = copy_publiccert_keychain_to_container();
1381 if(rv == 0)
1382 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1383 else{
1384 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1385 rv = 0;
1388 break;
1389 #endif /* APPLEKEYCHAIN */
1391 case 9: manage_certificates(ps, Public) ; break;
1392 case 10: manage_certificates(ps, Private); break;
1393 case 11: manage_certificates(ps, CACert) ; break;
1395 default:
1396 rv = -1;
1397 break;
1400 break;
1402 case MC_EXIT:
1403 rv = config_exit_cmd(flags);
1404 break;
1406 case MC_IMPORT:
1407 { WhichCerts ctype;
1408 /* keep this selection consistent with the codes above */
1409 ctype = (*cl)->varmem == 9 ? Public
1410 : ((*cl)->varmem == 10 ? Private : CACert);
1411 rv = import_certificate(ctype);
1413 break;
1415 default:
1416 rv = -1;
1417 break;
1420 return rv;
1425 * Compare saved user_val with current user_val to see if it changed.
1426 * If any have changed, change it back and take the appropriate action.
1428 void
1429 revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave)
1431 struct variable *vreal;
1432 SAVED_CONFIG_S *v;
1433 int i, n;
1434 int changed = 0;
1435 char *pval, **apval, **lval, ***alval;
1437 v = vsave;
1438 for(vreal = ps->vars; vreal->name; vreal++,v++){
1439 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
1440 continue;
1442 if(vreal->is_list){
1443 lval = LVAL(vreal, ew);
1444 alval = ALVAL(vreal, ew);
1446 if((v->saved_user_val.l && !lval)
1447 || (!v->saved_user_val.l && lval))
1448 changed++;
1449 else if(!v->saved_user_val.l && !lval)
1450 ;/* no change, nothing to do */
1451 else
1452 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
1453 if((v->saved_user_val.l[i]
1454 && (!lval[i]
1455 || strcmp(v->saved_user_val.l[i], lval[i])))
1457 (!v->saved_user_val.l[i] && lval[i])){
1458 changed++;
1459 break;
1462 if(changed){
1463 char **list;
1465 if(alval){
1466 if(*alval)
1467 free_list_array(alval);
1469 /* copy back the original one */
1470 if(v->saved_user_val.l){
1471 list = v->saved_user_val.l;
1472 n = 0;
1473 /* count how many */
1474 while(list[n])
1475 n++;
1477 *alval = (char **)fs_get((n+1) * sizeof(char *));
1479 for(i = 0; i < n; i++)
1480 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
1482 (*alval)[n] = NULL;
1487 else{
1488 pval = PVAL(vreal, ew);
1489 apval = APVAL(vreal, ew);
1491 if((v->saved_user_val.p &&
1492 (!pval || strcmp(v->saved_user_val.p, pval))) ||
1493 (!v->saved_user_val.p && pval)){
1494 /* It changed, fix it */
1495 changed++;
1496 if(apval){
1497 /* free the changed value */
1498 if(*apval)
1499 fs_give((void **)apval);
1501 if(v->saved_user_val.p)
1502 *apval = cpystr(v->saved_user_val.p);
1507 if(changed){
1508 if(vreal == &ps->vars[V_FEATURE_LIST])
1509 set_feature_list_current_val(vreal);
1510 else
1511 set_current_val(vreal, TRUE, FALSE);
1513 fix_side_effects(ps, vreal, 1);
1519 SAVED_CONFIG_S *
1520 save_smime_config_vars(struct pine *ps)
1522 struct variable *vreal;
1523 SAVED_CONFIG_S *vsave, *v;
1525 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
1526 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
1527 v = vsave;
1528 for(vreal = ps->vars; vreal->name; vreal++,v++){
1529 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
1530 continue;
1532 if(vreal->is_list){
1533 int n, i;
1534 char **list;
1536 if(LVAL(vreal, ew)){
1537 /* count how many */
1538 n = 0;
1539 list = LVAL(vreal, ew);
1540 while(list[n])
1541 n++;
1543 v->saved_user_val.l = (char **)fs_get((n+1) * sizeof(char *));
1544 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
1545 for(i = 0; i < n; i++)
1546 v->saved_user_val.l[i] = cpystr(list[i]);
1548 v->saved_user_val.l[n] = NULL;
1551 else{
1552 if(PVAL(vreal, ew))
1553 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
1557 return(vsave);
1561 void
1562 free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep)
1564 struct variable *vreal;
1565 SAVED_CONFIG_S *v;
1567 if(vsavep && *vsavep){
1568 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
1569 if(!(smime_related_var(ps, vreal)))
1570 continue;
1572 if(vreal->is_list){ /* free saved_user_val.l */
1573 if(v && v->saved_user_val.l)
1574 free_list_array(&v->saved_user_val.l);
1576 else if(v && v->saved_user_val.p)
1577 fs_give((void **)&v->saved_user_val.p);
1580 fs_give((void **)vsavep);
1584 #endif /* SMIME */