* Set default ssl configuration for Homebrew in MAC OSX to
[alpine.git] / alpine / smime.c
blobc24841083fee026f66b7040b4838f6fcbae2c177
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 "../pith/tempfile.h"
39 #include "radio.h"
40 #include "keymenu.h"
41 #include "mailview.h"
42 #include "conftype.h"
43 #include "confscroll.h"
44 #include "setup.h"
45 #include "smime.h"
47 /* internal prototypes */
48 void format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc);
49 void print_separator_line(int percent, int ch, gf_io_t pc);
50 void output_cert_info(X509 *cert, gf_io_t pc);
51 void output_X509_NAME(X509_NAME *name, gf_io_t pc);
52 void side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc);
53 STORE_S *wrap_store(STORE_S *in, int width);
54 void smime_config_init_display(struct pine *, CONF_S **, CONF_S **);
55 void revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave);
56 SAVED_CONFIG_S *save_smime_config_vars(struct pine *ps);
57 void free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep);
58 int smime_helper_tool(struct pine *, int, CONF_S **, unsigned);
59 int smime_public_certs_tool(struct pine *, int, CONF_S **, unsigned);
60 void manage_certificates(struct pine *, WhichCerts);
61 void smime_manage_certs_init (struct pine *, CONF_S **, CONF_S **, WhichCerts, int);
62 void display_certificate_information(struct pine *, X509 *, char *, WhichCerts, int num);
63 int manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags);
64 int manage_certificate_info_tool(int, MSGNO_S *, SCROLL_S *);
68 * prompt the user for their passphrase
69 * (possibly prompting with the email address in s_passphrase_emailaddr)
71 int
72 smime_get_passphrase(void)
74 int rc;
75 int flags;
76 char prompt[500];
77 HelpType help = NO_HELP;
79 assert(ps_global->smime != NULL);
80 snprintf(prompt, sizeof(prompt),
81 _("Enter passphrase for <%s>: "), (ps_global->smime && ps_global->smime->passphrase_emailaddr) ? ps_global->smime->passphrase_emailaddr[0] : "unknown");
83 do {
84 flags = OE_PASSWD | OE_DISALLOW_HELP;
85 ((char *) ps_global->smime->passphrase)[0] = '\0';
86 rc = optionally_enter((char *) ps_global->smime->passphrase,
87 -FOOTER_ROWS(ps_global), 0,
88 sizeof(ps_global->smime->passphrase),
89 prompt, NULL, help, &flags);
90 } while (rc!=0 && rc!=1 && rc>0);
92 if(rc==0){
93 if(ps_global->smime)
94 ps_global->smime->entered_passphrase = 1;
97 return rc; /* better return rc and make the caller check its return value */
101 void
102 smime_info_screen(struct pine *ps)
104 long msgno;
105 OtherMenu what;
106 int offset = 0;
107 BODY *body;
108 ENVELOPE *env;
109 HANDLE_S *handles = NULL;
110 SCROLL_S scrollargs;
111 STORE_S *store = NULL;
113 ps->prev_screen = smime_info_screen;
114 ps->next_screen = SCREEN_FUN_NULL;
116 if(mn_total_cur(ps->msgmap) > 1L){
117 q_status_message(SM_ORDER | SM_DING, 0, 3,
118 _("Can only view one message's information at a time."));
119 return;
121 /* else check for existence of smime bits */
123 msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
125 env = mail_fetch_structure(ps->mail_stream, msgno, &body, 0);
126 if(!env || !body){
127 q_status_message(SM_ORDER, 0, 3,
128 _("Can't fetch body of message."));
129 return;
132 what = FirstMenu;
134 store = so_get(CharStar, NULL, EDIT_ACCESS);
136 while(ps->next_screen == SCREEN_FUN_NULL){
138 ClearLine(1);
140 so_truncate(store, 0);
142 view_writec_init(store, &handles, HEADER_ROWS(ps),
143 HEADER_ROWS(ps) +
144 ps->ttyo->screen_rows - (HEADER_ROWS(ps)
145 + HEADER_ROWS(ps)));
147 gf_puts_uline("Overview", view_writec);
148 gf_puts(NEWLINE, view_writec);
150 format_smime_info(1, body, msgno, view_writec);
151 gf_puts(NEWLINE, view_writec);
152 format_smime_info(2, body, msgno, view_writec);
154 view_writec_destroy();
156 ps->next_screen = SCREEN_FUN_NULL;
158 memset(&scrollargs, 0, sizeof(SCROLL_S));
159 scrollargs.text.text = so_text(store);
160 scrollargs.text.src = CharStar;
161 scrollargs.text.desc = "S/MIME information";
162 scrollargs.body_valid = 1;
164 if(offset){ /* resize? preserve paging! */
165 scrollargs.start.on = Offset;
166 scrollargs.start.loc.offset = offset;
167 offset = 0L;
170 scrollargs.bar.title = "S/MIME INFORMATION";
171 /* scrollargs.end_scroll = view_end_scroll; */
172 scrollargs.resize_exit = 1;
173 scrollargs.help.text = NULL;
174 scrollargs.help.title = "HELP FOR S/MIME INFORMATION VIEW";
175 scrollargs.keys.menu = &smime_info_keymenu;
176 scrollargs.keys.what = what;
177 setbitmap(scrollargs.keys.bitmap);
179 if(scrolltool(&scrollargs) == MC_RESIZE)
180 offset = scrollargs.start.loc.offset;
183 so_give(&store);
187 void
188 format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc)
190 PKCS7 *p7;
191 int i;
193 if(body->type == TYPEMULTIPART){
194 PART *p;
196 for(p=body->nested.part; p; p=p->next)
197 format_smime_info(pass, &p->body, msgno, pc);
200 p7 = body->sparep;
201 if(p7){
203 if(PKCS7_type_is_signed(p7)){
204 STACK_OF(X509) *signers;
206 switch(pass){
207 case 1:
208 gf_puts(_("This message was cryptographically signed."), pc);
209 gf_puts(NEWLINE, pc);
210 break;
212 case 2:
213 signers = PKCS7_get0_signers(p7, NULL, 0);
215 if(signers){
217 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s used for signing"),
218 plural(sk_X509_num(signers)));
219 gf_puts_uline(tmp_20k_buf, pc);
220 gf_puts(NEWLINE, pc);
221 print_separator_line(100, '-', pc);
223 for(i=0; i<sk_X509_num(signers); i++){
224 X509 *x = sk_X509_value(signers, i);
226 if(x){
227 output_cert_info(x, pc);
228 gf_puts(NEWLINE, pc);
233 sk_X509_free(signers);
234 break;
238 else if(PKCS7_type_is_enveloped(p7)){
240 switch(pass){
241 case 1:
242 gf_puts(_("This message was encrypted."), pc);
243 gf_puts(NEWLINE, pc);
244 break;
246 case 2:
247 if(p7->d.enveloped && p7->d.enveloped->enc_data){
248 X509_ALGOR *alg = p7->d.enveloped->enc_data->algorithm;
249 STACK_OF(PKCS7_RECIP_INFO) *ris = p7->d.enveloped->recipientinfo;
250 int found = 0;
252 gf_puts(_("The algorithm used to encrypt was "), pc);
254 if(alg){
255 char *n = (char *) OBJ_nid2sn( OBJ_obj2nid(alg->algorithm));
257 gf_puts(n ? n : "<unknown>", pc);
260 else
261 gf_puts("<unknown>", pc);
263 gf_puts("." NEWLINE NEWLINE, pc);
265 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s for decrypting"),
266 plural(sk_PKCS7_RECIP_INFO_num(ris)));
267 gf_puts_uline(tmp_20k_buf, pc);
268 gf_puts(NEWLINE, pc);
269 print_separator_line(100, '-', pc);
271 for(i=0; i<sk_PKCS7_RECIP_INFO_num(ris); i++){
272 PKCS7_RECIP_INFO *ri;
273 PERSONAL_CERT *pcert;
275 ri = sk_PKCS7_RECIP_INFO_value(ris, i);
276 if(!ri)
277 continue;
279 pcert = find_certificate_matching_recip_info(ri);
281 if(pcert){
282 if(found){
283 print_separator_line(25, '*', pc);
284 gf_puts(NEWLINE, pc);
287 found = 1;
289 output_cert_info(pcert->cert, pc);
290 gf_puts(NEWLINE, pc);
295 if(!found){
296 gf_puts(_("No certificate capable of decrypting could be found."), pc);
297 gf_puts(NEWLINE, pc);
298 gf_puts(NEWLINE, pc);
302 break;
309 void
310 print_separator_line(int percent, int ch, gf_io_t pc)
312 int i, start, len;
314 len = ps_global->ttyo->screen_cols * percent / 100;
315 start = (ps_global->ttyo->screen_cols - len)/2;
317 for(i=0; i<start; i++)
318 pc(' ');
320 for(i=start; i<start+len; i++)
321 pc(ch);
323 gf_puts(NEWLINE, pc);
327 void
328 output_cert_info(X509 *cert, gf_io_t pc)
330 char buf[256];
331 STORE_S *left,*right;
332 gf_io_t spc;
333 int len;
335 left = so_get(CharStar, NULL, EDIT_ACCESS);
336 right = so_get(CharStar, NULL, EDIT_ACCESS);
337 if(!(left && right))
338 return;
340 gf_set_so_writec(&spc, left);
342 if(!cert->cert_info){
343 gf_puts("Couldn't find certificate info.", spc);
344 gf_puts(NEWLINE, spc);
346 else{
347 gf_puts_uline("Subject (whose certificate it is)", spc);
348 gf_puts(NEWLINE, spc);
350 output_X509_NAME(cert->cert_info->subject, spc);
351 gf_puts(NEWLINE, spc);
353 gf_puts_uline("Serial Number", spc);
354 gf_puts(NEWLINE, spc);
357 ASN1_INTEGER *bs;
358 long l;
359 const char *neg;
360 int i;
362 bs = X509_get_serialNumber(cert);
363 if (bs->length <= (int)sizeof(long)){
364 l = ASN1_INTEGER_get(bs);
365 if (bs->type == V_ASN1_NEG_INTEGER){
366 l = -l;
367 neg="-";
369 else
370 neg="";
371 snprintf(buf, sizeof(buf), " %s%lu (%s0x%lx)", neg, l, neg, l);
372 } else {
373 snprintf(buf, sizeof(buf), "%s", bs->type == V_ASN1_NEG_INTEGER ? "(Negative)" : "");
374 for (i = 0; i < bs->length; i++)
375 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%02x%s", bs->data[i],
376 i+1 == bs->length ? "" : ":");
379 gf_puts(buf, spc);
380 gf_puts(NEWLINE, spc);
381 gf_puts(NEWLINE, spc);
383 gf_puts_uline("Validity", spc);
384 gf_puts(NEWLINE, spc);
386 BIO *mb = BIO_new(BIO_s_mem());
387 char iobuf[4096];
389 gf_puts("Not Before: ", spc);
391 (void) BIO_reset(mb);
392 ASN1_UTCTIME_print(mb, cert->cert_info->validity->notBefore);
393 (void) BIO_flush(mb);
394 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
395 gf_nputs(iobuf, len, spc);
397 gf_puts(NEWLINE, spc);
399 gf_puts("Not After: ", spc);
401 (void) BIO_reset(mb);
402 ASN1_UTCTIME_print(mb, cert->cert_info->validity->notAfter);
403 (void) BIO_flush(mb);
404 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
405 gf_nputs(iobuf, len, spc);
407 gf_puts(NEWLINE, spc);
408 gf_puts(NEWLINE, spc);
410 BIO_free(mb);
414 gf_clear_so_writec(left);
416 gf_set_so_writec(&spc, right);
418 if(!cert->cert_info){
419 gf_puts(_("Couldn't find certificate info."), spc);
420 gf_puts(NEWLINE, spc);
422 else{
423 gf_puts_uline("Issuer", spc);
424 gf_puts(NEWLINE, spc);
426 output_X509_NAME(cert->cert_info->issuer, spc);
427 gf_puts(NEWLINE, spc);
430 gf_clear_so_writec(right);
432 side_by_side(left, right, pc);
434 gf_puts_uline("SHA1 Fingerprint", pc);
435 gf_puts(NEWLINE, pc);
436 get_fingerprint(cert, EVP_sha1(), buf, sizeof(buf));
437 gf_puts(buf, pc);
438 gf_puts(NEWLINE, pc);
440 gf_puts_uline("MD5 Fingerprint", pc);
441 gf_puts(NEWLINE, pc);
442 get_fingerprint(cert, EVP_md5(), buf, sizeof(buf));
443 gf_puts(buf, pc);
444 gf_puts(NEWLINE, pc);
446 so_give(&left);
447 so_give(&right);
451 void
452 output_X509_NAME(X509_NAME *name, gf_io_t pc)
454 int i, c;
455 char buf[256];
457 c = X509_NAME_entry_count(name);
459 for(i=c-1; i>=0; i--){
460 X509_NAME_ENTRY *e;
462 e = X509_NAME_get_entry(name,i);
463 if(!e)
464 continue;
466 X509_NAME_get_text_by_OBJ(name, e->object, buf, sizeof(buf));
468 gf_puts(buf, pc);
469 gf_puts(NEWLINE, pc);
475 * Output the contents of the given stores (left and right)
476 * to the given gf_io_t.
477 * The width of the terminal is inspected and two columns
478 * are created to fit the stores into. They are then wrapped
479 * and merged.
481 void
482 side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc)
484 STORE_S *left_wrapped;
485 STORE_S *right_wrapped;
486 char buf_l[256];
487 char buf_r[256];
488 char *l, *r;
489 char *b;
490 int i;
491 int w = ps_global->ttyo->screen_cols/2 - 1;
493 so_seek(left, 0, 0);
494 so_seek(right, 0, 0);
496 left_wrapped = wrap_store(left, w);
497 right_wrapped = wrap_store(right, w);
499 so_seek(left_wrapped, 0, 0);
500 so_seek(right_wrapped, 0, 0);
502 for(;;){
504 l = so_fgets(left_wrapped, buf_l, sizeof(buf_l));
505 r = so_fgets(right_wrapped, buf_r, sizeof(buf_r));
506 if(l == NULL && r == NULL)
507 break;
509 for(i=0, b=buf_l; i<w && *b && *b!='\r' && *b!='\n'; i++,b++){
510 pc(*b);
511 /* reduce accumulated width if an embed tag is discovered */
512 if(*b==TAG_EMBED)
513 i-=2;
516 if(buf_r[0]){
517 while(i<w){
518 pc(' ');
519 i++;
521 pc(' ');
523 for(i=0, b=buf_r; i<w && *b && *b!='\r' && *b!='\n'; i++,b++)
524 pc(*b);
527 gf_puts(NEWLINE, pc);
530 so_give(&left_wrapped);
531 so_give(&right_wrapped);
535 * Wrap the text in the given store to the given width.
536 * A new store is created for the result.
538 STORE_S *
539 wrap_store(STORE_S *in, int width)
541 STORE_S *result;
542 void *ws;
543 gf_io_t ipc,opc;
545 if(width<10)
546 width = 10;
548 result = so_get(CharStar, NULL, EDIT_ACCESS);
549 ws = gf_wrap_filter_opt(width, width, NULL, 0, 0);
551 gf_filter_init();
552 gf_link_filter(gf_wrap, ws);
554 gf_set_so_writec(&opc, result);
555 gf_set_so_readc(&ipc, in);
557 gf_pipe(ipc, opc);
559 gf_clear_so_readc(in);
560 gf_clear_so_writec(result);
562 return result;
566 void
567 smime_config_screen(struct pine *ps, int edit_exceptions)
569 CONF_S *ctmp = NULL, *first_line = NULL;
570 SAVED_CONFIG_S *vsave;
571 OPT_SCREEN_S screen;
572 int ew, readonly_warning = 0;
574 dprint((9, "smime_config_screen()"));
575 ps->next_screen = SCREEN_FUN_NULL;
578 * this is necessary because we need to know the correct paths
579 * to configure certificates and keys, and we could get here
580 * without having done that before we reach this place.
582 smime_reinit();
584 if(ps->fix_fixed_warning)
585 offer_to_fix_pinerc(ps);
587 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
589 if(ps->restricted)
590 readonly_warning = 1;
591 else{
592 PINERC_S *prc = NULL;
594 switch(ew){
595 case Main:
596 prc = ps->prc;
597 break;
598 case Post:
599 prc = ps->post_prc;
600 break;
601 default:
602 break;
605 readonly_warning = prc ? prc->readonly : 1;
606 if(prc && prc->quit_to_edit){
607 quit_to_edit_msg(prc);
608 return;
612 smime_config_init_display(ps, &ctmp, &first_line);
614 vsave = save_smime_config_vars(ps);
616 memset(&screen, 0, sizeof(screen));
617 screen.deferred_ro_warning = readonly_warning;
618 switch(conf_scroll_screen(ps, &screen, first_line,
619 edit_exceptions ? _("SETUP S/MIME EXCEPTIONS")
620 : _("SETUP S/MIME"),
621 /* TRANSLATORS: Print something1 using something2.
622 configuration is something1 */
623 _("configuration"), 0)){
624 case 0:
625 break;
627 case 1:
628 write_pinerc(ps, ew, WRP_NONE);
629 break;
631 case 10:
632 revert_to_saved_smime_config(ps, vsave);
633 break;
635 default:
636 q_status_message(SM_ORDER, 7, 10,
637 _("conf_scroll_screen bad ret in smime_config"));
638 break;
641 free_saved_smime_config(ps, &vsave);
642 smime_reinit();
647 smime_related_var(struct pine *ps, struct variable *var)
649 return(var == &ps->vars[V_PUBLICCERT_DIR] ||
650 var == &ps->vars[V_PUBLICCERT_CONTAINER] ||
651 var == &ps->vars[V_PRIVATEKEY_DIR] ||
652 var == &ps->vars[V_PRIVATEKEY_CONTAINER] ||
653 var == &ps->vars[V_CACERT_DIR] ||
654 var == &ps->vars[V_CACERT_CONTAINER]);
657 void
658 smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
660 char tmp[200];
661 int i, ind, ln = 0;
662 struct variable *vtmp;
663 CONF_S *ctmpb;
664 FEATURE_S *feature;
666 /* find longest variable name */
667 for(vtmp = ps->vars; vtmp->name; vtmp++){
668 if(!(smime_related_var(ps, vtmp)))
669 continue;
671 if((i = utf8_width(pretty_var_name(vtmp->name))) > ln)
672 ln = i;
675 for(vtmp = ps->vars; vtmp->name; vtmp++){
676 if(!(smime_related_var(ps, vtmp)))
677 continue;
679 new_confline(ctmp)->var = vtmp;
680 if(first_line && !*first_line)
681 *first_line = *ctmp;
683 (*ctmp)->valoffset = ln+3;
684 (*ctmp)->keymenu = &config_text_keymenu;
685 (*ctmp)->help = config_help(vtmp - ps->vars, 0);
686 (*ctmp)->tool = text_tool;
688 utf8_snprintf(tmp, sizeof(tmp), "%-*.100w =", ln, pretty_var_name(vtmp->name));
689 tmp[sizeof(tmp)-1] = '\0';
691 (*ctmp)->varname = cpystr(tmp);
692 (*ctmp)->varnamep = (*ctmp);
693 (*ctmp)->flags = CF_STARTITEM;
694 (*ctmp)->value = pretty_value(ps, *ctmp);
698 vtmp = &ps->vars[V_FEATURE_LIST];
700 new_confline(ctmp);
701 ctmpb = (*ctmp);
702 (*ctmp)->flags |= CF_NOSELECT | CF_STARTITEM;
703 (*ctmp)->keymenu = &config_checkbox_keymenu;
704 (*ctmp)->tool = NULL;
706 /* put a nice delimiter before list */
707 new_confline(ctmp)->var = NULL;
708 (*ctmp)->varnamep = ctmpb;
709 (*ctmp)->keymenu = &config_checkbox_keymenu;
710 (*ctmp)->help = NO_HELP;
711 (*ctmp)->tool = checkbox_tool;
712 (*ctmp)->valoffset = feature_indent();
713 (*ctmp)->flags |= CF_NOSELECT;
714 (*ctmp)->value = cpystr("Set Feature Name");
716 new_confline(ctmp)->var = NULL;
717 (*ctmp)->varnamep = ctmpb;
718 (*ctmp)->keymenu = &config_checkbox_keymenu;
719 (*ctmp)->help = NO_HELP;
720 (*ctmp)->tool = checkbox_tool;
721 (*ctmp)->valoffset = feature_indent();
722 (*ctmp)->flags |= CF_NOSELECT;
723 (*ctmp)->value = cpystr("--- ----------------------");
725 ind = feature_list_index(F_DONT_DO_SMIME);
726 feature = feature_list(ind);
727 new_confline(ctmp)->var = vtmp;
728 (*ctmp)->varnamep = ctmpb;
729 (*ctmp)->keymenu = &config_checkbox_keymenu;
730 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
731 (*ctmp)->tool = checkbox_tool;
732 (*ctmp)->valoffset = feature_indent();
733 (*ctmp)->varmem = ind;
734 (*ctmp)->value = pretty_value(ps, (*ctmp));
736 ind = feature_list_index(F_ENCRYPT_DEFAULT_ON);
737 feature = feature_list(ind);
738 new_confline(ctmp)->var = vtmp;
739 (*ctmp)->varnamep = ctmpb;
740 (*ctmp)->keymenu = &config_checkbox_keymenu;
741 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
742 (*ctmp)->tool = checkbox_tool;
743 (*ctmp)->valoffset = feature_indent();
744 (*ctmp)->varmem = ind;
745 (*ctmp)->value = pretty_value(ps, (*ctmp));
747 ind = feature_list_index(F_REMEMBER_SMIME_PASSPHRASE);
748 feature = feature_list(ind);
749 new_confline(ctmp)->var = vtmp;
750 (*ctmp)->varnamep = ctmpb;
751 (*ctmp)->keymenu = &config_checkbox_keymenu;
752 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
753 (*ctmp)->tool = checkbox_tool;
754 (*ctmp)->valoffset = feature_indent();
755 (*ctmp)->varmem = ind;
756 (*ctmp)->value = pretty_value(ps, (*ctmp));
758 ind = feature_list_index(F_SIGN_DEFAULT_ON);
759 feature = feature_list(ind);
760 new_confline(ctmp)->var = vtmp;
761 (*ctmp)->varnamep = ctmpb;
762 (*ctmp)->keymenu = &config_checkbox_keymenu;
763 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
764 (*ctmp)->tool = checkbox_tool;
765 (*ctmp)->valoffset = feature_indent();
766 (*ctmp)->varmem = ind;
767 (*ctmp)->value = pretty_value(ps, (*ctmp));
769 #ifdef APPLEKEYCHAIN
770 new_confline(ctmp);
771 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
773 new_confline(ctmp);
774 (*ctmp)->flags |= CF_NOSELECT;
775 (*ctmp)->value = cpystr(_("Mac OS X specific features"));
777 ind = feature_list_index(F_PUBLICCERTS_IN_KEYCHAIN);
778 feature = feature_list(ind);
779 new_confline(ctmp)->var = vtmp;
780 (*ctmp)->varnamep = ctmpb;
781 (*ctmp)->keymenu = &config_checkbox_keymenu;
782 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
783 (*ctmp)->tool = checkbox_tool;
784 (*ctmp)->valoffset = feature_indent();
785 (*ctmp)->varmem = ind;
786 (*ctmp)->value = pretty_value(ps, (*ctmp));
787 #endif /* APPLEKEYCHAIN */
789 new_confline(ctmp);
790 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
792 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
793 tmp[i] = '-';
794 new_confline(ctmp);
795 (*ctmp)->flags |= CF_NOSELECT;
796 (*ctmp)->value = cpystr(tmp);
798 new_confline(ctmp);
799 (*ctmp)->flags |= CF_NOSELECT;
800 (*ctmp)->value = cpystr(_("Be careful with the following commands, they REPLACE contents in the target"));
802 new_confline(ctmp);
803 (*ctmp)->flags |= CF_NOSELECT;
804 (*ctmp)->value = cpystr(tmp);
806 new_confline(ctmp);
807 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
809 /* copy public directory to container */
810 new_confline(ctmp);
811 (*ctmp)->tool = smime_helper_tool;
812 (*ctmp)->keymenu = &config_smime_helper_keymenu;
813 (*ctmp)->help = h_config_smime_transfer_pub_to_con;
814 (*ctmp)->value = cpystr(_("Transfer public certs FROM directory TO container"));
815 (*ctmp)->varmem = 1;
817 /* copy private directory to container */
818 new_confline(ctmp);
819 (*ctmp)->tool = smime_helper_tool;
820 (*ctmp)->keymenu = &config_smime_helper_keymenu;
821 (*ctmp)->help = h_config_smime_transfer_priv_to_con;
822 (*ctmp)->value = cpystr(_("Transfer private keys FROM directory TO container"));
823 (*ctmp)->varmem = 3;
825 /* copy cacert directory to container */
826 new_confline(ctmp);
827 (*ctmp)->tool = smime_helper_tool;
828 (*ctmp)->keymenu = &config_smime_helper_keymenu;
829 (*ctmp)->help = h_config_smime_transfer_cacert_to_con;
830 (*ctmp)->value = cpystr(_("Transfer CA certs FROM directory TO container"));
831 (*ctmp)->varmem = 5;
833 new_confline(ctmp)->var = vtmp;
834 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
836 /* copy public container to directory */
837 new_confline(ctmp);
838 (*ctmp)->tool = smime_helper_tool;
839 (*ctmp)->keymenu = &config_smime_helper_keymenu;
840 (*ctmp)->help = h_config_smime_transfer_pub_to_dir;
841 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO directory"));
842 (*ctmp)->varmem = 2;
844 /* copy private container to directory */
845 new_confline(ctmp);
846 (*ctmp)->tool = smime_helper_tool;
847 (*ctmp)->keymenu = &config_smime_helper_keymenu;
848 (*ctmp)->help = h_config_smime_transfer_priv_to_dir;
849 (*ctmp)->value = cpystr(_("Transfer private keys FROM container TO directory"));
850 (*ctmp)->varmem = 4;
852 /* copy cacert container to directory */
853 new_confline(ctmp);
854 (*ctmp)->tool = smime_helper_tool;
855 (*ctmp)->keymenu = &config_smime_helper_keymenu;
856 (*ctmp)->help = h_config_smime_transfer_cacert_to_dir;
857 (*ctmp)->value = cpystr(_("Transfer CA certs FROM container TO directory"));
858 (*ctmp)->varmem = 6;
860 #ifdef APPLEKEYCHAIN
862 new_confline(ctmp)->var = vtmp;
863 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
865 /* copy public container to keychain */
866 new_confline(ctmp);
867 (*ctmp)->tool = smime_helper_tool;
868 (*ctmp)->keymenu = &config_smime_helper_keymenu;
869 (*ctmp)->help = h_config_smime_transfer_pubcon_to_key;
870 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO keychain"));
871 (*ctmp)->varmem = 7;
873 /* copy public keychain to container */
874 new_confline(ctmp);
875 (*ctmp)->tool = smime_helper_tool;
876 (*ctmp)->keymenu = &config_smime_helper_keymenu;
877 (*ctmp)->help = h_config_smime_transfer_pubkey_to_con;
878 (*ctmp)->value = cpystr(_("Transfer public certs FROM keychain TO container"));
879 (*ctmp)->varmem = 8;
881 #endif /* APPLEKEYCHAIN */
883 new_confline(ctmp)->var = vtmp;
884 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
886 new_confline(ctmp);
887 (*ctmp)->flags |= CF_NOSELECT;
888 (*ctmp)->value = cpystr(tmp);
890 new_confline(ctmp);
891 (*ctmp)->flags |= CF_NOSELECT;
892 (*ctmp)->value = cpystr(_("Manage your own certificates"));
894 new_confline(ctmp);
895 (*ctmp)->flags |= CF_NOSELECT;
896 (*ctmp)->value = cpystr(tmp);
898 new_confline(ctmp)->var = vtmp;
899 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
901 /* manage public certificates */
902 new_confline(ctmp);
903 (*ctmp)->tool = smime_helper_tool;
904 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
905 (*ctmp)->help = h_config_smime_public_certificates;
906 (*ctmp)->value = cpystr(_("Manage Public Certificates"));
907 (*ctmp)->varmem = 9;
909 /* manage private keys */
910 new_confline(ctmp);
911 (*ctmp)->tool = smime_helper_tool;
912 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
913 (*ctmp)->help = h_config_smime_private_keys;
914 (*ctmp)->value = cpystr(_("Manage Private Keys"));
915 (*ctmp)->varmem = 10;
917 /* manage Certificate Authorities */
918 new_confline(ctmp);
919 (*ctmp)->tool = smime_helper_tool;
920 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
921 (*ctmp)->help = h_config_smime_certificate_authorities;
922 (*ctmp)->value = cpystr(_("Manage Certificate Authorities"));
923 (*ctmp)->varmem = 11;
926 void display_certificate_information(struct pine *ps, X509 *cert, char *email, WhichCerts ctype, int num)
928 STORE_S *store;
929 SCROLL_S scrollargs;
930 int cmd, offset, i;
931 int pub_cert, priv_cert, new_store;
932 long error;
933 BIO *out = NULL;
935 cmd = offset = pub_cert = priv_cert = 0;
936 new_store = 1;
937 ps->next_screen = SCREEN_FUN_NULL;
938 do {
939 /* MC_PRIVATE and MC_PUBLIC cancel each other,
940 * they can not be active at the same time
942 switch(cmd){
943 case MC_PRIVATE:
944 pub_cert = 0;
945 priv_cert = ++priv_cert % 2;
946 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
947 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
948 break;
950 case MC_PUBLIC:
951 priv_cert = 0;
952 pub_cert = ++pub_cert % 2;
953 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
954 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
955 break;
957 case MC_TRUST:
958 if(SMHOLDERTYPE(CACert) == Directory)
959 save_cert_for(email, cert, CACert);
960 else{ /* if(SMHOLDERTYPE(CACert) == Container) */
961 char path[MAXPATH];
962 char *upath = PATHCERTDIR(ctype);
963 char *tempfile = tempfile_in_same_dir(path, "az", NULL);
964 CertList *clist;
966 if(IS_REMOTE(upath))
967 strncpy(path, temp_nam(NULL, "a6"), sizeof(path)-1);
968 else
969 strncpy(path, upath, sizeof(path)-1);
970 path[sizeof(path)-1] = '\0';
972 add_to_end_of_certlist(&ps_global->smime->cacertlist, email, X509_dup(cert));
973 for(clist=ps_global->smime->cacertlist; clist && clist->next; clist = clist->next);
974 certlist_to_file(tempfile, clist);
975 add_file_to_container(CACert, tempfile, email);
976 unlink(tempfile);
978 renew_store();
979 new_store = 1;
980 break;
982 case MC_DELETE:
983 if (get_cert_deleted(ctype, num) != 0)
984 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
985 else{
986 mark_cert_deleted(ctype, num, 1);
987 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
989 break;
991 case MC_UNDELETE:
992 if (get_cert_deleted(ctype, num) != 0){
993 mark_cert_deleted(ctype, num, 0);
994 q_status_message(SM_ORDER, 1, 3, _("Certificate marked UNdeleted"));
996 else
997 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
998 break;
1000 default: break;
1003 if((pub_cert || priv_cert)
1004 && (out = print_private_key_information(email, priv_cert)) == NULL)
1005 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Private Certificate Information"));
1007 if(new_store){
1008 store = so_get(CharStar, NULL, EDIT_ACCESS);
1009 view_writec_init(store, NULL, HEADER_ROWS(ps),
1010 HEADER_ROWS(ps) + ps->ttyo->screen_rows - (HEADER_ROWS(ps)+ FOOTER_ROWS(ps)));
1012 snprintf(tmp_20k_buf, SIZEOF_20KBUF,"%s", _("Certificate Information"));
1013 gf_puts_uline(tmp_20k_buf, view_writec);
1014 gf_puts(NEWLINE, view_writec);
1015 print_separator_line(100, '-', view_writec);
1017 output_cert_info(cert, view_writec);
1018 gf_puts(NEWLINE, view_writec);
1020 if(smime_validate_cert(cert, &error) < 0){
1021 const char *errorp = X509_verify_cert_error_string(error);
1022 snprintf(tmp_20k_buf, SIZEOF_20KBUF,_("Error validating certificate: %s"), errorp);
1023 } else
1024 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s", _("Certificate validated without errors"));
1026 gf_puts_uline(tmp_20k_buf, view_writec);
1027 gf_puts(NEWLINE, view_writec);
1029 if(out != NULL){ /* print private key information */
1030 unsigned char ch[2];
1032 gf_puts(NEWLINE, view_writec);
1033 ch[1] = '\0';
1034 while(BIO_read(out, ch, 1) >= 1)
1035 gf_puts(ch, view_writec);
1036 gf_puts(NEWLINE, view_writec);
1037 q_status_message1(SM_ORDER, 1, 3, _("%s information shown at bottom of certificate information"), pub_cert ? _("Public") : _("Private"));
1038 BIO_free_all(out);
1039 out = NULL;
1041 view_writec_destroy();
1042 new_store = 0;
1045 memset(&scrollargs, 0, sizeof(SCROLL_S));
1047 scrollargs.text.text = so_text(store);
1048 scrollargs.text.src = CharStar;
1049 scrollargs.text.desc = "certificate information";
1050 scrollargs.body_valid = 1;
1052 if(offset){ /* resize? preserve paging! */
1053 scrollargs.start.on = Offset;
1054 scrollargs.start.loc.offset = offset;
1055 scrollargs.body_valid = 0;
1056 offset = 0L;
1059 scrollargs.use_indexline_color = 1;
1061 scrollargs.bar.title = _("CERTIFICATE INFORMATION");
1062 scrollargs.proc.tool = manage_certificate_info_tool;
1063 scrollargs.resize_exit = 1;
1064 scrollargs.help.text = h_certificate_information;
1065 scrollargs.help.title = _("HELP FOR MESSAGE TEXT VIEW");
1066 scrollargs.keys.what = FirstMenu;
1067 scrollargs.keys.menu = &smime_certificate_info_keymenu;
1068 setbitmap(scrollargs.keys.bitmap);
1069 if(ctype != Public || error != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
1070 clrbitn(TRUST_KEY, scrollargs.keys.bitmap);
1071 if(ctype != Private){
1072 clrbitn(PUBLIC_KEY, scrollargs.keys.bitmap);
1073 clrbitn(PRIVATE_KEY, scrollargs.keys.bitmap);
1076 cmd = scrolltool(&scrollargs);
1078 switch(cmd){
1079 case MC_RESIZE :
1080 case MC_PRIVATE:
1081 case MC_PUBLIC : if(scrollargs.start.on == Offset)
1082 offset = scrollargs.start.loc.offset;
1083 new_store = 1;
1084 default: break;
1086 if(new_store)
1087 so_give(&store);
1088 } while (cmd != MC_EXIT);
1089 ps->mangled_screen = 1;
1093 * This is silly, we just need this function so that we can tell scrolltool
1094 * that some commands are recognized. We use scrolltool because we do not
1095 * want to rewrite output_cert_info.
1098 manage_certificate_info_tool(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
1100 int rv;
1101 switch(cmd){
1102 case MC_DELETE:
1103 case MC_UNDELETE:
1104 case MC_PRIVATE:
1105 case MC_PUBLIC:
1106 case MC_TRUST: rv = 1; break;
1107 default: rv = 0; break;
1109 return rv;
1114 manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1116 int rv = 0;
1117 X509 *cert = NULL;
1118 WhichCerts ctype = (*cl)->d.s.ctype;
1120 switch(cmd){
1121 case MC_CHOICE:
1122 if(PATHCERTDIR(ctype) == NULL)
1123 return 0;
1125 if((cert = get_cert_for((*cl)->value+3, ctype)) == NULL){
1126 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Certificate"));
1127 rv = 0;
1129 else{
1130 display_certificate_information(ps, cert, (*cl)->value+3, ctype, (*cl)->varmem);
1131 rv = 10 + (*cl)->varmem;
1133 break;
1135 case MC_DELETE:
1136 if ((*cl)->d.s.deleted != 0)
1137 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
1138 else{
1139 (*cl)->d.s.deleted = 1;
1140 rv = 10 + (*cl)->varmem; /* forces redraw */
1141 mark_cert_deleted(ctype, (*cl)->varmem, 1);
1142 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
1144 break;
1146 case MC_UNDELETE:
1147 if ((*cl)->d.s.deleted == 0)
1148 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
1149 else{
1150 (*cl)->d.s.deleted = 0;
1151 mark_cert_deleted(ctype, (*cl)->varmem, 0);
1152 rv = 10 + (*cl)->varmem; /* forces redraw */
1153 q_status_message(SM_ORDER, 1, 3, _("Certificate marked UNdeleted"));
1155 break;
1157 case MC_EXPUNGE:
1158 { CertList *cl;
1160 for(cl = DATACERT(ctype); cl != NULL && DELETEDCERT(cl) == 0; cl = cl->next);
1161 if(cl != NULL && DELETEDCERT(cl) != 0){
1162 smime_expunge_cert(ctype);
1163 rv = 10; /* forces redraw */
1165 else{
1166 q_status_message(SM_ORDER, 3, 3, _("No certificates marked deleted"));
1167 rv = 0;
1169 break;
1171 case MC_IMPORT:
1172 rv = import_certificate(ctype);
1173 if(rv < 0){
1174 switch(rv){
1175 default:
1176 case -1:
1177 cmd_cancelled("Import certificate");
1178 break;
1180 case -2:
1181 q_status_message1(SM_ORDER, 0, 2, _("Can't import certificate outside of %s"),
1182 ps_global->VAR_OPER_DIR);
1183 break;
1186 rv = 10; /* forces redraw */
1187 break;
1189 case MC_EXIT:
1190 rv = config_exit_cmd(flags);
1191 break;
1193 default:
1194 rv = -1;
1195 break;
1198 X509_free(cert);
1199 return rv;
1202 void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, WhichCerts ctype, int fline)
1204 char tmp[200];
1205 char *ext;
1206 CertList *data;
1207 int i;
1209 smime_init();
1211 data = DATACERT(ctype);
1212 ext = EXTCERT(ctype);
1214 if(data == NULL || RENEWCERT(data))
1215 renew_cert_data(&data, ctype);
1217 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1218 tmp[i] = '-';
1219 new_confline(ctmp);
1220 (*ctmp)->flags |= CF_NOSELECT;
1221 (*ctmp)->value = cpystr(tmp);
1223 (*ctmp)->keymenu = &config_text_keymenu;
1225 new_confline(ctmp);
1226 (*ctmp)->flags |= CF_NOSELECT;
1227 sprintf(tmp, _("List of %scertificates"), ctype == Public ? _("public ")
1228 : (ctype == Private ? _("private ")
1229 : (ctype == CACert ? _("certificate authority ") : "unknown (?) ")));
1230 (*ctmp)->value = cpystr(tmp);
1232 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1233 tmp[i] = '-';
1234 new_confline(ctmp);
1235 (*ctmp)->flags |= CF_NOSELECT;
1236 (*ctmp)->value = cpystr(tmp);
1238 new_confline(ctmp);
1239 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1241 if(data){
1242 CertList *cl; int i;
1243 PERSONAL_CERT *pc;
1245 for(cl = data, i = 0; cl; cl = cl->next)
1246 if(cl->name){
1247 char *s, *t;
1249 new_confline(ctmp);
1250 (*ctmp)->d.s.ctype = ctype;
1251 (*ctmp)->d.s.deleted = get_cert_deleted(ctype, i);
1252 (*ctmp)->tool = manage_certs_tool;
1253 (*ctmp)->keymenu = &config_smime_manage_certs_work_keymenu;
1254 (*ctmp)->varmem = i++;
1255 (*ctmp)->help = ctype == Public ? h_config_smime_manage_public_menu
1256 : (ctype == Private ? h_config_smime_manage_private_menu
1257 : h_config_smime_manage_cacerts_menu);
1258 snprintf(tmp, sizeof(tmp), " %s\t%s", (*ctmp)->d.s.deleted ? "D" : " ", cl->name);
1259 (*ctmp)->value = cpystr(tmp);
1260 for(s = (*ctmp)->value; s && (t = strstr(s, ext)) != NULL; s = t+1);
1261 if(s) *(s-1) = '\0';
1262 if(i == fline+1 && first_line && !*first_line)
1263 *first_line = *ctmp;
1266 else {
1267 new_confline(ctmp);
1268 (*ctmp)->d.s.ctype = ctype;
1269 (*ctmp)->tool = manage_certs_tool;
1270 (*ctmp)->keymenu = &config_smime_add_certs_keymenu;
1271 (*ctmp)->value = cpystr(_(" \tNo certificates found, press \"RETURN\" to add one."));
1272 if(first_line && !*first_line)
1273 *first_line = *ctmp;
1277 void manage_certificates(struct pine *ps, WhichCerts ctype)
1279 OPT_SCREEN_S screen;
1280 int ew, readonly_warning = 0, rv = 10, fline;
1282 dprint((9, "manage_certificates(ps, %s)", ctype == Public ? _("Public") : (ctype == Private ? _("Private") : (ctype == CACert ? _("certificate authority") : _("unknown")))));
1283 ps->next_screen = SCREEN_FUN_NULL;
1285 do {
1286 CONF_S *ctmp = NULL, *first_line = NULL;
1288 fline = rv >= 10 ? rv - 10 : 0;
1290 smime_init();
1292 smime_manage_certs_init(ps, &ctmp, &first_line, ctype, fline);
1294 if(ctmp == NULL){
1295 ps->mangled_screen = 1;
1296 smime_reinit();
1297 return;
1300 memset(&screen, 0, sizeof(screen));
1301 screen.deferred_ro_warning = readonly_warning;
1302 rv = conf_scroll_screen(ps, &screen, first_line,
1303 _("MANAGE CERTIFICATES"),
1304 /* TRANSLATORS: Print something1 using something2.
1305 configuration is something1 */
1306 _("configuration"), 0);
1307 } while (rv != 0);
1309 ps->mangled_screen = 1;
1310 smime_reinit();
1314 smime_helper_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1316 int rv = 0;
1318 switch(cmd){
1319 case MC_CHOICE:
1320 switch((*cl)->varmem){
1321 case 1:
1322 rv = copy_publiccert_dir_to_container();
1323 if(rv == 0)
1324 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1325 else{
1326 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1327 rv = 0;
1330 break;
1332 case 2:
1333 rv = copy_publiccert_container_to_dir();
1334 if(rv == 0)
1335 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to directory, delete Container config to use"));
1336 else{
1337 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1338 rv = 0;
1341 break;
1343 case 3:
1344 rv = copy_privatecert_dir_to_container();
1345 if(rv == 0)
1346 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to container"));
1347 else{
1348 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1349 rv = 0;
1352 break;
1354 case 4:
1355 rv = copy_privatecert_container_to_dir();
1356 if(rv == 0)
1357 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to directory, delete Container config to use"));
1358 else{
1359 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1360 rv = 0;
1363 break;
1365 case 5:
1366 rv = copy_cacert_dir_to_container();
1367 if(rv == 0)
1368 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to container"));
1369 else{
1370 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1371 rv = 0;
1374 break;
1376 case 6:
1377 rv = copy_cacert_container_to_dir();
1378 if(rv == 0)
1379 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to directory, delete Container config to use"));
1380 else{
1381 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1382 rv = 0;
1385 break;
1387 #ifdef APPLEKEYCHAIN
1388 case 7:
1389 rv = copy_publiccert_container_to_keychain();
1390 if(rv == 0)
1391 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to keychain"));
1392 else{
1393 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1394 rv = 0;
1397 break;
1399 case 8:
1400 rv = copy_publiccert_keychain_to_container();
1401 if(rv == 0)
1402 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1403 else{
1404 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1405 rv = 0;
1408 break;
1409 #endif /* APPLEKEYCHAIN */
1411 case 9: manage_certificates(ps, Public) ; break;
1412 case 10: manage_certificates(ps, Private); break;
1413 case 11: manage_certificates(ps, CACert) ; break;
1415 default:
1416 rv = -1;
1417 break;
1420 break;
1422 case MC_EXIT:
1423 rv = config_exit_cmd(flags);
1424 break;
1426 case MC_IMPORT:
1427 { WhichCerts ctype;
1428 /* keep this selection consistent with the codes above */
1429 ctype = (*cl)->varmem == 9 ? Public
1430 : ((*cl)->varmem == 10 ? Private : CACert);
1431 rv = import_certificate(ctype);
1433 break;
1435 default:
1436 rv = -1;
1437 break;
1440 return rv;
1445 * Compare saved user_val with current user_val to see if it changed.
1446 * If any have changed, change it back and take the appropriate action.
1448 void
1449 revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave)
1451 struct variable *vreal;
1452 SAVED_CONFIG_S *v;
1453 int i, n;
1454 int changed = 0;
1455 char *pval, **apval, **lval, ***alval;
1457 v = vsave;
1458 for(vreal = ps->vars; vreal->name; vreal++,v++){
1459 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
1460 continue;
1462 if(vreal->is_list){
1463 lval = LVAL(vreal, ew);
1464 alval = ALVAL(vreal, ew);
1466 if((v->saved_user_val.l && !lval)
1467 || (!v->saved_user_val.l && lval))
1468 changed++;
1469 else if(!v->saved_user_val.l && !lval)
1470 ;/* no change, nothing to do */
1471 else
1472 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
1473 if((v->saved_user_val.l[i]
1474 && (!lval[i]
1475 || strcmp(v->saved_user_val.l[i], lval[i])))
1477 (!v->saved_user_val.l[i] && lval[i])){
1478 changed++;
1479 break;
1482 if(changed){
1483 char **list;
1485 if(alval){
1486 if(*alval)
1487 free_list_array(alval);
1489 /* copy back the original one */
1490 if(v->saved_user_val.l){
1491 list = v->saved_user_val.l;
1492 n = 0;
1493 /* count how many */
1494 while(list[n])
1495 n++;
1497 *alval = (char **)fs_get((n+1) * sizeof(char *));
1499 for(i = 0; i < n; i++)
1500 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
1502 (*alval)[n] = NULL;
1507 else{
1508 pval = PVAL(vreal, ew);
1509 apval = APVAL(vreal, ew);
1511 if((v->saved_user_val.p &&
1512 (!pval || strcmp(v->saved_user_val.p, pval))) ||
1513 (!v->saved_user_val.p && pval)){
1514 /* It changed, fix it */
1515 changed++;
1516 if(apval){
1517 /* free the changed value */
1518 if(*apval)
1519 fs_give((void **)apval);
1521 if(v->saved_user_val.p)
1522 *apval = cpystr(v->saved_user_val.p);
1527 if(changed){
1528 if(vreal == &ps->vars[V_FEATURE_LIST])
1529 set_feature_list_current_val(vreal);
1530 else
1531 set_current_val(vreal, TRUE, FALSE);
1533 fix_side_effects(ps, vreal, 1);
1539 SAVED_CONFIG_S *
1540 save_smime_config_vars(struct pine *ps)
1542 struct variable *vreal;
1543 SAVED_CONFIG_S *vsave, *v;
1545 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
1546 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
1547 v = vsave;
1548 for(vreal = ps->vars; vreal->name; vreal++,v++){
1549 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
1550 continue;
1552 if(vreal->is_list){
1553 int n, i;
1554 char **list;
1556 if(LVAL(vreal, ew)){
1557 /* count how many */
1558 n = 0;
1559 list = LVAL(vreal, ew);
1560 while(list[n])
1561 n++;
1563 v->saved_user_val.l = (char **)fs_get((n+1) * sizeof(char *));
1564 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
1565 for(i = 0; i < n; i++)
1566 v->saved_user_val.l[i] = cpystr(list[i]);
1568 v->saved_user_val.l[n] = NULL;
1571 else{
1572 if(PVAL(vreal, ew))
1573 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
1577 return(vsave);
1581 void
1582 free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep)
1584 struct variable *vreal;
1585 SAVED_CONFIG_S *v;
1587 if(vsavep && *vsavep){
1588 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
1589 if(!(smime_related_var(ps, vreal)))
1590 continue;
1592 if(vreal->is_list){ /* free saved_user_val.l */
1593 if(v && v->saved_user_val.l)
1594 free_list_array(&v->saved_user_val.l);
1596 else if(v && v->saved_user_val.p)
1597 fs_give((void **)&v->saved_user_val.p);
1600 fs_give((void **)vsavep);
1604 #endif /* SMIME */