/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 1999-2021 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #ifdef ENABLE_SENDMAIL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void sendmail_destroy (mu_mailer_t); static int sendmail_open (mu_mailer_t, int); static int sendmail_close (mu_mailer_t); static int sendmail_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t); static int _url_sendmail_init (mu_url_t url) { if (url->path == NULL) if ((url->path = strdup (PATH_SENDMAIL)) == 0) return ENOMEM; return 0; } int _mu_mailer_sendmail_init (mu_mailer_t mailer) { int status; mu_progmailer_t pm; status = mu_progmailer_create (&pm); if (status) return status; mailer->data = pm; mailer->_destroy = sendmail_destroy; mailer->_open = sendmail_open; mailer->_close = sendmail_close; mailer->_send_message = sendmail_send_message; /* Set our properties. */ { mu_property_t property = NULL; mu_mailer_get_property (mailer, &property); mu_property_set_value (property, "TYPE", "SENDMAIL", 1); } return 0; } static void sendmail_destroy (mu_mailer_t mailer) { mu_progmailer_destroy ((mu_progmailer_t*)&mailer->data); } static int sendmail_open (mu_mailer_t mailer, int flags) { mu_progmailer_t pm = mailer->data; int status; const char *path; /* Sanity checks. */ if (pm == NULL) return EINVAL; mailer->flags = flags; if ((status = mu_url_sget_path (mailer->url, &path))) return status; if (access (path, X_OK) == -1) return errno; status = mu_progmailer_set_command (pm, path); mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE, ("sendmail binary: %s", path)); return status; } static int sendmail_close (mu_mailer_t mailer) { return mu_progmailer_close (mailer->data); } static int mailer_property_is_set (mu_mailer_t mailer, const char *name) { mu_property_t property = NULL; mu_mailer_get_property (mailer, &property); return mu_property_is_set (property, name); } static int sendmail_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from, mu_address_t to) { mu_progmailer_t pm = mailer->data; int argc = 0; const char **argvec = NULL; size_t tocount = 0; const char *emailfrom = NULL; int status; if (!pm) return EINVAL; /* Count the length of the arg vec: */ argc++; /* terminating NULL */ argc++; /* sendmail */ argc++; /* -oi (do not treat '.' as message terminator) */ if (from) { if ((status = mu_address_sget_email (from, 1, &emailfrom)) != 0) { mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("cannot get recipient email: %s", mu_strerror (status))); return status; } if (!emailfrom) { /* the address wasn't fully qualified, choke (for now) */ mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE, ("envelope from (%s) not fully qualifed\n", emailfrom)); return MU_ERR_INVALID_EMAIL; } argc += 2; /* -f from */ } if (to) { status = mu_address_get_email_count (to, &tocount); if (status) return status; if (tocount == 0) { mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE, ("missing recipients")); return MU_ERR_NOENT; } argc += tocount; /* 1 per to address */ } argc++; /* -t */ /* Allocate arg vec: */ if ((argvec = calloc (argc, sizeof (*argvec))) == 0) return ENOMEM; argc = 0; if (mu_progmailer_sget_command (pm, &argvec[argc]) || argvec[argc] == NULL) { free (argvec); return EINVAL; } argc++; argvec[argc++] = "-oi"; if (from) { argvec[argc++] = "-f"; argvec[argc++] = emailfrom; } if (!to || mailer_property_is_set (mailer, "READ_RECIPIENTS")) { argvec[argc++] = "-t"; } else { size_t i; size_t count = 0; mu_address_get_count (to, &count); for (i = 1; i <= count; i++) { const char *email; if ((status = mu_address_sget_email (to, i, &email)) != 0) { free (argvec); mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("cannot get email of recipient #%lu: %s", (unsigned long) i, mu_strerror (status))); return status; } if (!email) { mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE, ("envelope to (%s) not fully qualifed", email)); free (argvec); return MU_ERR_INVALID_EMAIL; } argvec[argc++] = email; } } argvec[argc] = NULL; status = mu_progmailer_open (pm, (char**) argvec); if (status == 0) { status = mu_progmailer_send (pm, msg); if (status == 0) mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT, msg); else mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("progmailer error: %s", mu_strerror (status))); } free (argvec); return status; } static struct _mu_record _sendmail_record = { MU_SENDMAIL_PRIO, MU_SENDMAIL_SCHEME, MU_RECORD_DEFAULT, MU_URL_SCHEME | MU_URL_PATH, MU_URL_SCHEME, /* Nothing is required in the URL, except scheme. Missing path means using PATH_SENDMAIL. */ _url_sendmail_init, /* url init. */ _mu_mailer_mailbox_init, /* Mailbox entry. */ _mu_mailer_sendmail_init, /* Mailer entry. */ _mu_mailer_folder_init, /* Folder entry. */ NULL, /* No need for a back pointer. */ NULL, /* _is_scheme method. */ NULL, /* _get_url method. */ NULL, /* _get_mailbox method. */ NULL, /* _get_mailer method. */ NULL /* _get_folder method. */ }; /* We export, url parsing and the initialisation of the mailbox, via the register entry/record. */ mu_record_t mu_sendmail_record = &_sendmail_record; #else #include #include mu_record_t mu_sendmail_record = NULL; #endif