void output_X509_NAME(X509_NAME *name, gf_io_t pc) { int i, c; char buf[256]; c = X509_NAME_entry_count(name); for(i=c-1; i>=0; i--){ X509_NAME_ENTRY *e; e = X509_NAME_get_entry(name,i); if(!e) continue; X509_NAME_get_text_by_OBJ(name, e->object, buf, sizeof(buf)); gf_puts(buf, pc); gf_puts(NEWLINE, pc); } }
/* * Output the contents of the given stores (left and right) * to the given gf_io_t. * The width of the terminal is inspected and two columns * are created to fit the stores into. They are then wrapped * and merged. */ void side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc) { STORE_S *left_wrapped; STORE_S *right_wrapped; char buf_l[256]; char buf_r[256]; char *b; int i; int w = ps_global->ttyo->screen_cols/2 - 1; so_seek(left, 0, 0); so_seek(right, 0, 0); left_wrapped = wrap_store(left, w); right_wrapped = wrap_store(right, w); so_seek(left_wrapped, 0, 0); so_seek(right_wrapped, 0, 0); for(;;){ if(!so_fgets(left_wrapped, buf_l, sizeof(buf_l))) break; if(!so_fgets(right_wrapped, buf_r, sizeof(buf_r))) break; for(i=0, b=buf_l; i<w && *b && *b!='\r' && *b!='\n'; i++,b++){ pc(*b); /* reduce accumulated width if an embed tag is discovered */ if(*b==TAG_EMBED) i-=2; } if(buf_r[0]){ while(i<w){ pc(' '); i++; } for(i=0, b=buf_r; i<w && *b && *b!='\r' && *b!='\n'; i++,b++) pc(*b); } gf_puts(NEWLINE, pc); } so_give(&left_wrapped); so_give(&right_wrapped); }
void print_separator_line(int percent, int ch, gf_io_t pc) { int i, start, len; len = ps_global->ttyo->screen_cols * percent / 100; start = (ps_global->ttyo->screen_cols - len)/2; for(i=0; i<start; i++) pc(' '); for(i=start; i<start+len; i++) pc(ch); gf_puts(NEWLINE, pc); }
/*---------------------------------------------------------------------- Handle fetching and filtering a text message segment to be displayed by scrolltool or printed or exported or piped. Args: att -- segment to fetch msgno -- message number segment is a part of pc -- function to write characters from segment with style -- Indicates special handling for error messages flags -- Indicates special necessary handling Returns: 1 if errors encountered, 0 if everything went A-OK ----*/ int decode_text(ATTACH_S *att, long int msgno, gf_io_t pc, HANDLE_S **handlesp, DetachErrStyle style, int flags) { FILTLIST_S filters[14]; char *err, *charset; int filtcnt = 0, error_found = 0, column, wrapit; int is_in_sig = OUT_SIG_BLOCK; int is_flowed_msg = 0, add_me = 1, doraw = RAWSTRING; int is_delsp_yes = 0; int filt_only_c0 = 0; char *parmval; char *free_this = NULL; STORE_S *warn_so = NULL; DELQ_S dq; URL_HILITE_S uh; column = (flags & FM_DISPLAY) ? ps_global->ttyo->screen_cols : 80; if(!(flags & FM_DISPLAY)) flags |= FM_NOINDENT; wrapit = column; memset(filters, 0, sizeof(filters)); /* charset the body part is in */ charset = parameter_val(att->body->parameter, "charset"); /* determined if it's flowed, affects wrapping and quote coloring */ if(att->body->type == TYPETEXT && !strucmp(att->body->subtype, "plain") && (parmval = parameter_val(att->body->parameter, "format"))){ if(!strucmp(parmval, "flowed")) is_flowed_msg = 1; fs_give((void **) &parmval); if(is_flowed_msg){ if((parmval = parameter_val(att->body->parameter, "delsp")) != NULL){ if(!strucmp(parmval, "yes")) is_delsp_yes = 1; fs_give((void **) &parmval); } } } if(!ps_global->pass_ctrl_chars){ filters[filtcnt++].filter = gf_escape_filter; filters[filtcnt].filter = gf_control_filter; filt_only_c0 = 1; filters[filtcnt++].data = gf_control_filter_opt(&filt_only_c0); } if(flags & FM_DISPLAY) filters[filtcnt++].filter = gf_tag_filter; /* * if it's just plain old text, look for url's */ if(!(att->body->subtype && strucmp(att->body->subtype, "plain"))){ struct variable *vars = ps_global->vars; if((F_ON(F_VIEW_SEL_URL, ps_global) || F_ON(F_VIEW_SEL_URL_HOST, ps_global) || F_ON(F_SCAN_ADDR, ps_global)) && handlesp){ /* * The url_hilite filter really ought to come * after flowing, because flowing with the DelSp=yes parameter * can reassemble broken urls back into identifiable urls. * We add the preflow filter to do only the reassembly part * of the flowing so that we can spot the urls. * At this time (2005-03-29) we know that Apple Mail does * send mail like this sometimes. This filter removes the * sequence SP CRLF if that seems safe. */ if(ps_global->full_header != 2 && is_delsp_yes) filters[filtcnt++].filter = gf_preflow; filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(url_hilite, gf_url_hilite_opt(&uh,handlesp,0)); } if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_SPECIAL_TEXT_FORE_COLOR && VAR_SPECIAL_TEXT_BACK_COLOR){ filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(color_this_text, NULL); } /* * First, paint the signature. * Disclaimers noted below for coloring quotes apply here as well. */ if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR){ filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(color_signature, &is_in_sig); } /* * Gotta be careful with this. The color_a_quote filter adds color * to the beginning and end of the line. This will break some * line_test-style filters which come after it. For example, if they * are looking for something at the start of a line (like color_a_quote * itself). I guess we could fix that by ignoring tags at the * beginning of the line when doing the search. */ if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_QUOTE1_FORE_COLOR && VAR_QUOTE1_BACK_COLOR){ add_me = 0; filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(color_a_quote, &is_flowed_msg); } } else if(!strucmp(att->body->subtype, "richtext")){ int plain_opt; plain_opt = !(flags&FM_DISPLAY); /* maybe strip everything! */ filters[filtcnt].filter = gf_rich2plain; filters[filtcnt++].data = gf_rich2plain_opt(&plain_opt); /* width to use for file or printer */ if(wrapit - 5 > 0) wrapit -= 5; } else if(!strucmp(att->body->subtype, "enriched")){ int plain_opt; plain_opt = !(flags&FM_DISPLAY); filters[filtcnt].filter = gf_enriched2plain; filters[filtcnt++].data = gf_enriched2plain_opt(&plain_opt); /* width to use for file or printer */ if(wrapit - 5 > 0) wrapit -= 5; } else if(!strucmp(att->body->subtype, "html") && ps_global->full_header < 2){ /*BUG: sniff the params for "version=2.0" ala draft-ietf-html-spec-01 */ int opts = 0; clear_html_risk(); if(flags & FM_DISPLAY){ gf_io_t warn_pc; if(handlesp){ /* pass on handles awareness */ opts |= GFHP_HANDLES; if(F_OFF(F_QUELL_HOST_AFTER_URL, ps_global) && !(flags & FM_HIDESERVER)) opts |= GFHP_SHOW_SERVER; } if(!(flags & FM_NOEDITORIAL)){ warn_so = so_get(CharStar, NULL, EDIT_ACCESS); gf_set_so_writec(&warn_pc, warn_so); format_editorial(HTML_WARNING, column, flags, handlesp, warn_pc); gf_clear_so_writec(warn_so); so_puts(warn_so, "\015\012"); so_writec('\0', warn_so); } } else opts |= GFHP_STRIPPED; /* don't embed anything! */ if(flags & FM_NOHTMLREL) opts |= GFHP_NO_RELATIVE; if(flags & FM_HTMLRELATED) opts |= GFHP_RELATED_CONTENT; if(flags & FM_HTML) opts |= GFHP_HTML; if(flags & FM_HTMLIMAGES) opts |= GFHP_HTML_IMAGES; wrapit = 0; /* wrap already handled! */ filters[filtcnt].filter = gf_html2plain; filters[filtcnt++].data = gf_html2plain_opt(NULL, column, (flags & (FM_NOINDENT | FM_HTML)) ? 0 : format_view_margin(), handlesp, set_html_risk, opts); if(warn_so){ filters[filtcnt].filter = gf_prepend_editorial; filters[filtcnt++].data = gf_prepend_editorial_opt(get_html_risk, (char *) so_text(warn_so)); } } if (add_me){ filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(select_quote, &doraw); } /* * If the message is not flowed, we do the quote suppression before * the wrapping, because the wrapping does not preserve the quote * characters at the beginnings of the lines in that case. * Otherwise, we defer until after the wrapping. * * Also, this is a good place to do quote-replacement on nonflowed * messages because no other filters depend on the "> ". * Quote-replacement is easier in the flowed case and occurs * automatically in the flowed wrapping filter. */ if(!is_flowed_msg && ps_global->full_header == 0 && !(att->body->subtype && strucmp(att->body->subtype, "plain")) && (flags & FM_DISPLAY)){ if(ps_global->quote_suppression_threshold != 0){ memset(&dq, 0, sizeof(dq)); dq.lines = ps_global->quote_suppression_threshold; dq.is_flowed = is_flowed_msg; dq.indent_length = 0; /* indent didn't happen yet */ dq.saved_line = &free_this; dq.handlesp = handlesp; dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor()); filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } if(ps_global->VAR_QUOTE_REPLACE_STRING && F_ON(F_QUOTE_REPLACE_NOFLOW, ps_global)){ filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(replace_quotes, NULL); } } if(wrapit && !(flags & FM_NOWRAP)){ int wrapflags = (flags & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE; if(flags & FM_DISPLAY && !(flags & FM_NOCOLOR) && pico_usingcolor()) wrapflags |= GFW_USECOLOR; /* text/flowed (RFC 2646 + draft)? */ if(ps_global->full_header != 2 && is_flowed_msg){ wrapflags |= GFW_FLOWED; if(is_delsp_yes) wrapflags |= GFW_DELSP; } filters[filtcnt].filter = gf_wrap; filters[filtcnt++].data = gf_wrap_filter_opt(wrapit, column, (flags & FM_NOINDENT) ? 0 : format_view_margin(), 0, wrapflags); } /* * This has to come after wrapping has happened because the user tells * us how many quoted lines to display, and we want that number to be * the wrapped lines, not the pre-wrapped lines. We do it before the * wrapping if the message is not flowed, because the wrapping does not * preserve the quote characters at the beginnings of the lines in that * case. */ if(is_flowed_msg && ps_global->full_header == 0 && !(att->body->subtype && strucmp(att->body->subtype, "plain")) && (flags & FM_DISPLAY) && ps_global->quote_suppression_threshold != 0){ memset(&dq, 0, sizeof(dq)); dq.lines = ps_global->quote_suppression_threshold; dq.is_flowed = is_flowed_msg; dq.indent_length = (wrapit && !(flags & FM_NOWRAP) && !(flags & FM_NOINDENT)) ? format_view_margin()[0] : 0; dq.saved_line = &free_this; dq.handlesp = handlesp; dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor()); filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } if(charset){ if(F_OFF(F_QUELL_CHARSET_WARNING, ps_global) && !(flags & FM_NOEDITORIAL)){ int rv = TRUE; CONV_TABLE *ct = NULL; /* * Need editorial if message charset is not ascii * and the display charset is not either the same * as the message charset or UTF-8. */ if(strucmp(charset, "us-ascii") && !((ps_global->display_charmap && !strucmp(charset, ps_global->display_charmap)) || !strucmp("UTF-8", ps_global->display_charmap))){ /* * This is probably overkill. We're just using this * conversion_table routine to get at the quality. */ if(ps_global->display_charmap) ct = conversion_table(charset, ps_global->display_charmap); rv = charset_editorial(charset, msgno, handlesp, flags, ct ? ct->quality : CV_NO_TRANSLATE_POSSIBLE, column, pc); } if(!rv) goto write_error; } fs_give((void **) &charset); } /* Format editorial comment about unknown encoding */ if(att->body->encoding > ENCQUOTEDPRINTABLE){ char buf[2048]; snprintf(buf, sizeof(buf), ENCODING_DISCLAIMER, body_encodings[att->body->encoding]); if(!(format_editorial(buf, column, flags, handlesp, pc) == NULL && gf_puts(NEWLINE, pc) && gf_puts(NEWLINE, pc))) goto write_error; } err = detach(ps_global->mail_stream, msgno, att->number, 0L, NULL, pc, filtcnt ? filters : NULL, 0); delete_unused_handles(handlesp); if(free_this) fs_give((void **) &free_this); if(warn_so) so_give(&warn_so); if(err) { error_found++; if(style == QStatus) { q_status_message1(SM_ORDER, 3, 4, "%.200s", err); } else if(style == InLine) { char buftmp[MAILTMPLEN]; snprintf(buftmp, sizeof(buftmp), "%s", att->body->description ? att->body->description : ""); snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s [Error: %s] %c%s%c%s%s", NEWLINE, err, att->body->description ? '\"' : ' ', att->body->description ? buftmp : "", att->body->description ? '\"' : ' ', NEWLINE, NEWLINE); if(!gf_puts(tmp_20k_buf, pc)) goto write_error; } } if(att->body->subtype && (!strucmp(att->body->subtype, "richtext") || !strucmp(att->body->subtype, "enriched")) && !(flags & FM_DISPLAY)){ if(!gf_puts(NEWLINE, pc) || !gf_puts(NEWLINE, pc)) goto write_error; } return(error_found); write_error: if(style == QStatus) q_status_message1(SM_ORDER, 3, 4, "Error writing message: %.200s", error_description(errno)); return(1); }
/* * Format editorial comment about charset mismatch */ int charset_editorial(char *charset, long int msgno, HANDLE_S **handlesp, int flags, int quality, int width, gf_io_t pc) { char *p, color[64], buf[2048]; int i, n; HANDLE_S *h = NULL; snprintf(buf, sizeof(buf), CHARSET_DISCLAIMER_1, charset ? charset : "US-ASCII"); p = &buf[strlen(buf)]; if(!(ps_global->display_charmap && strucmp(ps_global->display_charmap, "US-ASCII")) && handlesp && (flags & FM_DISPLAY) == FM_DISPLAY){ h = new_handle(handlesp); h->type = URL; h->h.url.path = cpystr("x-alpine-help:h_config_char_set"); /* * Because this filter comes after the delete_quotes filter, we need * to tell delete_quotes that this handle is used, so it won't * delete it. This is a dangerous thing. */ h->is_used = 1; if(!(flags & FM_NOCOLOR) && scroll_handle_start_color(color, sizeof(color), &n)){ for(i = 0; i < n; i++) if(p-buf < sizeof(buf)) *p++ = color[i]; } else if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global)){ if(p-buf+1 < sizeof(buf)){ *p++ = TAG_EMBED; *p++ = TAG_BOLDON; } } if(p-buf+1 < sizeof(buf)){ *p++ = TAG_EMBED; *p++ = TAG_HANDLE; } snprintf(p + 1, sizeof(buf)-(p+1-buf), "%d", h->key); if(p-buf < sizeof(buf)) *p = strlen(p + 1); p += (*p + 1); } sstrncpy(&p, CHARSET_DISCLAIMER_2, sizeof(buf)-(p-buf)); if(h){ /* in case it was the current selection */ if(p-buf+1 < sizeof(buf)){ *p++ = TAG_EMBED; *p++ = TAG_INVOFF; } if(scroll_handle_end_color(color, sizeof(color), &n, 0)){ for(i = 0; i < n; i++) if(p-buf < sizeof(buf)) *p++ = color[i]; } else{ if(p-buf+1 < sizeof(buf)){ *p++ = TAG_EMBED; *p++ = TAG_BOLDOFF; } } if(p-buf < sizeof(buf)) *p = '\0'; } snprintf(p, sizeof(buf)-(p-buf), CHARSET_DISCLAIMER_3, ps_global->display_charmap ? ps_global->display_charmap : "US-ASCII", (quality == CV_LOSES_SPECIAL_CHARS) ? "special " : ""); buf[sizeof(buf)-1] = '\0'; return(format_editorial(buf, width, flags, handlesp, pc) == NULL && gf_puts(NEWLINE, pc) && gf_puts(NEWLINE, pc)); }
void smime_info_screen(struct pine *ps) { long msgno; OtherMenu what; int offset = 0; BODY *body; ENVELOPE *env; HANDLE_S *handles = NULL; SCROLL_S scrollargs; STORE_S *store = NULL; ps->prev_screen = smime_info_screen; ps->next_screen = SCREEN_FUN_NULL; if(mn_total_cur(ps->msgmap) > 1L){ q_status_message(SM_ORDER | SM_DING, 0, 3, _("Can only view one message's information at a time.")); return; } /* else check for existence of smime bits */ msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap)); env = mail_fetch_structure(ps->mail_stream, msgno, &body, 0); if(!env || !body){ q_status_message(SM_ORDER, 0, 3, _("Can't fetch body of message.")); return; } what = FirstMenu; store = so_get(CharStar, NULL, EDIT_ACCESS); while(ps->next_screen == SCREEN_FUN_NULL){ ClearLine(1); so_truncate(store, 0); view_writec_init(store, &handles, HEADER_ROWS(ps), HEADER_ROWS(ps) + ps->ttyo->screen_rows - (HEADER_ROWS(ps) + HEADER_ROWS(ps))); gf_puts_uline("Overview", view_writec); gf_puts(NEWLINE, view_writec); format_smime_info(1, body, msgno, view_writec); gf_puts(NEWLINE, view_writec); format_smime_info(2, body, msgno, view_writec); view_writec_destroy(); ps->next_screen = SCREEN_FUN_NULL; memset(&scrollargs, 0, sizeof(SCROLL_S)); scrollargs.text.text = so_text(store); scrollargs.text.src = CharStar; scrollargs.text.desc = "S/MIME information"; scrollargs.body_valid = 1; if(offset){ /* resize? preserve paging! */ scrollargs.start.on = Offset; scrollargs.start.loc.offset = offset; offset = 0L; } scrollargs.bar.title = "S/MIME INFORMATION"; /* scrollargs.end_scroll = view_end_scroll; */ scrollargs.resize_exit = 1; scrollargs.help.text = NULL; scrollargs.help.title = "HELP FOR S/MIME INFORMATION VIEW"; scrollargs.keys.menu = &smime_info_keymenu; scrollargs.keys.what = what; setbitmap(scrollargs.keys.bitmap); if(scrolltool(&scrollargs) == MC_RESIZE) offset = scrollargs.start.loc.offset; } so_give(&store); }
void output_cert_info(X509 *cert, gf_io_t pc) { char buf[256]; STORE_S *left,*right; gf_io_t spc; int len; left = so_get(CharStar, NULL, EDIT_ACCESS); right = so_get(CharStar, NULL, EDIT_ACCESS); if(!(left && right)) return; gf_set_so_writec(&spc, left); if(!cert->cert_info){ gf_puts("Couldn't find certificate info.", spc); gf_puts(NEWLINE, spc); } else{ gf_puts_uline("Subject (whose certificate it is)", spc); gf_puts(NEWLINE, spc); output_X509_NAME(cert->cert_info->subject, spc); gf_puts(NEWLINE, spc); gf_puts_uline("Serial Number", spc); gf_puts(NEWLINE, spc); snprintf(buf, sizeof(buf), "%ld", ASN1_INTEGER_get(cert->cert_info->serialNumber)); gf_puts(buf, spc); gf_puts(NEWLINE, spc); gf_puts(NEWLINE, spc); gf_puts_uline("Validity", spc); gf_puts(NEWLINE, spc); { BIO *mb = BIO_new(BIO_s_mem()); char iobuf[4096]; gf_puts("Not Before: ", spc); (void) BIO_reset(mb); ASN1_UTCTIME_print(mb, cert->cert_info->validity->notBefore); (void) BIO_flush(mb); while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0) gf_nputs(iobuf, len, spc); gf_puts(NEWLINE, spc); gf_puts("Not After: ", spc); (void) BIO_reset(mb); ASN1_UTCTIME_print(mb, cert->cert_info->validity->notAfter); (void) BIO_flush(mb); while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0) gf_nputs(iobuf, len, spc); gf_puts(NEWLINE, spc); gf_puts(NEWLINE, spc); BIO_free(mb); } } gf_clear_so_writec(left); gf_set_so_writec(&spc, right); if(!cert->cert_info){ gf_puts(_("Couldn't find certificate info."), spc); gf_puts(NEWLINE, spc); } else{ gf_puts_uline("Issuer", spc); gf_puts(NEWLINE, spc); output_X509_NAME(cert->cert_info->issuer, spc); gf_puts(NEWLINE, spc); } gf_clear_so_writec(right); side_by_side(left, right, pc); gf_puts_uline("SHA1 Fingerprint", pc); gf_puts(NEWLINE, pc); get_fingerprint(cert, EVP_sha1(), buf, sizeof(buf)); gf_puts(buf, pc); gf_puts(NEWLINE, pc); gf_puts_uline("MD5 Fingerprint", pc); gf_puts(NEWLINE, pc); get_fingerprint(cert, EVP_md5(), buf, sizeof(buf)); gf_puts(buf, pc); gf_puts(NEWLINE, pc); so_give(&left); so_give(&right); }
void format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc) { PKCS7 *p7; int i; if(body->type == TYPEMULTIPART){ PART *p; for(p=body->nested.part; p; p=p->next) format_smime_info(pass, &p->body, msgno, pc); } p7 = body->sparep; if(p7){ if(PKCS7_type_is_signed(p7)){ STACK_OF(X509) *signers; switch(pass){ case 1: gf_puts(_("This message was cryptographically signed."), pc); gf_puts(NEWLINE, pc); break; case 2: signers = PKCS7_get0_signers(p7, NULL, 0); if(signers){ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s used for signing"), plural(sk_X509_num(signers))); gf_puts_uline(tmp_20k_buf, pc); gf_puts(NEWLINE, pc); print_separator_line(100, '-', pc); for(i=0; i<sk_X509_num(signers); i++){ X509 *x = sk_X509_value(signers, i); if(x){ output_cert_info(x, pc); gf_puts(NEWLINE, pc); } } } sk_X509_free(signers); break; } } else if(PKCS7_type_is_enveloped(p7)){ switch(pass){ case 1: gf_puts(_("This message was encrypted."), pc); gf_puts(NEWLINE, pc); break; case 2: if(p7->d.enveloped && p7->d.enveloped->enc_data){ X509_ALGOR *alg = p7->d.enveloped->enc_data->algorithm; STACK_OF(PKCS7_RECIP_INFO) *ris = p7->d.enveloped->recipientinfo; int found = 0; gf_puts(_("The algorithm used to encrypt was "), pc); if(alg){ char *n = (char *) OBJ_nid2sn( OBJ_obj2nid(alg->algorithm)); gf_puts(n ? n : "<unknown>", pc); } else gf_puts("<unknown>", pc); gf_puts("." NEWLINE NEWLINE, pc); snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s for decrypting"), plural(sk_PKCS7_RECIP_INFO_num(ris))); gf_puts_uline(tmp_20k_buf, pc); gf_puts(NEWLINE, pc); print_separator_line(100, '-', pc); for(i=0; i<sk_PKCS7_RECIP_INFO_num(ris); i++){ PKCS7_RECIP_INFO *ri; PERSONAL_CERT *pcert; ri = sk_PKCS7_RECIP_INFO_value(ris, i); if(!ri) continue; pcert = find_certificate_matching_recip_info(ri); if(pcert){ if(found){ print_separator_line(25, '*', pc); gf_puts(NEWLINE, pc); } found = 1; output_cert_info(pcert->cert, pc); gf_puts(NEWLINE, pc); } } if(!found){ gf_puts(_("No certificate capable of decrypting could be found."), pc); gf_puts(NEWLINE, pc); gf_puts(NEWLINE, pc); } } break; } } } }