"Fossies" - the Fresh Open Source Software Archive

Member "msmtp-1.8.5/src/msmtp.c" (12 Jul 2019, 135298 Bytes) of package /linux/privat/msmtp-1.8.5.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.4_vs_1.8.5.

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