"Fossies" - the Fresh Open Source Software Archive

Member "msmtp-1.8.17/src/msmtp.c" (27 Sep 2021, 142274 Bytes) of package /linux/privat/msmtp-1.8.17.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "msmtp.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.8.16_vs_1.8.17.

    1 /*
    2  * msmtp.c
    3  *
    4  * This file is part of msmtp, an SMTP client.
    5  *
    6  * Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
    7  * 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021
    8  * Martin Lambers <marlam@marlam.de>
    9  * Martin Stenberg <martin@gnutiken.se> (passwordeval support)
   10  * Scott Shumate <sshumate@austin.rr.com> (aliases support)
   11  *
   12  *   This program is free software; you can redistribute it and/or modify
   13  *   it under the terms of the GNU General Public License as published by
   14  *   the Free Software Foundation; either version 3 of the License, or
   15  *   (at your option) any later version.
   16  *
   17  *   This program is distributed in the hope that it will be useful,
   18  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20  *   GNU General Public License for more details.
   21  *
   22  *   You should have received a copy of the GNU General Public License
   23  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   24  */
   25 
   26 #ifdef HAVE_CONFIG_H
   27 # include "config.h"
   28 #endif
   29 
   30 #include <stdio.h>
   31 #include <stdlib.h>
   32 #include <stdarg.h>
   33 #include <string.h>
   34 #include <ctype.h>
   35 #include <errno.h>
   36 #include <time.h>
   37 #include <getopt.h>
   38 extern char *optarg;
   39 extern int optind;
   40 #include <unistd.h>
   41 #include <fcntl.h>
   42 #ifdef ENABLE_NLS
   43 # include <locale.h>
   44 #endif
   45 #ifdef HAVE_SYSLOG
   46 # include <syslog.h>
   47 #endif
   48 #ifdef HAVE_SIGNAL
   49 # include <signal.h>
   50 #endif
   51 
   52 #include "gettext.h"
   53 #define _(string) gettext(string)
   54 
   55 #include "xalloc.h"
   56 #include "conf.h"
   57 #include "list.h"
   58 #include "net.h"
   59 #include "smtp.h"
   60 #include "tools.h"
   61 #include "aliases.h"
   62 #include "password.h"
   63 #ifdef HAVE_TLS
   64 # include "mtls.h"
   65 #endif /* HAVE_TLS */
   66 
   67 /* Default file names. */
   68 #ifdef W32_NATIVE
   69 #define SYSCONFFILE     "msmtprc.txt"
   70 #define USERCONFFILE    "msmtprc.txt"
   71 #else /* UNIX */
   72 #define SYSCONFFILE     "msmtprc"
   73 #define USERCONFFILE    ".msmtprc"
   74 #endif
   75 
   76 /* The name of this program */
   77 const char *prgname;
   78 
   79 
   80 /*
   81  * Die if memory allocation fails
   82  */
   83 
   84 void xalloc_die(void)
   85 {
   86     /* TRANSLATORS: msmtp shares a lot of code and translatable strings with
   87        mpop <https://marlam.de/mpop>. */
   88     fprintf(stderr, _("%s: FATAL: %s\n"), prgname, strerror(ENOMEM));
   89     exit(EX_OSERR);
   90 }
   91 
   92 
   93 /*
   94  * msmtp_password_callback()
   95  *
   96  * This function will be called by smtp_auth() to get a password if none was
   97  * given.
   98  */
   99 
  100 char *msmtp_password_callback(const char *hostname, const char *user)
  101 {
  102     return password_get(hostname, user, password_service_smtp, 1, 1);
  103 }
  104 
  105 
  106 /*
  107  * msmtp_endsession()
  108  *
  109  * Quit an SMTP session and close the connection.
  110  * QUIT is only sent when the flag 'quit' is set.
  111  */
  112 
  113 void msmtp_endsession(smtp_server_t *srv, int quit)
  114 {
  115     char *tmp_errstr;
  116 
  117     if (quit)
  118     {
  119         tmp_errstr = NULL;
  120         (void)smtp_quit(srv, &tmp_errstr);
  121         free(tmp_errstr);
  122     }
  123     smtp_close(srv);
  124 }
  125 
  126 
  127 /*
  128  * msmtp_rmqs()
  129  *
  130  * Sends an ETRN request to the SMTP server specified in the account 'acc'.
  131  * If an error occurred, '*errstr' points to an allocated string that describes
  132  * the error or is NULL, and '*msg' may contain the offending message from the
  133  * SMTP server (or be NULL).
  134  */
  135 
  136 int msmtp_rmqs(account_t *acc, int debug, const char *rmqs_argument,
  137         list_t **msg, char **errstr)
  138 {
  139     smtp_server_t srv;
  140     int e;
  141 #ifdef HAVE_TLS
  142     mtls_cert_info_t *tci = NULL;
  143     char *mtls_parameter_description = NULL;
  144 #endif /* HAVE_TLS */
  145 
  146     *errstr = NULL;
  147     *msg = NULL;
  148 
  149     /* create a new smtp_server_t */
  150     srv = smtp_new(debug ? stdout : NULL, acc->protocol);
  151 
  152     /* connect */
  153     if ((e = smtp_connect(&srv, acc->socketname, acc->proxy_host, acc->proxy_port,
  154                     acc->host, acc->port, acc->source_ip, acc->timeout,
  155                     NULL, NULL, errstr)) != NET_EOK)
  156     {
  157         return net_exitcode(e);
  158     }
  159 
  160     /* prepare tls */
  161 #ifdef HAVE_TLS
  162     if (acc->tls)
  163     {
  164         if ((e = smtp_tls_init(&srv,
  165                         acc->tls_key_file, acc->tls_cert_file, acc->password,
  166                         acc->tls_trust_file, acc->tls_crl_file,
  167                         acc->tls_sha256_fingerprint,
  168                         acc->tls_sha1_fingerprint, acc->tls_md5_fingerprint,
  169                         acc->tls_min_dh_prime_bits,
  170                         acc->tls_priorities,
  171                         acc->tls_host_override ? acc->tls_host_override : acc->host,
  172                         acc->tls_nocertcheck,
  173                         errstr)) != TLS_EOK)
  174         {
  175             return mtls_exitcode(e);
  176         }
  177     }
  178 #endif /* HAVE_TLS */
  179 
  180     /* start tls for smtps servers */
  181 #ifdef HAVE_TLS
  182     if (acc->tls && acc->tls_nostarttls)
  183     {
  184         if (debug)
  185         {
  186             tci = mtls_cert_info_new();
  187         }
  188         if ((e = smtp_tls(&srv, tci,
  189                         &mtls_parameter_description, errstr)) != TLS_EOK)
  190         {
  191             if (debug)
  192             {
  193                 mtls_cert_info_free(tci);
  194                 free(mtls_parameter_description);
  195             }
  196             msmtp_endsession(&srv, 0);
  197             return mtls_exitcode(e);
  198         }
  199         if (debug)
  200         {
  201             mtls_print_info(mtls_parameter_description, tci);
  202             mtls_cert_info_free(tci);
  203             free(mtls_parameter_description);
  204         }
  205     }
  206 #endif /* HAVE_TLS */
  207 
  208     /* get greeting */
  209     if ((e = smtp_get_greeting(&srv, msg, NULL, errstr)) != SMTP_EOK)
  210     {
  211         msmtp_endsession(&srv, 0);
  212         return smtp_exitcode(e);
  213     }
  214 
  215     /* initialize session */
  216     if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
  217     {
  218         msmtp_endsession(&srv, 0);
  219         return smtp_exitcode(e);
  220     }
  221 
  222     /* start tls for starttls servers */
  223 #ifdef HAVE_TLS
  224     if (acc->tls && !acc->tls_nostarttls)
  225     {
  226         if (!(srv.cap.flags & SMTP_CAP_STARTTLS))
  227         {
  228             *errstr = xasprintf(_("the server does not support TLS "
  229                         "via the STARTTLS command"));
  230             msmtp_endsession(&srv, 1);
  231             return EX_UNAVAILABLE;
  232         }
  233         if ((e = smtp_tls_starttls(&srv, msg, errstr)) != SMTP_EOK)
  234         {
  235             msmtp_endsession(&srv, 0);
  236             return smtp_exitcode(e);
  237         }
  238         if (debug)
  239         {
  240             tci = mtls_cert_info_new();
  241         }
  242         if ((e = smtp_tls(&srv, tci,
  243                         &mtls_parameter_description, errstr)) != TLS_EOK)
  244         {
  245             if (debug)
  246             {
  247                 mtls_cert_info_free(tci);
  248                 free(mtls_parameter_description);
  249             }
  250             msmtp_endsession(&srv, 0);
  251             return mtls_exitcode(e);
  252         }
  253         if (debug)
  254         {
  255             mtls_print_info(mtls_parameter_description, tci);
  256             mtls_cert_info_free(tci);
  257             free(mtls_parameter_description);
  258         }
  259         /* initialize again */
  260         if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
  261         {
  262             msmtp_endsession(&srv, 0);
  263             return smtp_exitcode(e);
  264         }
  265     }
  266 #endif /* HAVE_TLS */
  267 
  268     if (!(srv.cap.flags & SMTP_CAP_ETRN))
  269     {
  270         *errstr = xasprintf(_("the server does not support "
  271                     "Remote Message Queue Starting"));
  272         msmtp_endsession(&srv, 1);
  273         return EX_UNAVAILABLE;
  274     }
  275 
  276     /* authenticate */
  277     if (acc->auth_mech)
  278     {
  279         if (!(srv.cap.flags & SMTP_CAP_AUTH))
  280         {
  281             *errstr = xasprintf(
  282                     _("the server does not support authentication"));
  283             msmtp_endsession(&srv, 1);
  284             return EX_UNAVAILABLE;
  285         }
  286         if ((e = smtp_auth(&srv, acc->host, acc->port,
  287                         acc->username, acc->password,
  288                         acc->ntlmdomain, acc->auth_mech,
  289                         msmtp_password_callback, msg, errstr))
  290                 != SMTP_EOK)
  291         {
  292             msmtp_endsession(&srv, 0);
  293             return smtp_exitcode(e);
  294         }
  295     }
  296 
  297     /* send the ETRN request */
  298     if ((e = smtp_etrn(&srv, rmqs_argument, msg, errstr)) != SMTP_EOK)
  299     {
  300         msmtp_endsession(&srv, 0);
  301         return smtp_exitcode(e);
  302     }
  303 
  304     /* end session */
  305     msmtp_endsession(&srv, 1);
  306     return EX_OK;
  307 }
  308 
  309 
  310 /*
  311  * msmtp_serverinfo()
  312  *
  313  * Prints information about the SMTP server specified in the account 'acc'.
  314  * If an error occurred, '*errstr' points to an allocated string that describes
  315  * the error or is NULL, and '*msg' may contain the offending message from the
  316  * SMTP server (or be NULL).
  317  */
  318 
  319 int msmtp_serverinfo(account_t *acc, int debug, list_t **msg, char **errstr)
  320 {
  321     smtp_server_t srv;
  322     char *server_canonical_name = NULL;
  323     char *server_address = NULL;
  324     char *server_greeting = NULL;
  325     int e;
  326 #ifdef HAVE_TLS
  327     mtls_cert_info_t *tci = NULL;
  328     char *mtls_parameter_description = NULL;
  329 #endif /* HAVE_TLS */
  330 
  331     *errstr = NULL;
  332     *msg = NULL;
  333 
  334     /* create a new smtp_server_t */
  335     srv = smtp_new(debug ? stdout : NULL, acc->protocol);
  336 
  337     /* connect */
  338     if ((e = smtp_connect(&srv, acc->socketname, acc->proxy_host, acc->proxy_port,
  339                     acc->host, acc->port, acc->source_ip, acc->timeout,
  340                     &server_canonical_name, &server_address, errstr))
  341             != NET_EOK)
  342     {
  343         e = net_exitcode(e);
  344         goto error_exit;
  345     }
  346 
  347     /* prepare tls */
  348 #ifdef HAVE_TLS
  349     if (acc->tls)
  350     {
  351         tci = mtls_cert_info_new();
  352         if ((e = smtp_tls_init(&srv,
  353                         acc->tls_key_file, acc->tls_cert_file, acc->password,
  354                         acc->tls_trust_file, acc->tls_crl_file,
  355                         acc->tls_sha256_fingerprint,
  356                         acc->tls_sha1_fingerprint, acc->tls_md5_fingerprint,
  357                         acc->tls_min_dh_prime_bits,
  358                         acc->tls_priorities,
  359                         acc->tls_host_override ? acc->tls_host_override : acc->host,
  360                         acc->tls_nocertcheck,
  361                         errstr)) != TLS_EOK)
  362         {
  363             e = mtls_exitcode(e);
  364             goto error_exit;
  365         }
  366     }
  367 #endif /* HAVE_TLS */
  368 
  369     /* start tls for smtps servers */
  370 #ifdef HAVE_TLS
  371     if (acc->tls && acc->tls_nostarttls)
  372     {
  373         if ((e = smtp_tls(&srv, tci,
  374                         &mtls_parameter_description, errstr)) != TLS_EOK)
  375         {
  376             msmtp_endsession(&srv, 0);
  377             e = mtls_exitcode(e);
  378             goto error_exit;
  379         }
  380     }
  381 #endif /* HAVE_TLS */
  382 
  383     /* get greeting */
  384     if ((e = smtp_get_greeting(&srv, msg, &server_greeting,
  385                     errstr)) != SMTP_EOK)
  386     {
  387         msmtp_endsession(&srv, 0);
  388         e = smtp_exitcode(e);
  389         goto error_exit;
  390     }
  391 
  392     /* initialize session */
  393     if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
  394     {
  395         msmtp_endsession(&srv, 0);
  396         e = smtp_exitcode(e);
  397         goto error_exit;
  398     }
  399 
  400     /* start tls for starttls servers */
  401 #ifdef HAVE_TLS
  402     if (acc->tls && !acc->tls_nostarttls)
  403     {
  404         if (!(srv.cap.flags & SMTP_CAP_STARTTLS))
  405         {
  406             *errstr = xasprintf(_("the server does not support TLS "
  407                         "via the STARTTLS command"));
  408             msmtp_endsession(&srv, 1);
  409             e = EX_UNAVAILABLE;
  410             goto error_exit;
  411         }
  412         if ((e = smtp_tls_starttls(&srv, msg, errstr)) != SMTP_EOK)
  413         {
  414             msmtp_endsession(&srv, 0);
  415             e = smtp_exitcode(e);
  416             goto error_exit;
  417         }
  418         if ((e = smtp_tls(&srv, tci,
  419                         &mtls_parameter_description, errstr)) != TLS_EOK)
  420         {
  421             msmtp_endsession(&srv, 0);
  422             e = mtls_exitcode(e);
  423             goto error_exit;
  424         }
  425         /* initialize again */
  426         if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
  427         {
  428             msmtp_endsession(&srv, 0);
  429             e = smtp_exitcode(e);
  430             goto error_exit;
  431         }
  432     }
  433 #endif /* HAVE_TLS */
  434 
  435     /* end session */
  436     msmtp_endsession(&srv, 1);
  437 
  438     /* print results */
  439     if (server_canonical_name && server_address)
  440     {
  441         printf(_("%s server at %s (%s [%s]), port %d:\n"),
  442                 acc->protocol == SMTP_PROTO_SMTP ? "SMTP" : "LMTP",
  443                 acc->host, server_canonical_name, server_address, acc->port);
  444     }
  445     else if (server_canonical_name)
  446     {
  447         printf(_("%s server at %s (%s), port %d:\n"),
  448                 acc->protocol == SMTP_PROTO_SMTP ? "SMTP" : "LMTP",
  449                 acc->host, server_canonical_name, acc->port);
  450     }
  451     else if (server_address)
  452     {
  453         printf(_("%s server at %s ([%s]), port %d:\n"),
  454                 acc->protocol == SMTP_PROTO_SMTP ? "SMTP" : "LMTP",
  455                 acc->host, server_address, acc->port);
  456     }
  457     else
  458     {
  459         printf(_("%s server at %s, port %d:\n"),
  460                 acc->protocol == SMTP_PROTO_SMTP ? "SMTP" : "LMTP",
  461                 acc->host, acc->port);
  462     }
  463     if (*server_greeting != '\0')
  464     {
  465         printf("    %s\n", sanitize_string(server_greeting));
  466     }
  467 #ifdef HAVE_TLS
  468     if (acc->tls)
  469     {
  470         mtls_print_info(mtls_parameter_description, tci);
  471     }
  472 #endif /* HAVE_TLS */
  473 #ifdef HAVE_TLS
  474     if (srv.cap.flags == 0 && !(acc->tls && !acc->tls_nostarttls))
  475 #else /* not HAVE_TLS */
  476     if (srv.cap.flags == 0)
  477 #endif /* not HAVE_TLS */
  478     {
  479         printf(_("No special capabilities.\n"));
  480     }
  481     else
  482     {
  483         printf(_("Capabilities:\n"));
  484         if (srv.cap.flags & SMTP_CAP_SIZE)
  485         {
  486             printf("    SIZE %ld:\n        %s", srv.cap.size,
  487                     _("Maximum message size is "));
  488             if (srv.cap.size == 0)
  489             {
  490                 printf(_("unlimited\n"));
  491             }
  492             else
  493             {
  494                 printf(_("%ld bytes"), srv.cap.size);
  495                 if (srv.cap.size > 1024 * 1024)
  496                 {
  497                     printf(_(" = %.2f MiB"),
  498                             (float)srv.cap.size / (float)(1024 * 1024));
  499                 }
  500                 else if (srv.cap.size > 1024)
  501                 {
  502                     printf(_(" = %.2f KiB"), (float)srv.cap.size / 1024.0f);
  503                 }
  504                 printf("\n");
  505             }
  506         }
  507         if (srv.cap.flags & SMTP_CAP_PIPELINING)
  508         {
  509             printf("    PIPELINING:\n        %s\n", _("Support for command "
  510                         "grouping for faster transmission"));
  511         }
  512         if (srv.cap.flags & SMTP_CAP_ETRN)
  513         {
  514             printf("    ETRN:\n        %s\n", _("Support for RMQS "
  515                         "(Remote Message Queue Starting)"));
  516         }
  517         if (srv.cap.flags & SMTP_CAP_DSN)
  518         {
  519             printf("    DSN:\n        %s\n", _("Support for "
  520                         "Delivery Status Notifications"));
  521         }
  522 #ifdef HAVE_TLS
  523         if ((acc->tls && !acc->tls_nostarttls)
  524                 || (srv.cap.flags & SMTP_CAP_STARTTLS))
  525 #else /* not HAVE_TLS */
  526         if (srv.cap.flags & SMTP_CAP_STARTTLS)
  527 #endif /* not HAVE_TLS */
  528         {
  529             printf("    STARTTLS:\n        %s\n", _("Support for "
  530                         "TLS encryption via the STARTTLS command"));
  531         }
  532         if (srv.cap.flags & SMTP_CAP_AUTH)
  533         {
  534             printf("    AUTH:\n        %s\n        ",
  535                     _("Supported authentication methods:"));
  536             if (srv.cap.flags & SMTP_CAP_AUTH_PLAIN)
  537             {
  538                 printf("PLAIN ");
  539             }
  540             if (srv.cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_1)
  541             {
  542                 printf("SCRAM-SHA-1 ");
  543             }
  544             if (srv.cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_256)
  545             {
  546                 printf("SCRAM-SHA-256 ");
  547             }
  548             if (srv.cap.flags & SMTP_CAP_AUTH_EXTERNAL)
  549             {
  550                 printf("EXTERNAL ");
  551             }
  552             if (srv.cap.flags & SMTP_CAP_AUTH_GSSAPI)
  553             {
  554                 printf("GSSAPI ");
  555             }
  556             if (srv.cap.flags & SMTP_CAP_AUTH_CRAM_MD5)
  557             {
  558                 printf("CRAM-MD5 ");
  559             }
  560             if (srv.cap.flags & SMTP_CAP_AUTH_DIGEST_MD5)
  561             {
  562                 printf("DIGEST-MD5 ");
  563             }
  564             if (srv.cap.flags & SMTP_CAP_AUTH_LOGIN)
  565             {
  566                 printf("LOGIN ");
  567             }
  568             if (srv.cap.flags & SMTP_CAP_AUTH_NTLM)
  569             {
  570                 printf("NTLM ");
  571             }
  572             if (srv.cap.flags & SMTP_CAP_AUTH_OAUTHBEARER)
  573             {
  574                 printf("OAUTHBEARER ");
  575             }
  576             if (srv.cap.flags & SMTP_CAP_AUTH_XOAUTH2)
  577             {
  578                 printf("XOAUTH2 ");
  579             }
  580             printf("\n");
  581         }
  582 #ifdef HAVE_TLS
  583         if ((srv.cap.flags & SMTP_CAP_STARTTLS) && !acc->tls)
  584 #else /* not HAVE_TLS */
  585         if (srv.cap.flags & SMTP_CAP_STARTTLS)
  586 #endif /* not HAVE_TLS */
  587         {
  588             printf(_("This server might advertise more or other "
  589                     "capabilities when TLS is active.\n"));
  590         }
  591     }
  592 
  593     e = EX_OK;
  594 
  595 error_exit:
  596     free(server_canonical_name);
  597     free(server_address);
  598 #ifdef HAVE_TLS
  599     if (tci)
  600     {
  601         mtls_cert_info_free(tci);
  602     }
  603     free(mtls_parameter_description);
  604 #endif /* HAVE_TLS */
  605     free(server_greeting);
  606     return e;
  607 }
  608 
  609 
  610 /*
  611  * msmtp_read_headers()
  612  *
  613  * Copies the headers of the mail from 'mailf' to a temporary file 'tmpf',
  614  * including the blank line that separates the header from the body of the mail.
  615  *
  616  * If 'recipients' is not NULL: extracts all recipients from the To, Cc, and Bcc
  617  * headers and adds them to 'recipients'. If Resent-* headers are present, all
  618  * recipients from the Resent-To, Resent-Cc, Resent-Bcc headers in the first
  619  * block of Resent- headers are extracted instead.
  620  *
  621  * If 'from' is not NULL: extracts the address from the From header and stores
  622  * it in an allocated string. A pointer to this string is stored in 'from'.
  623  *
  624  * If 'have_date' is not NULL: set this flag to 1 if a Date header is present
  625  * , and to 0 otherwise.
  626  *
  627  * See RFC2822, section 3 for the format of these headers.
  628  *
  629  * Return codes: EX_OK, EX_IOERR
  630  */
  631 
  632 #define STATE_LINESTART_FRESH           0       /* a new line started; the
  633                                                    previous line was not a
  634                                                    recipient header */
  635 #define STATE_LINESTART_AFTER_ADDRHDR   1       /* a new line started; the
  636                                                    previous line was a
  637                                                    recipient header */
  638 #define STATE_OTHER_HDR                 2       /* a header we don't
  639                                                    care about */
  640 #define STATE_DATE1                     3       /* we saw "^D" */
  641 #define STATE_DATE2                     4       /* we saw "^Da" */
  642 #define STATE_DATE3                     5       /* we saw "^Dat" */
  643 #define STATE_DATE4                     6       /* we saw "^Date" */
  644 #define STATE_FROM1                     7       /* we saw "^F" */
  645 #define STATE_FROM2                     8       /* we saw "^Fr" */
  646 #define STATE_FROM3                     9       /* we saw "^Fro" */
  647 #define STATE_TO                        10      /* we saw "^T" */
  648 #define STATE_CC                        11      /* we saw "^C" */
  649 #define STATE_BCC1                      12      /* we saw "^B" */
  650 #define STATE_BCC2                      13      /* we saw "^Bc" */
  651 #define STATE_ADDRHDR_ALMOST            14      /* we saw "^To", "^Cc"
  652                                                    or "^Bcc" */
  653 #define STATE_RESENT                    15      /* we saw part of "^Resent-" */
  654 #define STATE_ADDRHDR_DEFAULT           16      /* in_rcpt_hdr and in_rcpt
  655                                                    state our position */
  656 #define STATE_ADDRHDR_DQUOTE            17      /* duoble quotes */
  657 #define STATE_ADDRHDR_BRACKETS_START    18      /* entering <...> */
  658 #define STATE_ADDRHDR_IN_BRACKETS       19      /* an address inside <> */
  659 #define STATE_ADDRHDR_PARENTH_START     20      /* entering (...) */
  660 #define STATE_ADDRHDR_IN_PARENTH        21      /* a comment inside () */
  661 #define STATE_ADDRHDR_IN_ADDRESS        22      /* a bare address */
  662 #define STATE_ADDRHDR_BACKQUOTE         23      /* we saw a '\\' */
  663 #define STATE_HEADERS_END               24      /* we saw "^$", the blank line
  664                                                    between headers and body */
  665 
  666 int msmtp_read_headers(FILE *mailf, FILE *tmpf,
  667         list_t *recipients,
  668         char **from,
  669         int *have_date,
  670         char **errstr)
  671 {
  672     int c;
  673     int state = STATE_LINESTART_FRESH;
  674     int oldstate = STATE_LINESTART_FRESH;
  675     int backquote_savestate = STATE_LINESTART_FRESH;
  676     int parentheses_depth = 0;
  677     int parentheses_savestate = STATE_LINESTART_FRESH;
  678     int folded_rcpthdr_savestate = STATE_LINESTART_FRESH;
  679     int from_hdr = -1;          /* -1 = before, 0 = in, 1 = after first From: */
  680     int resent_index = -1;
  681     int resent_block = -1;      /* -1 = before, 0 = in, 1 = after first block */
  682     char *current_recipient = NULL;
  683     size_t current_recipient_len = 0;
  684     int forget_current_recipient = 0;
  685     int finish_current_recipient = 0;
  686     size_t bufsize = 0;
  687     /* The buffer that is filled with the current recipient grows by
  688      * 'bufsize_step' if the remaining space becomes too small. This value must
  689      * be at least 2. Wasted characters are at most (bufsize_step - 1). A value
  690      * of 10 means low wasted space and a low number of realloc()s per
  691      * recipient. */
  692     const size_t bufsize_step = 10;
  693     /* We need two recipient lists: one for normal To, Cc, Bcc headers, and one
  694      * for Resent-To, Resent-Cc, Resent-Bcc. The first list gathers adresses
  695      * from all To, Cc, Bcc headers that are found. The second list gathers
  696      * adresses only for the first block of Resent-* headers. If a Resent- block
  697      * was seen, then the first list is ignored, and only the second list is
  698      * appended to the recipient list given by the caller. */
  699     list_t *normal_recipients_list = NULL;
  700     list_t *normal_recipients = NULL;
  701     list_t *resent_recipients_list = NULL;
  702     list_t *resent_recipients = NULL;
  703 
  704     if (from)
  705     {
  706         *from = NULL;
  707     }
  708     if (have_date)
  709     {
  710         *have_date = 0;
  711     }
  712     if (recipients)
  713     {
  714         normal_recipients_list = list_new();
  715         normal_recipients = normal_recipients_list;
  716         resent_recipients_list = list_new();
  717         resent_recipients = resent_recipients_list;
  718     }
  719 
  720     for (;;)
  721     {
  722         c = fgetc(mailf);
  723         /* Convert CRLF to LF. According to RFC 2822, CRs may only occur in a
  724          * mail when they are followed by LF, so just ignoring CRs is ok. */
  725         if (c == '\r')
  726         {
  727             continue;
  728         }
  729         oldstate = state;
  730         if (c == EOF)
  731         {
  732             state = STATE_HEADERS_END;
  733             if (current_recipient)
  734                 finish_current_recipient = 1;
  735         }
  736         else
  737         {
  738             switch (state)
  739             {
  740                 case STATE_LINESTART_FRESH:
  741                     parentheses_depth = 0;
  742                     resent_index = -1;
  743                     if (have_date && (c == 'd' || c == 'D'))
  744                         state = STATE_DATE1;
  745                     else if (from && from_hdr < 0 && (c == 'f' || c == 'F'))
  746                         state = STATE_FROM1;
  747                     else if (recipients && (c == 't' || c == 'T'))
  748                         state = STATE_TO;
  749                     else if (recipients && (c == 'c' || c == 'C'))
  750                         state = STATE_CC;
  751                     else if (recipients && (c == 'b' || c == 'B'))
  752                         state = STATE_BCC1;
  753                     else if (recipients && resent_block <= 0
  754                             && (c == 'r' || c == 'R'))
  755                     {
  756                         resent_index = 0;
  757                         state = STATE_RESENT;
  758                     }
  759                     else if (c == '\n')
  760                         state = STATE_HEADERS_END;
  761                     else
  762                         state = STATE_OTHER_HDR;
  763                     break;
  764 
  765                 case STATE_LINESTART_AFTER_ADDRHDR:
  766                     resent_index = -1;
  767                     if (c != ' ' && c != '\t')
  768                     {
  769                         if (current_recipient)
  770                             finish_current_recipient = 1;
  771                         else if (from_hdr == 0)
  772                             from_hdr = -1; /* the preceding From: header was empty */
  773                     }
  774                     if (c == ' ' || c == '\t')
  775                         state = folded_rcpthdr_savestate;
  776                     else if (have_date && (c == 'd' || c == 'D'))
  777                         state = STATE_DATE1;
  778                     else if (from && from_hdr < 0 && (c == 'f' || c == 'F'))
  779                         state = STATE_FROM1;
  780                     else if (recipients && (c == 't' || c == 'T'))
  781                         state = STATE_TO;
  782                     else if (recipients && (c == 'c' || c == 'C'))
  783                         state = STATE_CC;
  784                     else if (recipients && (c == 'b' || c == 'B'))
  785                         state = STATE_BCC1;
  786                     else if (recipients && resent_block <= 0
  787                         && (c == 'r' || c == 'R'))
  788                     {
  789                         resent_index = 0;
  790                         state = STATE_RESENT;
  791                     }
  792                     else if (c == '\n')
  793                         state = STATE_HEADERS_END;
  794                     else
  795                         state = STATE_OTHER_HDR;
  796                     break;
  797 
  798                 case STATE_OTHER_HDR:
  799                     if (resent_block == 0 && resent_index != 6)
  800                         resent_block = 1;
  801                     if (c == '\n')
  802                         state = STATE_LINESTART_FRESH;
  803                     break;
  804 
  805                 case STATE_RESENT:
  806                     if (resent_index == 0 && (c == 'e' || c == 'E'))
  807                         resent_index++;
  808                     else if (resent_index == 1 && (c == 's' || c == 'S'))
  809                         resent_index++;
  810                     else if (resent_index == 2 && (c == 'e' || c == 'E'))
  811                         resent_index++;
  812                     else if (resent_index == 3 && (c == 'n' || c == 'N'))
  813                         resent_index++;
  814                     else if (resent_index == 4 && (c == 't' || c == 'T'))
  815                         resent_index++;
  816                     else if (resent_index == 5 && c == '-')
  817                     {
  818                         if (resent_block == -1)
  819                             resent_block = 0;
  820                         resent_index++;
  821                     }
  822                     else if (resent_index == 6 && (c == 't' || c == 'T'))
  823                         state = STATE_TO;
  824                     else if (resent_index == 6 && (c == 'c' || c == 'C'))
  825                         state = STATE_CC;
  826                     else if (resent_index == 6 && (c == 'b' || c == 'B'))
  827                         state = STATE_BCC1;
  828                     else if (c == '\n')
  829                         state = STATE_LINESTART_FRESH;
  830                     else
  831                         state = STATE_OTHER_HDR;
  832                     break;
  833 
  834                 case STATE_DATE1:
  835                     if (c == 'a' || c == 'A')
  836                         state = STATE_DATE2;
  837                     else if (c == '\n')
  838                         state = STATE_LINESTART_FRESH;
  839                     else
  840                         state = STATE_OTHER_HDR;
  841                     break;
  842 
  843                 case STATE_DATE2:
  844                     if (c == 't' || c == 'T')
  845                         state = STATE_DATE3;
  846                     else if (c == '\n')
  847                         state = STATE_LINESTART_FRESH;
  848                     else
  849                         state = STATE_OTHER_HDR;
  850                     break;
  851 
  852                 case STATE_DATE3:
  853                     if (c == 'e' || c == 'E')
  854                         state = STATE_DATE4;
  855                     else if (c == '\n')
  856                         state = STATE_LINESTART_FRESH;
  857                     else
  858                         state = STATE_OTHER_HDR;
  859                     break;
  860 
  861                 case STATE_DATE4:
  862                     if (c == ':')
  863                     {
  864                         *have_date = 1;
  865                         state = STATE_OTHER_HDR;
  866                     }
  867                     else if (c == '\n')
  868                         state = STATE_LINESTART_FRESH;
  869                     else
  870                         state = STATE_OTHER_HDR;
  871                     break;
  872 
  873                 case STATE_FROM1:
  874                     if (resent_block == 0 && resent_index != 6)
  875                         resent_block = 1;
  876                     if (c == 'r' || c == 'R')
  877                         state = STATE_FROM2;
  878                     else if (c == '\n')
  879                         state = STATE_LINESTART_FRESH;
  880                     else
  881                         state = STATE_OTHER_HDR;
  882                     break;
  883 
  884                 case STATE_FROM2:
  885                     if (c == 'o' || c == 'O')
  886                         state = STATE_FROM3;
  887                     else if (c == '\n')
  888                         state = STATE_LINESTART_FRESH;
  889                     else
  890                         state = STATE_OTHER_HDR;
  891                     break;
  892 
  893                 case STATE_FROM3:
  894                     if (c == 'm' || c == 'M')
  895                     {
  896                         from_hdr = 0;
  897                         state = STATE_ADDRHDR_ALMOST;
  898                     }
  899                     else if (c == '\n')
  900                         state = STATE_LINESTART_FRESH;
  901                     else
  902                         state = STATE_OTHER_HDR;
  903                     break;
  904 
  905                 case STATE_TO:
  906                     if (resent_block == 0 && resent_index != 6)
  907                         resent_block = 1;
  908                     if (c == 'o' || c == 'O')
  909                         state = STATE_ADDRHDR_ALMOST;
  910                     else if (c == '\n')
  911                         state = STATE_LINESTART_FRESH;
  912                     else
  913                         state = STATE_OTHER_HDR;
  914                     break;
  915 
  916                 case STATE_CC:
  917                     if (resent_block == 0 && resent_index != 6)
  918                         resent_block = 1;
  919                     if (c == 'c' || c == 'C')
  920                         state = STATE_ADDRHDR_ALMOST;
  921                     else if (c == '\n')
  922                         state = STATE_LINESTART_FRESH;
  923                     else
  924                         state = STATE_OTHER_HDR;
  925                     break;
  926 
  927                 case STATE_BCC1:
  928                     if (resent_block == 0 && resent_index != 6)
  929                         resent_block = 1;
  930                     if (c == 'c' || c == 'C')
  931                         state = STATE_BCC2;
  932                     else if (c == '\n')
  933                         state = STATE_LINESTART_FRESH;
  934                     else
  935                         state = STATE_OTHER_HDR;
  936                     break;
  937 
  938                 case STATE_BCC2:
  939                     if (c == 'c' || c == 'C')
  940                         state = STATE_ADDRHDR_ALMOST;
  941                     else if (c == '\n')
  942                         state = STATE_LINESTART_FRESH;
  943                     else
  944                         state = STATE_OTHER_HDR;
  945                     break;
  946 
  947                 case STATE_ADDRHDR_ALMOST:
  948                     if (from_hdr == 0 && c != ':')
  949                         from_hdr = -1;
  950                     if (c == ':')
  951                         state = STATE_ADDRHDR_DEFAULT;
  952                     else if (c == '\n')
  953                         state = STATE_LINESTART_FRESH;
  954                     else
  955                         state = STATE_OTHER_HDR;
  956                     break;
  957 
  958                 case STATE_ADDRHDR_DEFAULT:
  959                     if (c == '\n')
  960                     {
  961                         if (current_recipient)
  962                             finish_current_recipient = 1;
  963                         folded_rcpthdr_savestate = state;
  964                         state = STATE_LINESTART_AFTER_ADDRHDR;
  965                     }
  966                     else if (c == '\\')
  967                     {
  968                         backquote_savestate = state;
  969                         state = STATE_ADDRHDR_BACKQUOTE;
  970                     }
  971                     else if (c == '(')
  972                     {
  973                         parentheses_savestate = state;
  974                         state = STATE_ADDRHDR_PARENTH_START;
  975                     }
  976                     else if (c == '"')
  977                     {
  978                         if (current_recipient)
  979                             forget_current_recipient = 1;
  980                         state = STATE_ADDRHDR_DQUOTE;
  981                     }
  982                     else if (c == '<')
  983                     {
  984                         if (current_recipient)
  985                             forget_current_recipient = 1;
  986                         state = STATE_ADDRHDR_BRACKETS_START;
  987                     }
  988                     else if (c == ' ' || c == '\t')
  989                         ; /* keep state */
  990                     else if (c == ':')
  991                     {
  992                         if (current_recipient)
  993                             forget_current_recipient = 1;
  994                     }
  995                     else if (c == ';' || c == ',')
  996                     {
  997                         if (current_recipient)
  998                             finish_current_recipient = 1;
  999                     }
 1000                     else
 1001                     {
 1002                         if (current_recipient)
 1003                             forget_current_recipient = 1;
 1004                         state = STATE_ADDRHDR_IN_ADDRESS;
 1005                     }
 1006                     break;
 1007 
 1008                 case STATE_ADDRHDR_DQUOTE:
 1009                     if (c == '\n')
 1010                     {
 1011                         folded_rcpthdr_savestate = state;
 1012                         state = STATE_LINESTART_AFTER_ADDRHDR;
 1013                     }
 1014                     else if (c == '\\')
 1015                     {
 1016                         backquote_savestate = state;
 1017                         state = STATE_ADDRHDR_BACKQUOTE;
 1018                     }
 1019                     else if (c == '"')
 1020                         state = STATE_ADDRHDR_DEFAULT;
 1021                     break;
 1022 
 1023                 case STATE_ADDRHDR_BRACKETS_START:
 1024                     if (c == '\n')
 1025                     {
 1026                         folded_rcpthdr_savestate = state;
 1027                         state = STATE_LINESTART_AFTER_ADDRHDR;
 1028                     }
 1029                     else if (c == '(')
 1030                     {
 1031                         parentheses_savestate = state;
 1032                         state = STATE_ADDRHDR_PARENTH_START;
 1033                     }
 1034                     else if (c == '>')
 1035                         state = STATE_ADDRHDR_DEFAULT;
 1036                     else
 1037                         state = STATE_ADDRHDR_IN_BRACKETS;
 1038                     break;
 1039 
 1040                 case STATE_ADDRHDR_IN_BRACKETS:
 1041                     if (c == '\n')
 1042                     {
 1043                         folded_rcpthdr_savestate = state;
 1044                         state = STATE_LINESTART_AFTER_ADDRHDR;
 1045                     }
 1046                     else if (c == '\\')
 1047                     {
 1048                         backquote_savestate = state;
 1049                         state = STATE_ADDRHDR_BACKQUOTE;
 1050                     }
 1051                     else if (c == '(')
 1052                     {
 1053                         parentheses_savestate = state;
 1054                         state = STATE_ADDRHDR_PARENTH_START;
 1055                     }
 1056                     else if (c == '>')
 1057                     {
 1058                         finish_current_recipient = 1;
 1059                         state = STATE_ADDRHDR_DEFAULT;
 1060                     }
 1061                     break;
 1062 
 1063                 case STATE_ADDRHDR_PARENTH_START:
 1064                     if (c == '\n')
 1065                     {
 1066                         folded_rcpthdr_savestate = state;
 1067                         state = STATE_LINESTART_AFTER_ADDRHDR;
 1068                     }
 1069                     else if (c == ')')
 1070                         state = parentheses_savestate;
 1071                     else
 1072                     {
 1073                         parentheses_depth++;
 1074                         state = STATE_ADDRHDR_IN_PARENTH;
 1075                     }
 1076                     break;
 1077 
 1078                 case STATE_ADDRHDR_IN_PARENTH:
 1079                     if (c == '\n')
 1080                     {
 1081                         folded_rcpthdr_savestate = state;
 1082                         state = STATE_LINESTART_AFTER_ADDRHDR;
 1083                     }
 1084                     else if (c == '\\')
 1085                     {
 1086                         backquote_savestate = state;
 1087                         state = STATE_ADDRHDR_BACKQUOTE;
 1088                     }
 1089                     else if (c == '(')
 1090                         state = STATE_ADDRHDR_PARENTH_START;
 1091                     else if (c == ')')
 1092                     {
 1093                         parentheses_depth--;
 1094                         if (parentheses_depth == 0)
 1095                             state = parentheses_savestate;
 1096                     }
 1097                     break;
 1098 
 1099                 case STATE_ADDRHDR_IN_ADDRESS:
 1100                     if (c == '\n')
 1101                     {
 1102                         folded_rcpthdr_savestate = STATE_ADDRHDR_DEFAULT;
 1103                         state = STATE_LINESTART_AFTER_ADDRHDR;
 1104                     }
 1105                     else if (c == '\\')
 1106                     {
 1107                         backquote_savestate = state;
 1108                         state = STATE_ADDRHDR_BACKQUOTE;
 1109                     }
 1110                     else if (c == '"')
 1111                     {
 1112                         forget_current_recipient = 1;
 1113                         state = STATE_ADDRHDR_DQUOTE;
 1114                     }
 1115                     else if (c == '(')
 1116                     {
 1117                         parentheses_savestate = state;
 1118                         state = STATE_ADDRHDR_PARENTH_START;
 1119                     }
 1120                     else if (c == '<')
 1121                     {
 1122                         forget_current_recipient = 1;
 1123                         state = STATE_ADDRHDR_BRACKETS_START;
 1124                     }
 1125                     else if (c == ' ' || c == '\t')
 1126                         state = STATE_ADDRHDR_DEFAULT;
 1127                     else if (c == ':')
 1128                     {
 1129                         forget_current_recipient = 1;
 1130                         state = STATE_ADDRHDR_DEFAULT;
 1131                     }
 1132                     else if (c == ',' || c == ';')
 1133                     {
 1134                         finish_current_recipient = 1;
 1135                         state = STATE_ADDRHDR_DEFAULT;
 1136                     }
 1137                     break;
 1138 
 1139                 case STATE_ADDRHDR_BACKQUOTE:
 1140                     if (c == '\n')
 1141                     {
 1142                         folded_rcpthdr_savestate = STATE_ADDRHDR_DEFAULT;
 1143                         state = STATE_LINESTART_AFTER_ADDRHDR;
 1144                     }
 1145                     else
 1146                         state = backquote_savestate;
 1147                     break;
 1148             }
 1149         }
 1150 
 1151         if (tmpf && c != EOF && fputc(c, tmpf) == EOF)
 1152         {
 1153             *errstr = xasprintf(_("cannot write mail headers to temporary "
 1154                         "file: output error"));
 1155             goto error_exit;
 1156         }
 1157 
 1158         if (forget_current_recipient)
 1159         {
 1160             /* this was just junk */
 1161             free(current_recipient);
 1162             current_recipient = NULL;
 1163             current_recipient_len = 0;
 1164             bufsize = 0;
 1165             forget_current_recipient = 0;
 1166         }
 1167         if (finish_current_recipient)
 1168         {
 1169             /* The current recipient just ended. Add it to the list */
 1170             current_recipient[current_recipient_len] = '\0';
 1171             if (from_hdr == 0)
 1172             {
 1173                 *from = current_recipient;
 1174                 from_hdr = 1;
 1175             }
 1176             else if (recipients && resent_block == 0)
 1177             {
 1178                 list_insert(resent_recipients, current_recipient);
 1179                 resent_recipients = resent_recipients->next;
 1180             }
 1181             else if (recipients)
 1182             {
 1183                 list_insert(normal_recipients, current_recipient);
 1184                 normal_recipients = normal_recipients->next;
 1185             }
 1186             /* Reset for the next recipient */
 1187             current_recipient = NULL;
 1188             current_recipient_len = 0;
 1189             bufsize = 0;
 1190             finish_current_recipient = 0;
 1191         }
 1192         if ((state == STATE_ADDRHDR_IN_ADDRESS
 1193                     || state == STATE_ADDRHDR_IN_BRACKETS)
 1194                 && oldstate != STATE_ADDRHDR_PARENTH_START
 1195                 && oldstate != STATE_ADDRHDR_IN_PARENTH
 1196                 && oldstate != STATE_LINESTART_AFTER_ADDRHDR)
 1197         {
 1198             /* Add this character to the current recipient */
 1199             current_recipient_len++;
 1200             if (bufsize < current_recipient_len + 1)
 1201             {
 1202                 bufsize += bufsize_step;
 1203                 current_recipient = xrealloc(current_recipient,
 1204                         bufsize * sizeof(char));
 1205             }
 1206             /* sanitize characters */
 1207             if (!iscntrl((unsigned char)c) && !isspace((unsigned char)c))
 1208             {
 1209                 current_recipient[current_recipient_len - 1] = (char)c;
 1210             }
 1211             else
 1212             {
 1213                 current_recipient[current_recipient_len - 1] = '_';
 1214             }
 1215         }
 1216 
 1217         if (state == STATE_HEADERS_END)
 1218         {
 1219             break;
 1220         }
 1221     }
 1222 
 1223     /* Corner case: we saw a "From: " header without a recipient. */
 1224     if (from_hdr == 0)
 1225     {
 1226         *from = xstrdup("");
 1227     }
 1228 
 1229     if (recipients)
 1230     {
 1231         if (resent_block >= 0)
 1232         {
 1233             list_xfree(normal_recipients_list, free);
 1234             resent_recipients = resent_recipients_list;
 1235             while (!list_is_empty(resent_recipients))
 1236             {
 1237                 resent_recipients = resent_recipients->next;
 1238                 list_insert(recipients, resent_recipients->data);
 1239                 recipients = recipients->next;
 1240             }
 1241             list_free(resent_recipients_list);
 1242         }
 1243         else
 1244         {
 1245             list_xfree(resent_recipients_list, free);
 1246             normal_recipients = normal_recipients_list;
 1247             while (!list_is_empty(normal_recipients))
 1248             {
 1249                 normal_recipients = normal_recipients->next;
 1250                 list_insert(recipients, normal_recipients->data);
 1251                 recipients = recipients->next;
 1252             }
 1253             list_free(normal_recipients_list);
 1254         }
 1255         normal_recipients_list = NULL;
 1256         resent_recipients_list = NULL;
 1257     }
 1258 
 1259     if (ferror(mailf))
 1260     {
 1261         *errstr = xasprintf(_("input error while reading the mail"));
 1262         goto error_exit;
 1263     }
 1264 
 1265     return EX_OK;
 1266 
 1267 error_exit:
 1268     if (normal_recipients_list)
 1269     {
 1270         list_xfree(normal_recipients_list, free);
 1271     }
 1272     if (resent_recipients_list)
 1273     {
 1274         list_xfree(resent_recipients_list, free);
 1275     }
 1276     if (from)
 1277     {
 1278         free(*from);
 1279         *from = NULL;
 1280     }
 1281     free(current_recipient);
 1282     return EX_IOERR;
 1283 }
 1284 
 1285 
 1286 /*
 1287  * msmtp_sendmail()
 1288  *
 1289  * Sends a mail. Returns a value from sysexits.h.
 1290  * If an error occurred, '*errstr' points to an allocated string that describes
 1291  * the error or is NULL, and '*msg' may contain the offending message from the
 1292  * SMTP server (or be NULL).
 1293  * In case of success, 'mailsize' contains the number of bytes of the mail
 1294  * transferred to the SMTP server. In case of failure, its contents are
 1295  * undefined.
 1296  */
 1297 
 1298 int msmtp_sendmail(account_t *acc, list_t *recipients,
 1299         FILE *prepend_header_file, int prepend_header_contains_from,
 1300         FILE *header_file, FILE *f,
 1301         int debug, long *mailsize,
 1302         list_t **lmtp_errstrs, list_t **lmtp_error_msgs,
 1303         list_t **msg, char **errstr)
 1304 {
 1305     smtp_server_t srv;
 1306     int e;
 1307 #ifdef HAVE_TLS
 1308     mtls_cert_info_t *tci = NULL;
 1309     char *mtls_parameter_description = NULL;
 1310 #endif /* HAVE_TLS */
 1311 
 1312     *errstr = NULL;
 1313     *msg = NULL;
 1314     *lmtp_errstrs = NULL;
 1315     *lmtp_error_msgs = NULL;
 1316 
 1317     /* create a new smtp_server_t */
 1318     srv = smtp_new(debug ? stdout : NULL, acc->protocol);
 1319 
 1320     /* prepare tls */
 1321 #ifdef HAVE_TLS
 1322     if (acc->tls)
 1323     {
 1324         if ((e = smtp_tls_init(&srv,
 1325                         acc->tls_key_file, acc->tls_cert_file, acc->password,
 1326                         acc->tls_trust_file, acc->tls_crl_file,
 1327                         acc->tls_sha256_fingerprint,
 1328                         acc->tls_sha1_fingerprint, acc->tls_md5_fingerprint,
 1329                         acc->tls_min_dh_prime_bits,
 1330                         acc->tls_priorities,
 1331                         acc->tls_host_override ? acc->tls_host_override : acc->host,
 1332                         acc->tls_nocertcheck,
 1333                         errstr)) != TLS_EOK)
 1334         {
 1335             e = mtls_exitcode(e);
 1336             return e;
 1337         }
 1338     }
 1339 #endif /* HAVE_TLS */
 1340 
 1341     /* connect */
 1342     if ((e = smtp_connect(&srv, acc->socketname, acc->proxy_host, acc->proxy_port,
 1343                     acc->host, acc->port, acc->source_ip, acc->timeout,
 1344                     NULL, NULL, errstr)) != NET_EOK)
 1345     {
 1346         e = net_exitcode(e);
 1347         return e;
 1348     }
 1349 
 1350     /* start tls for smtps servers */
 1351 #ifdef HAVE_TLS
 1352     if (acc->tls && acc->tls_nostarttls)
 1353     {
 1354         if (debug)
 1355         {
 1356             tci = mtls_cert_info_new();
 1357         }
 1358         if ((e = smtp_tls(&srv, tci,
 1359                         &mtls_parameter_description, errstr)) != TLS_EOK)
 1360         {
 1361             if (debug)
 1362             {
 1363                 mtls_cert_info_free(tci);
 1364                 free(mtls_parameter_description);
 1365             }
 1366             msmtp_endsession(&srv, 0);
 1367             e = mtls_exitcode(e);
 1368             return e;
 1369         }
 1370         if (debug)
 1371         {
 1372             mtls_print_info(mtls_parameter_description, tci);
 1373             mtls_cert_info_free(tci);
 1374             free(mtls_parameter_description);
 1375         }
 1376     }
 1377 #endif /* HAVE_TLS */
 1378 
 1379     /* get greeting */
 1380     if ((e = smtp_get_greeting(&srv, msg, NULL, errstr)) != SMTP_EOK)
 1381     {
 1382         msmtp_endsession(&srv, 0);
 1383         e = smtp_exitcode(e);
 1384         return e;
 1385     }
 1386 
 1387     /* initialize session */
 1388     if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
 1389     {
 1390         msmtp_endsession(&srv, 0);
 1391         e = smtp_exitcode(e);
 1392         return e;
 1393     }
 1394 
 1395     /* start tls for starttls servers */
 1396 #ifdef HAVE_TLS
 1397     if (acc->tls && !acc->tls_nostarttls)
 1398     {
 1399         if (!(srv.cap.flags & SMTP_CAP_STARTTLS))
 1400         {
 1401             *errstr = xasprintf(_("the server does not support TLS "
 1402                         "via the STARTTLS command"));
 1403             msmtp_endsession(&srv, 1);
 1404             e = EX_UNAVAILABLE;
 1405             return e;
 1406         }
 1407         if ((e = smtp_tls_starttls(&srv, msg, errstr)) != SMTP_EOK)
 1408         {
 1409             msmtp_endsession(&srv, 0);
 1410             e = smtp_exitcode(e);
 1411             return e;
 1412         }
 1413         if (debug)
 1414         {
 1415             tci = mtls_cert_info_new();
 1416         }
 1417         if ((e = smtp_tls(&srv, tci,
 1418                         &mtls_parameter_description, errstr)) != TLS_EOK)
 1419         {
 1420             if (debug)
 1421             {
 1422                 mtls_cert_info_free(tci);
 1423                 free(mtls_parameter_description);
 1424             }
 1425             msmtp_endsession(&srv, 0);
 1426             e = mtls_exitcode(e);
 1427             return e;
 1428         }
 1429         if (debug)
 1430         {
 1431             mtls_print_info(mtls_parameter_description, tci);
 1432             mtls_cert_info_free(tci);
 1433             free(mtls_parameter_description);
 1434         }
 1435         /* initialize again */
 1436         if ((e = smtp_init(&srv, acc->domain, msg, errstr)) != SMTP_EOK)
 1437         {
 1438             msmtp_endsession(&srv, 0);
 1439             e = smtp_exitcode(e);
 1440             return e;
 1441         }
 1442     }
 1443 #endif /* HAVE_TLS */
 1444 
 1445     /* test for needed features */
 1446     if ((acc->dsn_return || acc->dsn_notify) && !(srv.cap.flags & SMTP_CAP_DSN))
 1447     {
 1448         *errstr = xasprintf(_("the server does not support DSN"));
 1449         msmtp_endsession(&srv, 1);
 1450         e = EX_UNAVAILABLE;
 1451         return e;
 1452     }
 1453     /* authenticate */
 1454     if (acc->auth_mech)
 1455     {
 1456         if (!(srv.cap.flags & SMTP_CAP_AUTH))
 1457         {
 1458             *errstr = xasprintf(
 1459                     _("the server does not support authentication"));
 1460             msmtp_endsession(&srv, 1);
 1461             e = EX_UNAVAILABLE;
 1462             return e;
 1463         }
 1464         if ((e = smtp_auth(&srv, acc->host, acc->port,
 1465                         acc->username, acc->password,
 1466                         acc->ntlmdomain, acc->auth_mech,
 1467                         msmtp_password_callback, msg, errstr))
 1468                 != SMTP_EOK)
 1469         {
 1470             msmtp_endsession(&srv, 0);
 1471             e = smtp_exitcode(e);
 1472             return e;
 1473         }
 1474     }
 1475 
 1476     /* send the envelope */
 1477     if ((e = smtp_send_envelope(&srv, acc->from, recipients,
 1478                     acc->dsn_notify, acc->dsn_return, msg, errstr)) != SMTP_EOK)
 1479     {
 1480         msmtp_endsession(&srv, 0);
 1481         e = smtp_exitcode(e);
 1482         return e;
 1483     }
 1484     /* send header and body */
 1485     *mailsize = 0;
 1486     if (prepend_header_file)
 1487     {
 1488         /* first: prepended headers, if any */
 1489         if ((e = smtp_send_mail(&srv, prepend_header_file,
 1490                         1, 1, 1, 1, mailsize,
 1491                         errstr)) != SMTP_EOK)
 1492         {
 1493             msmtp_endsession(&srv, 0);
 1494             e = smtp_exitcode(e);
 1495             return e;
 1496         }
 1497     }
 1498     /* next: original mail headers */
 1499     if ((e = smtp_send_mail(&srv, header_file,
 1500                     !prepend_header_contains_from, /* keep_from */
 1501                     !acc->undisclosed_recipients,  /* keep_to */
 1502                     !acc->undisclosed_recipients,  /* keep_cc */
 1503                     !acc->undisclosed_recipients
 1504                     && !acc->remove_bcc_headers,   /* keep_bcc */
 1505                     mailsize, errstr)) != SMTP_EOK)
 1506     {
 1507         msmtp_endsession(&srv, 0);
 1508         e = smtp_exitcode(e);
 1509         return e;
 1510     }
 1511     /* then: the body from the original file */
 1512     if ((e = smtp_send_mail(&srv, f, 1, 1, 1, 1, mailsize, errstr)) != SMTP_EOK)
 1513     {
 1514         msmtp_endsession(&srv, 0);
 1515         e = smtp_exitcode(e);
 1516         return e;
 1517     }
 1518     /* end the mail */
 1519     if (acc->protocol == SMTP_PROTO_SMTP)
 1520     {
 1521         e = smtp_end_mail(&srv, msg, errstr);
 1522     }
 1523     else
 1524     {
 1525         e = smtp_end_mail_lmtp(&srv, recipients,
 1526                 lmtp_errstrs, lmtp_error_msgs, errstr);
 1527     }
 1528     if (e != SMTP_EOK)
 1529     {
 1530         msmtp_endsession(&srv, 0);
 1531         e = smtp_exitcode(e);
 1532         return e;
 1533     }
 1534 
 1535     /* end session */
 1536     msmtp_endsession(&srv, 1);
 1537 
 1538     return EX_OK;
 1539 }
 1540 
 1541 
 1542 /*
 1543  * print_error()
 1544  *
 1545  * Print an error message
 1546  */
 1547 
 1548 /* make gcc print format warnings for this function */
 1549 #ifdef __GNUC__
 1550 void print_error(const char *format, ...)
 1551     __attribute__ ((format (printf, 1, 2)));
 1552 #endif
 1553 
 1554 void print_error(const char *format, ...)
 1555 {
 1556     va_list args;
 1557     fprintf(stderr, "%s: ", prgname);
 1558     va_start(args, format);
 1559     vfprintf(stderr, format, args);
 1560     va_end(args);
 1561     fprintf(stderr, "\n");
 1562 }
 1563 
 1564 
 1565 /*
 1566  * msmtp_configure()
 1567  *
 1568  * Tries autoconfiguration for the given mail address based on the methods
 1569  * described in RFC 8314 (SRV records).
 1570  * If successfull, this function will print a configuration file excerpt to
 1571  * standard output and return EX_OK.
 1572  * Otherwise, it will print an appropriate error message to standard error
 1573  * and return an EX_* status.
 1574  */
 1575 
 1576 int msmtp_configure(const char *address, const char *conffile)
 1577 {
 1578 #ifdef HAVE_LIBRESOLV
 1579 
 1580     int e;
 1581 
 1582     char *local_part;
 1583     char *domain_part;
 1584 
 1585     char *submissions_query;
 1586     char *submission_query;
 1587 
 1588     char *hostname = NULL;
 1589     int port = -1;
 1590     int starttls = -1;
 1591 
 1592     char *tmpstr;
 1593 
 1594     split_mail_address(address, &local_part, &domain_part);
 1595     if (!domain_part || domain_part[0] == '\0' || local_part[0] == '\0')
 1596     {
 1597         print_error(_("automatic configuration based on SRV records failed: %s"),
 1598                 _("invalid mail address"));
 1599         free(local_part);
 1600         free(domain_part);
 1601         return EX_DATAERR;
 1602     }
 1603 
 1604     submissions_query = net_get_srv_query(domain_part, "submissions");
 1605     e = net_get_srv_record(submissions_query, &hostname, &port);
 1606     if (e == NET_EOK) {
 1607         starttls = 0;
 1608     } else {
 1609         submission_query = net_get_srv_query(domain_part, "submission");
 1610         e = net_get_srv_record(submission_query, &hostname, &port);
 1611         if (e == NET_EOK) {
 1612             starttls = 1;
 1613         } else {
 1614             char *errstr = xasprintf(_("no SRV records for %s or %s"),
 1615                     submissions_query, submission_query);
 1616             print_error(_("automatic configuration based on SRV records failed: %s"),
 1617                     errstr);
 1618             free(errstr);
 1619             free(submissions_query);
 1620             free(submission_query);
 1621             free(local_part);
 1622             free(domain_part);
 1623             return EX_NOHOST;
 1624         }
 1625         free(submission_query);
 1626     }
 1627     free(submissions_query);
 1628 
 1629     /* comment header */
 1630 
 1631     tmpstr = xasprintf(_("copy this to your configuration file %s"), conffile);
 1632     printf("# - %s\n", tmpstr);
 1633     free(tmpstr);
 1634     if (!check_hostname_matches_domain(hostname, domain_part))
 1635         printf("# - %s\n", _("warning: the host does not match the mail domain; please check"));
 1636 #if defined HAVE_LIBSECRET
 1637     tmpstr = xasprintf("secret-tool store --label=msmtp host %s service smtp user %s", hostname, local_part);
 1638     printf("# - %s\n#   %s\n", _("add your password to the key ring:"), tmpstr);
 1639     free(tmpstr);
 1640 #elif defined HAVE_MACOSXKEYRING
 1641     tmpstr = xasprintf("security add-internet-password -s %s -r smtp -a %s -w", hostname, local_part);
 1642     printf("# - %s\n#   %s\n", _("add your password to the key ring:"), tmpstr);
 1643     free(tmpstr);
 1644 #else
 1645     printf("# - %s\n#   %s\n", _("encrypt your password:"), "gpg -e -o ~/.msmtp-password.gpg");
 1646 #endif
 1647 
 1648     /* account definition */
 1649     printf("account %s\n", address);
 1650     printf("host %s\n", hostname);
 1651     printf("port %d\n", port);
 1652     printf("tls on\n");
 1653     printf("tls_starttls %s\n", starttls ? "on" : "off");
 1654     printf("auth on\n");
 1655     printf("user %s\n", local_part);
 1656 #if !defined HAVE_LIBSECRET && !defined HAVE_MACOSXKEYRING
 1657     printf("passwordeval gpg --no-tty -q -d ~/.msmtp-password.gpg\n");
 1658 #endif
 1659     printf("from %s\n", address);
 1660 
 1661     free(local_part);
 1662     free(domain_part);
 1663     free(hostname);
 1664     return EX_OK;
 1665 
 1666 #else
 1667 
 1668     print_error(_("automatic configuration based on SRV records failed: %s"),
 1669             _("this system lacks libresolv"));
 1670     return EX_UNAVAILABLE;
 1671 
 1672 #endif
 1673 }
 1674 
 1675 
 1676 /*
 1677  * msmtp_get_log_info()
 1678  *
 1679  * Gather log information for syslog or logfile and put it in a string:
 1680  * - host=%s
 1681  * - tls=on|off
 1682  * - auth=on|off
 1683  * - user=%s (only if auth == on and username != NULL)
 1684  * - from=%s
 1685  * - recipients=%s,%s,...
 1686  * - mailsize=%s (only if exitcode == EX_OK)
 1687  * - smtpstatus=%s (only if a smtp msg is available)
 1688  * - smtpmsg='%s' (only if a smtp msg is available)
 1689  * - errormsg='%s' (only if exitcode != EX_OK and an error msg is available)
 1690  * - exitcode=%s
 1691  * 'exitcode' must be one of the sysexits.h exitcodes.
 1692  * This function cannot fail.
 1693  */
 1694 
 1695 char *msmtp_get_log_info(account_t *acc, list_t *recipients, long mailsize,
 1696         list_t *errmsg, char *errstr, int exitcode)
 1697 {
 1698     int i;
 1699     size_t s;
 1700     list_t *l;
 1701     char *line;
 1702     int n;
 1703     char *p;
 1704     char *tmp;
 1705     /* temporary strings: */
 1706     char *mailsize_str = NULL;
 1707     const char *exitcode_str;
 1708     char *smtpstatus_str = NULL;
 1709     char *smtperrmsg_str = NULL;
 1710 
 1711 
 1712     /* gather information */
 1713 
 1714     line = NULL;
 1715     /* mailsize */
 1716     if (exitcode == EX_OK)
 1717     {
 1718         mailsize_str = xasprintf("%ld", mailsize);
 1719     }
 1720     /* exitcode */
 1721     exitcode_str = exitcode_to_string(exitcode);
 1722     /* smtp status and smtp error message */
 1723     if (errmsg)
 1724     {
 1725         smtpstatus_str = xasprintf("%d", smtp_msg_status(errmsg));
 1726         l = errmsg;
 1727         s = 0;
 1728         while (!list_is_empty(l))
 1729         {
 1730             l = l->next;
 1731             s += strlen(l->data) + 2;
 1732         }
 1733         s += 1;
 1734         smtperrmsg_str = xmalloc(s * sizeof(char));
 1735         smtperrmsg_str[0] = '\'';
 1736         i = 1;
 1737         l = errmsg;
 1738         while (!list_is_empty(l))
 1739         {
 1740             l = l->next;
 1741             p = sanitize_string(l->data);
 1742             while (*p != '\0')
 1743             {
 1744                 /* hide single quotes to make the info easy to parse */
 1745                 smtperrmsg_str[i] = (*p == '\'') ? '?' : *p;
 1746                 p++;
 1747                 i++;
 1748             }
 1749             smtperrmsg_str[i++] = '\\';
 1750             smtperrmsg_str[i++] = 'n';
 1751         }
 1752         i -= 2;
 1753         smtperrmsg_str[i++] = '\'';
 1754         smtperrmsg_str[i++] = '\0';
 1755     }
 1756 
 1757     /* calculate the length of the log line */
 1758 
 1759     s = 0;
 1760     /* "host=%s " */
 1761     s += 5 + strlen(acc->host) + 1;
 1762     /* "tls=on|off " */
 1763     s += 4 + (acc->tls ? 2 : 3) + 1;
 1764     /* "auth=on|off " */
 1765     s += 5 + (acc->auth_mech ? 2 : 3) + 1;
 1766     /* "user=%s " */
 1767     if (acc->auth_mech && acc->username)
 1768     {
 1769         s += 5 + strlen(acc->username) + 1;
 1770     }
 1771     /* "from=%s " */
 1772     s += 5 + strlen(acc->from) + 1;
 1773     /* "recipients=%s,%s,... " */
 1774     s += 11;
 1775     l = recipients;
 1776     while (!list_is_empty(l))
 1777     {
 1778         l = l->next;
 1779         s += strlen(l->data) + 1;
 1780     }
 1781     /* "mailsize=%s " */
 1782     if (exitcode == EX_OK)
 1783     {
 1784         s += 9 + strlen(mailsize_str) + 1;
 1785     }
 1786     /* "smtpstatus=%s smtpmsg=%s " */
 1787     if (errmsg)
 1788     {
 1789         s += 11 + strlen(smtpstatus_str) + 1 + 8 + strlen(smtperrmsg_str) + 1;
 1790     }
 1791     /* "errormsg='%s' */
 1792     if (exitcode != EX_OK && errstr[0] != '\0')
 1793     {
 1794         s += 10 + strlen(errstr) + 2;
 1795     }
 1796     /* "exitcode=%s" */
 1797     s += 9 + strlen(exitcode_str);
 1798     /* '\0' */
 1799     s++;
 1800 
 1801     line = xmalloc(s * sizeof(char));
 1802 
 1803     /* build the log line */
 1804 
 1805     p = line;
 1806     n = snprintf(p, s, "host=%s tls=%s auth=%s ",
 1807             acc->host, (acc->tls ? "on" : "off"),
 1808             (acc->auth_mech ? "on" : "off"));
 1809     s -= n;
 1810     p += n;
 1811     if (acc->auth_mech && acc->username)
 1812     {
 1813         n = snprintf(p, s, "user=%s ", acc->username);
 1814         s -= n;
 1815         p += n;
 1816     }
 1817     n = snprintf(p, s, "from=%s recipients=", acc->from);
 1818     s -= n;
 1819     p += n;
 1820     l = recipients;
 1821     while (!list_is_empty(l))
 1822     {
 1823         l = l->next;
 1824         n = snprintf(p, s, "%s,", (char *)(l->data));
 1825         s -= n;
 1826         p += n;
 1827     }
 1828     /* delete the last ',' */
 1829     *(p - 1) = ' ';
 1830     if (exitcode == EX_OK)
 1831     {
 1832         n = snprintf(p, s, "mailsize=%s ", mailsize_str);
 1833         s -= n;
 1834         p += n;
 1835     }
 1836     if (errmsg)
 1837     {
 1838         n = snprintf(p, s, "smtpstatus=%s smtpmsg=%s ",
 1839                 smtpstatus_str, smtperrmsg_str);
 1840         s -= n;
 1841         p += n;
 1842     }
 1843     if (exitcode != EX_OK && errstr[0] != '\0')
 1844     {
 1845         /* hide single quotes to make the info easy to parse */
 1846         tmp = errstr;
 1847         while (*tmp)
 1848         {
 1849             if (*tmp == '\'')
 1850             {
 1851                 *tmp = '?';
 1852             }
 1853             tmp++;
 1854         }
 1855         n = snprintf(p, s, "errormsg='%s' ", sanitize_string(errstr));
 1856         s -= n;
 1857         p += n;
 1858     }
 1859     (void)snprintf(p, s, "exitcode=%s", exitcode_str);
 1860 
 1861     free(mailsize_str);
 1862     free(smtpstatus_str);
 1863     free(smtperrmsg_str);
 1864     return line;
 1865 }
 1866 
 1867 
 1868 /*
 1869  * msmtp_log_to_file()
 1870  *
 1871  * Append a log entry to 'logfile' with the following information:
 1872  * - date/time in the format given by 'logfile_time_format' (may be NULL)
 1873  * - the log line as delivered by msmtp_get_log_info
 1874  */
 1875 
 1876 void msmtp_log_to_file(const char *logfile, const char *logfile_time_format,
 1877         const char *loginfo)
 1878 {
 1879     FILE *f = NULL;
 1880     time_t t;
 1881     struct tm *tm;
 1882     char *failure_reason;
 1883     const char *time_fmt;
 1884     char time_str[128];
 1885     int e;
 1886 
 1887     /* get time */
 1888     t = time(NULL); /* cannot fail */
 1889     tm = localtime(&t); /* cannot fail */
 1890     time_fmt = logfile_time_format ? logfile_time_format : "%b %d %H:%M:%S";
 1891     if (strftime(time_str, sizeof(time_str), time_fmt, tm) == 0)
 1892     {
 1893         /* a return value of 0 is only an error with a non-empty time_fmt,
 1894          * but we know it is non-empty since we cannot configure an empty
 1895          * logfile_time_format in msmtp (it would be set to NULL). */
 1896         failure_reason = xasprintf(_("invalid logfile_time_format"));
 1897         goto log_failure;
 1898     }
 1899 
 1900     /* write log to file */
 1901     if (strcmp(logfile, "-") == 0)
 1902     {
 1903         f = stdout;
 1904     }
 1905     else
 1906     {
 1907         if (!(f = fopen(logfile, "a")))
 1908         {
 1909             failure_reason = xasprintf(_("cannot open: %s"), strerror(errno));
 1910             goto log_failure;
 1911         }
 1912         if ((e = lock_file(f, TOOLS_LOCK_WRITE, 10)) != 0)
 1913         {
 1914             if (e == 1)
 1915             {
 1916                 failure_reason = xasprintf(
 1917                         _("cannot lock (tried for %d seconds): %s"),
 1918                         10, strerror(errno));
 1919             }
 1920             else
 1921             {
 1922                 failure_reason = xasprintf(_("cannot lock: %s"),
 1923                         strerror(errno));
 1924             }
 1925             goto log_failure;
 1926         }
 1927     }
 1928     if ((fputs(time_str, f) == EOF) || (fputc(' ', f) == EOF)
 1929         || (fputs(loginfo, f) == EOF) || (fputc('\n', f) == EOF))
 1930     {
 1931         failure_reason = xstrdup(_("output error"));
 1932         goto log_failure;
 1933     }
 1934     if (f != stdout && fclose(f) != 0)
 1935     {
 1936         failure_reason = xstrdup(strerror(errno));
 1937         goto log_failure;
 1938     }
 1939 
 1940     return;
 1941 
 1942     /* error exit target */
 1943 log_failure:
 1944     if (f && f != stdout)
 1945     {
 1946         fclose(f);
 1947     }
 1948     print_error(_("cannot log to %s: %s"), logfile, failure_reason);
 1949     free(failure_reason);
 1950     if (loginfo)
 1951     {
 1952         print_error(_("log info was: %s"), loginfo);
 1953     }
 1954 }
 1955 
 1956 
 1957 /*
 1958  * msmtp_log_to_syslog()
 1959  *
 1960  * Log the information delivered by msmtp_get_log_info() to syslog
 1961  * the facility_str must be one of "LOG_MAIL", "LOG_USER", "LOG_LOCAL0", ...
 1962  * "LOG_LOCAL7"
 1963  * If 'error' is set, LOG_ERR is used, else LOG_INFO is used.
 1964  */
 1965 
 1966 #ifdef HAVE_SYSLOG
 1967 void msmtp_log_to_syslog(const char *facility_str,
 1968         const char *loginfo, int error)
 1969 {
 1970     int facility;
 1971 
 1972     if (facility_str[4] == 'M')
 1973     {
 1974         facility = LOG_MAIL;
 1975     }
 1976     else if (facility_str[4] == 'U')
 1977     {
 1978         facility = LOG_USER;
 1979     }
 1980     else if (facility_str[9] == '0')
 1981     {
 1982         facility = LOG_LOCAL0;
 1983     }
 1984     else if (facility_str[9] == '1')
 1985     {
 1986         facility = LOG_LOCAL1;
 1987     }
 1988     else if (facility_str[9] == '2')
 1989     {
 1990         facility = LOG_LOCAL2;
 1991     }
 1992     else if (facility_str[9] == '3')
 1993     {
 1994         facility = LOG_LOCAL3;
 1995     }
 1996     else if (facility_str[9] == '4')
 1997     {
 1998         facility = LOG_LOCAL4;
 1999     }
 2000     else if (facility_str[9] == '5')
 2001     {
 2002         facility = LOG_LOCAL5;
 2003     }
 2004     else if (facility_str[9] == '6')
 2005     {
 2006         facility = LOG_LOCAL6;
 2007     }
 2008     else
 2009     {
 2010         facility = LOG_LOCAL7;
 2011     }
 2012 
 2013     openlog(PACKAGE_NAME, 0, facility);
 2014     syslog(error ? LOG_ERR : LOG_INFO, "%s", loginfo);
 2015     closelog();
 2016 }
 2017 #endif /* HAVE_SYSLOG */
 2018 
 2019 
 2020 /*
 2021  * msmtp_construct_env_from()
 2022  *
 2023  * OBSOLETE: triggered by auto_from, uses maildomain. both are replaced
 2024  * with substitution patterns supported in from.
 2025  *
 2026  * Build an envelope from address for the current user.
 2027  * If maildomain is not NULL and not the empty string, it will be the domain
 2028  * part of the address. Otherwise, the address won't have a domain part.
 2029  */
 2030 
 2031 char *msmtp_construct_env_from(const char *maildomain)
 2032 {
 2033     char *envelope_from;
 2034     size_t len;
 2035 
 2036     envelope_from = get_username();
 2037     if (maildomain && *maildomain != '\0')
 2038     {
 2039         len = strlen(envelope_from);
 2040         envelope_from = xrealloc(envelope_from,
 2041                 ((len + 1 + strlen(maildomain) + 1) * sizeof(char)));
 2042         envelope_from[len] = '@';
 2043         strcpy(envelope_from + len + 1, maildomain);
 2044     }
 2045     return envelope_from;
 2046 }
 2047 
 2048 
 2049 /*
 2050  * msmtp_print_version()
 2051  *
 2052  * Print --version information
 2053  */
 2054 
 2055 void msmtp_print_version(void)
 2056 {
 2057     char *sysconfdir;
 2058     char *sysconffile;
 2059     char *userconffile;
 2060 
 2061     printf(_("%s version %s\n"), PACKAGE_NAME, VERSION);
 2062     printf(_("Platform: %s\n"), PLATFORM);
 2063     /* TLS/SSL support */
 2064     printf(_("TLS/SSL library: %s\n"),
 2065 #ifdef HAVE_LIBGNUTLS
 2066             "GnuTLS"
 2067 #elif defined (HAVE_LIBSSL)
 2068             "OpenSSL"
 2069 #elif defined (HAVE_LIBTLS)
 2070             "libtls"
 2071 #else
 2072             _("none")
 2073 #endif
 2074           );
 2075     /* Authentication support */
 2076     printf(_("Authentication library: %s\n"
 2077                 "Supported authentication methods:\n"),
 2078 #ifdef HAVE_LIBGSASL
 2079             _("GNU SASL; oauthbearer and xoauth2: built-in")
 2080 #else
 2081             _("built-in")
 2082 #endif /* HAVE_LIBGSASL */
 2083           );
 2084     if (smtp_client_supports_authmech("PLAIN"))
 2085     {
 2086         printf("plain ");
 2087     }
 2088     if (smtp_client_supports_authmech("SCRAM-SHA-1"))
 2089     {
 2090         printf("scram-sha-1 ");
 2091     }
 2092     if (smtp_client_supports_authmech("SCRAM-SHA-256"))
 2093     {
 2094         printf("scram-sha-256 ");
 2095     }
 2096     if (smtp_client_supports_authmech("EXTERNAL"))
 2097     {
 2098         printf("external ");
 2099     }
 2100     if (smtp_client_supports_authmech("GSSAPI"))
 2101     {
 2102         printf("gssapi ");
 2103     }
 2104     if (smtp_client_supports_authmech("CRAM-MD5"))
 2105     {
 2106         printf("cram-md5 ");
 2107     }
 2108     if (smtp_client_supports_authmech("DIGEST-MD5"))
 2109     {
 2110         printf("digest-md5 ");
 2111     }
 2112     if (smtp_client_supports_authmech("LOGIN"))
 2113     {
 2114         printf("login ");
 2115     }
 2116     if (smtp_client_supports_authmech("NTLM"))
 2117     {
 2118         printf("ntlm ");
 2119     }
 2120     if (smtp_client_supports_authmech("OAUTHBEARER"))
 2121     {
 2122         printf("oauthbearer ");
 2123     }
 2124     if (smtp_client_supports_authmech("XOAUTH2"))
 2125     {
 2126         printf("xoauth2 ");
 2127     }
 2128     printf("\n");
 2129     /* Internationalized Domain Names support */
 2130     printf(_("IDN support: "));
 2131 #if defined(HAVE_LIBIDN) \
 2132         || (defined(HAVE_GAI_IDN) && (!defined(HAVE_TLS) \
 2133             || (defined(HAVE_LIBGNUTLS) && GNUTLS_VERSION_NUMBER >= 0x030400)))
 2134     printf(_("enabled"));
 2135 #else
 2136     printf(_("disabled"));
 2137 #endif
 2138     printf("\n");
 2139     /* Native language support */
 2140     printf(_("NLS: "));
 2141 #ifdef ENABLE_NLS
 2142     printf(_("enabled"));
 2143     printf(_(", LOCALEDIR is %s"), LOCALEDIR);
 2144 #else
 2145     printf(_("disabled"));
 2146 #endif
 2147     printf("\n");
 2148     printf(_("Keyring support: "));
 2149 #if !defined HAVE_LIBSECRET && !defined HAVE_MACOSXKEYRING
 2150     printf(_("none"));
 2151 #else
 2152 # ifdef HAVE_LIBSECRET
 2153     printf(_("Gnome "));
 2154 # endif
 2155 # ifdef HAVE_MACOSXKEYRING
 2156     printf(_("MacOS "));
 2157 # endif
 2158 #endif
 2159     printf("\n");
 2160     sysconfdir = get_sysconfdir();
 2161     sysconffile = get_filename(sysconfdir, SYSCONFFILE);
 2162     printf(_("System configuration file name: %s\n"), sysconffile);
 2163     free(sysconffile);
 2164     free(sysconfdir);
 2165     userconffile = get_userconfig(USERCONFFILE);
 2166     printf(_("User configuration file name: %s\n"), userconffile);
 2167     free(userconffile);
 2168     printf("\n");
 2169     printf(_("Copyright (C) 2021 Martin Lambers and others.\n"
 2170                 "This is free software.  You may redistribute copies of "
 2171                     "it under the terms of\n"
 2172                 "the GNU General Public License "
 2173                     "<http://www.gnu.org/licenses/gpl.html>.\n"
 2174                 "There is NO WARRANTY, to the extent permitted by law.\n"));
 2175 }
 2176 
 2177 
 2178 /*
 2179  * msmtp_print_help()
 2180  *
 2181  * Print --help information
 2182  */
 2183 
 2184 void msmtp_print_help(void)
 2185 {
 2186     printf(_("Usage:\n\n"));
 2187     printf(_("Sendmail mode (default):\n"
 2188              "  %s [option...] [--] recipient...\n"
 2189              "  %s [option...] -t [--] [recipient...]\n"
 2190              "  Read a mail from standard input and transmit it to an SMTP "
 2191                 "or LMTP server.\n"), prgname, prgname);
 2192     printf(_("Configuration mode:\n"
 2193              "  %s --configure=mailadress\n"
 2194              "  Generate and print configuration for address.\n"), prgname);
 2195     printf(_("Server information mode:\n"
 2196              "  %s [option...] --serverinfo\n"
 2197              "  Print information about a server.\n"), prgname);
 2198     printf(_("Remote Message Queue Starting mode:\n"
 2199              "  %s [option...] --rmqs=host|@domain|#queue\n"
 2200              "  Send a Remote Message Queue Starting request to a server.\n\n"),
 2201              prgname);
 2202     printf(_("General options:\n"));
 2203     printf(_("  --version                    print version\n"));
 2204     printf(_("  --help                       print help\n"));
 2205     printf(_("  -P, --pretend                print configuration info and exit\n"));
 2206     printf(_("  -d, --debug                  print debugging information\n"));
 2207     printf(_("Changing the mode of operation:\n"));
 2208     printf(_("  --configure=mailaddress      generate and print configuration for address\n"));
 2209     printf(_("  -S, --serverinfo             print information about the server\n"));
 2210     printf(_("  --rmqs=host|@domain|#queue   send a Remote Message Queue Starting request\n"));
 2211     printf(_("Configuration options:\n"));
 2212     printf(_("  -C, --file=filename          set configuration file\n"));
 2213     printf(_("  -a, --account=id             use the given account instead of the account\n"
 2214              "                               named \"default\"; its settings may be changed\n"
 2215              "                               with command-line options\n"));
 2216     printf(_("  --host=hostname              set the server, use only command-line settings;\n"
 2217              "                               do not use any configuration file data\n"));
 2218     printf(_("  --port=number                set port number\n"));
 2219     printf(_("  --source-ip=[IP]             set/unset source ip address to bind the socket to\n"));
 2220     printf(_("  --proxy-host=[IP|hostname]   set/unset proxy\n"));
 2221     printf(_("  --proxy-port=[number]        set/unset proxy port\n"));
 2222     printf(_("  --socket=[socketname]        set/unset local socket to connect to\n"));
 2223     printf(_("  --timeout=(off|seconds)      set/unset network timeout in seconds\n"));
 2224     printf(_("  --protocol=(smtp|lmtp)       use the given sub protocol\n"));
 2225     printf(_("  --domain=string              set the argument of EHLO or LHLO command\n"));
 2226     printf(_("  --auth[=(on|off|method)]     enable/disable authentication and optionally\n"
 2227              "                               choose the method\n"));
 2228     printf(_("  --user=[username]            set/unset user name for authentication\n"));
 2229     printf(_("  --passwordeval=[eval]        evaluate password for authentication\n"));
 2230     printf(_("  --tls[=(on|off)]             enable/disable TLS encryption\n"));
 2231     printf(_("  --tls-starttls[=(on|off)]    enable/disable STARTTLS for TLS\n"));
 2232     printf(_("  --tls-trust-file=[file]      set/unset trust file for TLS\n"));
 2233     printf(_("  --tls-crl-file=[file]        set/unset revocation file for TLS\n"));
 2234     printf(_("  --tls-fingerprint=[f]        set/unset trusted certificate fingerprint for TLS\n"));
 2235     printf(_("  --tls-certcheck[=(on|off)]   enable/disable server certificate checks for TLS\n"));
 2236     printf(_("  --tls-key-file=[file]        set/unset private key file for TLS\n"));
 2237     printf(_("  --tls-cert-file=[file]       set/unset private cert file for TLS\n"));
 2238     printf(_("  --tls-priorities=[prios]     set/unset TLS priorities.\n"));
 2239     printf(_("  --tls-host-override=[host]   set/unset override for TLS host verification.\n"));
 2240     printf(_("  --tls-min-dh-prime-bits=[b]  set/unset minimum bit size of DH prime\n"));
 2241     printf(_("Options specific to sendmail mode:\n"));
 2242     printf(_("  --auto-from[=(on|off)]       enable/disable automatic envelope-from addresses\n"));
 2243     printf(_("  -f, --from=address           set envelope from address\n"));
 2244     printf(_("  --maildomain=[domain]        set the domain for automatic envelope from\n"
 2245              "                               addresses\n"));
 2246     printf(_("  -N, --dsn-notify=(off|cond)  set/unset DSN conditions\n"));
 2247     printf(_("  -R, --dsn-return=(off|ret)   set/unset DSN amount\n"));
 2248     printf(_("  -X, --logfile=[file]         set/unset log file\n"));
 2249     printf(_("  --logfile-time-format=[fmt]  set/unset log file time format for strftime()\n"));
 2250     printf(_("  --syslog[=(on|off|facility)] enable/disable/configure syslog logging\n"));
 2251     printf(_("  -t, --read-recipients        read additional recipients from the mail\n"));
 2252     printf(_("  --read-envelope-from         read envelope from address from the mail\n"));
 2253     printf(_("  --aliases=[file]             set/unset aliases file\n"));
 2254     printf(_("  --set-from-header[=(auto|on|off)] set From header handling\n"));
 2255     printf(_("  --set-date-header[=(auto|off)] set Date header handling\n"));
 2256     printf(_("  --remove-bcc-headers[=(on|off)] enable/disable removal of Bcc headers\n"));
 2257     printf(_("  --undisclosed-recipients[=(on|off)] enable/disable replacement of To/Cc/Bcc\n"
 2258              "                               with To: undisclosed-recipients:;\n"));
 2259     printf(_("  --                           end of options\n"));
 2260     printf(_("Accepted but ignored: -A, -B, -bm, -F, -G, -h, -i, -L, -m, -n, -O, -o, -v\n"));
 2261     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
 2262 }
 2263 
 2264 
 2265 /*
 2266  * msmtp_cmdline()
 2267  *
 2268  * Process the command line
 2269  */
 2270 
 2271 typedef struct
 2272 {
 2273     /* the configuration */
 2274     int print_version;
 2275     int print_help;
 2276     int print_conf;
 2277     int debug;
 2278     int pretend;
 2279     int read_recipients;
 2280     int read_envelope_from;
 2281     /* mode of operation */
 2282     int sendmail;
 2283     int configure;
 2284     char *configure_address;
 2285     int serverinfo;
 2286     int rmqs;
 2287     char *rmqs_argument;
 2288     /* account information from the command line */
 2289     account_t *cmdline_account;
 2290     const char *account_id;
 2291     char *user_conffile;
 2292     /* additional information */
 2293     char *full_name;
 2294     /* the list of recipients */
 2295     list_t *recipients;
 2296 } msmtp_cmdline_conf_t;
 2297 
 2298 /* long options without a corresponding short option */
 2299 #define LONGONLYOPT_VERSION                     (256 + 0)
 2300 #define LONGONLYOPT_HELP                        (256 + 1)
 2301 #define LONGONLYOPT_HOST                        (256 + 2)
 2302 #define LONGONLYOPT_PORT                        (256 + 3)
 2303 #define LONGONLYOPT_TIMEOUT                     (256 + 4)
 2304 #define LONGONLYOPT_AUTH                        (256 + 5)
 2305 #define LONGONLYOPT_USER                        (256 + 6)
 2306 #define LONGONLYOPT_PASSWORDEVAL                (256 + 7)
 2307 #define LONGONLYOPT_TLS                         (256 + 8)
 2308 #define LONGONLYOPT_TLS_STARTTLS                (256 + 9)
 2309 #define LONGONLYOPT_TLS_TRUST_FILE              (256 + 10)
 2310 #define LONGONLYOPT_TLS_CRL_FILE                (256 + 11)
 2311 #define LONGONLYOPT_TLS_FINGERPRINT             (256 + 12)
 2312 #define LONGONLYOPT_TLS_KEY_FILE                (256 + 13)
 2313 #define LONGONLYOPT_TLS_CERT_FILE               (256 + 14)
 2314 #define LONGONLYOPT_TLS_CERTCHECK               (256 + 15)
 2315 #define LONGONLYOPT_TLS_FORCE_SSLV3             (256 + 16)
 2316 #define LONGONLYOPT_TLS_MIN_DH_PRIME_BITS       (256 + 17)
 2317 #define LONGONLYOPT_TLS_PRIORITIES              (256 + 18)
 2318 #define LONGONLYOPT_TLS_HOST_OVERRIDE           (256 + 19)
 2319 #define LONGONLYOPT_PROTOCOL                    (256 + 20)
 2320 #define LONGONLYOPT_DOMAIN                      (256 + 21)
 2321 #define LONGONLYOPT_KEEPBCC                     (256 + 22)
 2322 #define LONGONLYOPT_RMQS                        (256 + 23)
 2323 #define LONGONLYOPT_SYSLOG                      (256 + 24)
 2324 #define LONGONLYOPT_MAILDOMAIN                  (256 + 25)
 2325 #define LONGONLYOPT_AUTO_FROM                   (256 + 26)
 2326 #define LONGONLYOPT_READ_ENVELOPE_FROM          (256 + 27)
 2327 #define LONGONLYOPT_ALIASES                     (256 + 28)
 2328 #define LONGONLYOPT_PROXY_HOST                  (256 + 29)
 2329 #define LONGONLYOPT_PROXY_PORT                  (256 + 30)
 2330 #define LONGONLYOPT_ADD_MISSING_FROM_HEADER     (256 + 31)
 2331 #define LONGONLYOPT_ADD_MISSING_DATE_HEADER     (256 + 32)
 2332 #define LONGONLYOPT_REMOVE_BCC_HEADERS          (256 + 33)
 2333 #define LONGONLYOPT_UNDISCLOSED_RECIPIENTS      (256 + 34)
 2334 #define LONGONLYOPT_SOURCE_IP                   (256 + 35)
 2335 #define LONGONLYOPT_LOGFILE_TIME_FORMAT         (256 + 36)
 2336 #define LONGONLYOPT_CONFIGURE                   (256 + 37)
 2337 #define LONGONLYOPT_SOCKET                      (256 + 38)
 2338 #define LONGONLYOPT_SET_FROM_HEADER             (256 + 39)
 2339 #define LONGONLYOPT_SET_DATE_HEADER             (256 + 40)
 2340 
 2341 int msmtp_cmdline(msmtp_cmdline_conf_t *conf, int argc, char *argv[])
 2342 {
 2343     struct option options[] =
 2344     {
 2345         { "version", no_argument, 0, LONGONLYOPT_VERSION },
 2346         { "help", no_argument, 0, LONGONLYOPT_HELP },
 2347         { "configure", required_argument, 0, LONGONLYOPT_CONFIGURE },
 2348         { "pretend", no_argument, 0, 'P' },
 2349         /* accept an optional argument for sendmail compatibility: */
 2350         { "debug", optional_argument, 0, 'd' },
 2351         { "serverinfo", no_argument, 0, 'S' },
 2352         { "rmqs", required_argument, 0, LONGONLYOPT_RMQS },
 2353         { "file", required_argument, 0, 'C' },
 2354         { "account", required_argument, 0, 'a' },
 2355         { "host", required_argument, 0, LONGONLYOPT_HOST },
 2356         { "port", required_argument, 0, LONGONLYOPT_PORT },
 2357         { "timeout", required_argument, 0, LONGONLYOPT_TIMEOUT},
 2358         /* for compatibility with versions <= 1.4.1: */
 2359         { "connect-timeout", required_argument, 0, LONGONLYOPT_TIMEOUT},
 2360         { "auto-from", optional_argument, 0, LONGONLYOPT_AUTO_FROM },
 2361         { "from", required_argument, 0, 'f' },
 2362         { "maildomain", required_argument, 0, LONGONLYOPT_MAILDOMAIN },
 2363         { "auth", optional_argument, 0, LONGONLYOPT_AUTH },
 2364         { "user", required_argument, 0, LONGONLYOPT_USER },
 2365         { "passwordeval", required_argument, 0, LONGONLYOPT_PASSWORDEVAL },
 2366         { "tls", optional_argument, 0, LONGONLYOPT_TLS },
 2367         { "tls-starttls", optional_argument, 0, LONGONLYOPT_TLS_STARTTLS },
 2368         { "tls-trust-file", required_argument, 0, LONGONLYOPT_TLS_TRUST_FILE },
 2369         { "tls-crl-file", required_argument, 0, LONGONLYOPT_TLS_CRL_FILE },
 2370         { "tls-fingerprint", required_argument, 0,
 2371             LONGONLYOPT_TLS_FINGERPRINT },
 2372         { "tls-key-file", required_argument, 0, LONGONLYOPT_TLS_KEY_FILE },
 2373         { "tls-cert-file", required_argument, 0, LONGONLYOPT_TLS_CERT_FILE },
 2374         { "tls-certcheck", optional_argument, 0, LONGONLYOPT_TLS_CERTCHECK },
 2375         { "tls-force-sslv3", optional_argument, 0,
 2376             LONGONLYOPT_TLS_FORCE_SSLV3 },
 2377         { "tls-min-dh-prime-bits", required_argument, 0,
 2378             LONGONLYOPT_TLS_MIN_DH_PRIME_BITS },
 2379         { "tls-priorities", required_argument, 0, LONGONLYOPT_TLS_PRIORITIES },
 2380         { "tls-host-override", required_argument, 0, LONGONLYOPT_TLS_HOST_OVERRIDE },
 2381         { "dsn-notify", required_argument, 0, 'N' },
 2382         { "dsn-return", required_argument, 0, 'R' },
 2383         { "protocol", required_argument, 0, LONGONLYOPT_PROTOCOL },
 2384         { "domain", required_argument, 0, LONGONLYOPT_DOMAIN },
 2385         { "logfile", required_argument, 0, 'X' },
 2386         { "logfile-time-format", required_argument, 0,
 2387             LONGONLYOPT_LOGFILE_TIME_FORMAT },
 2388         { "syslog", optional_argument, 0, LONGONLYOPT_SYSLOG },
 2389         { "aliases", required_argument, 0, LONGONLYOPT_ALIASES },
 2390         { "proxy-host", required_argument, 0, LONGONLYOPT_PROXY_HOST },
 2391         { "proxy-port", required_argument, 0, LONGONLYOPT_PROXY_PORT },
 2392         { "add-missing-from-header", optional_argument, 0,
 2393             LONGONLYOPT_ADD_MISSING_FROM_HEADER },
 2394         { "add-missing-date-header", optional_argument, 0,
 2395             LONGONLYOPT_ADD_MISSING_DATE_HEADER },
 2396         { "set-from-header", optional_argument, 0,
 2397             LONGONLYOPT_SET_FROM_HEADER },
 2398         { "set-date-header", optional_argument, 0,
 2399             LONGONLYOPT_SET_DATE_HEADER },
 2400         { "remove-bcc-headers", optional_argument, 0,
 2401             LONGONLYOPT_REMOVE_BCC_HEADERS },
 2402         { "undisclosed-recipients", optional_argument, 0,
 2403             LONGONLYOPT_UNDISCLOSED_RECIPIENTS },
 2404         { "source-ip", required_argument, 0, LONGONLYOPT_SOURCE_IP },
 2405         { "socket", required_argument, 0, LONGONLYOPT_SOCKET },
 2406         { "keepbcc", optional_argument, 0, LONGONLYOPT_KEEPBCC },
 2407         { "read-recipients", no_argument, 0, 't' },
 2408         { "read-envelope-from", no_argument, 0,
 2409             LONGONLYOPT_READ_ENVELOPE_FROM },
 2410         { 0, 0, 0, 0 }
 2411     };
 2412     int error_code;
 2413     int c;
 2414     int i;
 2415     int rcptc;
 2416     char **rcptv;
 2417     FILE *tmpf = NULL;
 2418     char *errstr;
 2419 #ifdef HAVE_FMEMOPEN
 2420     size_t rcptf_size;
 2421     void *rcptf_buf = NULL;
 2422 #endif
 2423 
 2424     /* the program name */
 2425     prgname = get_prgname(argv[0]);
 2426     /* the configuration */
 2427     conf->print_version = 0;
 2428     conf->print_help = 0;
 2429     conf->print_conf = 0;
 2430     conf->debug = 0;
 2431     conf->pretend = 0;
 2432     conf->read_recipients = 0;
 2433     conf->read_envelope_from = 0;
 2434     /* mode of operation */
 2435     conf->sendmail = 1;
 2436     conf->configure = 0;
 2437     conf->configure_address = NULL;
 2438     conf->serverinfo = 0;
 2439     conf->rmqs = 0;
 2440     conf->rmqs_argument = NULL;
 2441     /* account information from the command line */
 2442     conf->cmdline_account = account_new(NULL, NULL);
 2443     conf->account_id = NULL;
 2444     conf->user_conffile = NULL;
 2445     /* additional information */
 2446     conf->full_name = NULL;
 2447     /* the recipients */
 2448     conf->recipients = NULL;
 2449 
 2450     /* process the command line */
 2451     error_code = 0;
 2452     for (;;)
 2453     {
 2454         c = getopt_long(argc, argv, "Pd::SC:a:f:N:R:X:tA:B:b:F:Gh:iL:mnO:o:v",
 2455                 options, NULL);
 2456         if (c == -1)
 2457         {
 2458             break;
 2459         }
 2460         switch(c)
 2461         {
 2462             case LONGONLYOPT_VERSION:
 2463                 conf->print_version = 1;
 2464                 conf->sendmail = 0;
 2465                 conf->serverinfo = 0;
 2466                 break;
 2467 
 2468             case LONGONLYOPT_HELP:
 2469                 conf->print_help = 1;
 2470                 conf->sendmail = 0;
 2471                 conf->serverinfo = 0;
 2472                 break;
 2473 
 2474             case LONGONLYOPT_CONFIGURE:
 2475                 conf->configure = 1;
 2476                 free(conf->configure_address);
 2477                 conf->configure_address = xstrdup(optarg);
 2478                 conf->sendmail = 0;
 2479                 conf->serverinfo = 0;
 2480                 break;
 2481 
 2482             case 'P':
 2483                 conf->print_conf = 1;
 2484                 conf->pretend = 1;
 2485                 break;
 2486 
 2487             case 'v':
 2488             case 'd':
 2489                 conf->print_conf = 1;
 2490                 conf->debug = 1;
 2491                 /* only care about the optional argument if it's "0.1", which is
 2492                  * the only argument that's documented for sendmail: it prints
 2493                  * version information */
 2494                 if (optarg && strcmp(optarg, "0.1") == 0)
 2495                 {
 2496                     conf->print_version = 1;
 2497                 }
 2498                 break;
 2499 
 2500             case 'S':
 2501                 if (conf->rmqs)
 2502                 {
 2503                     print_error(_("cannot use both --serverinfo and --rmqs"));
 2504                     error_code = 1;
 2505                 }
 2506                 else
 2507                 {
 2508                     conf->serverinfo = 1;
 2509                     conf->sendmail = 0;
 2510                     conf->rmqs = 0;
 2511                 }
 2512                 break;
 2513 
 2514             case LONGONLYOPT_RMQS:
 2515                 if (conf->serverinfo)
 2516                 {
 2517                     print_error(_("cannot use both --serverinfo and --rmqs"));
 2518                     error_code = 1;
 2519                 }
 2520                 else
 2521                 {
 2522                     conf->rmqs = 1;
 2523                     conf->rmqs_argument = optarg;
 2524                     conf->sendmail = 0;
 2525                     conf->serverinfo = 0;
 2526                 }
 2527                 break;
 2528 
 2529             case 'C':
 2530                 free(conf->user_conffile);
 2531                 conf->user_conffile = xstrdup(optarg);
 2532                 break;
 2533 
 2534             case 'a':
 2535                 if (conf->cmdline_account->host)
 2536                 {
 2537                     print_error(_("cannot use both --host and --account"));
 2538                     error_code = 1;
 2539                 }
 2540                 else
 2541                 {
 2542                     conf->account_id = optarg;
 2543                 }
 2544                 break;
 2545 
 2546             case LONGONLYOPT_HOST:
 2547                 if (conf->account_id)
 2548                 {
 2549                     print_error(_("cannot use both --host and --account"));
 2550                     error_code = 1;
 2551                 }
 2552                 else
 2553                 {
 2554                     free(conf->cmdline_account->host);
 2555                     conf->cmdline_account->host = xstrdup(optarg);
 2556                     conf->cmdline_account->mask |= ACC_HOST;
 2557                 }
 2558                 break;
 2559 
 2560             case LONGONLYOPT_PORT:
 2561                 conf->cmdline_account->port = get_pos_int(optarg);
 2562                 if (conf->cmdline_account->port < 1
 2563                         || conf->cmdline_account->port > 65535)
 2564                 {
 2565                     print_error(_("invalid argument %s for %s"),
 2566                             optarg, "--port");
 2567                     error_code = 1;
 2568                 }
 2569                 conf->cmdline_account->mask |= ACC_PORT;
 2570                 break;
 2571 
 2572             case LONGONLYOPT_TIMEOUT:
 2573                 if (is_off(optarg))
 2574                 {
 2575                     conf->cmdline_account->timeout = 0;
 2576                 }
 2577                 else
 2578                 {
 2579                     conf->cmdline_account->timeout =
 2580                         get_pos_int(optarg);
 2581                     if (conf->cmdline_account->timeout < 1)
 2582                     {
 2583                         print_error(_("invalid argument %s for %s"),
 2584                                 optarg, "--timeout");
 2585                         error_code = 1;
 2586                     }
 2587                 }
 2588                 conf->cmdline_account->mask |= ACC_TIMEOUT;
 2589                 break;
 2590 
 2591             case LONGONLYOPT_AUTO_FROM:
 2592                 if (!optarg || is_on(optarg))
 2593                 {
 2594                     conf->cmdline_account->auto_from = 1;
 2595                 }
 2596                 else if (is_off(optarg))
 2597                 {
 2598                     conf->cmdline_account->auto_from = 0;
 2599                 }
 2600                 else
 2601                 {
 2602                     print_error(_("invalid argument %s for %s"),
 2603                             optarg, "--auto-from");
 2604                     error_code = 1;
 2605                 }
 2606                 conf->cmdline_account->mask |= ACC_AUTO_FROM;
 2607                 break;
 2608 
 2609             case 'f':
 2610                 if (conf->read_envelope_from)
 2611                 {
 2612                     print_error(_("cannot use both --from and "
 2613                                 "--read-envelope-from"));
 2614                     error_code = 1;
 2615                 }
 2616                 else
 2617                 {
 2618                     free(conf->cmdline_account->from);
 2619                     /* Accept '<>' to mean an empty from address, to fix Debian
 2620                      * bug 612679. */
 2621                     if (strcmp(optarg, "<>") == 0)
 2622                     {
 2623                         conf->cmdline_account->from = xstrdup("");
 2624                     }
 2625                     else
 2626                     {
 2627                         conf->cmdline_account->from = xstrdup(optarg);
 2628                     }
 2629                     conf->cmdline_account->mask |= ACC_FROM;
 2630                 }
 2631                 break;
 2632 
 2633             case LONGONLYOPT_MAILDOMAIN:
 2634                 free(conf->cmdline_account->maildomain);
 2635                 conf->cmdline_account->maildomain =
 2636                     (*optarg == '\0') ? NULL : xstrdup(optarg);
 2637                 conf->cmdline_account->mask |= ACC_MAILDOMAIN;
 2638                 break;
 2639 
 2640             case LONGONLYOPT_AUTH:
 2641                 free(conf->cmdline_account->auth_mech);
 2642                 if (!optarg || is_on(optarg))
 2643                 {
 2644                     conf->cmdline_account->auth_mech = xstrdup("");
 2645                 }
 2646                 else if (is_off(optarg))
 2647                 {
 2648                     conf->cmdline_account->auth_mech = NULL;
 2649                 }
 2650                 else if (check_auth_arg(optarg) == 0)
 2651                 {
 2652                     conf->cmdline_account->auth_mech = xstrdup(optarg);
 2653                 }
 2654                 else
 2655                 {
 2656                     conf->cmdline_account->auth_mech = NULL;
 2657                     print_error(_("invalid argument %s for %s"),
 2658                             optarg, "--auth");
 2659                     error_code = 1;
 2660                 }
 2661                 conf->cmdline_account->mask |= ACC_AUTH_MECH;
 2662                 break;
 2663 
 2664             case LONGONLYOPT_USER:
 2665                 free(conf->cmdline_account->username);
 2666                 conf->cmdline_account->username =
 2667                     (*optarg == '\0') ? NULL : xstrdup(optarg);
 2668                 conf->cmdline_account->mask |= ACC_USERNAME;
 2669                 break;
 2670 
 2671             case LONGONLYOPT_PASSWORDEVAL:
 2672                 free(conf->cmdline_account->passwordeval);
 2673                 conf->cmdline_account->passwordeval =
 2674                     (*optarg == '\0') ? NULL : xstrdup(optarg);
 2675                 conf->cmdline_account->mask |= ACC_PASSWORDEVAL;
 2676                 break;
 2677 
 2678             case LONGONLYOPT_TLS:
 2679                 if (!optarg || is_on(optarg))
 2680                 {
 2681                     conf->cmdline_account->tls = 1;
 2682                 }
 2683                 else if (is_off(optarg))
 2684                 {
 2685                     conf->cmdline_account->tls = 0;
 2686                 }
 2687                 else
 2688                 {
 2689                     print_error(_("invalid argument %s for %s"),
 2690                             optarg, "--tls");
 2691                     error_code = 1;
 2692                 }
 2693                 conf->cmdline_account->mask |= ACC_TLS;
 2694                 break;
 2695 
 2696             case LONGONLYOPT_TLS_STARTTLS:
 2697                 if (!optarg || is_on(optarg))
 2698                 {
 2699                     conf->cmdline_account->tls_nostarttls = 0;
 2700                 }
 2701                 else if (is_off(optarg))
 2702                 {
 2703                     conf->cmdline_account->tls_nostarttls = 1;
 2704                 }
 2705                 else
 2706                 {
 2707                     print_error(_("invalid argument %s for %s"),
 2708                             optarg, "--tls-starttls");
 2709                     error_code = 1;
 2710                 }
 2711                 conf->cmdline_account->mask |= ACC_TLS_NOSTARTTLS;
 2712                 break;
 2713 
 2714             case LONGONLYOPT_TLS_TRUST_FILE:
 2715                 free(conf->cmdline_account->tls_trust_file);
 2716                 if (*optarg)
 2717                 {
 2718                     conf->cmdline_account->tls_trust_file =
 2719                         expand_tilde(optarg);
 2720                 }
 2721                 else
 2722                 {
 2723                     conf->cmdline_account->tls_trust_file = NULL;
 2724                 }
 2725                 conf->cmdline_account->mask |= ACC_TLS_TRUST_FILE;
 2726                 break;
 2727 
 2728             case LONGONLYOPT_TLS_CRL_FILE:
 2729                 free(conf->cmdline_account->tls_crl_file);
 2730                 if (*optarg)
 2731                 {
 2732                     conf->cmdline_account->tls_crl_file =
 2733                         expand_tilde(optarg);
 2734                 }
 2735                 else
 2736                 {
 2737                     conf->cmdline_account->tls_crl_file = NULL;
 2738                 }
 2739                 conf->cmdline_account->mask |= ACC_TLS_CRL_FILE;
 2740                 break;
 2741 
 2742             case LONGONLYOPT_TLS_FINGERPRINT:
 2743                 free(conf->cmdline_account->tls_sha256_fingerprint);
 2744                 conf->cmdline_account->tls_sha256_fingerprint = NULL;
 2745                 free(conf->cmdline_account->tls_sha1_fingerprint);
 2746                 conf->cmdline_account->tls_sha1_fingerprint = NULL;
 2747                 free(conf->cmdline_account->tls_md5_fingerprint);
 2748                 conf->cmdline_account->tls_md5_fingerprint = NULL;
 2749                 if (*optarg)
 2750                 {
 2751                     if (strlen(optarg) == 2 * 32 + 31)
 2752                     {
 2753                         conf->cmdline_account->tls_sha256_fingerprint =
 2754                             get_fingerprint(optarg, 32);
 2755                     }
 2756                     else if (strlen(optarg) == 2 * 20 + 19)
 2757                     {
 2758                         conf->cmdline_account->tls_sha1_fingerprint =
 2759                             get_fingerprint(optarg, 20);
 2760                     }
 2761                     else if (strlen(optarg) == 2 * 16 + 15)
 2762                     {
 2763                         conf->cmdline_account->tls_md5_fingerprint =
 2764                             get_fingerprint(optarg, 16);
 2765                     }
 2766                     if (!conf->cmdline_account->tls_sha256_fingerprint
 2767                             && !conf->cmdline_account->tls_sha1_fingerprint
 2768                             && !conf->cmdline_account->tls_md5_fingerprint)
 2769                     {
 2770                         print_error(_("invalid argument %s for %s"),
 2771                                 optarg, "--tls-fingerprint");
 2772                         error_code = 1;
 2773                     }
 2774                 }
 2775                 conf->cmdline_account->mask |= ACC_TLS_FINGERPRINT;
 2776                 break;
 2777 
 2778             case LONGONLYOPT_TLS_KEY_FILE:
 2779                 free(conf->cmdline_account->tls_key_file);
 2780                 if (*optarg)
 2781                 {
 2782                     conf->cmdline_account->tls_key_file = expand_tilde(optarg);
 2783                 }
 2784                 else
 2785                 {
 2786                     conf->cmdline_account->tls_key_file = NULL;
 2787                 }
 2788                 conf->cmdline_account->mask |= ACC_TLS_KEY_FILE;
 2789                 break;
 2790 
 2791             case LONGONLYOPT_TLS_CERT_FILE:
 2792                 free(conf->cmdline_account->tls_cert_file);
 2793                 if (*optarg)
 2794                 {
 2795                     conf->cmdline_account->tls_cert_file = expand_tilde(optarg);
 2796                 }
 2797                 else
 2798                 {
 2799                     conf->cmdline_account->tls_cert_file = NULL;
 2800                 }
 2801                 conf->cmdline_account->mask |= ACC_TLS_CERT_FILE;
 2802                 break;
 2803 
 2804             case LONGONLYOPT_TLS_CERTCHECK:
 2805                 if (!optarg || is_on(optarg))
 2806                 {
 2807                     conf->cmdline_account->tls_nocertcheck = 0;
 2808                 }
 2809                 else if (is_off(optarg))
 2810                 {
 2811                     conf->cmdline_account->tls_nocertcheck = 1;
 2812                 }
 2813                 else
 2814                 {
 2815                     print_error(_("invalid argument %s for %s"),
 2816                             optarg, "--tls-certcheck");
 2817                     error_code = 1;
 2818                 }
 2819                 conf->cmdline_account->mask |= ACC_TLS_NOCERTCHECK;
 2820                 break;
 2821 
 2822             case LONGONLYOPT_TLS_FORCE_SSLV3:
 2823                 /* silently ignored for compatibility with versions <= 1.4.32 */
 2824                 break;
 2825 
 2826             case LONGONLYOPT_TLS_MIN_DH_PRIME_BITS:
 2827                 if (*optarg == '\0')
 2828                 {
 2829                     conf->cmdline_account->tls_min_dh_prime_bits = -1;
 2830                 }
 2831                 else
 2832                 {
 2833                     conf->cmdline_account->tls_min_dh_prime_bits =
 2834                         get_pos_int(optarg);
 2835                     if (conf->cmdline_account->tls_min_dh_prime_bits < 1)
 2836                     {
 2837                         print_error(_("invalid argument %s for %s"),
 2838                                 optarg, "--tls-min-dh-prime-bits");
 2839                         error_code = 1;
 2840                     }
 2841                 }
 2842                 conf->cmdline_account->mask |= ACC_TLS_MIN_DH_PRIME_BITS;
 2843                 break;
 2844 
 2845             case LONGONLYOPT_TLS_PRIORITIES:
 2846                 free(conf->cmdline_account->tls_priorities);
 2847                 if (*optarg)
 2848                 {
 2849                     conf->cmdline_account->tls_priorities = xstrdup(optarg);
 2850                 }
 2851                 else
 2852                 {
 2853                     conf->cmdline_account->tls_priorities = NULL;
 2854                 }
 2855                 conf->cmdline_account->mask |= ACC_TLS_PRIORITIES;
 2856                 break;
 2857 
 2858             case LONGONLYOPT_TLS_HOST_OVERRIDE:
 2859                 free(conf->cmdline_account->tls_host_override);
 2860                 if (*optarg)
 2861                 {
 2862                     conf->cmdline_account->tls_host_override = xstrdup(optarg);
 2863                 }
 2864                 else
 2865                 {
 2866                     conf->cmdline_account->tls_host_override = NULL;
 2867                 }
 2868                 conf->cmdline_account->mask |= ACC_TLS_HOST_OVERRIDE;
 2869                 break;
 2870 
 2871             case 'N':
 2872                 free(conf->cmdline_account->dsn_notify);
 2873                 if (is_off(optarg))
 2874                 {
 2875                     conf->cmdline_account->dsn_notify = NULL;
 2876                 }
 2877                 else if (check_dsn_notify_arg(optarg) == 0)
 2878                 {
 2879                     conf->cmdline_account->dsn_notify = xstrdup(optarg);
 2880                 }
 2881                 else
 2882                 {
 2883                     print_error(_("invalid argument %s for %s"),
 2884                             optarg, "--dsn-notify");
 2885                     error_code = 1;
 2886                 }
 2887                 conf->cmdline_account->mask |= ACC_DSN_NOTIFY;
 2888                 break;
 2889 
 2890             case 'R':
 2891                 /* be compatible to both sendmail and the dsn_notify command */
 2892                 free(conf->cmdline_account->dsn_return);
 2893                 if (is_off(optarg))
 2894                 {
 2895                     conf->cmdline_account->dsn_return = NULL;
 2896                 }
 2897                 else if (strcmp(optarg, "hdrs") == 0
 2898                         || strcmp(optarg, "headers") == 0)
 2899                 {
 2900                     conf->cmdline_account->dsn_return = xstrdup("HDRS");
 2901                 }
 2902                 else if (strcmp(optarg, "full") == 0)
 2903                 {
 2904                     conf->cmdline_account->dsn_return = xstrdup("FULL");
 2905                 }
 2906                 else
 2907                 {
 2908                     print_error(_("invalid argument %s for %s"),
 2909                             optarg, "--dsn-return");
 2910                     error_code = 1;
 2911                 }
 2912                 conf->cmdline_account->mask |= ACC_DSN_RETURN;
 2913                 break;
 2914 
 2915             case LONGONLYOPT_PROTOCOL:
 2916                 conf->cmdline_account->mask |= ACC_PROTOCOL;
 2917                 if (strcmp(optarg, "smtp") == 0)
 2918                 {
 2919                     conf->cmdline_account->protocol = SMTP_PROTO_SMTP;
 2920                 }
 2921                 else if (strcmp(optarg, "lmtp") == 0)
 2922                 {
 2923                     conf->cmdline_account->protocol = SMTP_PROTO_LMTP;
 2924                 }
 2925                 else
 2926                 {
 2927                     print_error(_("invalid argument %s for %s"),
 2928                             optarg, "--protocol");
 2929                     error_code = 1;
 2930                 }
 2931                 break;
 2932 
 2933             case LONGONLYOPT_DOMAIN:
 2934                 free(conf->cmdline_account->domain);
 2935                 conf->cmdline_account->domain = xstrdup(optarg);
 2936                 conf->cmdline_account->mask |= ACC_DOMAIN;
 2937                 break;
 2938 
 2939             case 'X':
 2940                 free(conf->cmdline_account->logfile);
 2941                 if (*optarg)
 2942                 {
 2943                     conf->cmdline_account->logfile = expand_tilde(optarg);
 2944                 }
 2945                 else
 2946                 {
 2947                     conf->cmdline_account->logfile = NULL;
 2948                 }
 2949                 conf->cmdline_account->mask |= ACC_LOGFILE;
 2950                 break;
 2951 
 2952             case LONGONLYOPT_LOGFILE_TIME_FORMAT:
 2953                 free(conf->cmdline_account->logfile_time_format);
 2954                 if (*optarg)
 2955                 {
 2956                     conf->cmdline_account->logfile_time_format = xstrdup(optarg);
 2957                 }
 2958                 else
 2959                 {
 2960                     conf->cmdline_account->logfile_time_format = NULL;
 2961                 }
 2962                 conf->cmdline_account->mask |= ACC_LOGFILE_TIME_FORMAT;
 2963                 break;
 2964 
 2965             case LONGONLYOPT_SYSLOG:
 2966                 free(conf->cmdline_account->syslog);
 2967                 if (!optarg || is_on(optarg))
 2968                 {
 2969                     conf->cmdline_account->syslog =
 2970                         get_default_syslog_facility();
 2971                 }
 2972                 else if (is_off(optarg))
 2973                 {
 2974                     conf->cmdline_account->syslog = NULL;
 2975                 }
 2976                 else
 2977                 {
 2978                     if (check_syslog_arg(optarg) != 0)
 2979                     {
 2980                         print_error(_("invalid argument %s for %s"),
 2981                                 optarg, "--syslog");
 2982                         error_code = 1;
 2983                     }
 2984                     else
 2985                     {
 2986                         conf->cmdline_account->syslog = xstrdup(optarg);
 2987                     }
 2988                 }
 2989                 conf->cmdline_account->mask |= ACC_SYSLOG;
 2990                 break;
 2991 
 2992             case LONGONLYOPT_ALIASES:
 2993                 free(conf->cmdline_account->aliases);
 2994                 if (*optarg)
 2995                 {
 2996                     conf->cmdline_account->aliases = expand_tilde(optarg);
 2997                 }
 2998                 else
 2999                 {
 3000                     conf->cmdline_account->aliases = NULL;
 3001                 }
 3002                 conf->cmdline_account->mask |= ACC_ALIASES;
 3003                 break;
 3004 
 3005             case LONGONLYOPT_PROXY_HOST:
 3006                 free(conf->cmdline_account->proxy_host);
 3007                 if (*optarg)
 3008                 {
 3009                     conf->cmdline_account->proxy_host = xstrdup(optarg);
 3010                 }
 3011                 else
 3012                 {
 3013                     conf->cmdline_account->proxy_host = NULL;
 3014                 }
 3015                 conf->cmdline_account->mask |= ACC_PROXY_HOST;
 3016                 break;
 3017 
 3018             case LONGONLYOPT_PROXY_PORT:
 3019                 if (*optarg)
 3020                 {
 3021                     conf->cmdline_account->proxy_port = get_pos_int(optarg);
 3022                     if (conf->cmdline_account->proxy_port < 1
 3023                             || conf->cmdline_account->proxy_port > 65535)
 3024                     {
 3025                         print_error(_("invalid argument %s for %s"),
 3026                                 optarg, "--proxy-port");
 3027                         error_code = 1;
 3028                     }
 3029                 }
 3030                 else
 3031                 {
 3032                     conf->cmdline_account->proxy_port = 0;
 3033                 }
 3034                 conf->cmdline_account->mask |= ACC_PROXY_PORT;
 3035                 break;
 3036 
 3037             case LONGONLYOPT_SET_FROM_HEADER:
 3038                 if (!optarg || is_auto(optarg))
 3039                 {
 3040                     conf->cmdline_account->set_from_header = 2;
 3041                 }
 3042                 else if (is_on(optarg))
 3043                 {
 3044                     conf->cmdline_account->set_from_header = 1;
 3045                 }
 3046                 else if (is_off(optarg))
 3047                 {
 3048                     conf->cmdline_account->set_from_header = 0;
 3049                 }
 3050                 else
 3051                 {
 3052                     print_error(_("invalid argument %s for %s"),
 3053                             optarg, "--set-from-header");
 3054                     error_code = 1;
 3055                 }
 3056                 conf->cmdline_account->mask |= ACC_SET_FROM_HEADER;
 3057                 break;
 3058 
 3059             case LONGONLYOPT_SET_DATE_HEADER:
 3060                 if (!optarg || is_auto(optarg))
 3061                 {
 3062                     conf->cmdline_account->set_date_header = 2;
 3063                 }
 3064                 else if (is_off(optarg))
 3065                 {
 3066                     conf->cmdline_account->set_date_header = 0;
 3067                 }
 3068                 else
 3069                 {
 3070                     print_error(_("invalid argument %s for %s"),
 3071                             optarg, "--set-date-header");
 3072                     error_code = 1;
 3073                 }
 3074                 conf->cmdline_account->mask |= ACC_SET_DATE_HEADER;
 3075                 break;
 3076 
 3077             case LONGONLYOPT_ADD_MISSING_FROM_HEADER:
 3078                 /* compatibility with < 1.8.8 */
 3079                 if (!optarg || is_on(optarg))
 3080                 {
 3081                     conf->cmdline_account->set_from_header = 2;
 3082                 }
 3083                 else if (is_off(optarg))
 3084                 {
 3085                     conf->cmdline_account->set_from_header = 0;
 3086                 }
 3087                 else
 3088                 {
 3089                     print_error(_("invalid argument %s for %s"),
 3090                             optarg, "--add-missing-from-header");
 3091                     error_code = 1;
 3092                 }
 3093                 conf->cmdline_account->mask |= ACC_SET_FROM_HEADER;
 3094                 break;
 3095 
 3096             case LONGONLYOPT_ADD_MISSING_DATE_HEADER:
 3097                 /* compatibility with < 1.8.8 */
 3098                 if (!optarg || is_on(optarg))
 3099                 {
 3100                     conf->cmdline_account->set_date_header = 2;
 3101                 }
 3102                 else if (is_off(optarg))
 3103                 {
 3104                     conf->cmdline_account->set_date_header = 0;
 3105                 }
 3106                 else
 3107                 {
 3108                     print_error(_("invalid argument %s for %s"),
 3109                             optarg, "--add-missing-date-header");
 3110                     error_code = 1;
 3111                 }
 3112                 conf->cmdline_account->mask |= ACC_SET_DATE_HEADER;
 3113                 break;
 3114 
 3115             case LONGONLYOPT_REMOVE_BCC_HEADERS:
 3116                 if (!optarg || is_on(optarg))
 3117                 {
 3118                     conf->cmdline_account->remove_bcc_headers = 1;
 3119                 }
 3120                 else if (is_off(optarg))
 3121                 {
 3122                     conf->cmdline_account->remove_bcc_headers = 0;
 3123                 }
 3124                 else
 3125                 {
 3126                     print_error(_("invalid argument %s for %s"),
 3127                             optarg, "--remove-bcc-headers");
 3128                     error_code = 1;
 3129                 }
 3130                 conf->cmdline_account->mask |= ACC_REMOVE_BCC_HEADERS;
 3131                 break;
 3132 
 3133             case LONGONLYOPT_UNDISCLOSED_RECIPIENTS:
 3134                 if (!optarg || is_on(optarg))
 3135                 {
 3136                     conf->cmdline_account->undisclosed_recipients = 1;
 3137                 }
 3138                 else if (is_off(optarg))
 3139                 {
 3140                     conf->cmdline_account->undisclosed_recipients = 0;
 3141                 }
 3142                 else
 3143                 {
 3144                     print_error(_("invalid argument %s for %s"),
 3145                             optarg, "--undisclosed-recipients");
 3146                     error_code = 1;
 3147                 }
 3148                 conf->cmdline_account->mask |= ACC_UNDISCLOSED_RECIPIENTS;
 3149                 break;
 3150 
 3151             case LONGONLYOPT_SOURCE_IP:
 3152                 free(conf->cmdline_account->source_ip);
 3153                 if (*optarg)
 3154                 {
 3155                     conf->cmdline_account->source_ip = xstrdup(optarg);
 3156                 }
 3157                 else
 3158                 {
 3159                     conf->cmdline_account->source_ip = NULL;
 3160                 }
 3161                 conf->cmdline_account->mask |= ACC_SOURCE_IP;
 3162                 break;
 3163 
 3164             case LONGONLYOPT_SOCKET:
 3165                 free(conf->cmdline_account->socketname);
 3166                 if (*optarg)
 3167                 {
 3168                     conf->cmdline_account->socketname = xstrdup(optarg);
 3169                 }
 3170                 else
 3171                 {
 3172                     conf->cmdline_account->socketname = NULL;
 3173                 }
 3174                 conf->cmdline_account->mask |= ACC_SOCKET;
 3175                 break;
 3176 
 3177             case 't':
 3178                 conf->read_recipients = 1;
 3179                 break;
 3180 
 3181             case LONGONLYOPT_READ_ENVELOPE_FROM:
 3182                 if (conf->cmdline_account->from)
 3183                 {
 3184                     print_error(_("cannot use both --from and "
 3185                                 "--read-envelope-from"));
 3186                     error_code = 1;
 3187                 }
 3188                 else
 3189                 {
 3190                     conf->read_envelope_from = 1;
 3191                     conf->cmdline_account->mask |= ACC_FROM;
 3192                 }
 3193                 break;
 3194 
 3195             case 'b':
 3196                 /* only m makes sense */
 3197                 if (strcmp(optarg, "m") != 0)
 3198                 {
 3199                     print_error(_("unsupported operation mode b%s"), optarg);
 3200                     error_code = 1;
 3201                 }
 3202                 break;
 3203 
 3204             case 'F':
 3205                 free(conf->full_name);
 3206                 conf->full_name = xstrdup(optarg);
 3207                 break;
 3208 
 3209             case LONGONLYOPT_KEEPBCC:
 3210                 /* compatibility with 1.4.x */
 3211                 if (!optarg || is_on(optarg))
 3212                 {
 3213                     conf->cmdline_account->remove_bcc_headers = 0;
 3214                 }
 3215                 else if (is_off(optarg))
 3216                 {
 3217                     conf->cmdline_account->remove_bcc_headers = 1;
 3218                 }
 3219                 else
 3220                 {
 3221                     print_error(_("invalid argument %s for %s"),
 3222                             optarg, "--keepbcc");
 3223                     error_code = 1;
 3224                 }
 3225                 conf->cmdline_account->mask |= ACC_REMOVE_BCC_HEADERS;
 3226                 break;
 3227 
 3228             case 'A':
 3229             case 'B':
 3230             case 'G':
 3231             case 'h':
 3232             case 'i':
 3233             case 'L':
 3234             case 'm':
 3235             case 'n':
 3236             case 'O':
 3237             case 'o':
 3238                 break;
 3239 
 3240             /* unknown option */
 3241             default:
 3242                 error_code = 1;
 3243                 break;
 3244         }
 3245         if (error_code)
 3246         {
 3247             break;
 3248         }
 3249     }
 3250     if (error_code)
 3251     {
 3252         return EX_USAGE;
 3253     }
 3254 
 3255     /* The list of recipients.
 3256      * Write these to a temporary mail header so that msmtp_read_headers() can
 3257      * parse them. */
 3258     conf->recipients = list_new();
 3259     rcptc = argc - optind;
 3260     rcptv = &(argv[optind]);
 3261     if (rcptc > 0)
 3262     {
 3263 #ifdef HAVE_FMEMOPEN
 3264         rcptf_size = 2;     /* terminating "\n\0" */
 3265         for (i = 0; i < rcptc; i++)
 3266         {
 3267             rcptf_size += 4 + strlen(rcptv[i]) + 1;
 3268         }
 3269         rcptf_buf = xmalloc(rcptf_size);
 3270         tmpf = fmemopen(rcptf_buf, rcptf_size, "w+");
 3271 #else
 3272         tmpf = tmpfile();
 3273 #endif
 3274         if (!tmpf)
 3275         {
 3276             print_error(_("cannot create temporary file: %s"),
 3277                     sanitize_string(strerror(errno)));
 3278             error_code = EX_IOERR;
 3279             goto error_exit;
 3280         }
 3281         for (i = 0; i < rcptc && error_code != EOF; i++)
 3282         {
 3283             error_code = fputs("To: ", tmpf);
 3284             if (error_code != EOF)
 3285             {
 3286                 error_code = fputs(rcptv[i], tmpf);
 3287             }
 3288             if (error_code != EOF)
 3289             {
 3290                 error_code = fputc('\n', tmpf);
 3291             }
 3292         }
 3293         if (error_code != EOF)
 3294         {
 3295             error_code = fputc('\n', tmpf);
 3296         }
 3297         if (error_code == EOF)
 3298         {
 3299             print_error(_("cannot write mail headers to temporary "
 3300                         "file: output error"));
 3301             error_code = EX_IOERR;
 3302             goto error_exit;
 3303         }
 3304         if (fseeko(tmpf, 0, SEEK_SET) != 0)
 3305         {
 3306             print_error(_("cannot rewind temporary file: %s"),
 3307                     sanitize_string(strerror(errno)));
 3308             error_code = EX_IOERR;
 3309             goto error_exit;
 3310         }
 3311         if ((error_code = msmtp_read_headers(tmpf, NULL,
 3312                         list_last(conf->recipients), NULL, NULL, &errstr))
 3313                 != EX_OK)
 3314         {
 3315             print_error("%s", sanitize_string(errstr));
 3316             goto error_exit;
 3317         }
 3318     }
 3319     error_code = EX_OK;
 3320 
 3321 error_exit:
 3322     if (tmpf)
 3323     {
 3324         fclose(tmpf);
 3325     }
 3326 #ifdef HAVE_FMEMOPEN
 3327     free(rcptf_buf);
 3328 #endif
 3329     return error_code;
 3330 }
 3331 
 3332 
 3333 /*
 3334  * msmtp_get_conffile_accounts()
 3335  * Read the system and user configuration files and merge the data
 3336  */
 3337 
 3338 int msmtp_get_conffile_accounts(list_t **account_list,
 3339         int print_info, const char *user_conffile,
 3340         char **loaded_system_conffile, char **loaded_user_conffile)
 3341 {
 3342     char *errstr;
 3343     char *system_confdir;
 3344     char *system_conffile;
 3345     char *real_user_conffile;
 3346     list_t *system_account_list;
 3347     list_t *user_account_list;
 3348     list_t *lps;
 3349     list_t *lpu;
 3350     int securitycheck;
 3351     int e;
 3352 
 3353 
 3354     *loaded_system_conffile = NULL;
 3355     *loaded_user_conffile = NULL;
 3356 
 3357     /* Read the system configuration file.
 3358      * It is not an error if system_conffile cannot be opened,
 3359      * but it is an error is the file content is invalid */
 3360     system_confdir = get_sysconfdir();
 3361     system_conffile = get_filename(system_confdir, SYSCONFFILE);
 3362     free(system_confdir);
 3363     securitycheck = 0;
 3364     if ((e = get_conf(system_conffile, securitycheck,
 3365                     &system_account_list, &errstr)) != CONF_EOK)
 3366     {
 3367         if (e == CONF_ECANTOPEN)
 3368         {
 3369             if (print_info)
 3370             {
 3371                 printf(_("ignoring system configuration file %s: %s\n"),
 3372                         system_conffile, sanitize_string(errstr));
 3373             }
 3374         }
 3375         else
 3376         {
 3377             print_error("%s: %s", system_conffile,
 3378                     sanitize_string(errstr));
 3379             return (e == CONF_EIO) ? EX_IOERR : EX_CONFIG;
 3380         }
 3381     }
 3382     else
 3383     {
 3384         if (print_info)
 3385         {
 3386             printf(_("loaded system configuration file %s\n"), system_conffile);
 3387         }
 3388         *loaded_system_conffile = xstrdup(system_conffile);
 3389     }
 3390     free(system_conffile);
 3391 
 3392     /* Read the user configuration file.
 3393      * It is not an error if user_conffile cannot be opened (unless it was
 3394      * chosen with -C/--file), but it is an error is the file content is
 3395      * invalid */
 3396     if (user_conffile)
 3397     {
 3398         real_user_conffile = xstrdup(user_conffile);
 3399     }
 3400     else
 3401     {
 3402         real_user_conffile = get_userconfig(USERCONFFILE);
 3403     }
 3404 #ifdef W32_NATIVE
 3405     securitycheck = 1;
 3406 #else
 3407     securitycheck = (geteuid() != 0);
 3408 #endif
 3409     if ((e = get_conf(real_user_conffile, securitycheck,
 3410                     &user_account_list, &errstr)) != CONF_EOK)
 3411     {
 3412         if (e == CONF_ECANTOPEN)
 3413         {
 3414             /* If the configuration file was set with -C/--file, it is an
 3415              * error if we cannot open it */
 3416             if (user_conffile)
 3417             {
 3418                 print_error("%s: %s", real_user_conffile,
 3419                         sanitize_string(errstr));
 3420                 return EX_IOERR;
 3421             }
 3422             /* otherwise, we can ignore it */
 3423             if (print_info)
 3424             {
 3425                 printf(_("ignoring user configuration file %s: %s\n"),
 3426                         real_user_conffile, sanitize_string(errstr));
 3427             }
 3428         }
 3429         else
 3430         {
 3431             print_error("%s: %s", real_user_conffile,
 3432                     sanitize_string(errstr));
 3433             return (e == CONF_EIO) ? EX_IOERR : EX_CONFIG;
 3434         }
 3435     }
 3436     else
 3437     {
 3438         if (print_info)
 3439         {
 3440             printf(_("loaded user configuration file %s\n"),
 3441                     real_user_conffile);
 3442         }
 3443         *loaded_user_conffile = xstrdup(real_user_conffile);
 3444     }
 3445     free(real_user_conffile);
 3446 
 3447     /* Merge system_account_list and user_account_list into account_list.
 3448      * If an account exist in both files, only the one from the user conffile is
 3449      * kept. It is important that the order of accounts is maintained, so that
 3450      * --from can choose the *first* account with a matching envelope from
 3451      * address. */
 3452     if (*loaded_system_conffile && *loaded_user_conffile)
 3453     {
 3454         lpu = user_account_list;
 3455         lps = system_account_list;
 3456         while (!list_is_empty(lps))
 3457         {
 3458             lps = lps->next;
 3459             if (!find_account(user_account_list, ((account_t *)lps->data)->id))
 3460             {
 3461                 list_insert(lpu, account_copy(lps->data));
 3462                 lpu = lpu->next;
 3463             }
 3464         }
 3465         *account_list = user_account_list;
 3466         list_xfree(system_account_list, account_free);
 3467     }
 3468     else if (*loaded_system_conffile)
 3469     {
 3470         *account_list = system_account_list;
 3471     }
 3472     else if (*loaded_user_conffile)
 3473     {
 3474         *account_list = user_account_list;
 3475     }
 3476     else
 3477     {
 3478         *account_list = list_new();
 3479     }
 3480 
 3481     return EX_OK;
 3482 }
 3483 
 3484 
 3485 /*
 3486  * msmtp_print_conf
 3487  *
 3488  * Print configuration information, for example for --pretend
 3489  */
 3490 
 3491 void msmtp_print_conf(msmtp_cmdline_conf_t conf, account_t *account)
 3492 {
 3493     char fingerprint_string[2 * 32 + 31 + 1];
 3494 
 3495     if (account->id && account->conffile)
 3496     {
 3497         printf(_("using account %s from %s\n"),
 3498                 account->id, account->conffile);
 3499     }
 3500     printf("host = %s\n", account->host);
 3501     printf("port = %d\n", account->port);
 3502     printf("source ip = %s\n",
 3503             account->source_ip ? account->source_ip : _("(not set)"));
 3504     printf("proxy host = %s\n",
 3505             account->proxy_host ? account->proxy_host : _("(not set)"));
 3506     printf("proxy port = %d\n", account->proxy_port);
 3507     printf("socket = %s\n",
 3508             account->socketname ? account->socketname : _("(not set)"));
 3509     printf("timeout = ");
 3510     if (account->timeout <= 0)
 3511     {
 3512         printf(_("off\n"));
 3513     }
 3514     else
 3515     {
 3516         if (account->timeout > 1)
 3517         {
 3518             printf(_("%d seconds\n"), account->timeout);
 3519         }
 3520         else
 3521         {
 3522             printf(_("1 second\n"));
 3523         }
 3524     }
 3525     printf("protocol = %s\n",
 3526             account->protocol == SMTP_PROTO_SMTP ? "smtp" : "lmtp");
 3527     printf("domain = %s\n", account->domain);
 3528     printf("auth = ");
 3529     if (!account->auth_mech)
 3530     {
 3531         printf(_("none\n"));
 3532     }
 3533     else if (account->auth_mech[0] == '\0')
 3534     {
 3535         printf(_("choose\n"));
 3536     }
 3537     else
 3538     {
 3539         printf("%s\n", account->auth_mech);
 3540     }
 3541     printf("user = %s\n",
 3542             account->username ? account->username : _("(not set)"));
 3543     printf("password = %s\n", account->password ? "*" : _("(not set)"));
 3544     printf("passwordeval = %s\n",
 3545             account->passwordeval ? account->passwordeval : _("(not set)"));
 3546     printf("ntlmdomain = %s\n",
 3547             account->ntlmdomain ? account->ntlmdomain : _("(not set)"));
 3548     printf("tls = %s\n", account->tls ? _("on") : _("off"));
 3549     printf("tls_starttls = %s\n", account->tls_nostarttls ? _("off") : _("on"));
 3550     printf("tls_trust_file = %s\n",
 3551             account->tls_trust_file ? account->tls_trust_file : _("(not set)"));
 3552     printf("tls_crl_file = %s\n",
 3553             account->tls_crl_file ? account->tls_crl_file : _("(not set)"));
 3554     if (account->tls_sha256_fingerprint)
 3555     {
 3556         print_fingerprint(fingerprint_string,
 3557                 account->tls_sha256_fingerprint, 32);
 3558     }
 3559     else if (account->tls_sha1_fingerprint)
 3560     {
 3561         print_fingerprint(fingerprint_string,
 3562                 account->tls_sha1_fingerprint, 20);
 3563     }
 3564     else if (account->tls_md5_fingerprint)
 3565     {
 3566         print_fingerprint(fingerprint_string,
 3567                 account->tls_md5_fingerprint, 16);
 3568     }
 3569     printf("tls_fingerprint = %s\n",
 3570             account->tls_sha256_fingerprint
 3571             || account->tls_sha1_fingerprint || account->tls_md5_fingerprint
 3572             ? fingerprint_string : _("(not set)"));
 3573     printf("tls_key_file = %s\n",
 3574             account->tls_key_file ? account->tls_key_file : _("(not set)"));
 3575     printf("tls_cert_file = %s\n",
 3576             account->tls_cert_file ? account->tls_cert_file : _("(not set)"));
 3577     printf("tls_certcheck = %s\n",
 3578             account->tls_nocertcheck ? _("off") : _("on"));
 3579     printf("tls_min_dh_prime_bits = ");
 3580     if (account->tls_min_dh_prime_bits >= 0)
 3581     {
 3582         printf("%d\n", account->tls_min_dh_prime_bits);
 3583     }
 3584     else
 3585     {
 3586         printf("%s\n", _("(not set)"));
 3587     }
 3588     printf("tls_priorities = %s\n",
 3589             account->tls_priorities ? account->tls_priorities : _("(not set)"));
 3590     printf("tls_host_override = %s\n",
 3591             account->tls_host_override ? account->tls_host_override : _("(not set)"));
 3592     if (conf.sendmail)
 3593     {
 3594         printf("auto_from = %s\n", account->auto_from ? _("on") : _("off"));
 3595         printf("maildomain = %s\n",
 3596                 account->maildomain ? account->maildomain : _("(not set)"));
 3597         printf("from = %s\n",
 3598                 account->from ? account->from : conf.read_envelope_from
 3599                 ? _("(read from mail)") : _("(not set)"));
 3600         printf("set_from_header = %s\n",
 3601                 account->set_from_header == 2 ? _("auto")
 3602                 : account->set_from_header == 1 ? _("on") : _("off"));
 3603         printf("set_date_header = %s\n",
 3604                 account->set_date_header == 2 ? _("auto")
 3605                 : _("off"));
 3606         printf("remove_bcc_headers = %s\n",
 3607                 account->remove_bcc_headers ? _("on") : _("off"));
 3608         printf("undisclosed_recipients = %s\n",
 3609                 account->undisclosed_recipients ? _("on") : _("off"));
 3610         printf("dsn_notify = %s\n",
 3611                 account->dsn_notify ? account->dsn_notify : _("(not set)"));
 3612         printf("dsn_return = %s\n",
 3613                 account->dsn_return ? account->dsn_return : _("(not set)"));
 3614         printf("logfile = %s\n",
 3615                 account->logfile ? account->logfile : _("(not set)"));
 3616         printf("logfile_time_format = %s\n",
 3617                 account->logfile_time_format ? account->logfile_time_format
 3618                 : _("(not set)"));
 3619         printf("syslog = %s\n",
 3620                 account->syslog ? account->syslog : _("(not set)"));
 3621         printf("aliases = %s\n",
 3622                 account->aliases ? account->aliases : _("(not set)"));
 3623         if (conf.read_recipients)
 3624         {
 3625             printf(_("reading recipients from the command line "
 3626                         "and the mail\n"));
 3627         }
 3628         else
 3629         {
 3630             printf(_("reading recipients from the command line\n"));
 3631         }
 3632     }
 3633     if (conf.rmqs)
 3634     {
 3635         printf("RMQS argument = %s\n", conf.rmqs_argument);
 3636     }
 3637 }
 3638 
 3639 
 3640 /*
 3641  * The main function.
 3642  * It returns values from sysexits.h (like sendmail does).
 3643  */
 3644 
 3645 int main(int argc, char *argv[])
 3646 {
 3647     msmtp_cmdline_conf_t conf;
 3648     /* account information from the configuration file(s) */
 3649     list_t *account_list = NULL;
 3650     char *loaded_system_conffile = NULL;
 3651     char *loaded_user_conffile = NULL;
 3652     /* environment variables */
 3653     int allow_fallback_to_env;
 3654     char *env_email;
 3655     char *env_smtpserver;
 3656     /* the account data that will be used */
 3657     account_t *account = NULL;
 3658     /* error handling */
 3659     char *errstr;
 3660     list_t *errmsg;
 3661     int error_code;
 3662     int e;
 3663     list_t *lp;
 3664     /* misc */
 3665 #ifdef HAVE_TLS
 3666     int tls_lib_initialized = 0;
 3667 #endif
 3668     int net_lib_initialized = 0;
 3669     /* the size of a sent mail */
 3670     long mailsize = 0;
 3671     /* special LMTP error info */
 3672     list_t *lmtp_errstrs;
 3673     list_t *lmtp_error_msgs;
 3674     list_t *lp_lmtp_errstrs;
 3675     list_t *lp_lmtp_error_msgs;
 3676     /* log information */
 3677     char *log_info;
 3678     /* needed to read the headers and extract addresses */
 3679     FILE *header_tmpfile = NULL;
 3680     FILE *prepend_header_tmpfile = NULL;
 3681     int have_from_header = 0;
 3682     int have_date_header = 0;
 3683 
 3684 
 3685     /* Avoid the side effects of text mode interpretations on DOS systems. */
 3686 #if defined W32_NATIVE
 3687     setmode(fileno(stdin), O_BINARY);
 3688     _fmode = O_BINARY;
 3689 #endif
 3690 
 3691     errstr = NULL;
 3692     errmsg = NULL;
 3693 
 3694     /* internationalization with gettext */
 3695 #ifdef ENABLE_NLS
 3696     setlocale(LC_ALL, "");
 3697     bindtextdomain(PACKAGE, LOCALEDIR);
 3698     textdomain(PACKAGE);
 3699 #endif
 3700 
 3701     /* Avoid receiving SIGPIPE when writing to sockets that were closed by the
 3702      * remote end; we handle write errors where they occur. */
 3703 #ifdef HAVE_SIGNAL
 3704 #ifdef SIGPIPE
 3705     signal(SIGPIPE, SIG_IGN);
 3706 #endif
 3707 #endif
 3708 
 3709     /* the command line */
 3710     if ((error_code = msmtp_cmdline(&conf, argc, argv)) != EX_OK)
 3711     {
 3712         goto exit;
 3713     }
 3714 
 3715     if (conf.print_version)
 3716     {
 3717         msmtp_print_version();
 3718     }
 3719     if (conf.print_help)
 3720     {
 3721         msmtp_print_help();
 3722     }
 3723 
 3724     if (conf.configure)
 3725     {
 3726         char *userconfigfile = conf.user_conffile ? xstrdup(conf.user_conffile) : get_userconfig(USERCONFFILE);
 3727         error_code = msmtp_configure(conf.configure_address, userconfigfile);
 3728         free(userconfigfile);
 3729         free(conf.configure_address);
 3730         goto exit;
 3731     }
 3732 
 3733     if (conf.print_help || conf.print_version
 3734             || (!conf.sendmail && !conf.serverinfo && !conf.rmqs
 3735                 && !conf.print_conf))
 3736     {
 3737         error_code = EX_OK;
 3738         goto exit;
 3739     }
 3740 
 3741     if ((conf.serverinfo || conf.rmqs) && !list_is_empty(conf.recipients))
 3742     {
 3743         print_error(_("too many arguments"));
 3744         error_code = EX_USAGE;
 3745         goto exit;
 3746     }
 3747     /* Read recipients and/or the envelope from address from the mail. */
 3748     if (conf.sendmail)
 3749     {
 3750         char *envelope_from = NULL;
 3751         if (!(header_tmpfile = tmpfile()))
 3752         {
 3753             print_error(_("cannot create temporary file: %s"),
 3754                     sanitize_string(strerror(errno)));
 3755             error_code = EX_IOERR;
 3756             goto exit;
 3757         }
 3758         if ((error_code = msmtp_read_headers(stdin, header_tmpfile,
 3759                         conf.read_recipients
 3760                             ? list_last(conf.recipients) : NULL,
 3761                         &envelope_from, &have_date_header, &errstr)) != EX_OK)
 3762         {
 3763             print_error("%s", sanitize_string(errstr));
 3764             goto exit;
 3765         }
 3766         have_from_header = (envelope_from ? 1 : 0);
 3767         if (conf.read_envelope_from)
 3768         {
 3769             conf.cmdline_account->from = envelope_from;
 3770             if (conf.pretend || conf.debug)
 3771             {
 3772                 printf(_("envelope from address extracted from mail: %s\n"),
 3773                         conf.cmdline_account->from);
 3774             }
 3775         }
 3776         if (fseeko(header_tmpfile, 0, SEEK_SET) != 0)
 3777         {
 3778             print_error(_("cannot rewind temporary file: %s"),
 3779                     sanitize_string(strerror(errno)));
 3780             error_code = EX_IOERR;
 3781             goto exit;
 3782         }
 3783     }
 3784     /* check the list of recipients */
 3785     if (conf.sendmail && list_is_empty(conf.recipients) && !conf.pretend)
 3786     {
 3787         print_error(_("no recipients found"));
 3788         error_code = EX_USAGE;
 3789         goto exit;
 3790     }
 3791 
 3792     /* get the account to be used, either from the conffile(s) or from the
 3793      * command line */
 3794     allow_fallback_to_env = 0;
 3795     if (!conf.cmdline_account->host)
 3796     {
 3797         if ((error_code = msmtp_get_conffile_accounts(&account_list,
 3798                         (conf.pretend || conf.debug), conf.user_conffile,
 3799                         &loaded_system_conffile, &loaded_user_conffile))
 3800                 != EX_OK)
 3801         {
 3802             goto exit;
 3803         }
 3804         if (!conf.account_id)
 3805         {
 3806             if (conf.cmdline_account->from)
 3807             {
 3808                 /* No account was chosen, but the envelope from address is
 3809                  * given. Choose the right account with this address.
 3810                  */
 3811                 account = account_copy(find_account_by_envelope_from(
 3812                             account_list, conf.cmdline_account->from));
 3813                 if (account)
 3814                 {
 3815                     if (conf.pretend || conf.debug)
 3816                     {
 3817                         printf(_("account chosen by "
 3818                                     "envelope from address %s: %s\n"),
 3819                                 conf.cmdline_account->from, account->id);
 3820                     }
 3821                 }
 3822             }
 3823             if (!account)
 3824             {
 3825                 /* No envelope from address or no matching account.
 3826                  * Use default if available, but allow fallback to environment
 3827                  * variables. */
 3828                 conf.account_id = "default";
 3829                 if (conf.pretend || conf.debug)
 3830                 {
 3831                     printf(_("falling back to default account\n"));
 3832                 }
 3833                 allow_fallback_to_env = 1;
 3834             }
 3835         }
 3836         if (!account && !(account =
 3837                     account_copy(find_account(account_list, conf.account_id))))
 3838         {
 3839             env_email = getenv("EMAIL");
 3840             env_smtpserver = getenv("SMTPSERVER");
 3841             if (allow_fallback_to_env
 3842                     && (!conf.sendmail
 3843                         || conf.cmdline_account->from || env_email)
 3844                     && env_smtpserver)
 3845             {
 3846                 if (conf.sendmail && !conf.cmdline_account->from)
 3847                 {
 3848                     conf.cmdline_account->from = xstrdup(env_email);
 3849                 }
 3850                 conf.cmdline_account->host = xstrdup(env_smtpserver);
 3851                 account = account_copy(conf.cmdline_account);
 3852                 if (conf.pretend || conf.debug)
 3853                 {
 3854                     printf(_("using environment variables "
 3855                                 "EMAIL and SMTPSERVER\n"));
 3856                 }
 3857             }
 3858             else
 3859             {
 3860                 if (loaded_system_conffile && loaded_user_conffile)
 3861                 {
 3862                     print_error(_("account %s not found in %s and %s"),
 3863                             conf.account_id, loaded_system_conffile,
 3864                             loaded_user_conffile);
 3865                 }
 3866                 else if (loaded_system_conffile)
 3867                 {
 3868                     print_error(_("account %s not found in %s"),
 3869                             conf.account_id, loaded_system_conffile);
 3870                 }
 3871                 else if (loaded_user_conffile)
 3872                 {
 3873                     print_error(_("account %s not found in %s"),
 3874                             conf.account_id, loaded_user_conffile);
 3875                 }
 3876                 else /* no conffile was read */
 3877                 {
 3878                     print_error(_("account %s not found: "
 3879                                 "no configuration file available"),
 3880                             conf.account_id);
 3881                 }
 3882                 error_code = EX_CONFIG;
 3883                 goto exit;
 3884             }
 3885         }
 3886         override_account(account, conf.cmdline_account);
 3887     }
 3888     else
 3889     {
 3890         account = account_copy(conf.cmdline_account);
 3891         if (conf.pretend || conf.debug)
 3892         {
 3893             printf(_("using account specified on command line\n"));
 3894         }
 3895     }
 3896 
 3897     /* OK, we're using the settings in 'account'. Complete them and check
 3898      * them. */
 3899     if (account->auth_mech && !account->password && account->passwordeval)
 3900     {
 3901         if (password_eval(account->passwordeval,
 3902                     &account->password, &errstr) != 0)
 3903         {
 3904             print_error("%s", sanitize_string(errstr));
 3905             error_code = EX_CONFIG;
 3906             goto exit;
 3907         }
 3908     }
 3909     if (account->port == 0)
 3910     {
 3911         if (account->protocol == SMTP_PROTO_SMTP)
 3912         {
 3913             if (account->tls && account->tls_nostarttls)
 3914             {
 3915                 account->port = 465;
 3916             }
 3917             else
 3918             {
 3919                 account->port = 25;
 3920             }
 3921         }
 3922         else /* LMTP. Has no default port as of 2006-06-17. */
 3923         {
 3924         }
 3925     }
 3926     if (!account->tls_trust_file && !(account->mask & ACC_TLS_TRUST_FILE))
 3927     {
 3928         account->tls_trust_file = xstrdup("system");
 3929     }
 3930     if (account->proxy_host && account->proxy_port == 0)
 3931     {
 3932         account->proxy_port = 1080;
 3933     }
 3934     if (expand_domain(&(account->domain), &errstr) != CONF_EOK)
 3935     {
 3936         print_error("%s", sanitize_string(errstr));
 3937         error_code = EX_CONFIG;
 3938         goto exit;
 3939     }
 3940     if (conf.sendmail && account->from)
 3941     {
 3942         if (expand_from(&(account->from), &errstr) != CONF_EOK)
 3943         {
 3944             print_error("%s", sanitize_string(errstr));
 3945             error_code = EX_CONFIG;
 3946             goto exit;
 3947         }
 3948     }
 3949     if (conf.sendmail && account->auto_from /* obsolete */)
 3950     {
 3951         free(account->from);
 3952         account->from = msmtp_construct_env_from(account->maildomain);
 3953     }
 3954     if (check_account(account, (conf.sendmail && !conf.pretend),
 3955                 &errstr) != CONF_EOK)
 3956     {
 3957         if (account->id && account->conffile)
 3958         {
 3959             print_error(_("account %s from %s: %s"), account->id,
 3960                     account->conffile, sanitize_string(errstr));
 3961         }
 3962         else
 3963         {
 3964             print_error("%s", sanitize_string(errstr));
 3965         }
 3966         error_code = EX_CONFIG;
 3967         goto exit;
 3968     }
 3969 
 3970     /* print configuration */
 3971     if (conf.print_conf)
 3972     {
 3973         msmtp_print_conf(conf, account);
 3974     }
 3975 
 3976     /* replace aliases */
 3977     if (conf.sendmail && account->aliases)
 3978     {
 3979         if ((e = aliases_replace(account->aliases, conf.recipients,
 3980                          &errstr)) != ALIASES_EOK)
 3981         {
 3982             print_error("%s: %s", account->aliases,
 3983                     sanitize_string(errstr));
 3984             error_code = EX_CONFIG;
 3985             goto exit;
 3986         }
 3987     }
 3988 
 3989     /* stop if there's nothing to do */
 3990     if (conf.pretend || (!conf.sendmail && !conf.serverinfo && !conf.rmqs))
 3991     {
 3992         error_code = EX_OK;
 3993         goto exit;
 3994     }
 3995 
 3996     /* initialize libraries */
 3997 #ifndef HAVE_SYSLOG
 3998     if (conf.sendmail && account->syslog)
 3999     {
 4000         print_error(_("this platform does not support syslog logging"));
 4001         error_code = EX_UNAVAILABLE;
 4002         goto exit;
 4003     }
 4004 #endif /* not HAVE_SYSLOG */
 4005     if ((conf.sendmail || conf.rmqs) /* serverinfo does not use auth */
 4006             && account->auth_mech && (strcmp(account->auth_mech, "") != 0)
 4007             && !smtp_client_supports_authmech(account->auth_mech))
 4008     {
 4009         print_error(_("support for authentication method %s "
 4010                     "is not compiled in"),
 4011                 account->auth_mech);
 4012         error_code = EX_UNAVAILABLE;
 4013         goto exit;
 4014     }
 4015     if ((e = net_lib_init(&errstr)) != NET_EOK)
 4016     {
 4017         print_error(_("cannot initialize networking: %s"),
 4018                 sanitize_string(errstr));
 4019         error_code = EX_SOFTWARE;
 4020         goto exit;
 4021     }
 4022     net_lib_initialized = 1;
 4023     if (account->tls)
 4024     {
 4025 #ifdef HAVE_TLS
 4026         if ((e = mtls_lib_init(&errstr)) != TLS_EOK)
 4027         {
 4028             print_error(_("cannot initialize TLS library: %s"),
 4029                     sanitize_string(errstr));
 4030             error_code = EX_SOFTWARE;
 4031             goto exit;
 4032         }
 4033         tls_lib_initialized = 1;
 4034 #else /* not HAVE_TLS */
 4035         print_error(_("support for TLS is not compiled in"));
 4036         error_code = EX_UNAVAILABLE;
 4037         goto exit;
 4038 #endif /* not HAVE_TLS */
 4039     }
 4040 
 4041     /* do the work */
 4042     if (conf.sendmail)
 4043     {
 4044         int prepend_header_contains_from = 0;
 4045         if (account->undisclosed_recipients
 4046                 || account->set_from_header == 1
 4047                 || (!have_from_header && account->set_from_header == 2)
 4048                 || (!have_date_header && account->set_date_header == 2))
 4049         {
 4050             if (!(prepend_header_tmpfile = tmpfile()))
 4051             {
 4052                 print_error(_("cannot create temporary file: %s"),
 4053                         sanitize_string(strerror(errno)));
 4054                 error_code = EX_IOERR;
 4055                 goto exit;
 4056             }
 4057         }
 4058         if (account->set_from_header == 1
 4059                 || (!have_from_header && account->set_from_header == 2))
 4060         {
 4061             if (conf.full_name)
 4062             {
 4063                 fprintf(prepend_header_tmpfile, "From: %s <%s>\n",
 4064                         conf.full_name, account->from);
 4065             }
 4066             else
 4067             {
 4068                 fprintf(prepend_header_tmpfile, "From: %s\n", account->from);
 4069             }
 4070             prepend_header_contains_from = 1;
 4071         }
 4072         if (account->undisclosed_recipients)
 4073         {
 4074             fputs("To: undisclosed-recipients:;\n", prepend_header_tmpfile);
 4075         }
 4076         if (!have_date_header && account->set_date_header == 2)
 4077         {
 4078             char rfc2822_timestamp[32];
 4079             print_time_rfc2822(time(NULL), rfc2822_timestamp);
 4080             fprintf(prepend_header_tmpfile, "Date: %s\n", rfc2822_timestamp);
 4081         }
 4082         if (prepend_header_tmpfile
 4083                 && fseeko(prepend_header_tmpfile, 0, SEEK_SET) != 0)
 4084         {
 4085             print_error(_("cannot rewind temporary file: %s"),
 4086                     sanitize_string(strerror(errno)));
 4087             error_code = EX_IOERR;
 4088             goto exit;
 4089         }
 4090         if ((error_code = msmtp_sendmail(account, conf.recipients,
 4091                         prepend_header_tmpfile, prepend_header_contains_from,
 4092                         header_tmpfile, stdin,
 4093                         conf.debug, &mailsize,
 4094                         &lmtp_errstrs, &lmtp_error_msgs,
 4095                         &errmsg, &errstr)) != EX_OK)
 4096         {
 4097             if (account->protocol == SMTP_PROTO_LMTP && lmtp_errstrs)
 4098             {
 4099                 lp_lmtp_errstrs = lmtp_errstrs;
 4100                 lp_lmtp_error_msgs = lmtp_error_msgs;
 4101                 while (!list_is_empty(lp_lmtp_errstrs))
 4102                 {
 4103                     lp_lmtp_errstrs = lp_lmtp_errstrs->next;
 4104                     lp_lmtp_error_msgs = lp_lmtp_error_msgs->next;
 4105                     if (lp_lmtp_errstrs->data)
 4106                     {
 4107                         print_error("%s", sanitize_string(
 4108                                     lp_lmtp_errstrs->data));
 4109                         if ((lp = lp_lmtp_error_msgs->data))
 4110                         {
 4111                             while (!list_is_empty(lp))
 4112                             {
 4113                                 lp = lp->next;
 4114                                 print_error(_("LMTP server message: %s"),
 4115                                         sanitize_string(lp->data));
 4116                             }
 4117                             list_xfree(lp_lmtp_error_msgs->data, free);
 4118                         }
 4119                     }
 4120                 }
 4121                 list_xfree(lmtp_errstrs, free);
 4122                 list_free(lmtp_error_msgs);
 4123                 if (account->id && account->conffile)
 4124                 {
 4125                     print_error(_("could not send mail to all recipients "
 4126                                 "(account %s from %s)"),
 4127                             account->id, account->conffile);
 4128                 }
 4129                 else
 4130                 {
 4131                     print_error(_("could not send mail to all recipients"));
 4132                 }
 4133             }
 4134             else
 4135             {
 4136                 if (errstr)
 4137                 {
 4138                     print_error("%s", sanitize_string(errstr));
 4139                 }
 4140                 if (errmsg)
 4141                 {
 4142                     lp = errmsg;
 4143                     while (!list_is_empty(lp))
 4144                     {
 4145                         lp = lp->next;
 4146                         print_error(_("server message: %s"),
 4147                                 sanitize_string(lp->data));
 4148                     }
 4149                 }
 4150                 if (account->id && account->conffile)
 4151                 {
 4152                     print_error(_("could not send mail (account %s from %s)"),
 4153                             account->id, account->conffile);
 4154                 }
 4155                 else
 4156                 {
 4157                     print_error(_("could not send mail"));
 4158                 }
 4159             }
 4160         }
 4161         if (account->logfile || account->syslog)
 4162         {
 4163             if (account->protocol == SMTP_PROTO_LMTP && lmtp_errstrs)
 4164             {
 4165                 /* errstr is NULL; print short info to it */
 4166                 errstr = xasprintf(
 4167                         _("delivery to one or more recipients failed"));
 4168                 /* we know that errmsg is NULL. that's ok. */
 4169             }
 4170             log_info = msmtp_get_log_info(account, conf.recipients, mailsize,
 4171                     errmsg, errstr, error_code);
 4172             if (account->logfile)
 4173             {
 4174                 msmtp_log_to_file(account->logfile, account->logfile_time_format, log_info);
 4175             }
 4176 #ifdef HAVE_SYSLOG
 4177             if (account->syslog)
 4178             {
 4179                 msmtp_log_to_syslog(account->syslog, log_info,
 4180                         (error_code != EX_OK));
 4181             }
 4182 #endif
 4183             free(log_info);
 4184         }
 4185     }
 4186     else if (conf.serverinfo)
 4187     {
 4188         if ((error_code = msmtp_serverinfo(account, conf.debug,
 4189                         &errmsg, &errstr)) != EX_OK)
 4190         {
 4191             if (errstr)
 4192             {
 4193                 print_error("%s", sanitize_string(errstr));
 4194             }
 4195             if (errmsg)
 4196             {
 4197                 lp = errmsg;
 4198                 while (!list_is_empty(lp))
 4199                 {
 4200                     lp = lp->next;
 4201                     print_error(_("server message: %s"),
 4202                             sanitize_string(lp->data));
 4203                 }
 4204             }
 4205         }
 4206     }
 4207     else /* rmqs */
 4208     {
 4209         if ((error_code = msmtp_rmqs(account, conf.debug, conf.rmqs_argument,
 4210                         &errmsg, &errstr)) != EX_OK)
 4211         {
 4212             if (errstr)
 4213             {
 4214                 print_error("%s", sanitize_string(errstr));
 4215             }
 4216             if (errmsg)
 4217             {
 4218                 lp = errmsg;
 4219                 while (!list_is_empty(lp))
 4220                 {
 4221                     lp = lp->next;
 4222                     print_error(_("server message: %s"),
 4223                             sanitize_string(lp->data));
 4224                 }
 4225             }
 4226         }
 4227     }
 4228 
 4229 
 4230 exit:
 4231 
 4232     /* clean up */
 4233     if (header_tmpfile)
 4234     {
 4235         fclose(header_tmpfile);
 4236     }
 4237     if (prepend_header_tmpfile)
 4238     {
 4239         fclose(prepend_header_tmpfile);
 4240     }
 4241     free(loaded_system_conffile);
 4242     free(loaded_user_conffile);
 4243 #ifdef HAVE_TLS
 4244     if (tls_lib_initialized)
 4245     {
 4246         mtls_lib_deinit();
 4247     }
 4248 #endif /* HAVE_TLS */
 4249     if (net_lib_initialized)
 4250     {
 4251         net_lib_deinit();
 4252     }
 4253     if (account_list)
 4254     {
 4255         list_xfree(account_list, account_free);
 4256     }
 4257     account_free(conf.cmdline_account);
 4258     account_free(account);
 4259     if (conf.recipients)
 4260     {
 4261         list_xfree(conf.recipients, free);
 4262     }
 4263     free(errstr);
 4264     if (errmsg)
 4265     {
 4266         list_xfree(errmsg, free);
 4267     }
 4268 
 4269     return error_code;
 4270 }