+ if ((in = fopen (filename, "r")) != NULL) {
+ /* There must be a non-blank Envelope-From or {Resent-}Sender or
+ {Resent-}From header. */
+ char *addrformat = "%(addr{Envelope-From})";
+ char *hostformat = "%(host{Envelope-From})";
+
+ if ((*addr = get_message_header_info (in, addrformat)) == NULL ||
+ !**addr) {
+ addrformat = distfile == NULL ? "%(addr{Sender})" : "%(addr{Resent-Sender})";
+ hostformat = distfile == NULL ? "%(host{Sender})" : "%(host{Resent-Sender})";
+
+ if ((*addr = get_message_header_info (in, addrformat)) == NULL) {
+ addrformat = distfile == NULL ? "%(addr{From})" : "%(addr{Resent-From})";
+ hostformat = distfile == NULL ? "%(host{From})" : "%(host{Resent-From})";
+
+ if ((*addr = get_message_header_info (in, addrformat)) == NULL) {
+ *message = "unable to find sender address in";
+ fclose(in);
+ return NOTOK;
+ }
+ }
+ }
+
+ /* Use the hostformat that corresponds to the successful addrformat. */
+ if ((*host = get_message_header_info(in, hostformat)) == NULL) {
+ *message = "unable to find sender host";
+ fclose(in);
+ return NOTOK;
+ }
+ fclose(in);
+
+ return OK;
+ }
+
+ *message = "unable to open";
+ return NOTOK;
+}
+
+
+/*
+ * Get formatted information from header of a message.
+ * Adapted from process_single_file() in uip/fmttest.c.
+ */
+static
+const char *
+get_message_header_info(FILE *in, char *format) {
+ int dat[5];
+ struct format *fmt;
+ struct stat st;
+ int parsing_header;
+ m_getfld_state_t gstate = 0;
+ charstring_t buffer = charstring_create(0);
+ char *retval;
+
+ dat[0] = dat[1] = dat[4] = 0;
+ dat[2] = fstat(fileno(in), &st) == 0 ? st.st_size : 0;
+ dat[3] = INT_MAX;
+
+ (void) fmt_compile(new_fs(NULL, NULL, format), &fmt, 1);
+ free_fs();
+
+ /*
+ * Read in the message and process the header.
+ */
+ rewind (in);
+ parsing_header = 1;
+ do {
+ char name[NAMESZ], rbuf[NMH_BUFSIZ];
+ int bufsz = sizeof rbuf;
+ int state = m_getfld(&gstate, name, rbuf, &bufsz, in);
+
+ switch (state) {
+ case FLD:
+ case FLDPLUS: {
+ int bucket = fmt_addcomptext(name, rbuf);
+
+ if (bucket != -1) {
+ while (state == FLDPLUS) {
+ bufsz = sizeof rbuf;
+ state = m_getfld(&gstate, name, rbuf, &bufsz, in);
+ fmt_appendcomp(bucket, name, rbuf);
+ }
+ }
+
+ while (state == FLDPLUS) {
+ bufsz = sizeof rbuf;
+ state = m_getfld(&gstate, name, rbuf, &bufsz, in);
+ }
+ break;
+ }
+ default:
+ parsing_header = 0;
+ }
+ } while (parsing_header);
+ m_getfld_state_destroy(&gstate);
+
+ fmt_scan(fmt, buffer, INT_MAX, dat, NULL);
+ fmt_free(fmt, 1);
+
+ /* Trim trailing newline, if any. */
+ retval = rtrim(charstring_buffer_copy((buffer)));
+ charstring_free(buffer);
+ if (*retval)
+ return retval;
+
+ free(retval);
+ return NULL;
+}
+
+
+/*
+ * Look in profile for entry corresponding to addr or host, and add its contents to vec.
+ *
+ * Could do some of this automatically, by looking for:
+ * 1) access-$(mbox{from}) in oauth-svc file using mh_oauth_cred_load(), which isn't
+ * static and doesn't have side effects; free the result with mh_oauth_cred_free())
+ * 2) machine $(mbox{from}) in creds
+ * If no -server passed in from profile or commandline, could use smtp.<svc>.com for gmail,
+ * but that might not generalize for other svcs.
+ */
+static
+void
+merge_profile_entry(const char *addr, const char *host, char *vec[], int *vecp) {
+ char *addr_entry = concat("sendfrom-", addr, NULL);
+ char *profile_entry = context_find(addr_entry);
+
+ free(addr_entry);
+ if (profile_entry == NULL) {
+ /* No entry for the user. Look for one for the host. */
+ char *host_entry = concat("sendfrom-", host, NULL);
+
+ profile_entry = context_find(host_entry);
+ free(host_entry);
+ }
+
+ /* Use argsplit() to do the real work of splitting the args in the profile entry. */
+ if (profile_entry && *profile_entry) {
+ int profile_vecp;
+ char *file;
+ char **profile_vec = argsplit(profile_entry, &file, &profile_vecp);
+ int i;
+
+ for (i = 0; i < profile_vecp; ++i) {
+ vec[(*vecp)++] = getcpy(profile_vec[i]);
+ }
+
+ arglist_free(file, profile_vec);
+ }
+}
+
+
+static void NORETURN
+armed_done (int status)
+{
+ longjmp (env, status ? status : NOTOK);