+handle_sendfrom(char **vec, int *vecp, char *draft, const char *auth_svc) {
+ const char *addr, *host;
+ const char *message;
+
+ /* Extract address and host from From: header line in draft. */
+ if (get_from_header_info(draft, &addr, &host, &message) != OK) {
+ adios(draft, message);
+ }
+
+ /* Merge in any address or host specific switches to post(1) from profile. */
+ merge_profile_entry(addr, host, vec, vecp);
+ free((void *) host);
+ free((void *) addr);
+
+ vec[*vecp] = NULL;
+
+ {
+ char **vp;
+
+ for (vp = vec; *vp; ++vp) {
+ if (strcmp(*vp, "xoauth2") == 0) {
+#ifdef OAUTH_SUPPORT
+ if (setup_oauth_params(vec, vecp, auth_svc, &message) != OK) {
+ adios(NULL, message);
+ }
+ break;
+#else
+ NMH_UNUSED(auth_svc);
+ adios(NULL, "send built without OAUTH_SUPPORT, "
+ "so -saslmech xoauth2 is not supported");
+#endif /* OAUTH_SUPPORT */
+ }
+ }
+ }
+}
+
+
+#ifdef OAUTH_SUPPORT
+/*
+ * For XOAUTH2, append profile entries so post can do the heavy lifting
+ */
+static int
+setup_oauth_params(char *vec[], int *vecp, const char *auth_svc,
+ const char **message) {
+ const char *saslmech = NULL, *user = NULL;
+ mh_oauth_service_info svc;
+ char errbuf[256];
+ int i;
+
+ /* Make sure we have all the information we need. */
+ for (i = 1; i < *vecp; ++i) {
+ /* Don't support abbreviated switches, to avoid collisions in the
+ future if new ones are added. */
+ if (! strcmp(vec[i-1], "-saslmech")) {
+ saslmech = vec[i];
+ } else if (! strcmp(vec[i-1], "-user")) {
+ user = vec[i];
+ } else if (! strcmp(vec[i-1], "-authservice")) {
+ auth_svc = vec[i];
+ }
+ }
+
+ if (auth_svc == NULL) {
+ if (saslmech && ! strcasecmp(saslmech, "xoauth2")) {
+ *message = "must specify -authservice with -saslmech xoauth2";
+ return NOTOK;
+ }
+ } else {
+ if (user == NULL) {
+ *message = "must specify -user with -saslmech xoauth2";
+ return NOTOK;
+ }
+
+ if (saslmech && ! strcasecmp(saslmech, "xoauth2")) {
+ if (! mh_oauth_get_service_info(auth_svc, &svc, errbuf,
+ sizeof(errbuf)))
+ adios(NULL, "Unable to retrieve oauth profile entries: %s",
+ errbuf);
+
+ vec[(*vecp)++] = mh_xstrdup("-authservice");
+ vec[(*vecp)++] = mh_xstrdup(auth_svc);
+ vec[(*vecp)++] = mh_xstrdup("-oauthcredfile");
+ vec[(*vecp)++] = mh_xstrdup(mh_oauth_cred_fn(auth_svc));
+ vec[(*vecp)++] = mh_xstrdup("-oauthclientid");
+ vec[(*vecp)++] = getcpy(svc.client_id);
+ vec[(*vecp)++] = mh_xstrdup("-oauthclientsecret");
+ vec[(*vecp)++] = getcpy(svc.client_secret);
+ vec[(*vecp)++] = mh_xstrdup("-oauthauthendpoint");
+ vec[(*vecp)++] = getcpy(svc.auth_endpoint);
+ vec[(*vecp)++] = mh_xstrdup("-oauthredirect");
+ vec[(*vecp)++] = getcpy(svc.redirect_uri);
+ vec[(*vecp)++] = mh_xstrdup("-oauthtokenendpoint");
+ vec[(*vecp)++] = getcpy(svc.token_endpoint);
+ vec[(*vecp)++] = mh_xstrdup("-oauthscope");
+ vec[(*vecp)++] = getcpy(svc.scope);
+ }
+ }
+
+ return 0;
+}
+#endif /* OAUTH_SUPPORT */
+
+
+/*
+ * Extract user and domain from From: header line in draft.
+ */
+static
+int
+get_from_header_info(const char *filename, const char **addr, const char **host, const char **message) {
+ struct stat st;
+ FILE *in;
+
+ if (stat (filename, &st) == NOTOK) {
+ *message = "unable to stat draft file";
+ return NOTOK;
+ }
+
+ 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;
+}