static HEADER *select_msg (void) { MUTTMENU *menu; int i, done=0, r=-1; char helpstr[LONG_STRING]; short orig_sort; menu = mutt_new_menu (MENU_POST); menu->make_entry = post_entry; menu->max = PostContext->msgcount; menu->title = _("Postponed Messages"); menu->data = PostContext; menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_POST, PostponeHelp); /* The postponed mailbox is setup to have sorting disabled, but the global * Sort variable may indicate something different. Sorting has to be * disabled while the postpone menu is being displayed. */ orig_sort = Sort; Sort = SORT_ORDER; while (!done) { switch (i = mutt_menuLoop (menu)) { case OP_DELETE: case OP_UNDELETE: /* should deleted draft messages be saved in the trash folder? */ mutt_set_flag (PostContext, PostContext->hdrs[menu->current], MUTT_DELETE, (i == OP_DELETE) ? 1 : 0); PostCount = PostContext->msgcount - PostContext->deleted; if (option (OPTRESOLVE) && menu->current < menu->max - 1) { menu->oldcurrent = menu->current; menu->current++; if (menu->current >= menu->top + menu->pagelen) { menu->top = menu->current; menu->redraw = REDRAW_INDEX | REDRAW_STATUS; } else menu->redraw |= REDRAW_MOTION_RESYNCH; } else menu->redraw = REDRAW_CURRENT; break; case OP_GENERIC_SELECT_ENTRY: r = menu->current; done = 1; break; case OP_EXIT: done = 1; break; } } Sort = orig_sort; mutt_menuDestroy (&menu); return (r > -1 ? PostContext->hdrs[r] : NULL); }
static HEADER *select_msg (void) { MUTTMENU *menu; int i, done=0, r=-1; char helpstr[SHORT_STRING]; menu = mutt_new_menu (); menu->make_entry = post_entry; menu->menu = MENU_POST; menu->max = PostContext->msgcount; menu->title = _("Postponed Messages"); menu->data = PostContext; menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_POST, PostponeHelp); while (!done) { switch (i = mutt_menuLoop (menu)) { case OP_DELETE: case OP_UNDELETE: mutt_set_flag (PostContext, PostContext->hdrs[menu->current], M_DELETE, (i == OP_DELETE) ? 1 : 0); PostCount = PostContext->msgcount - PostContext->deleted; if (option (OPTRESOLVE) && menu->current < menu->max - 1) { menu->oldcurrent = menu->current; menu->current++; if (menu->current >= menu->top + menu->pagelen) { menu->top = menu->current; menu->redraw = REDRAW_INDEX | REDRAW_STATUS; } else menu->redraw |= REDRAW_MOTION_RESYNCH; } else menu->redraw = REDRAW_CURRENT; break; case OP_GENERIC_SELECT_ENTRY: r = menu->current; done = 1; break; case OP_EXIT: done = 1; break; } } mutt_menuDestroy (&menu); return (r > -1 ? PostContext->hdrs[r] : NULL); }
static pgp_key_t pgp_select_key (pgp_key_t keys, ADDRESS * p, const char *s) { int keymax; pgp_uid_t **KeyTable; MUTTMENU *menu; int i, done = 0; char helpstr[LONG_STRING], buf[LONG_STRING], tmpbuf[STRING]; char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX]; FILE *fp, *devnull; pid_t thepid; pgp_key_t kp; pgp_uid_t *a; int (*f) (const void *, const void *); int unusable = 0; keymax = 0; KeyTable = NULL; for (i = 0, kp = keys; kp; kp = kp->next) { if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) { unusable = 1; continue; } for (a = kp->address; a; a = a->next) { if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) { unusable = 1; continue; } if (i == keymax) { keymax += 5; safe_realloc (&KeyTable, sizeof (pgp_uid_t *) * keymax); } KeyTable[i++] = a; } } if (!i && unusable) { mutt_error _("All matching keys are expired, revoked, or disabled."); mutt_sleep (1); return NULL; } switch (PgpSortKeys & SORT_MASK) { case SORT_DATE: f = pgp_compare_date; break; case SORT_KEYID: f = pgp_compare_keyid; break; case SORT_ADDRESS: f = pgp_compare_address; break; case SORT_TRUST: default: f = pgp_compare_trust; break; } qsort (KeyTable, i, sizeof (pgp_uid_t *), f); helpstr[0] = 0; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP, OP_GENERIC_SELECT_ENTRY); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP, OP_VERIFY_KEY); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ menu = mutt_new_menu (MENU_PGP); menu->max = i; menu->make_entry = pgp_entry; menu->help = helpstr; menu->data = KeyTable; if (p) snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox); else snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s); menu->title = buf; kp = NULL; mutt_clear_error (); while (!done) { switch (mutt_menuLoop (menu)) { case OP_VERIFY_KEY: mutt_mktemp (tempfile, sizeof (tempfile)); if ((devnull = fopen ("/dev/null", "w")) == NULL) /* __FOPEN_CHECKED__ */ { mutt_perror _("Can't open /dev/null"); break; } if ((fp = safe_fopen (tempfile, "w")) == NULL) { safe_fclose (&devnull); mutt_perror _("Can't create temporary file"); break; } mutt_message _("Invoking PGP..."); snprintf (tmpbuf, sizeof (tmpbuf), "0x%s", pgp_fpr_or_lkeyid (pgp_principal_key (KeyTable[menu->current]->parent))); if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1, fileno (fp), fileno (devnull), tmpbuf)) == -1) { mutt_perror _("Can't create filter"); unlink (tempfile); safe_fclose (&fp); safe_fclose (&devnull); } mutt_wait_filter (thepid); safe_fclose (&fp); safe_fclose (&devnull); mutt_clear_error (); snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent))); mutt_do_pager (cmd, tempfile, 0, NULL); menu->redraw = REDRAW_FULL; break; case OP_VIEW_ID: mutt_message ("%s", NONULL (KeyTable[menu->current]->addr)); break; case OP_GENERIC_SELECT_ENTRY: /* XXX make error reporting more verbose */ if (option (OPTPGPCHECKTRUST)) if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) { mutt_error _("This key can't be used: expired/disabled/revoked."); break; } if (option (OPTPGPCHECKTRUST) && (!pgp_id_is_valid (KeyTable[menu->current]) || !pgp_id_is_strong (KeyTable[menu->current]))) { char *s = ""; char buff[LONG_STRING]; if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE) s = N_("ID is expired/disabled/revoked."); else switch (KeyTable[menu->current]->trust & 0x03) { case 0: s = N_("ID has undefined validity."); break; case 1: s = N_("ID is not valid."); break; case 2: s = N_("ID is only marginally valid."); break; } snprintf (buff, sizeof (buff), _("%s Do you really want to use the key?"), _(s)); if (mutt_yesorno (buff, M_NO) != M_YES) { mutt_clear_error (); break; } } # if 0 kp = pgp_principal_key (KeyTable[menu->current]->parent); # else kp = KeyTable[menu->current]->parent; # endif done = 1; break; case OP_EXIT: kp = NULL; done = 1; break; } } mutt_menuDestroy (&menu); FREE (&KeyTable); set_option (OPTNEEDREDRAW); return (kp); }
static void query_menu(char *buf, size_t buflen, QUERY *results, int retbuf) { MUTTMENU *menu; HEADER *msg = NULL; ENTRY *QueryTable = NULL; QUERY *queryp = NULL; int i, done = 0; int op; char helpstr[LONG_STRING]; char title[STRING]; snprintf(title, sizeof(title), _("Query")); /* FIXME */ menu = mutt_new_menu(MENU_QUERY); menu->make_entry = query_entry; menu->search = query_search; menu->tag = query_tag; menu->title = title; menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_QUERY, QueryHelp); if (results == NULL) { /* Prompt for Query */ if ((mutt_get_field(_("Query: "), buf, buflen, 0) == 0) && buf[0]) { results = run_query(buf, 0); } } if (results) { snprintf(title, sizeof(title), _("Query '%s'"), buf); /* count the number of results */ for (queryp = results; queryp; queryp = queryp->next) menu->max++; menu->data = QueryTable = (ENTRY *)safe_calloc(menu->max, sizeof(ENTRY)); for (i = 0, queryp = results; queryp; queryp = queryp->next, i++) QueryTable[i].data = queryp; while (!done) { switch ((op = mutt_menuLoop(menu))) { case OP_QUERY_APPEND: case OP_QUERY: if ((mutt_get_field(_("Query: "), buf, buflen, 0) == 0) && buf[0]) { QUERY *newresults = NULL; newresults = run_query(buf, 0); menu->redraw = REDRAW_FULL; if (newresults) { snprintf(title, sizeof(title), _("Query '%s'"), buf); if (op == OP_QUERY) { free_query(&results); results = newresults; safe_free(&QueryTable); } else { /* append */ for (queryp = results; queryp->next; queryp = queryp->next) ; queryp->next = newresults; } menu->current = 0; mutt_menuDestroy(&menu); menu = mutt_new_menu(MENU_QUERY); menu->make_entry = query_entry; menu->search = query_search; menu->tag = query_tag; menu->title = title; menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_QUERY, QueryHelp); /* count the number of results */ for (queryp = results; queryp; queryp = queryp->next) menu->max++; if (op == OP_QUERY) { menu->data = QueryTable = (ENTRY *)safe_calloc(menu->max, sizeof(ENTRY)); for (i = 0, queryp = results; queryp; queryp = queryp->next, i++) QueryTable[i].data = queryp; } else { int clear = 0; /* append */ safe_realloc(&QueryTable, menu->max * sizeof(ENTRY)); menu->data = QueryTable; for (i = 0, queryp = results; queryp; queryp = queryp->next, i++) { /* once we hit new entries, clear/init the tag */ if (queryp == newresults) clear = 1; QueryTable[i].data = queryp; if (clear) QueryTable[i].tagged = 0; } } } } break; case OP_CREATE_ALIAS: if (menu->tagprefix) { ADDRESS *naddr = NULL; for (i = 0; i < menu->max; i++) if (QueryTable[i].tagged) { ADDRESS *a = result_to_addr(QueryTable[i].data); rfc822_append(&naddr, a, 0); rfc822_free_address(&a); } mutt_create_alias(NULL, naddr); } else { ADDRESS *a = result_to_addr(QueryTable[menu->current].data); mutt_create_alias(NULL, a); rfc822_free_address(&a); } break; case OP_GENERIC_SELECT_ENTRY: if (retbuf) { done = 2; break; } /* fall through to OP_MAIL */ case OP_MAIL: msg = mutt_new_header(); msg->env = mutt_new_envelope(); if (!menu->tagprefix) { msg->env->to = result_to_addr(QueryTable[menu->current].data); } else { for (i = 0; i < menu->max; i++) if (QueryTable[i].tagged) { ADDRESS *a = result_to_addr(QueryTable[i].data); rfc822_append(&msg->env->to, a, 0); rfc822_free_address(&a); } } ci_send_message(0, msg, NULL, Context, NULL); menu->redraw = REDRAW_FULL; break; case OP_EXIT: done = 1; break; } } /* if we need to return the selected entries */ if (retbuf && (done == 2)) { int tagged = 0; size_t curpos = 0; memset(buf, 0, buflen); /* check for tagged entries */ for (i = 0; i < menu->max; i++) { if (QueryTable[i].tagged) { if (curpos == 0) { ADDRESS *tmpa = result_to_addr(QueryTable[i].data); mutt_addrlist_to_local(tmpa); tagged = 1; rfc822_write_address(buf, buflen, tmpa, 0); curpos = mutt_strlen(buf); rfc822_free_address(&tmpa); } else if (curpos + 2 < buflen) { ADDRESS *tmpa = result_to_addr(QueryTable[i].data); mutt_addrlist_to_local(tmpa); strcat(buf, ", "); /* __STRCAT_CHECKED__ */ rfc822_write_address((char *)buf + curpos + 1, buflen - curpos - 1, tmpa, 0); curpos = mutt_strlen(buf); rfc822_free_address(&tmpa); } } } /* then enter current message */ if (!tagged) { ADDRESS *tmpa = result_to_addr(QueryTable[menu->current].data); mutt_addrlist_to_local(tmpa); rfc822_write_address(buf, buflen, tmpa, 0); rfc822_free_address(&tmpa); } } free_query(&results); safe_free(&QueryTable); /* tell whoever called me to redraw the screen when I return */ globals.set_option(OPTNEEDREDRAW); } mutt_menuDestroy(&menu); }
static int tls_check_one_certificate (const gnutls_datum_t *certdata, gnutls_certificate_status certstat, const char* hostname, int idx, int len) { int certerr, savedcert; gnutls_x509_crt cert; char buf[SHORT_STRING]; char fpbuf[SHORT_STRING]; size_t buflen; char dn_common_name[SHORT_STRING]; char dn_email[SHORT_STRING]; char dn_organization[SHORT_STRING]; char dn_organizational_unit[SHORT_STRING]; char dn_locality[SHORT_STRING]; char dn_province[SHORT_STRING]; char dn_country[SHORT_STRING]; time_t t; char datestr[30]; MUTTMENU *menu; char helpstr[LONG_STRING]; char title[STRING]; FILE *fp; gnutls_datum pemdata; int i, row, done, ret; if (!tls_check_preauth (certdata, certstat, hostname, idx, &certerr, &savedcert)) return 1; /* skip signers if insecure algorithm was used */ if (idx && (certerr & CERTERR_INSECUREALG)) { if (idx == 1) { mutt_error (_("Warning: Server certificate was signed using an insecure algorithm")); mutt_sleep (2); } return 0; } /* interactive check from user */ if (gnutls_x509_crt_init (&cert) < 0) { mutt_error (_("Error initialising gnutls certificate data")); mutt_sleep (2); return 0; } if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0) { mutt_error (_("Error processing certificate data")); mutt_sleep (2); gnutls_x509_crt_deinit (cert); return -1; } menu = mutt_new_menu (-1); menu->max = 25; menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *)); for (i = 0; i < menu->max; i++) menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char)); row = 0; strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING); row++; buflen = sizeof (dn_common_name); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn_common_name, &buflen) != 0) dn_common_name[0] = '\0'; buflen = sizeof (dn_email); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, dn_email, &buflen) != 0) dn_email[0] = '\0'; buflen = sizeof (dn_organization); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, dn_organization, &buflen) != 0) dn_organization[0] = '\0'; buflen = sizeof (dn_organizational_unit); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, dn_organizational_unit, &buflen) != 0) dn_organizational_unit[0] = '\0'; buflen = sizeof (dn_locality); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, dn_locality, &buflen) != 0) dn_locality[0] = '\0'; buflen = sizeof (dn_province); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, dn_province, &buflen) != 0) dn_province[0] = '\0'; buflen = sizeof (dn_country); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, dn_country, &buflen) != 0) dn_country[0] = '\0'; snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email); snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization); snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit); snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s", dn_locality, dn_province, dn_country); row++; strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING); row++; buflen = sizeof (dn_common_name); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn_common_name, &buflen) != 0) dn_common_name[0] = '\0'; buflen = sizeof (dn_email); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, dn_email, &buflen) != 0) dn_email[0] = '\0'; buflen = sizeof (dn_organization); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, dn_organization, &buflen) != 0) dn_organization[0] = '\0'; buflen = sizeof (dn_organizational_unit); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, dn_organizational_unit, &buflen) != 0) dn_organizational_unit[0] = '\0'; buflen = sizeof (dn_locality); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, dn_locality, &buflen) != 0) dn_locality[0] = '\0'; buflen = sizeof (dn_province); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, dn_province, &buflen) != 0) dn_province[0] = '\0'; buflen = sizeof (dn_country); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, dn_country, &buflen) != 0) dn_country[0] = '\0'; snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email); snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization); snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit); snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s", dn_locality, dn_province, dn_country); row++; snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid")); t = gnutls_x509_crt_get_activation_time (cert); snprintf (menu->dialog[row++], SHORT_STRING, _(" from %s"), tls_make_date (t, datestr, 30)); t = gnutls_x509_crt_get_expiration_time (cert); snprintf (menu->dialog[row++], SHORT_STRING, _(" to %s"), tls_make_date (t, datestr, 30)); fpbuf[0] = '\0'; tls_fingerprint (GNUTLS_DIG_SHA, fpbuf, sizeof (fpbuf), certdata); snprintf (menu->dialog[row++], SHORT_STRING, _("SHA1 Fingerprint: %s"), fpbuf); fpbuf[0] = '\0'; tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), certdata); snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf); if (certerr & CERTERR_NOTYETVALID) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING); } if (certerr & CERTERR_EXPIRED) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING); } if (certerr & CERTERR_REVOKED) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING); } if (certerr & CERTERR_HOSTNAME) { row++; strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING); } if (certerr & CERTERR_SIGNERNOTCA) { row++; strfcpy (menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), SHORT_STRING); } snprintf (title, sizeof (title), _("SSL Certificate check (certificate %d of %d in chain)"), len - idx, len); menu->title = title; /* certificates with bad dates, or that are revoked, must be accepted manually each and every time */ if (SslCertFile && !savedcert && !(certerr & (CERTERR_EXPIRED | CERTERR_NOTYETVALID | CERTERR_REVOKED))) { menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); menu->keys = _("roa"); } else { menu->prompt = _("(r)eject, accept (o)nce"); menu->keys = _("ro"); } helpstr[0] = '\0'; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT); safe_strcat (helpstr, sizeof (helpstr), buf); mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP); safe_strcat (helpstr, sizeof (helpstr), buf); menu->help = helpstr; done = 0; set_option (OPTUNBUFFEREDINPUT); while (!done) { switch (mutt_menuLoop (menu)) { case -1: /* abort */ case OP_MAX + 1: /* reject */ case OP_EXIT: done = 1; break; case OP_MAX + 3: /* accept always */ done = 0; if ((fp = fopen (SslCertFile, "a"))) { /* save hostname if necessary */ if (certerr & CERTERR_HOSTNAME) { fprintf(fp, "#H %s %s\n", hostname, fpbuf); done = 1; } if (certerr & CERTERR_NOTTRUSTED) { done = 0; ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", certdata, &pemdata); if (ret == 0) { if (fwrite (pemdata.data, pemdata.size, 1, fp) == 1) { done = 1; } gnutls_free (pemdata.data); } } safe_fclose (&fp); } if (!done) { mutt_error (_("Warning: Couldn't save certificate")); mutt_sleep (2); } else { mutt_message (_("Certificate saved")); mutt_sleep (0); } /* fall through */ case OP_MAX + 2: /* accept once */ done = 2; break; } } unset_option (OPTUNBUFFEREDINPUT); mutt_menuDestroy (&menu); gnutls_x509_crt_deinit (cert); return (done == 2); }
static int interactive_check_cert (X509 *cert, int idx, int len) { static const char * const part[] = {"/CN=", "/Email=", "/O=", "/OU=", "/L=", "/ST=", "/C="}; char helpstr[LONG_STRING]; char buf[STRING]; char title[STRING]; MUTTMENU *menu = mutt_new_menu (-1); int done, row, i; FILE *fp; char *name = NULL, *c; dprint (2, (debugfile, "interactive_check_cert: %s\n", cert->name)); menu->max = 19; menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *)); for (i = 0; i < menu->max; i++) menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char)); row = 0; strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING); row++; name = X509_NAME_oneline (X509_get_subject_name (cert), buf, sizeof (buf)); dprint (2, (debugfile, "oneline: %s\n", name)); for (i = 0; i < 5; i++) { c = x509_get_part (name, part[i]); snprintf (menu->dialog[row++], SHORT_STRING, " %s", c); } row++; strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING); row++; name = X509_NAME_oneline (X509_get_issuer_name (cert), buf, sizeof (buf)); for (i = 0; i < 5; i++) { c = x509_get_part (name, part[i]); snprintf (menu->dialog[row++], SHORT_STRING, " %s", c); } row++; snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid")); snprintf (menu->dialog[row++], SHORT_STRING, _(" from %s"), asn1time_to_string (X509_get_notBefore (cert))); snprintf (menu->dialog[row++], SHORT_STRING, _(" to %s"), asn1time_to_string (X509_get_notAfter (cert))); row++; buf[0] = '\0'; x509_fingerprint (buf, sizeof (buf), cert); snprintf (menu->dialog[row++], SHORT_STRING, _("Fingerprint: %s"), buf); snprintf (title, sizeof (title), _("SSL Certificate check (certificate %d of %d in chain)"), len - idx, len); menu->title = title; if (SslCertFile && (option (OPTSSLVERIFYDATES) == M_NO || (X509_cmp_current_time (X509_get_notAfter (cert)) >= 0 && X509_cmp_current_time (X509_get_notBefore (cert)) < 0))) { menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); menu->keys = _("roa"); } else { menu->prompt = _("(r)eject, accept (o)nce"); menu->keys = _("ro"); } helpstr[0] = '\0'; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT); safe_strcat (helpstr, sizeof (helpstr), buf); mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP); safe_strcat (helpstr, sizeof (helpstr), buf); menu->help = helpstr; done = 0; set_option(OPTUNBUFFEREDINPUT); while (!done) { switch (mutt_menuLoop (menu)) { case -1: /* abort */ case OP_MAX + 1: /* reject */ case OP_EXIT: done = 1; break; case OP_MAX + 3: /* accept always */ done = 0; if ((fp = fopen (SslCertFile, "a"))) { if (PEM_write_X509 (fp, cert)) done = 1; safe_fclose (&fp); } if (!done) { mutt_error (_("Warning: Couldn't save certificate")); mutt_sleep (2); } else { mutt_message (_("Certificate saved")); mutt_sleep (0); } /* fall through */ case OP_MAX + 2: /* accept once */ done = 2; ssl_cache_trusted_cert (cert); break; } } unset_option(OPTUNBUFFEREDINPUT); mutt_menuDestroy (&menu); dprint (2, (debugfile, "ssl interactive_check_cert: done=%d\n", done)); return (done == 2); }
/* return values: * * 1 message should be postponed * 0 normal exit * -1 abort message */ int mutt_compose_menu (HEADER *msg, /* structure for new message */ char *fcc, /* where to save a copy of the message */ size_t fcclen, HEADER *cur, /* current message */ int flags) { char helpstr[LONG_STRING]; char buf[LONG_STRING]; char fname[_POSIX_PATH_MAX]; MUTTMENU *menu; ATTACHPTR **idx = NULL; short idxlen = 0; short idxmax = 0; int i, close = 0; int r = -1; /* return value */ int op = 0; int loop = 1; int fccSet = 0; /* has the user edited the Fcc: field ? */ CONTEXT *ctx = NULL, *this = NULL; /* Sort, SortAux could be changed in mutt_index_menu() */ int oldSort, oldSortAux; struct stat st; mutt_attach_init (msg->content); idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1); menu = mutt_new_menu (MENU_COMPOSE); menu->offset = HDR_ATTACH; menu->max = idxlen; menu->make_entry = snd_entry; menu->tag = mutt_tag_attach; menu->data = idx; menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp); while (loop) { switch (op = mutt_menuLoop (menu)) { case OP_REDRAW: draw_envelope (msg, fcc); menu->offset = HDR_ATTACH; menu->pagelen = LINES - HDR_ATTACH - 2; break; case OP_COMPOSE_EDIT_FROM: menu->redraw = edit_address_list (HDR_FROM, &msg->env->from); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_TO: menu->redraw = edit_address_list (HDR_TO, &msg->env->to); if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) { crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_BCC: menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc); if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) { crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_CC: menu->redraw = edit_address_list (HDR_CC, &msg->env->cc); if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) { crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_SUBJECT: if (msg->env->subject) strfcpy (buf, msg->env->subject, sizeof (buf)); else buf[0] = 0; if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) == 0) { mutt_str_replace (&msg->env->subject, buf); move (HDR_SUBJECT, HDR_XOFFSET); if (msg->env->subject) mutt_paddstr (W, msg->env->subject); else clrtoeol(); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_REPLY_TO: menu->redraw = edit_address_list (HDR_REPLYTO, &msg->env->reply_to); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_FCC: strfcpy (buf, fcc, sizeof (buf)); if (mutt_get_field ("Fcc: ", buf, sizeof (buf), M_FILE | M_CLEAR) == 0) { strfcpy (fcc, buf, fcclen); mutt_pretty_mailbox (fcc, fcclen); move (HDR_FCC, HDR_XOFFSET); mutt_paddstr (W, fcc); fccSet = 1; } MAYBE_REDRAW (menu->redraw); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_MESSAGE: if (Editor && (mutt_strcmp ("builtin", Editor) != 0) && !option (OPTEDITHDRS)) { mutt_edit_file (Editor, msg->content->filename); mutt_update_encoding (msg->content); menu->redraw = REDRAW_FULL; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; } /* fall through */ case OP_COMPOSE_EDIT_HEADERS: if (mutt_strcmp ("builtin", Editor) != 0 && (op == OP_COMPOSE_EDIT_HEADERS || (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS)))) { char *tag = NULL, *err = NULL; mutt_env_to_local (msg->env); mutt_edit_headers (NONULL (Editor), msg->content->filename, msg, fcc, fcclen); if (mutt_env_to_intl (msg->env, &tag, &err)) { mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); FREE (&err); } if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) crypt_opportunistic_encrypt (msg); } else { /* this is grouped with OP_COMPOSE_EDIT_HEADERS because the attachment list could change if the user invokes ~v to edit the message with headers, in which we need to execute the code below to regenerate the index array */ mutt_builtin_editor (msg->content->filename, msg, cur); } mutt_update_encoding (msg->content); /* attachments may have been added */ if (idxlen && idx[idxlen - 1]->content->next) { for (i = 0; i < idxlen; i++) { FREE (&idx[i]->tree); FREE (&idx[i]); } idxlen = 0; idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1); menu->data = idx; menu->max = idxlen; } menu->redraw = REDRAW_FULL; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_ATTACH_KEY: if (!(WithCrypto & APPLICATION_PGP)) break; if (idxlen == idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5)); menu->data = idx; } idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); if ((idx[idxlen]->content = crypt_pgp_make_key_attachment(NULL)) != NULL) { update_idx (menu, idx, idxlen++); menu->redraw |= REDRAW_INDEX; } else FREE (&idx[idxlen]); menu->redraw |= REDRAW_STATUS; if (option(OPTNEEDREDRAW)) { menu->redraw = REDRAW_FULL; unset_option(OPTNEEDREDRAW); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_ATTACH_FILE: { char *prompt, **files; int error, numfiles; fname[0] = 0; prompt = _("Attach file"); numfiles = 0; files = NULL; if (_mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 0, 1, &files, &numfiles) == -1 || *fname == '\0') break; if (idxlen + numfiles >= idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + numfiles)); menu->data = idx; } error = 0; if (numfiles > 1) mutt_message _("Attaching selected files..."); for (i = 0; i < numfiles; i++) { char *att = files[i]; idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); idx[idxlen]->unowned = 1; idx[idxlen]->content = mutt_make_file_attach (att); if (idx[idxlen]->content != NULL) update_idx (menu, idx, idxlen++); else { error = 1; mutt_error (_("Unable to attach %s!"), att); FREE (&idx[idxlen]); } } FREE (&files); if (!error) mutt_clear_error (); menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_ATTACH_MESSAGE: { char *prompt; HEADER *h; fname[0] = 0; prompt = _("Open mailbox to attach message from"); if (Context) { strfcpy (fname, NONULL (Context->path), sizeof (fname)); mutt_pretty_mailbox (fname, sizeof (fname)); } if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1) == -1 || !fname[0]) break; mutt_expand_path (fname, sizeof (fname)); #ifdef USE_IMAP if (!mx_is_imap (fname)) #endif #ifdef USE_POP if (!mx_is_pop (fname)) #endif /* check to make sure the file exists and is readable */ if (access (fname, R_OK) == -1) { mutt_perror (fname); break; } menu->redraw = REDRAW_FULL; ctx = mx_open_mailbox (fname, M_READONLY, NULL); if (ctx == NULL) { mutt_error (_("Unable to open mailbox %s"), fname); break; } if (!ctx->msgcount) { mx_close_mailbox (ctx, NULL); FREE (&ctx); mutt_error _("No messages in that folder."); break; } this = Context; /* remember current folder and sort methods*/ oldSort = Sort; oldSortAux = SortAux; Context = ctx; set_option(OPTATTACHMSG); mutt_message _("Tag the messages you want to attach!"); close = mutt_index_menu (); unset_option(OPTATTACHMSG); if (!Context) { /* go back to the folder we started from */ Context = this; /* Restore old $sort and $sort_aux */ Sort = oldSort; SortAux = oldSortAux; menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; break; } if (idxlen + Context->tagged >= idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + Context->tagged)); menu->data = idx; } for (i = 0; i < Context->msgcount; i++) { h = Context->hdrs[i]; if (h->tagged) { idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); idx[idxlen]->content = mutt_make_message_attach (Context, h, 1); if (idx[idxlen]->content != NULL) update_idx (menu, idx, idxlen++); else { mutt_error _("Unable to attach!"); FREE (&idx[idxlen]); } } } menu->redraw |= REDRAW_FULL; if (close == OP_QUIT) mx_close_mailbox (Context, NULL); else mx_fastclose_mailbox (Context); FREE (&Context); /* go back to the folder we started from */ Context = this; /* Restore old $sort and $sort_aux */ Sort = oldSort; SortAux = oldSortAux; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_DELETE: CHECK_COUNT; if (idx[menu->current]->unowned) idx[menu->current]->content->unlink = 0; if (delete_attachment (menu, &idxlen, menu->current) == -1) break; mutt_update_tree (idx, idxlen); if (idxlen) { if (menu->current > idxlen - 1) menu->current = idxlen - 1; } else menu->current = 0; if (menu->current == 0) msg->content = idx[0]->content; menu->redraw |= REDRAW_STATUS; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; #define CURRENT idx[menu->current]->content case OP_COMPOSE_TOGGLE_RECODE: { CHECK_COUNT; if (!mutt_is_text_part (CURRENT)) { mutt_error (_("Recoding only affects text attachments.")); break; } CURRENT->noconv = !CURRENT->noconv; if (CURRENT->noconv) mutt_message (_("The current attachment won't be converted.")); else mutt_message (_("The current attachment will be converted.")); menu->redraw = REDRAW_CURRENT; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; } #undef CURRENT case OP_COMPOSE_EDIT_DESCRIPTION: CHECK_COUNT; strfcpy (buf, idx[menu->current]->content->description ? idx[menu->current]->content->description : "", sizeof (buf)); /* header names should not be translated */ if (mutt_get_field ("Description: ", buf, sizeof (buf), 0) == 0) { mutt_str_replace (&idx[menu->current]->content->description, buf); menu->redraw = REDRAW_CURRENT; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_UPDATE_ENCODING: CHECK_COUNT; if (menu->tagprefix) { BODY *top; for (top = msg->content; top; top = top->next) { if (top->tagged) mutt_update_encoding (top); } menu->redraw = REDRAW_FULL; } else { mutt_update_encoding(idx[menu->current]->content); menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_TOGGLE_DISPOSITION: /* toggle the content-disposition between inline/attachment */ idx[menu->current]->content->disposition = (idx[menu->current]->content->disposition == DISPINLINE) ? DISPATTACH : DISPINLINE; menu->redraw = REDRAW_CURRENT; break; case OP_EDIT_TYPE: CHECK_COUNT; { mutt_edit_content_type (NULL, idx[menu->current]->content, NULL); /* this may have been a change to text/something */ mutt_update_encoding (idx[menu->current]->content); menu->redraw = REDRAW_CURRENT; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_ENCODING: CHECK_COUNT; strfcpy (buf, ENCODING (idx[menu->current]->content->encoding), sizeof (buf)); if (mutt_get_field ("Content-Transfer-Encoding: ", buf, sizeof (buf), 0) == 0 && buf[0]) { if ((i = mutt_check_encoding (buf)) != ENCOTHER && i != ENCUUENCODED) { idx[menu->current]->content->encoding = i; menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; mutt_clear_error(); } else mutt_error _("Invalid encoding."); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_SEND_MESSAGE: /* Note: We don't invoke send2-hook here, since we want to leave * users an opportunity to change settings from the ":" prompt. */ if(check_attachments(idx, idxlen) != 0) { menu->redraw = REDRAW_FULL; break; } #ifdef MIXMASTER if (msg->chain && mix_check_message (msg) != 0) break; #endif if (!fccSet && *fcc) { if ((i = query_quadoption (OPT_COPY, _("Save a copy of this message?"))) == -1) break; else if (i == M_NO) *fcc = 0; } loop = 0; r = 0; break; case OP_COMPOSE_EDIT_FILE: CHECK_COUNT; mutt_edit_file (NONULL(Editor), idx[menu->current]->content->filename); mutt_update_encoding (idx[menu->current]->content); menu->redraw = REDRAW_CURRENT | REDRAW_STATUS; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_TOGGLE_UNLINK: CHECK_COUNT; idx[menu->current]->content->unlink = !idx[menu->current]->content->unlink; #if 0 /* OPTRESOLVE is otherwise ignored on this menu. * Where's the bug? */ if (option (OPTRESOLVE) && menu->current + 1 < menu->max) menu->current++; # endif menu->redraw = REDRAW_INDEX; /* No send2hook since this doesn't change the message. */ break; case OP_COMPOSE_GET_ATTACHMENT: CHECK_COUNT; if(menu->tagprefix) { BODY *top; for(top = msg->content; top; top = top->next) { if(top->tagged) mutt_get_tmp_attachment(top); } menu->redraw = REDRAW_FULL; } else if (mutt_get_tmp_attachment(idx[menu->current]->content) == 0) menu->redraw = REDRAW_CURRENT; /* No send2hook since this doesn't change the message. */ break; case OP_COMPOSE_RENAME_FILE: CHECK_COUNT; strfcpy (fname, idx[menu->current]->content->filename, sizeof (fname)); mutt_pretty_mailbox (fname, sizeof (fname)); if (mutt_get_field (_("Rename to: "), fname, sizeof (fname), M_FILE) == 0 && fname[0]) { if (stat(idx[menu->current]->content->filename, &st) == -1) { /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */ mutt_error (_("Can't stat %s: %s"), fname, strerror (errno)); break; } mutt_expand_path (fname, sizeof (fname)); if(mutt_rename_file (idx[menu->current]->content->filename, fname)) break; mutt_str_replace (&idx[menu->current]->content->filename, fname); menu->redraw = REDRAW_CURRENT; if(idx[menu->current]->content->stamp >= st.st_mtime) mutt_stamp_attachment(idx[menu->current]->content); } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_NEW_MIME: { char type[STRING]; char *p; int itype; FILE *fp; CLEARLINE (LINES-1); fname[0] = 0; if (mutt_get_field (_("New file: "), fname, sizeof (fname), M_FILE) != 0 || !fname[0]) continue; mutt_expand_path (fname, sizeof (fname)); /* Call to lookup_mime_type () ? maybe later */ type[0] = 0; if (mutt_get_field ("Content-Type: ", type, sizeof (type), 0) != 0 || !type[0]) continue; if (!(p = strchr (type, '/'))) { mutt_error _("Content-Type is of the form base/sub"); continue; } *p++ = 0; if ((itype = mutt_check_mime_type (type)) == TYPEOTHER) { mutt_error (_("Unknown Content-Type %s"), type); continue; } if (idxlen == idxmax) { safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5)); menu->data = idx; } idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR)); /* Touch the file */ if (!(fp = safe_fopen (fname, "w"))) { mutt_error (_("Can't create file %s"), fname); FREE (&idx[idxlen]); continue; } safe_fclose (&fp); if ((idx[idxlen]->content = mutt_make_file_attach (fname)) == NULL) { mutt_error _("What we have here is a failure to make an attachment"); continue; } update_idx (menu, idx, idxlen++); idx[menu->current]->content->type = itype; mutt_str_replace (&idx[menu->current]->content->subtype, p); idx[menu->current]->content->unlink = 1; menu->redraw |= REDRAW_INDEX | REDRAW_STATUS; if (mutt_compose_attachment (idx[menu->current]->content)) { mutt_update_encoding (idx[menu->current]->content); menu->redraw = REDRAW_FULL; } } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_MIME: CHECK_COUNT; if (mutt_edit_attachment (idx[menu->current]->content)) { mutt_update_encoding (idx[menu->current]->content); menu->redraw = REDRAW_FULL; } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_VIEW_ATTACH: case OP_DISPLAY_HEADERS: CHECK_COUNT; mutt_attach_display_loop (menu, op, NULL, NULL, NULL, &idx, &idxlen, NULL, 0); menu->redraw = REDRAW_FULL; /* no send2hook, since this doesn't modify the message */ break; case OP_SAVE: CHECK_COUNT; mutt_save_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, NULL, menu); MAYBE_REDRAW (menu->redraw); /* no send2hook, since this doesn't modify the message */ break; case OP_PRINT: CHECK_COUNT; mutt_print_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content); /* no send2hook, since this doesn't modify the message */ break; case OP_PIPE: case OP_FILTER: CHECK_COUNT; mutt_pipe_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, op == OP_FILTER); if (op == OP_FILTER) /* cte might have changed */ menu->redraw = menu->tagprefix ? REDRAW_FULL : REDRAW_CURRENT; menu->redraw |= REDRAW_STATUS; mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_EXIT: if ((i = query_quadoption (OPT_POSTPONE, _("Postpone this message?"))) == M_NO) { for (i = 0; i < idxlen; i++) if (idx[i]->unowned) idx[i]->content->unlink = 0; if (!(flags & M_COMPOSE_NOFREEHEADER)) { while (idxlen-- > 0) { /* avoid freeing other attachments */ idx[idxlen]->content->next = NULL; idx[idxlen]->content->parts = NULL; mutt_free_body (&idx[idxlen]->content); FREE (&idx[idxlen]->tree); FREE (&idx[idxlen]); } FREE (&idx); idxlen = 0; idxmax = 0; } r = -1; loop = 0; break; } else if (i == -1) break; /* abort */ /* fall through to postpone! */ case OP_COMPOSE_POSTPONE_MESSAGE: if(check_attachments(idx, idxlen) != 0) { menu->redraw = REDRAW_FULL; break; } loop = 0; r = 1; break; case OP_COMPOSE_ISPELL: endwin (); snprintf (buf, sizeof (buf), "%s -x %s", NONULL(Ispell), msg->content->filename); if (mutt_system (buf) == -1) mutt_error (_("Error running \"%s\"!"), buf); else { mutt_update_encoding (msg->content); menu->redraw |= REDRAW_STATUS; } break; case OP_COMPOSE_WRITE_MESSAGE: fname[0] = '\0'; if (Context) { strfcpy (fname, NONULL (Context->path), sizeof (fname)); mutt_pretty_mailbox (fname, sizeof (fname)); } if (idxlen) msg->content = idx[0]->content; if (mutt_enter_fname (_("Write message to mailbox"), fname, sizeof (fname), &menu->redraw, 1) != -1 && fname[0]) { mutt_message (_("Writing message to %s ..."), fname); mutt_expand_path (fname, sizeof (fname)); if (msg->content->next) msg->content = mutt_make_multipart (msg->content); if (mutt_write_fcc (fname, msg, NULL, 0, NULL) < 0) msg->content = mutt_remove_multipart (msg->content); else mutt_message _("Message written."); } break; case OP_COMPOSE_PGP_MENU: if (!(WithCrypto & APPLICATION_PGP)) break; if ((WithCrypto & APPLICATION_SMIME) && (msg->security & APPLICATION_SMIME)) { if (msg->security & (ENCRYPT | SIGN)) { if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "), M_YES) != M_YES) { mutt_clear_error (); break; } msg->security &= ~(ENCRYPT | SIGN); } msg->security &= ~APPLICATION_SMIME; msg->security |= APPLICATION_PGP; crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } msg->security = crypt_pgp_send_menu (msg, &menu->redraw); redraw_crypt_lines (msg); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_FORGET_PASSPHRASE: crypt_forget_passphrase (); break; case OP_COMPOSE_SMIME_MENU: if (!(WithCrypto & APPLICATION_SMIME)) break; if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP)) { if (msg->security & (ENCRYPT | SIGN)) { if (mutt_yesorno (_("PGP already selected. Clear & continue ? "), M_YES) != M_YES) { mutt_clear_error (); break; } msg->security &= ~(ENCRYPT | SIGN); } msg->security &= ~APPLICATION_PGP; msg->security |= APPLICATION_SMIME; crypt_opportunistic_encrypt (msg); redraw_crypt_lines (msg); } msg->security = crypt_smime_send_menu(msg, &menu->redraw); redraw_crypt_lines (msg); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; #ifdef MIXMASTER case OP_COMPOSE_MIX: mix_make_chain (&msg->chain, &menu->redraw); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; #endif } /* Draw formatted compose status line */ if (menu->redraw & REDRAW_STATUS) { compose_status_line (buf, sizeof (buf), 0, menu, NONULL(ComposeFormat)); move(option (OPTSTATUSONTOP) ? 0 : LINES-2, 0); SETCOLOR (MT_COLOR_STATUS); mutt_paddstr (COLS, buf); NORMAL_COLOR; menu->redraw &= ~REDRAW_STATUS; } } mutt_menuDestroy (&menu); if (idxlen) { msg->content = idx[0]->content; for (i = 0; i < idxlen; i++) { idx[i]->content->aptr = NULL; FREE (&idx[i]->tree); FREE (&idx[i]); } } else msg->content = NULL; FREE (&idx); return (r); }
static smime_key_t *smime_select_key(smime_key_t *keys, char *query) { smime_key_t **table = NULL; int table_size = 0; int table_index = 0; smime_key_t *key = NULL; smime_key_t *selected_key = NULL; char helpstr[LONG_STRING]; char buf[LONG_STRING]; char title[256]; MUTTMENU* menu; char *s = ""; int done = 0; for (table_index = 0, key = keys; key; key = key->next) { if (table_index == table_size) { table_size += 5; safe_realloc(&table, sizeof(smime_key_t *) * table_size); } table[table_index++] = key; } snprintf(title, sizeof(title),("S/MIME certificates matching \"%s\"."), query); /* Make Helpstring */ helpstr[0] = 0; mutt_make_help(buf, sizeof(buf),("Exit "), MENU_SMIME, OP_EXIT); strcat(helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help(buf, sizeof(buf),("Select "), MENU_SMIME, OP_GENERIC_SELECT_ENTRY); strcat(helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help(buf, sizeof(buf),("Help"), MENU_SMIME, OP_HELP); strcat(helpstr, buf); /* __STRCAT_CHECKED__ */ /* Create the menu */ menu = mutt_new_menu(MENU_SMIME); menu->max = table_index; menu->make_entry = smime_entry; menu->help = helpstr; menu->data = table; menu->title = title; /* sorting keys might be done later - TODO */ mutt_clear_error (); done = 0; while (!done) { switch(mutt_menuLoop(menu)) { case OP_GENERIC_SELECT_ENTRY: if (table[menu->current]->trust != 't') { switch(table[menu->current]->trust) { case 'i': case 'r': case 'e': s =("ID is expired/disabled/revoked."); break; case 'u': s =("ID has undefined validity."); break; case 'v': s =("ID is not trusted."); break; } snprintf(buf, sizeof(buf),("%s Do you really want to use the key?"), (s)); if (mutt_yesorno(buf, M_NO) != M_YES) { mutt_clear_error (); break; } } selected_key = table[menu->current]; done = 1; break; case OP_EXIT: done = 1; break; } } mutt_menuDestroy(&menu); safe_free(&table); set_bit(options, OPTNEEDREDRAW); return selected_key; }
void mix_make_chain (LIST **chainp, int *redraw) { LIST *p; MIXCHAIN *chain; int c_cur = 0, c_old = 0; short c_redraw = 1; REMAILER **type2_list = NULL; size_t ttll = 0; struct coord *coords = NULL; MUTTMENU *menu; char helpstr[LONG_STRING]; short loop = 1; int op; int i, j; char *t; if (!(type2_list = mix_type2_list (&ttll))) { mutt_error _("Can't get mixmaster's type2.list!"); return; } *redraw = REDRAW_FULL; chain = safe_calloc (sizeof (MIXCHAIN), 1); for (p = *chainp; p; p = p->next) mix_chain_add (chain, (char *) p->data, type2_list); mutt_free_list (chainp); /* safety check */ for (i = 0; i < chain->cl; i++) { if (chain->ch[i] >= ttll) chain->ch[i] = 0; } mix_screen_coordinates (type2_list, &coords, chain, 0); menu = mutt_new_menu (MENU_MIX); menu->max = ttll; menu->make_entry = mix_entry; menu->tag = NULL; menu->title = _("Select a remailer chain."); menu->data = type2_list; menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MIX, RemailerHelp); menu->pagelen = MIX_VOFFSET - 1; while (loop) { if (menu->pagelen != MIX_VOFFSET - 1) { menu->pagelen = MIX_VOFFSET - 1; menu->redraw = REDRAW_FULL; } if (c_redraw) { mix_redraw_head (chain); mix_redraw_chain (type2_list, coords, chain, c_cur); c_redraw = 0; } else if (c_cur != c_old) { mix_redraw_ce (type2_list, coords, chain, c_old, 0); mix_redraw_ce (type2_list, coords, chain, c_cur, 1); } c_old = c_cur; switch ((op = mutt_menuLoop (menu))) { case OP_REDRAW: { menu_redraw_status (menu); mix_redraw_head (chain); mix_screen_coordinates (type2_list, &coords, chain, 0); mix_redraw_chain (type2_list, coords, chain, c_cur); menu->pagelen = MIX_VOFFSET - 1; break; } case OP_EXIT: { chain->cl = 0; loop = 0; break; } case OP_MIX_USE: { if (!chain->cl) { chain->cl++; chain->ch[0] = menu->current; mix_screen_coordinates (type2_list, &coords, chain, c_cur); c_redraw = 1; } if (chain->cl && chain->ch[chain->cl - 1] && (type2_list[chain->ch[chain->cl-1]]->caps & MIX_CAP_MIDDLEMAN)) { mutt_error ( _("Error: %s can't be used as the final remailer of a chain."), type2_list[chain->ch[chain->cl - 1]]->shortname); } else { loop = 0; } break; } case OP_GENERIC_SELECT_ENTRY: case OP_MIX_APPEND: { if (chain->cl < MAXMIXES && c_cur < chain->cl) c_cur++; } /* fallthrough */ case OP_MIX_INSERT: { if (chain->cl < MAXMIXES) { chain->cl++; for (i = chain->cl - 1; i > c_cur; i--) chain->ch[i] = chain->ch[i-1]; chain->ch[c_cur] = menu->current; mix_screen_coordinates (type2_list, &coords, chain, c_cur); c_redraw = 1; } else mutt_error ( _("Mixmaster chains are limited to %d elements."), MAXMIXES); break; } case OP_MIX_DELETE: { if (chain->cl) { chain->cl--; for (i = c_cur; i < chain->cl; i++) chain->ch[i] = chain->ch[i+1]; if (c_cur == chain->cl && c_cur) c_cur--; mix_screen_coordinates (type2_list, &coords, chain, c_cur); c_redraw = 1; } else { mutt_error _("The remailer chain is already empty."); } break; } case OP_MIX_CHAIN_PREV: { if (c_cur) c_cur--; else mutt_error _("You already have the first chain element selected."); break; } case OP_MIX_CHAIN_NEXT: { if (chain->cl && c_cur < chain->cl - 1) c_cur++; else mutt_error _("You already have the last chain element selected."); break; } } } mutt_menuDestroy (&menu); /* construct the remailer list */ if (chain->cl) { for (i = 0; i < chain->cl; i++) { if ((j = chain->ch[i])) t = type2_list[j]->shortname; else t = "*"; *chainp = mutt_add_list (*chainp, t); } } mix_free_type2_list (&type2_list); FREE (&coords); FREE (&chain); }