Back to index

courier  0.68.2
Classes | Defines | Functions | Variables
esmtpclient.c File Reference
#include "soxwrap/soxwrap.h"
#include "soxwrap/sconnect.h"
#include "courier.h"
#include "smtproutes.h"
#include "localstatedir.h"
#include "moduledel.h"
#include "comctlfile.h"
#include "comreadtime.h"
#include "comqueuename.h"
#include "maxlongsize.h"
#include "comverp.h"
#include "rfc1035/rfc1035.h"
#include "rfc1035/rfc1035mxlist.h"
#include "rfc822.h"
#include "rfc2045/rfc2045.h"
#include "numlib/numlib.h"
#include "tcpd/spipe.h"
#include "tcpd/tlsclient.h"
#include <courierauthsaslclient.h>
#include "mybuf.h"
#include "rw.h"
#include "esmtpconfig.h"
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>

Go to the source code of this file.

Classes

struct  rw_for_esmtp
struct  esmtpauthinfo

Defines

#define mybuf_readfunc   sox_read
#define cork(n)
#define ISFINALLINE(p)
#define KEYWORD(x)   (strcmp(hellobuf, x) == 0)
#define KEYWORDARG(x)   (strncmp(hellobuf, x, sizeof(x)-1) == 0)

Functions

static void sendesmtp (struct moduledel *, struct ctlfile *)
static const char * readline ()
static void quit ()
static int dowritestr (const char *)
static int writeflush ()
static void sock_timeout (unsigned)
struct rw_list * esmtp_rw_install (const struct rw_install_info *)
int isloopback (const char *)
void rfc2045_error (const char *p)
static void setconfig ()
void esmtpchild (unsigned childnum)
static void hard_error (struct moduledel *, struct ctlfile *, const char *)
static void soft_error (struct moduledel *, struct ctlfile *, const char *)
static void connect_error (struct moduledel *, struct ctlfile *)
static int hello (struct moduledel *, struct ctlfile *)
static int starttls (struct moduledel *, struct ctlfile *, const char *)
static int authclient (struct moduledel *, struct ctlfile *, const char *)
static int rset (struct moduledel *, struct ctlfile *)
static int smtpreply (const char *, struct moduledel *, struct ctlfile *, int)
static int dowrite (const char *, unsigned)
static void push (struct moduledel *, struct ctlfile *)
static const char * want_security (struct ctlfile *ctf)
static int get_sourceaddr (int af, const RFC1035_ADDR *dest_addr, RFC1035_NETADDR *addrbuf, const struct sockaddr **addrptr, int *addrptrlen)
static int backscatter (const char *src)
static void hard_error1 (struct moduledel *del, struct ctlfile *ctf, const char *msg, int n)
static void soft_error1 (struct moduledel *del, struct ctlfile *ctf, const char *msg, int n)
static void connection_closed (struct moduledel *del, struct ctlfile *ctf)
static void smtp_error (struct moduledel *del, struct ctlfile *ctf, const char *msg, int errcode)
static void sockipname (char *buf)
static void talking2 (struct moduledel *del, struct ctlfile *ctf, int n)
static void talking (struct moduledel *del, struct ctlfile *ctf)
static void connect_error1 (struct moduledel *del, struct ctlfile *ctf, int n)
static void smtp_msg (struct moduledel *del, struct ctlfile *ctf)
static void reply (struct moduledel *del, struct ctlfile *ctf, const char *msg)
static void sent (struct moduledel *del, struct ctlfile *ctf, const char *msg)
static void wait_rw (int *waitr, int *waitw)
static int wait_read ()
static int wait_write ()
static void swallow (unsigned)
static void burp (const char *, unsigned)
static void doflush ()
static int hello2 (struct moduledel *, struct ctlfile *, int)
static void report_broken_starttls (const char *reply)
static int smtpcommand (const char *cmd, struct moduledel *del, struct ctlfile *ctf, int istalking)
static void pushdsn (struct moduledel *, struct ctlfile *)
static char * mailfrom (struct moduledel *del, struct ctlfile *ctf, int messagefd, int is8bitmsg)
static char * rcptcmd (struct moduledel *del, struct ctlfile *ctf, unsigned rcptnum)
static const char * readpipelinercpt (struct iovec **, unsigned *)
static int parsedatareply (struct moduledel *, struct ctlfile *, int *, struct iovec **, unsigned *, int)
static int do_pipeline_rcpt (struct moduledel *del, struct ctlfile *ctf, int *rcptok)
static int my_writev (int fd, const struct iovec *vector, size_t count)
static int parseexdatareply (const char *, struct moduledel *, struct ctlfile *, int *)
static char * logsuccessto ()
static void call_rewrite_func (struct rw_info *p, void(*f)(struct rw_info *), void *arg)
static int data_wait (struct moduledel *del, struct ctlfile *ctf, int *rcptok)
static void parserfc (int fd, struct rfc2045 *rfcp)
static int convert_to_crlf (const char *, unsigned, void *)
static int escape_dots (const char *, unsigned, struct rw_for_esmtp *)
static const char * start_esmtpauth (const char *, const char *, void *)
static const char * esmtpauth (const char *, void *)
static int final_esmtpauth (const char *, void *)
static int plain_esmtpauth (const char *, const char *, void *)
static const char * getresp (struct esmtpauthinfo *x)

Variables

static time_t esmtpkeepaliveping
static time_t connect_timeout
static time_t cmd_timeout
static time_t helo_timeout
static time_t quit_timeout
static time_t data_timeout
static time_t net_timeout
static int net_error
static int sockfd
static void(* rewrite_func )(struct rw_info *, void(*)(struct rw_info *))
static RFC1035_ADDR sockfdaddr
static char * sockfdaddrname = 0
static char * auth_key = 0
static struct mybuf
static char writebuf [BUFSIZ]
static char * writebufptr
static unsigned writebufleft
static time_t timeout_time
static char socklinebuf [sizeof(sockbuf.buffer)+1]
static unsigned socklinesize
static char * host
static char * authsasllist = 0
static int is_secure_connection = 0
static int smtproutes_flags = 0
static int hasdsn
static int haspipelining
static int has8bitmime
static int hasverp
static int hassize
static int hasexdata
static int hascourier
static int hasstarttls
static int hassecurity_starttls
static RFC1035_ADDR laddr

Class Documentation

struct rw_for_esmtp

Definition at line 2660 of file esmtpclient.c.

Class Members
unsigned byte_counter
int is_sol
struct esmtpauthinfo

Definition at line 2825 of file esmtpclient.c.

Collaboration diagram for esmtpauthinfo:
Class Members
struct ctlfile * ctf
struct moduledel * del
int error_sent

Define Documentation

#define cork (   n)

Definition at line 98 of file esmtpclient.c.

#define ISFINALLINE (   p)
Value:
( isdigit((int)(unsigned char)p[0]) && \
                     isdigit((int)(unsigned char)p[1]) && \
                     isdigit((int)(unsigned char)p[2]) \
                            && p[3] == ' ')

Definition at line 116 of file esmtpclient.c.

#define KEYWORD (   x)    (strcmp(hellobuf, x) == 0)
#define KEYWORDARG (   x)    (strncmp(hellobuf, x, sizeof(x)-1) == 0)
#define mybuf_readfunc   sox_read

Definition at line 29 of file esmtpclient.c.


Function Documentation

static int authclient ( struct moduledel del,
struct ctlfile ctf,
const char *  auth_key 
) [static]

Definition at line 2831 of file esmtpclient.c.

{
FILE   *configfile;
char   uidpwbuf[256];
char   *q;
const char *p;
struct authsaslclientinfo info;
struct esmtpauthinfo xinfo;
int    rc;

       q=config_localfilename("esmtpauthclient");
       configfile=fopen( q, "r");
       free(q);

       if (!configfile)     return (0);

       xinfo.del=del;
       xinfo.ctf=ctf;
       xinfo.error_sent=0;

       for (;;)
       {
              if (fgets(uidpwbuf, sizeof(uidpwbuf), configfile) == 0)
              {
                     fclose(configfile);
                     return (0);
              }
              q=strtok(uidpwbuf, " \t\r\n");

              if (!sockfdaddrname || !q)  continue;

#if    HAVE_STRCASECMP
              if (strcasecmp(q, auth_key) == 0)
                     break;
#else
              if (stricmp(q, auth_key) == 0)
                     break;
#endif
       }
       fclose(configfile);
       memset(&info, 0, sizeof(info));
       info.userid=strtok(0, " \t\r\n");
       info.password=strtok(0, " \t\r\n");

       info.sasl_funcs=authsasllist;

       info.start_conv_func= &start_esmtpauth;
       info.conv_func= &esmtpauth;
       info.final_conv_func= &final_esmtpauth;
       info.plain_conv_func= &plain_esmtpauth;
       info.conv_func_arg= &xinfo;

       rc=auth_sasl_client(&info);
       if (rc == AUTHSASL_NOMETHODS)
       {
              talking(del, ctf);
              hard_error(del, ctf,
                     "Compatible SASL authentication not available.");
              return (-1);
       }

       if (rc && !xinfo.error_sent)
       {
              talking(del, ctf);
              soft_error(del, ctf, "Temporary SASL authentication error.");
       }

       if (rc)
              return (-1);

       if ((p=readline()) == 0)
       {
              talking(del, ctf);
              connect_error(del, ctf);
              return (-1);
       }

       if (*p != '1' && *p != '2' && *p != '3') /* Some kind of an error */
       {
              talking(del, ctf);
              sent(del, ctf, "AUTH");
              smtp_msg(del, ctf);
              while (!ISFINALLINE(p))
              {
                     reply(del, ctf, p);
                     if ((p=readline()) == 0)
                     {
                            connection_closed(del, ctf);
                            return (-1);
                     }
              }
              smtp_error(del, ctf, p, 0);
              quit();
              return (-1);
       }

       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int backscatter ( const char *  src) [static]

Definition at line 368 of file esmtpclient.c.

{
       char buf[1024];
       const char *env;
       char *p;

       buf[0]=0;

       env=getenv("ESMTP_BLOCKBACKSCATTER");

       strncat(buf, env ? env:"", 1000);

       for (p=buf; (p=strtok(p, ",")); p=NULL)
       {
              if (strcmp(p, src) == 0)
                     return 1;
       }
       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void burp ( const char *  p,
unsigned  n 
) [static]

Definition at line 1126 of file esmtpclient.c.

{
       if (n > sizeof(socklinebuf)-1-socklinesize)
              n=sizeof(socklinebuf)-1-socklinesize;
       memcpy(socklinebuf+socklinesize, p, n);
       socklinesize += n;
}

Here is the caller graph for this function:

static void call_rewrite_func ( struct rw_info *  p,
void(*)(struct rw_info *)  f,
void *  arg 
) [static]

Definition at line 2626 of file esmtpclient.c.

{
       (*rewrite_func)(p, f);
}

Here is the caller graph for this function:

static void connect_error ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 855 of file esmtpclient.c.

{
       connect_error1(del, ctf, -1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void connect_error1 ( struct moduledel del,
struct ctlfile ctf,
int  n 
) [static]

Definition at line 842 of file esmtpclient.c.

{
#if    HAVE_STRERROR

       if (errno)
              soft_error1(del, ctf, errno == ECONNRESET
                         ? "Network connection shut down by the remote mail server"
                         : strerror(errno), n);
       else
#endif
              soft_error1(del, ctf, "Connection closed by remote host.", n);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void connection_closed ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 763 of file esmtpclient.c.

{
       soft_error(del, ctf, "Connection unexpectedly closed by remote host.");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int convert_to_crlf ( const char *  msg,
unsigned  l,
void *  voidp 
) [static]

Definition at line 2771 of file esmtpclient.c.

{
unsigned i, j;
int    rc;

       for (i=j=0; i < l; i++)
       {
              if (msg[i] != '\n')
                     continue;
              if ((rc=escape_dots(msg+j, i-j,
                     (struct rw_for_esmtp *)voidp)) != 0 ||
                     (rc=escape_dots("\r", 1,
                            (struct rw_for_esmtp *)voidp)) != 0)
                     return (rc);
              j=i;
       }
       return (escape_dots(msg+j, i-j, (struct rw_for_esmtp *)voidp));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int data_wait ( struct moduledel del,
struct ctlfile ctf,
int *  rcptok 
) [static]

Definition at line 2634 of file esmtpclient.c.

{
       sock_timeout(data_timeout);
       if (dowrite(".\r\n", 3) || writeflush())  return (-1);

       cork(0);

       (void)parsedatareply(del, ctf, rcptok, 0, 0, 1);

       if (sockfd < 0)      return (-1);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int do_pipeline_rcpt ( struct moduledel del,
struct ctlfile ctf,
int *  rcptok 
) [static]

Definition at line 2115 of file esmtpclient.c.

{
char   **cmdarray;
struct iovec *iov;
struct iovec *       iovw;
unsigned      niovw;

unsigned i;
const char *p;

int    rc=0;

       /* Construct all the RCPT TOs we'll issue. */

       cmdarray=(char **)courier_malloc(sizeof(char *)*
              (del->nreceipients+1));     /* 1 extra PTR for the DATA */
       iov=(struct iovec *)courier_malloc(sizeof(struct iovec)*
              (del->nreceipients+1));

       /* Allocate cmdarray[], also set up iovecs to point to each cmd */

       for (i=0; i <= del->nreceipients; i++)
       {
              cmdarray[i]= i < del->nreceipients ?  rcptcmd(del, ctf, i):
                            strcpy(courier_malloc(sizeof("DATA\r\n")),
                                          "DATA\r\n");
              iov[i].iov_base=(caddr_t)cmdarray[i];
              iov[i].iov_len=strlen(cmdarray[i]);
       }

       iovw=iov;
       niovw= i;

       if (haspipelining)   /* One timeout */
              sock_timeout(cmd_timeout);

       /* Read replies for the RCPT TO commands */

       for (i=0; i<del->nreceipients; i++)
       {
       char   err_code=0;
       unsigned line_num=0;

              /* If server can't do pipelining, just set niovw to one!!! */

              if (!haspipelining)
              {
                     iovw=iov+i;
                     niovw=1;
                     sock_timeout(cmd_timeout);
              }

              do
              {
                     if ((p=readpipelinercpt( &iovw, &niovw)) == 0)
                            break;

                     if (line_num == 0)
                            err_code= *p;

                     if ( SMTPREPLY_TYPE(&err_code) ==
                            COMCTLFILE_DELSUCCESS)
                            continue;

                     if (line_num >= 10)  continue;
                     /* Ignore SMTP replies longer than 10 lines */

                     if (line_num == 0)
                     {
                            ctlfile_append_connectioninfo(ctf,
                                   (unsigned)atol(del->receipients[i*2]),
                                   COMCTLFILE_DELINFO_SENT,
                                   cmdarray[i]);
                            ctlfile_append_connectioninfo(ctf,
                                   (unsigned)atol(del->receipients[i*2]),
                                   COMCTLFILE_DELINFO_REPLYTYPE,
                                   "smtp");
                     }
                     ctlfile_append_connectioninfo(ctf,
                            (unsigned)atol(del->receipients[i*2]),
                                   COMCTLFILE_DELINFO_REPLY, p);
              } while (!ISFINALLINE(p));

              if (!p)
              {
                     while (i < del->nreceipients)
                            rcptok[i++]=1;
                     break;
              }

              if ( SMTPREPLY_TYPE(&err_code) == COMCTLFILE_DELSUCCESS)
              {
                     rcptok[i]=1;  /* This recipient was accepted */
                     continue;
              }

              /* Failed.  Report it */

              rcptok[i]=0;

              if (SMTPREPLY_TYPE(&err_code) == COMCTLFILE_DELFAIL)
                     hard_error1(del, ctf, 0, i);
              else
                     soft_error1(del, ctf, 0, i);
       }

/* ------------------- Read the reply to the DATA ----------------- */

       if (sockfd >= 0)
       {
              if (!haspipelining)  /* DATA hasn't been sent yet */
              {
                     for (i=0; i<del->nreceipients; i++)
                            if (rcptok[i])       break;

                     if (i >= del->nreceipients) return (-1);
                                   /* All RCPT TOs failed */

                     iovw=iov+del->nreceipients;
                     niovw=1;
                     sock_timeout(cmd_timeout);
              }
              rc=parsedatareply(del, ctf, rcptok, &iovw, &niovw, 0);
                     /* One more reply */
       }

       if (sockfd < 0)
       {
              for (i=0; i<del->nreceipients; i++)
              {
                     if (!rcptok[i])      continue;
                     connect_error1(del, ctf, i);
              }
              rc= -1;
       }

       for (i=0; i<del->nreceipients; i++)
              free(cmdarray[i]);
       free(cmdarray);
       free(iov);
       return (rc);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void doflush ( ) [static]

Definition at line 1046 of file esmtpclient.c.

{
int    n;
int    i;

       if (wait_write())
       {
              if (sockfd >= 0)
                     sox_close(sockfd);
              sockfd= -1;
              return;
       }
       if ((n=sox_write(sockfd, writebuf, writebufptr-writebuf)) <= 0)
       {
              if (sockfd >= 0)
                     sox_close(sockfd);
              sockfd= -1;
              return;
       }

       for (i=n; writebuf+i < writebufptr; i++)
              writebuf[i-n]=writebuf[i];
       writebufptr -= n;
       writebufleft += n;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dowrite ( const char *  p,
unsigned  l 
) [static]

Definition at line 1074 of file esmtpclient.c.

{
       while (l)
       {
       int n;

              if (sockfd < 0)      return (-1);

              if (writebufleft == 0)
              {
                     doflush();
                     continue;
              }
              if (writebufleft < l)
                     n=writebufleft;
              else
                     n=l;

              memcpy(writebufptr, p, n);
              p += n;
              l -= n;
              writebufptr += n;
              writebufleft -= n;
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dowritestr ( const char *  p) [static]

Definition at line 1101 of file esmtpclient.c.

{
       return (dowrite(p, strlen(p)));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int escape_dots ( const char *  msg,
unsigned  l,
struct rw_for_esmtp ptr 
) [static]

Definition at line 2790 of file esmtpclient.c.

{
unsigned i, j;
int    rc;

       if ( (ptr->byte_counter += l) >= BUFSIZ)
              ptr->byte_counter=0;

       if (ptr->byte_counter == 0)
              sock_timeout(data_timeout);

       for (i=j=0; i<l; i++)
       {
              if (ptr->is_sol && msg[i] == '.')
              {
                     if ((rc=dowrite(msg+j, i-j)) != 0 ||
                            (rc=dowrite(".", 1)) != 0)
                            return (rc);
                     j=i;
              }
              ptr->is_sol= msg[i] == '\n' ? 1:0;
       }

       return (dowrite(msg+j, i-j));
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct rw_list* esmtp_rw_install ( const struct rw_install_info *  ) [read]

Definition at line 28 of file esmtp.c.

{
static struct rw_list esmtp_info={0, "module.esmtp - " COURIER_COPYRIGHT,
                             rw_esmtp, rw_del_esmtp, 0};

       return (&esmtp_info);
}

Here is the call graph for this function:

static const char * esmtpauth ( const char *  msg,
void *  voidp 
) [static]

Definition at line 2987 of file esmtpclient.c.

{
       if (dowritestr(msg) || dowritestr("\r\n") || writeflush())
              return (0);
       return (getresp((struct esmtpauthinfo *)voidp));
}

Here is the call graph for this function:

Here is the caller graph for this function:

void esmtpchild ( unsigned  childnum)

Definition at line 147 of file esmtpclient.c.

{
struct moduledel *del;
struct ctlfile       ctf;
unsigned long mypid=(unsigned long)getpid();

       signal(SIGPIPE, SIG_IGN);
       srand(time(NULL));
       rw_init_courier("esmtp");
       rewrite_func=rw_search_transport("esmtp")->rw_ptr->rewrite;

       if (chdir(courierdir()))
              clog_msg_errno();
       sockfd= -1;

       setconfig();

       net_timeout=0;

#ifdef TCP_CORK

       {
       const char *p=getenv("ESMTP_CORK");

              esmtp_cork=p ? atoi(p):0;
              corked=0;
       }

#endif

       /* Retrieve delivery request until courieresmtp closes the pipe */

       while ((del=module_getdel()) != 0)
       {
       fd_set fdr;
       struct timeval       tv;
       const char *p;

#if 0
              clog_msg_start_info();
              clog_msg_str("Process ");
              clog_msg_uint(getpid());
              clog_msg_str(" ready to be grabbed.");
              clog_msg_send();
              sleep(60);
#endif

              /*
              ** Open the message control file, send the message, close
              ** the control file, we're done.
              */

              if (ctlfile_openi(del->inum, &ctf, 0) == 0)
              {
                     int changed_vhosts=ctlfile_setvhost(&ctf);

                     if (changed_vhosts)
                     {
                            quit();
                            setconfig();
                     }

                     sendesmtp(del, &ctf);
                     ctlfile_close(&ctf);
              }
              {
              char   pidbuf[NUMBUFSIZE];

                     printf("%u %s\n", childnum, libmail_str_pid_t(mypid, pidbuf));
                     fflush(stdout);
              }

              /*
              ** While waiting for the next message, push a RSET every
              ** so-so seconds
              */

              while (esmtpkeepaliveping && sockfd >= 0)
              {
                     FD_ZERO(&fdr);
                     FD_SET(0, &fdr);
                     tv.tv_sec=esmtpkeepaliveping;
                     tv.tv_usec=0;

                     if ( sox_select(1, &fdr, 0, 0, &tv) > 0)
                            break;
                     sock_timeout(data_timeout);
                     if (dowritestr("RSET\r\n") || writeflush())
                            break;

                     while ( (p=readline()) != 0 && !ISFINALLINE(p))
                            ;

                     if (p == 0)
                     {
                            quit();
                            break;
                     }
              }
       }
       if (sockfd >= 0)
              quit();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int final_esmtpauth ( const char *  msg,
void *  voidp 
) [static]

Definition at line 2994 of file esmtpclient.c.

{
       if (dowritestr(msg) || dowritestr("\r\n") || writeflush())
              return (AUTHSASL_CANCELLED);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int get_sourceaddr ( int  af,
const RFC1035_ADDR *  dest_addr,
RFC1035_NETADDR *  addrbuf,
const struct sockaddr **  addrptr,
int *  addrptrlen 
) [static]

Definition at line 301 of file esmtpclient.c.

{
       int rc;
       RFC1035_ADDR in;
       const char *vhost=config_get_local_vhost();
       char vhost_ip_buf[100];
       const char *buf=getenv(
#if RFC1035_IPV6

                            !IN6_IS_ADDR_V4MAPPED(dest_addr)
                            ? "SOURCE_ADDRESS_IPV6":
#endif
                            "SOURCE_ADDRESS");

       char *source=config_localfilename(
#if RFC1035_IPV6

                                     !IN6_IS_ADDR_V4MAPPED(dest_addr)
                                     ? "ip6out":
#endif
                                     "ipout");
       FILE *fp;
       fp=fopen(source, "r");
       free(source);

       if (fp)
       {
              char *p;

              /*
              ** If ip[6]out.xxxx exists, read the IP address from it.
              */
              vhost_ip_buf[0]=0;
              if (fgets(vhost_ip_buf, sizeof(vhost_ip_buf), fp) == NULL)
                     vhost_ip_buf[0]=0;
              fclose(fp);

              p=strchr(vhost_ip_buf, '\n');
              if (p) *p=0;

              /*
              ** If the file is empty, use the vhost IP address itself.
              */
              if (vhost_ip_buf[0])
                     buf=vhost_ip_buf;
              else if (vhost && *vhost)
                     buf=vhost;
       }

       if (buf && strcmp(buf, "0")) {
              rc = rfc1035_aton(buf, &in);
              if (rc != 0)
                     return rc;
       } else
              in = RFC1035_ADDRANY;

       rc = rfc1035_mkaddress(af, addrbuf, &in, htons(0),
                     addrptr, addrptrlen);
       if (rc != 0)
              return rc;

       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static const char* getresp ( struct esmtpauthinfo x) [static]

Definition at line 2931 of file esmtpclient.c.

{
const char *p=readline();

       if (p && *p == '3')
       {
              do
              {
                     ++p;
              } while ( isdigit((int)(unsigned char)*p));

              do
              {
                     ++p;
              } while ( isspace((int)(unsigned char)*p));
              return (p);
       }
       x->error_sent=1;
       talking(x->del, x->ctf);
       sent(x->del, x->ctf, "AUTH");
       smtp_msg(x->del, x->ctf);

       if (!p)
       {
              connection_closed(x->del, x->ctf);
              return (0);
       }

       while (!ISFINALLINE(p))
       {
              reply(x->del, x->ctf, p);
              if ((p=readline()) == 0)
              {
                     connection_closed(x->del, x->ctf);
                     return (0);
              }
       }
       smtp_error(x->del, x->ctf, p, 0);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void hard_error ( struct moduledel del,
struct ctlfile ctf,
const char *  msg 
) [static]

Definition at line 734 of file esmtpclient.c.

{
       hard_error1(del, ctf, msg, -1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void hard_error1 ( struct moduledel del,
struct ctlfile ctf,
const char *  msg,
int  n 
) [static]

Definition at line 719 of file esmtpclient.c.

{
unsigned        i;

       if (n >= 0)
              ctlfile_append_reply(ctf,
                     (unsigned)atol(del->receipients[n*2]), msg,
                     COMCTLFILE_DELFAIL, 0);
       else for (i=0; i<del->nreceipients; i++)
              ctlfile_append_reply(ctf,
                     (unsigned)atol(del->receipients[i*2]), msg,
                     COMCTLFILE_DELFAIL, 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int hello ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 1142 of file esmtpclient.c.

{
       const char *p;
       RFC1035_NETADDR lsin;
       socklen_t i;

       i=sizeof(lsin);
       if (sox_getsockname(sockfd, (struct sockaddr *)&lsin, &i) ||
           rfc1035_sockaddrip(&lsin, i, &laddr))
       {
              soft_error1(del, ctf, "Cannot obtain local socket IP address.",
                         -1);
              return -1;
       }

       mybuf_init(&sockbuf, sockfd);
       writebufptr=writebuf;
       writebufleft=sizeof(writebuf);
       sock_timeout(helo_timeout);
       if ((p=readline()) == 0)    /* Wait for server first */
              return (1);

       if (*p == '5')       /* Hard error */
       {
              talking(del, ctf);
              smtp_msg(del, ctf);
              while (!ISFINALLINE(p))     /* Skip multiline replies */
              {
                     reply(del, ctf, p);
                     if ((p=readline()) == 0)
                            return (1);
                            /* Caller will report the error */
              }
              hard_error(del, ctf, p);
              return (-1);
       }

       if (*p != '1' && *p != '2' && *p != '3')  /* Soft error */
       {
              for (;;)
              {
                     if (ISFINALLINE(p))
                            break;

                     if ((p=readline()) == 0)
                     {
                            talking(del, ctf);
                            return (1);
                     }
              }
              quit();
              return (-1);  /*
                            ** Let caller handle this as a hard error,
                            ** so that it does not try the next MX.
                            */
       }

       /* Skip multiline good response. */

       while (!ISFINALLINE(p))
       {
              if ((p=readline()) == 0)
              {
                     talking(del, ctf);
                     return (1);
              }
       }

       return (hello2(del, ctf, 0));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int hello2 ( struct moduledel del,
struct ctlfile ctf,
int  using_tls 
) [static]

Definition at line 1215 of file esmtpclient.c.

{
       const  char *p;
       char   hellobuf[512];
       char buf[RFC1035_MAXNAMESIZE+128];

       haspipelining=hasdsn=has8bitmime=hasverp=hassize=hasexdata=hascourier=
       hasstarttls=hassecurity_starttls=0;
       if (authsasllist)    free(authsasllist);
       authsasllist=0;

       p=config_esmtphelo();

       /*
       ** If the remote host is "*", use reverse DNS from the local IP addr.
       */

       if (strcmp(p, "*") == 0)
       {
              struct rfc1035_res res;
              int rc;

              rfc1035_init_resolv(&res);

              p=buf;
              rc=rfc1035_ptr(&res, &laddr, buf);

              rfc1035_destroy_resolv(&res);

              if (rc != 0)
              {
                     char *q;

                     rfc1035_ntoa(&laddr, buf+1);

                     q=buf+1;

                     if (strncmp(q, "::ffff:", 7) == 0)
                            q += 7;
                     *--q='[';
                     strcat(q, "]");
                     p=q;
              }
       }

       strcpy(hellobuf, "EHLO ");
       strncat(hellobuf, p, sizeof(hellobuf)-10);
       strcat(hellobuf, "\r\n");

       if (dowritestr(hellobuf) || writeflush())
       {
              talking(del, ctf);
              return (1);
       }

       if ((p=readline()) == 0)
       {
              talking(del, ctf);
              return (1);
       }

       if (*p == '5')       /* Hard error, let's try a HELO */
       {
              while (!ISFINALLINE(p))     /* Skip multiline error */
              {
                     if ((p=readline()) == 0)
                     {
                            talking(del, ctf);
                            return (1);
                     }
              }
              hellobuf[0]='H';
              hellobuf[1]='E';

              sock_timeout(helo_timeout);
              if (dowritestr(hellobuf) || writeflush())
              {
                     talking(del, ctf);
                     return (1);
              }

              if ((p=readline()) == 0)
              {
                     talking(del, ctf);
                     return (1);
              }
       }

       if (*p != '1' && *p != '2' && *p != '3') /* Some kind of an error */
       {
              talking(del, ctf);
              sent(del, ctf, hellobuf);
              smtp_msg(del, ctf);
              while (!ISFINALLINE(p))
              {
                     reply(del, ctf, p);
                     if ((p=readline()) == 0)
                            return (1);
              }
              smtp_error(del, ctf, p, 0);
              quit();
              return (-1);  /*
                            ** Let the caller consider this a hard error,
                            ** so that it doesn't try the next MX.
                            */
       }

       /*
       ** If we're here after a HELO, just eat it up, otherwise, we want to
       ** parse available ESMTP keywords.
       */

       if (hellobuf[0] == 'H')
       {
              while (!ISFINALLINE(p))
              {
                     if ((p=readline()) == 0)
                     {
                            talking(del, ctf);
                            return (1);
                     }
              }
              return (0);
       }

       if (!ISFINALLINE(p))
       {
/*
**     Read remaining lines, parse the keywords.
*/
              do
              {
              const char *q;
              unsigned l;

                     if ((p=readline()) == 0)
                     {
                            talking(del, ctf);
                            return (1);
                     }

                     if (!isdigit((int)(unsigned char)p[0]) ||
                            !isdigit((int)(unsigned char)p[1]) ||
                            !isdigit((int)(unsigned char)p[2]) ||
                            (p[3] != ' ' && p[3] != '-'))
                     {
                            continue;
                     }
                     q=p+4;
                     for (l=0; q[l] && q[l] != ' '; l++)
                     {
                            if (l >= sizeof(hellobuf)-1)       break;
                            hellobuf[l]=toupper(q[l]);
                     }
                     hellobuf[l]=0;

                     if (strcmp(hellobuf, "PIPELINING") == 0)
                            haspipelining=1;
                     if (strcmp(hellobuf, "DSN") == 0)
                            hasdsn=1;
                     if (strcmp(hellobuf, "8BITMIME") == 0)
                            has8bitmime=1;
                     if (strcmp(hellobuf, "SIZE") == 0)
                            hassize=1;
                     if (strcmp(hellobuf, "STARTTLS") == 0 && !(smtproutes_flags & ROUTE_NOSECURITY))
                            hasstarttls=1;

                     if (strcmp(hellobuf, "AUTH") == 0
                            || strncmp(hellobuf, "AUTH=", 5) == 0)
                     {
                     const char *p=q+4;

                            if (isspace((int)(unsigned char)*p)||*p == '=')
                            {
                            char   *s;
                            unsigned      l=(authsasllist ?
                                   strlen(authsasllist)+1: 0)+strlen(p)+1;

                                   if (l > 10000)       continue;
                                                 /* Script kiddies... */
                                   ++p;
                                   s=courier_malloc(l);
                                   *s=0;
                                   if (authsasllist)
                                          strcat(strcpy(s, authsasllist),
                                                 " ");
                                   strcat(s, p);
                                   if (authsasllist)
                                          free(authsasllist);
                                   authsasllist=s;
                            }
                     }


#define       KEYWORD(x)    (strcmp(hellobuf, x) == 0)
#define KEYWORDARG(x)       (strncmp(hellobuf, x, sizeof(x)-1) == 0)

                     if (IS_EXDATA_KEYWORD)
                            hasexdata=1;

                     if (IS_VERP_KEYWORD)
                     {
                            char *p=strchr(hellobuf, '=');

                            if (p)
                            {
                                   for (++p; (p=strtok(p, ",")) != 0; p=0)
                                          if (strcasecmp(p, "Courier")
                                              == 0)
                                                 hasverp=1;
                            }
                     }

                     if (IS_COURIER_EXTENSIONS)
                            hascourier=1;

                     if (IS_SECURITY_KEYWORD)
                     {
                            char *p=strchr(hellobuf, '=');

                            if (p)
                            {
                                   for (++p; (p=strtok(p, ",")) != 0; p=0)
                                          if (strcmp(p, "STARTTLS") == 0 && !(smtproutes_flags & ROUTE_NOSECURITY))
                                                 hassecurity_starttls=1;
                            }
                     }
              } while (!ISFINALLINE(p));

              if (!hascourier) /* No courier extensions, no EXDATA or VERP */
                     hasexdata=hasverp=hassecurity_starttls=0;
       }

       if (hasstarttls)
       {
              const char *q=getenv("COURIERTLS");
              struct stat stat_buf;

              if (!q || stat(q, &stat_buf))
                     hasstarttls=0;
       }

       if ((p=want_security(ctf)) != 0)
       {
              if ( strcmp(p, "STARTTLS") == 0)
              {
                     if ((hasstarttls || using_tls) && hassecurity_starttls)
                            return (0);
              }

              talking(del, ctf);
              sent(del, ctf, "SECURITY=STARTTLS REQUESTED FOR THIS MESSAGE");
              smtp_msg(del, ctf);
              smtp_error(del, ctf,
                        "500 Unable to set minimum security level.", 0);
              quit();
              return (-1);
       }

       if (hasstarttls)
       {
              const char *p=getenv("ESMTP_USE_STARTTLS");

              if (!p || !atoi(p))
                     hasstarttls=0;
       }

       if (getenv("COURIER_ESMTP_DEBUG_NO8BITMIME"))
              has8bitmime=0;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int isloopback ( const char *  )

Definition at line 88 of file courieresmtp.c.

{
       struct rfc1035_ifconf *p;

       for (p=interfaces; p; p=p->next)
       {
              char buf[RFC1035_NTOABUFSIZE];

              rfc1035_ntoa(&p->ifaddr, buf);
              if (strcmp(buf, ip) == 0)
                     return (1);
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* logsuccessto ( ) [static]

Definition at line 2352 of file esmtpclient.c.

{
char   buf[RFC1035_NTOABUFSIZE];
char   *p;

       sockipname(buf);
       p=courier_malloc(sizeof("delivered:  []")+
              (sockfdaddrname ?
                     strlen(sockfdaddrname):0)+strlen(buf));

       strcpy(p, "delivered: ");
       if (sockfdaddrname && *sockfdaddrname)
              strcat(strcat(p, sockfdaddrname), " ");
       strcat(p, "[");
       strcat(p, buf);
       strcat(p, "]");
       return (p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* mailfrom ( struct moduledel del,
struct ctlfile ctf,
int  messagefd,
int  is8bitmsg 
) [static]

Definition at line 1937 of file esmtpclient.c.

{
char   *bodyverb="", *verpverb="", *retverb="";
char   *oenvidverb="", *sizeverb="";
const char *seclevel="";
char   *mailfromcmd;
int    n;
struct stat stat_buf;
const char *sec=want_security(ctf);

static const char seclevel_starttls[]=" SECURITY=STARTTLS";

       if (has8bitmime)     /* ESMTP 8BITMIME capability */
              bodyverb= is8bitmsg ? " BODY=8BITMIME":" BODY=7BIT";

       if (hasverp && ctlfile_searchfirst(ctf, COMCTLFILE_VERP) >= 0)
              verpverb=" VERP";    /* ESMTP VERP capability */

       /* ESMTP DSN capability */
       if (hasdsn && (n=ctlfile_searchfirst(ctf, COMCTLFILE_DSNFORMAT)) >= 0)
              retverb=strchr(ctf->lines[n]+1, 'F') ? " RET=FULL":
                     strchr(ctf->lines[n]+1, 'H') ? " RET=HDRS":"";
       if (hasdsn && (n=ctlfile_searchfirst(ctf, COMCTLFILE_ENVID)) >= 0 &&
                     ctf->lines[n][1])
       {
              oenvidverb=courier_malloc(sizeof(" ENVID=")+
                     strlen(ctf->lines[n]+1));
              strcat(strcpy(oenvidverb, " ENVID="), ctf->lines[n]+1);
       }

       /* ESMTP SIZE capability */

       if (fstat(messagefd, &stat_buf) == 0)
       {
              ctf->msgsize=stat_buf.st_size;

              if (hassize)
              {
                     off_t s=stat_buf.st_size;
                     char   buf[MAXLONGSIZE+1];

                     s= s/75 * 77+256;    /* Size estimate */
                     if (!has8bitmime && is8bitmsg)
                            s=s/70 * 100;
                     sprintf(buf, "%lu", (unsigned long)s);
                     sizeverb=courier_malloc(sizeof(" SIZE=")+strlen(buf));
                     strcat(strcpy(sizeverb, " SIZE="), buf);
              }
       }

       /* SECURITY extension */

       if (sec && strcmp(sec, "STARTTLS") == 0)
              seclevel=seclevel_starttls;

       mailfromcmd=courier_malloc(sizeof("MAIL FROM:<>\r\n")+
                               strlen(del->sender)+
                               strlen(bodyverb)+
                               strlen(verpverb)+
                               strlen(retverb)+
                               strlen(oenvidverb)+
                               strlen(sizeverb)+
                               strlen(seclevel));

       strcat(strcat(strcat(strcat(strcat(
              strcat(strcat(strcat(strcat(strcpy(
                                             mailfromcmd, "MAIL FROM:<"),
                                       del->sender),
                                 ">"),
                           bodyverb),
                     verpverb),
              retverb),
                                oenvidverb),
                          sizeverb),
                    seclevel),
              "\r\n");

       if (*oenvidverb)     free(oenvidverb);
       if (*sizeverb)              free(sizeverb);
       return (mailfromcmd);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int my_writev ( int  fd,
const struct iovec vector,
size_t  count 
) [static]

Definition at line 2262 of file esmtpclient.c.

{
char   buf[BUFSIZ];
size_t i=0;

       while (count)
       {
              if (vector->iov_len > sizeof(buf)-i)      break;

              memcpy(buf+i, vector->iov_base, vector->iov_len);
              i += vector->iov_len;
              ++vector;
              --count;
       }
       if (i)
              return (sox_write(fd, buf, i));

       return (sox_write(fd, vector->iov_base, vector->iov_len));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int parsedatareply ( struct moduledel del,
struct ctlfile ctf,
int *  rcptok,
struct iovec **  iovw,
unsigned *  niovw,
int  isfinal 
) [static]

Definition at line 2371 of file esmtpclient.c.

{
const char *p;
unsigned line_num=0;
unsigned i;

       p=readpipelinercpt(iovw, niovw);

       if (!p)       return (-1);

       if (SMTPREPLY_TYPE(p) == COMCTLFILE_DELSUCCESS)
       {
              /*
              ** DATA went through.  What we do depends on whether this is
              ** the first or the last DATA.
              */

              for (;;)
              {
                     if (isfinal && line_num < 10)
                     {
                            /* We want to record the final DATA reply in
                            ** the log.
                            */

                            for (i=0; i<del->nreceipients; i++)
                            {
                                   if (!rcptok[i])      continue;

                                   if (line_num == 0)
                                          ctlfile_append_connectioninfo(
                                                 ctf,
                                          (unsigned)atol(
                                                 del->receipients[i*2]),
                                          COMCTLFILE_DELINFO_REPLYTYPE,
                                          "smtp");

                                   ctlfile_append_connectioninfo(ctf,
                                          (unsigned)atol(
                                                 del->receipients[i*2]),
                                          COMCTLFILE_DELINFO_REPLY, p);
                            }
                            ++line_num;
                     }
                     if (ISFINALLINE(p))  break;
                     if ((p=readline()) == 0)
                            return (-1);
              }

              if (isfinal)
              {
              char   *p=logsuccessto();

                     /*
                     ** Final reply - record a success for recipients that
                     ** haven't previously failed (in RCPT TO).
                     */

                     for (i=0; i<del->nreceipients; i++)
                     {
                            if (!rcptok[i])      continue;

                            ctlfile_append_reply(ctf,
                                   (unsigned)atol(del->receipients[i*2]),
                                   p, COMCTLFILE_DELSUCCESS_NOLOG,
                                   (hasdsn ? "":" r"));
                     }
                     free(p);
              }
              else
              {
                     /* Good response to the first DATA */

                     for (i=0; i<del->nreceipients; i++)
                            if (rcptok[i]) break;

                     if (i >= del->nreceipients)
                            /* Stupid server wants message with no
                            ** receipients
                            */
                     {
                            sock_timeout(data_timeout);
                            if (dowritestr(".\r\n") || writeflush())
                                   return (-1);
                            do
                            {
                                   p=readline();
                                   if (!p)       return (-1);
                            } while (!ISFINALLINE(p));
                            return (-1);
                     }
              }
              return (0);
       }

       /* DATA error */

       if (hasexdata && isfinal && *p == '5' && p[1] == '5'  && p[2] == '8')
              return (parseexdatareply(p, del, ctf, rcptok));
              /* Special logic for EXDATA extended replies */

       /* Fail the recipients that haven't been failed already */

       for (i=0; i<del->nreceipients; i++)
       {
              if (!rcptok[i])      continue;
              ctlfile_append_connectioninfo(ctf,
                     (unsigned)atol(del->receipients[i*2]),
                     COMCTLFILE_DELINFO_SENT, "DATA");

              ctlfile_append_connectioninfo(ctf,
                     (unsigned)atol(del->receipients[i*2]),
                     COMCTLFILE_DELINFO_REPLYTYPE, "smtp");
       }

       for (;;)
       {
              if (line_num < 10)
              {
                     for (i=0; i<del->nreceipients; i++)
                     {
                            if (!rcptok[i])      continue;

                            ctlfile_append_connectioninfo(ctf,
                                   (unsigned)atol(
                                          del->receipients[i*2]),
                                   COMCTLFILE_DELINFO_REPLY, p);
                     }
                     ++line_num;
              }
              if (ISFINALLINE(p))
              {
                     for (i=0; i<del->nreceipients; i++)
                     {
                            if (!rcptok[i])      continue;

                            if (SMTPREPLY_TYPE(p) == COMCTLFILE_DELFAIL)
                                   hard_error1(del, ctf, "", i);
                            else
                                   soft_error1(del, ctf, "", i);
                            rcptok[i]=0;
                     }
                     break;
              }
              if ((p=readline()) == 0)
                     return (-1);
       }
       return (-1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int parseexdatareply ( const char *  p,
struct moduledel del,
struct ctlfile ctf,
int *  rcptok 
) [static]

Definition at line 2528 of file esmtpclient.c.

{
unsigned i;
char err_code=0;
unsigned line_num=0;

       for (i=0; i<del->nreceipients; i++)
              if (rcptok[i])       break;

       /* i is the next recipient that's getting an extended reply */

       for (;;p=readline())
       {
              if (!p)       return (-1);

              if (!isdigit((int)(unsigned char)*p) ||
                     !isdigit((int)(unsigned char)p[1]) ||
                     !isdigit((int)(unsigned char)p[2]) || !p[3])
                     continue;

              if (line_num == 0)
                     err_code=p[4];

              if (i >= del->nreceipients) /* Bad extended reply */
              {
                     if (ISFINALLINE(p))  break;
                     continue;
              }

              if (line_num == 0 &&
                     SMTPREPLY_TYPE(&err_code) != COMCTLFILE_DELSUCCESS)
              {
                     ctlfile_append_connectioninfo( ctf,
                            (unsigned)atol(del->receipients[i*2]),
                            COMCTLFILE_DELINFO_SENT, "DATA");
              }

              if (line_num == 0)
                     ctlfile_append_connectioninfo( ctf,
                            (unsigned)atol(del->receipients[i*2]),
                            COMCTLFILE_DELINFO_REPLYTYPE, "smtp");


              if (line_num < 10)
              {
                     ctlfile_append_connectioninfo(ctf,
                            (unsigned)atol(del->receipients[i*2]),
                            COMCTLFILE_DELINFO_REPLY, p+4);
                     ++line_num;
              }

              if (ISFINALLINE((p+4)))
              {
                     switch (SMTPREPLY_TYPE( &err_code))       {
                     case COMCTLFILE_DELFAIL:
                            hard_error1(del, ctf, "", i);
                            rcptok[i]=0;
                            break;
                     case COMCTLFILE_DELSUCCESS:
                            {
                            char   *p=logsuccessto();

                            ctlfile_append_reply(ctf,
                                   (unsigned)atol( del->receipients[i*2]),
                                   p, COMCTLFILE_DELSUCCESS_NOLOG,
                                   (hasdsn ? "":" r"));

                                   free(p);
                            }
                            break;
                     default:
                            soft_error1(del, ctf, "", i);
                            rcptok[i]=0;
                            break;
                     }

                     /* Find next recipient that gets an extended reply */

                     while (i < del->nreceipients &&
                            !rcptok[++i])
                            ;
                     line_num=0;
              }
              if (ISFINALLINE(p))  break;
       }

       while (i < del->nreceipients)
              if (rcptok[++i])
              {
                     hard_error1(del, ctf,
                            "Invalid 558 response from server.", i);
                     rcptok[i]=0;
              }

       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void parserfc ( int  fd,
struct rfc2045 rfcp 
) [static]

Definition at line 2647 of file esmtpclient.c.

{
char   buf[8192];
int    n;

       while ((n=sox_read(fd, buf, sizeof(buf))) > 0)
              rfc2045_parse(rfcp, buf, n);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int plain_esmtpauth ( const char *  method,
const char *  arg,
void *  voidp 
) [static]

Definition at line 3001 of file esmtpclient.c.

{
       if (arg && !*arg)
              arg="=";

       if (dowritestr("AUTH ") || dowritestr(method) ||
                     (arg && (dowritestr(" ") || dowritestr(arg))) ||
                     dowritestr("\r\n") ||
              writeflush())
              return (AUTHSASL_CANCELLED);

       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void push ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 1866 of file esmtpclient.c.

{
unsigned      i;
char   **real_receipients;
const char    *real_sender;
int    pass;
unsigned real_nreceipients;

       real_sender=del->sender;
       real_receipients=del->receipients;
       real_nreceipients=del->nreceipients;

       if (real_nreceipients == 0) return;

       /* If the sender is <> already, I don't care */

       if (hasdsn || real_sender == 0 || *real_sender == '\0')
       {
              pushdsn(del, ctf);
              return;
       }

       /*
       ** If the remote MTA does not support DSNs, and we have some
       ** receipients with NOTIFY=NEVER, what we do is set the MAIL FROM:
       ** for those recipients to <>.  We call pushdsn twice, once for
       ** receipients with NOTIFY=NEVER, and once more for ones without
       ** NOTIFY=NEVER.
       */

       del->receipients=(char **)courier_malloc(
                     sizeof(char *)*2*del->nreceipients);

       for (pass=0; pass<2; pass++)
       {
              if (pass)     del->sender="";
              del->nreceipients=0;

              for (i=0; i<real_nreceipients; i++)
              {
              const char *dsnptr=ctf->dsnreceipients[
                     atol(real_receipients[i*2])];

                     if (dsnptr && strchr(dsnptr, 'N'))
                     {
                            if (pass == 0)       continue;
                     }
                     else
                     {
                            if (pass == 1)       continue;
                     }
                     del->receipients[del->nreceipients*2]=
                            real_receipients[i*2];
                     del->receipients[del->nreceipients*2+1]=
                            real_receipients[i*2+1];
                     ++del->nreceipients;
              }
              if (del->nreceipients == 0) continue;
              pushdsn(del, ctf);
       }
       free(del->receipients);
       del->receipients=real_receipients;
       del->nreceipients=real_nreceipients;
       del->sender=real_sender;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void pushdsn ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 2671 of file esmtpclient.c.

{
unsigned i;
int    *rcptok;
int    fd;
char   *mailfroms;
struct rfc2045 *rfcp=0;
int    is8bitmsg;

       if ((fd=open(qmsgsdatname(del->inum), O_RDONLY)) < 0)
       {
              connect_error1(del, ctf, -1);
              return;
       }

       is8bitmsg=ctlfile_searchfirst(ctf, COMCTLFILE_8BIT) >= 0;
       if ((mailfroms=mailfrom(del, ctf, fd, is8bitmsg)) == 0)
       {
              sox_close(fd);
              return;
       }

       talking(del, ctf);
       sock_timeout(cmd_timeout);

       if (dowritestr(mailfroms) || writeflush())
       {
              sox_close(fd);
              free(mailfroms);
              connect_error(del, ctf);
              quit();
              return;
       }

       /*
       ** While waiting for MAIL FROM to come back, check if the message
       ** needs to be converted to quoted-printable.
       */

       if (!has8bitmime && is8bitmsg)
       {
              rfcp=rfc2045_alloc_ac();
              if (!rfcp)    clog_msg_errno();
              parserfc(fd, rfcp);

              rfc2045_ac_check(rfcp, RFC2045_RW_7BIT);
       }

       if (smtpreply(mailfroms, del, ctf, 1))    /* MAIL FROM rejected */
       {
              if (rfcp)     rfc2045_free(rfcp);
              sox_close(fd);

              free(mailfroms);
              return;
       }
       free(mailfroms);

       rcptok=courier_malloc(sizeof(int)*(del->nreceipients+1));

       if ( do_pipeline_rcpt(del, ctf, rcptok) )
       {
              if (rfcp)     rfc2045_free(rfcp);
              free(rcptok);
              sox_close(fd);
              return;
       }

       {
       struct rw_for_esmtp rfe;

              rfe.is_sol=1;
              rfe.byte_counter=0;

              cork(1);

              if ((rfcp ?
                     rw_rewrite_msg_7bit(fd, rfcp,
                            &convert_to_crlf,
                            &call_rewrite_func,
                            &rfe):
                     rw_rewrite_msg(fd,
                            &convert_to_crlf,
                            &call_rewrite_func,
                            &rfe))
                     || data_wait(del, ctf, rcptok))
                     for (i=0; i<del->nreceipients; i++)
                            if (rcptok[i])
                                   connect_error1(del, ctf, i);
              free(rcptok);
              sox_close(fd);
              cork(0);
       }
       if (rfcp)     rfc2045_free(rfcp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void quit ( ) [static]

Definition at line 1748 of file esmtpclient.c.

{
const char *p;

       if (sockfd < 0)      return;

       sock_timeout(quit_timeout);
       if (dowritestr("QUIT\r\n") || writeflush())      return;

       while ((p=readline()) != 0 && !ISFINALLINE(p))
              ;
       if (sockfd >= 0)
              sox_close(sockfd);
       sockfd= -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* rcptcmd ( struct moduledel del,
struct ctlfile ctf,
unsigned  rcptnum 
) [static]

Definition at line 2024 of file esmtpclient.c.

{
char notify[sizeof(" NOTIFY=SUCCESS,FAILURE,DELAY")];
char *orcpt="";
const char *p;
char   *q;
unsigned n=atol(del->receipients[rcptnum*2]);

       notify[0]=0;
       if ((p=ctf->dsnreceipients[n]) != 0 && *p && hasdsn)
       {
       int s=0,f=0,d=0,n=0;

              while (*p)
                     switch (*p++) {
                     case 'N':
                            n=1;
                            break;
                     case 'D':
                            d=1;
                            break;
                     case 'F':
                            f=1;
                            break;
                     case 'S':
                            s=1;
                            break;
                     }
              if (n)
                     strcpy(notify, " NOTIFY=NEVER");
              else
              {
                     p=" NOTIFY=";
                     if (s)
                     {
                            strcat(strcat(notify, p), "SUCCESS");
                            p=",";
                     }
                     if (f)
                     {
                            strcat(strcat(notify, p), "FAILURE");
                            p=",";
                     }
                     if (d)
                            strcat(strcat(notify, p), "DELAY");
              }
       }

       if ((p=ctf->oreceipients[n]) != 0 && *p && hasdsn)
       {
              orcpt=courier_malloc(sizeof(" ORCPT=")+strlen(p));
              strcat(strcpy(orcpt, " ORCPT="), p);
       }

       p=del->receipients[rcptnum*2+1];

       q=courier_malloc(sizeof("RCPT TO:<>\r\n")+strlen(p)+strlen(notify)+
              strlen(orcpt));

       strcat(strcat(strcat(strcat(strcat(strcpy(q,
              "RCPT TO:<"),
              p),
              ">"),
              notify),
              orcpt),
              "\r\n");
       if (*orcpt)   free(orcpt);
       return (q);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static const char * readline ( ) [static]

Definition at line 978 of file esmtpclient.c.

{
int    c;
char   cc;
char   *p;
unsigned cnt, i;

       socklinesize=0;
       if (sockfd < 0)      return (0);
       for (;;)
       {
              p=mybuf_ptr( &sockbuf );
              cnt=mybuf_ptrleft( &sockbuf );
              if (cnt == 0)
              {
                     if (wait_read())     return (0);

                     /* Check for unexpected shutdown */

                     if ((c=mybuf_get( &sockbuf )) < 0)
                     {
                            sox_close(sockfd);
                            sockfd= -1;
                            errno=ECONNRESET;
                            return (0);
                     }
                     p = --mybuf_ptr( &sockbuf );
                     cnt = ++mybuf_ptrleft( &sockbuf );
              }
              for (i=0; i<cnt; i++)
                     if (p[i] == '\r')
                            break;

              if (i < cnt)
              {
                     swallow(i);
                     (void)mybuf_get( &sockbuf );       /* Skip the CR */

                     for (;;)      /* Skip continuous CRs */
                     {
                            if (mybuf_ptrleft( &sockbuf ) == 0 &&
                                   wait_read())  return (0);

                            if ((c=mybuf_get( &sockbuf )) != '\r')
                                   break;
                            burp("\r", 1);
                     }

                     if (c < 0)
                     {
                            sox_close(sockfd);
                            sockfd= -1;
                            return (0);
                     }
                     if (c == '\n')       break; /* Seen CRLF */
                     cc=c;
                     burp(&cc, 1);
                     continue;
              }
              swallow(i);
       }

       socklinebuf[socklinesize]=0;
       return (socklinebuf);
}

Here is the call graph for this function:

static const char * readpipelinercpt ( struct iovec **  iovw,
unsigned *  niovw 
) [static]

Definition at line 2284 of file esmtpclient.c.

{
int    read_flag, write_flag, *writeptr;

       if (sockfd < 0)      return (0);

       if (mybuf_more(&sockbuf))
              return (readline()); /* We have the reply buffered */

       do
       {
              write_flag=0;
              writeptr= &write_flag;
              if (iovw == 0 || niovw == 0 || *niovw == 0)
                     writeptr=0;

              wait_rw(&read_flag, writeptr);

              if (write_flag)      /* We can squeeze something out now */
              {
              int    n=my_writev(sockfd, *iovw, *niovw);

                     if (n < 0)
                     {
                            sox_close(sockfd);
                            sockfd=-1;
                            return (0);
                     }

                     /* Update iovecs to reflect # bytes written */

                     while (n)
                     {
                            if (n < (*iovw)->iov_len)
                            {
                                   (*iovw)->iov_base=(caddr_t)
                                          ( (char *)(*iovw)->iov_base+n);
                                   (*iovw)->iov_len -= n;
                                   break;
                            }
                            n -= (*iovw)->iov_len;
                            ++*iovw;
                            --*niovw;
                     }
              }
       } while (!read_flag && sockfd >= 0);

       return (readline());
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void reply ( struct moduledel del,
struct ctlfile ctf,
const char *  msg 
) [static]

Definition at line 872 of file esmtpclient.c.

{
unsigned        i;

       for (i=0; i<del->nreceipients; i++)
              ctlfile_append_connectioninfo(ctf,
                     (unsigned)atol(del->receipients[i*2]),
                     COMCTLFILE_DELINFO_REPLY, msg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void report_broken_starttls ( const char *  reply) [static]

Definition at line 1487 of file esmtpclient.c.

{
       const char *cmd=getenv("TLS_ERROR_REPORT");
       const char *shell;

       char   buf[RFC1035_NTOABUFSIZE];
       pid_t p;

       if (!cmd || !*cmd)
              return;

       p=fork();

       if (p < 0)
       {
              clog_msg_start_err();
              clog_msg_str("fork() failed");
              clog_msg_send();
              return;
       }

       if (p > 0)
       {
              wait(NULL); /* Better be this child */
              return;
       }

       close(sockfd);

       p=fork();

       if (p)
              _exit(0);

       sockipname(buf);

       setenv("ERROR_HOST", sockfdaddrname ? sockfdaddrname:"", 1);
       setenv("ERROR_IP", buf, 1);
       setenv("ERROR_CODE", "STARTTLS", 1);
       setenv("ERROR_TEXT", reply, 1);

       shell=getenv("SHELL");

       if (!shell || !*shell)
              shell="/bin/sh";

       execl(shell, shell, "-c", cmd, NULL);
       _exit(1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rfc2045_error ( const char *  p)

Definition at line 126 of file esmtpclient.c.

Here is the caller graph for this function:

static int rset ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 1845 of file esmtpclient.c.

{
       sock_timeout(helo_timeout);
       return (smtpcommand("RSET\r\n", del, ctf, 0));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sendesmtp ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 390 of file esmtpclient.c.

{
       char *smtproute;
       int cn;

       if (!host)
              host=strcpy(courier_malloc(strlen(del->host)+1), del->host);

       /* Sanity check */

       if (strcmp(host, del->host))
       {
              clog_msg_start_err();
              clog_msg_str("Internal failure in courieresmtp - daemon mixup.");
              clog_msg_send();
              _exit(1);
       }

       /* If we're connected, send a RSET to make sure the socket is working */

       if (sockfd >= 0)
       {
              sock_timeout(helo_timeout);
              if (dowritestr("RSET\r\n") == 0 && writeflush() == 0)
              {
                     if (smtpreply("RSET", del, ctf, -1))
                     {
                            quit();
                            return;
                     }
              }
       }

       if (sockfd < 0 && net_timeout)
       {
       time_t t;

              time (&t);
              if (t < net_timeout)
              {
                     errno=net_error;
                     if (!errno)   errno=ENETDOWN;
                     connect_error(del, ctf);
                     return;
              }
              net_timeout=0;
       }

       if ((cn=ctlfile_searchfirst(ctf, COMCTLFILE_MSGSOURCE)) >= 0 &&
           backscatter(ctf->lines[cn]+1))
       {
              int i;

              for (i=0; i<del->nreceipients; i++)
              {
                     ctlfile_append_connectioninfo(ctf,
                                                (unsigned)
                                                atol(del->receipients
                                                    [i*2]),
                                                COMCTLFILE_DELINFO_REPLYTYPE,
                                                "smtp");

                     ctlfile_append_connectioninfo(ctf,
                                                (unsigned)
                                                atol(del->receipients
                                                    [i*2]),
                                                COMCTLFILE_DELINFO_REPLY,
                                                "250 Backscatter bounce dropped.");

                     ctlfile_append_reply(ctf,
                                        (unsigned)atol( del->receipients[i*2]),
                                        "delivered: backscatter bounce dropped",
                                        COMCTLFILE_DELSUCCESS_NOLOG,
                                        (hasdsn ? "":" r"));
              }
              return;
       }

       /*
       ** If the message wants a secured connection, and the current
       ** connection has not been secured, close it, so it can be reopened.
       */

       smtproute=smtproutes(host, &smtproutes_flags);

       if (sockfd >= 0 && want_security(ctf) && !is_secure_connection)
              quit();

       if (sockfd < 0)      /* First time, connect to a server */
       {
              struct rfc1035_mxlist *mxlist, *p, *q;
              int static_route= smtproute != NULL;
              struct rfc1035_res res;
              int rc;

              errno=0;      /* Detect network failures */

              if (auth_key)
                     free(auth_key);

              auth_key=strdup(smtproute ? smtproute:host);

              if (!auth_key)
                     clog_msg_errno();

              rfc1035_init_resolv(&res);

              rc=rfc1035_mxlist_create_x(&res,
                                      auth_key,
                                      RFC1035_MX_AFALLBACK |
                                      RFC1035_MX_IGNORESOFTERR,
                                      &mxlist);
              rfc1035_destroy_resolv(&res);

              switch (rc)   {
              case RFC1035_MX_OK:
                     break;
              case RFC1035_MX_HARDERR:
                     if (smtproute)       free(smtproute);
                     hard_error(del, ctf, "No such domain.");
                     return;
              case RFC1035_MX_BADDNS:
                     if (smtproute)       free(smtproute);
                     hard_error(del, ctf,
                            "This domain's DNS violates RFC 1035.");
                     return;
              default:
                     if (smtproute)       free(smtproute);
                     soft_error(del, ctf, "DNS lookup failed.");

                     if (errno)
                     {
                            net_error=errno;
                            time (&net_timeout);
                            net_timeout += config_time_esmtpdelay();
                     }
                     return;
              }
              if (smtproute)       free(smtproute);

              /* Check for broken MX records - BOFH */

              q=0;   /* Also see if I'm in the MX list */

              for (p=mxlist; p; p=p->next)
              {
              RFC1035_ADDR    addr;
              char    buf[RFC1035_NTOABUFSIZE];

                     if (rfc1035_sockaddrip(&p->address,
                                   sizeof(p->address), &addr))
                            continue;

                     rfc1035_ntoa(&addr, buf);
                     if (strcmp(buf, p->hostname) == 0)
                     {
                            hard_error(del, ctf,
                                   "This domain's DNS violates RFC 1035.");
                            rfc1035_mxlist_free(mxlist);
                            return;
                     }
              
                     if (!q && !static_route &&
                         (config_islocal(p->hostname, 0)
                          || isloopback(buf)))
                            q=p;
              }

              if (q && q->priority == mxlist->priority)
              {
                     hard_error(del, ctf, "configuration error: mail loops back to myself (MX problem).");
                     rfc1035_mxlist_free(mxlist);
                     return;
              }

              /* Ok, try each MX server until we get through */

              for (p=mxlist; p; p=p->next)
              {
              RFC1035_ADDR addr;
              int    port;
              int    af;
              RFC1035_NETADDR addrbuf, saddrbuf;
              const struct sockaddr *addrptr, *saddrptr;
              int    addrptrlen, saddrptrlen;

                     if (q && q->priority == p->priority)
                            break;
                     /*
                     ** We're a backup MX for this domain, ignore MXs
                     ** with same, or higher, priority than us
                     */

                     if (rfc1035_sockaddrip(&p->address,
                            sizeof(p->address), &addr) ||
                            rfc1035_sockaddrport(&p->address,
                            sizeof(p->address), &port))
                            continue;
 
                     sockfdaddr=addr;
                     if (sockfdaddrname)  free(sockfdaddrname);
                     sockfdaddrname=strcpy(
                            courier_malloc(strlen(p->hostname)+1),
                            p->hostname); /* Save this for later */

                     is_secure_connection=0;
                     if ((sockfd=rfc1035_mksocket(SOCK_STREAM, 0, &af))
                                   >= 0 &&
                         rfc1035_mkaddress(af, &addrbuf, &addr, port,
                                         &addrptr, &addrptrlen) == 0 &&
                         get_sourceaddr(af, &addr, &saddrbuf, &saddrptr,
                                      &saddrptrlen) == 0 &&
                         rfc1035_bindsource(sockfd, saddrptr,
                                          saddrptrlen) == 0 &&
                         s_connect(sockfd, addrptr, addrptrlen,
                                  connect_timeout) == 0)
                     {
                            /*
                            ** If we're connected, make sure EHLO or HELO
                            ** is cool, before blessing the connection.
                            */

                     int    rc=hello(del, ctf);

                            if (rc == 0)
                            {
                                   if (hasstarttls && starttls(del, ctf,
                                          p->hostname))
                                   {
                                          sox_close(sockfd);
                                          return;
                                   }
                                   if (authclient(del, ctf, auth_key))
                                   {
                                          sox_close(sockfd);
                                          return;
                                   }
                                   break;
                            }
                            quit();       /* We don't want to talk to him */
                            if (rc < 0)
                                   return;       /* HELO failed, perm error */
                     }
                     if (sockfd >= 0)
                            sox_close(sockfd);
                     sockfd= -1;

#if 0
                     if (p->next && p->priority == p->next->priority &&
                            strcmp(p->hostname, p->next->hostname) == 0)
                     {
                            continue; /* Another IP address for same MX */
                     }

                     /* Skip other MX records with the same priority */
                     while (p->next && p->priority == p->next->priority)
                            p=p->next;
#endif
              }

              rfc1035_mxlist_free(mxlist);
              if (sockfd < 0)      /* Couldn't find an active server */
              {
                     net_error=errno;
                     connect_error(del, ctf);
                     time (&net_timeout);
                     net_timeout += config_time_esmtpdelay();
                     return;
              }
       }
       else
       {
              if (smtproute)
                     free(smtproute);
       }

       /*
       ** Ok, we now have a connection.  We want to call push() to deliver
       ** this message, but if the VERP flag is set but the remote server
       ** does not grok VERPs, we need to do a song-n-dance routine.
       */

       if (hasverp || ctlfile_searchfirst(ctf, COMCTLFILE_VERP) < 0)
       {
              push(del, ctf);      /* ... but not this time */
              return;
       }

       /*
       ** Ok, so what we do is to call push() individually for each
       ** recipient, manually munging the return address each time, and
       ** fudging the delivery record setting it for that one recipient
       ** only.
       */

       {
       unsigned i;
       unsigned real_recip=del->nreceipients;

              del->nreceipients=1;
              for (i=0; i<real_recip; i++, del->receipients += 2)
              {
              char   *verp_sender;

                     if (i && sockfd >= 0)       /* Call RSET in between */
                     {
                            if (rset(del, ctf))
                            {
                                   quit();
                                   continue;
                            }
                     }
                     if (sockfd < 0)
                     {
                            connect_error(del, ctf);
                            continue;
                     }

                     verp_sender=verp_getsender(ctf, del->receipients[1]);

                     del->sender=verp_sender;
                     push(del, ctf);
                     free(verp_sender);
              }
       }
}

Here is the caller graph for this function:

static void sent ( struct moduledel del,
struct ctlfile ctf,
const char *  msg 
) [static]

Definition at line 884 of file esmtpclient.c.

{
unsigned        i;

       for (i=0; i<del->nreceipients; i++)
              ctlfile_append_connectioninfo(ctf,
                     (unsigned)atol(del->receipients[i*2]),
                            COMCTLFILE_DELINFO_SENT, msg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void setconfig ( ) [static]
static void smtp_error ( struct moduledel del,
struct ctlfile ctf,
const char *  msg,
int  errcode 
) [static]

Definition at line 770 of file esmtpclient.c.

{
       if (!msg)
       {
              connect_error(del, ctf);
              return;
       }

       if (errcode == 0)
              errcode= *msg;

       if (errcode == '5')
              hard_error1(del, ctf, msg, -1);
       else
              soft_error1(del, ctf, msg, -1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void smtp_msg ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 862 of file esmtpclient.c.

{
unsigned      i;

       for (i=0; i<del->nreceipients; i++)
              ctlfile_append_connectioninfo(ctf,
                     (unsigned)atol(del->receipients[i*2]),
                     COMCTLFILE_DELINFO_REPLYTYPE, "smtp");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int smtpcommand ( const char *  cmd,
struct moduledel del,
struct ctlfile ctf,
int  istalking 
) [static]

Definition at line 1830 of file esmtpclient.c.

{
       if (dowritestr(cmd) || writeflush())
       {
              if (!istalking)
                     talking(del, ctf);
              connect_error(del, ctf);
              quit();
              return (-1);
       }
       return (smtpreply(cmd, del, ctf, istalking));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int smtpreply ( const char *  cmd,
struct moduledel del,
struct ctlfile ctf,
int  istalking 
) [static]

Definition at line 1766 of file esmtpclient.c.

{
const char *p;
unsigned line_num;

       if ((p=readline()) == 0)
       {
              if (istalking < 0)   return (0);

              if (!istalking)
                     talking(del, ctf);
              connect_error(del, ctf);
              quit();
              return (-1);
       }

       line_num=0;

       switch (SMTPREPLY_TYPE(p))  {
       case COMCTLFILE_DELDEFERRED:
       case COMCTLFILE_DELFAIL:

              if (!istalking || istalking < 0)
                     talking(del, ctf);
              sent(del, ctf, cmd);
              smtp_msg(del, ctf);
              while (!ISFINALLINE(p))
              {
                     if (line_num < 10)   /* We record up to 10 lines
                                          ** of the reply in our log
                                          ** files.
                                          */
                     {
                            reply(del, ctf, p);
                            ++line_num;
                     }
                     if ((p=readline()) == 0)
                     {
                            connect_error(del, ctf);
                            quit();
                            return (-1);
                     }
              }
              smtp_error(del, ctf, p, 0);
              return (-1);
       }

       while (!ISFINALLINE(p))
       {
              if ((p=readline()) == 0)
              {
                     if (!istalking || istalking < 0)
                            talking(del, ctf);
                     connect_error(del, ctf);
                     quit();
                     return (-1);
              }
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sock_timeout ( unsigned  nsecs) [static]

Definition at line 904 of file esmtpclient.c.

{
       time(&timeout_time);
       timeout_time += nsecs;
}

Here is the caller graph for this function:

static void sockipname ( char *  buf) [static]

Definition at line 791 of file esmtpclient.c.

{
       rfc1035_ntoa( &sockfdaddr, buf);

#if    RFC1035_IPV6

       if (IN6_IS_ADDR_V4MAPPED(&sockfdaddr))
       {
       char   *p, *q;

              if ((p=strrchr(buf, ':')) != 0)
              {
                     ++p;
                     q=buf;
                     while ( (*q++ = *p++ ) )
                            ;
              }
       }
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void soft_error ( struct moduledel del,
struct ctlfile ctf,
const char *  msg 
) [static]

Definition at line 757 of file esmtpclient.c.

{
       soft_error1(del, ctf, msg, -1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void soft_error1 ( struct moduledel del,
struct ctlfile ctf,
const char *  msg,
int  n 
) [static]

Definition at line 742 of file esmtpclient.c.

{
unsigned        i;

       if (n >= 0)
              ctlfile_append_reply(ctf,
                     (unsigned)atol(del->receipients[n*2]), msg,
                     COMCTLFILE_DELDEFERRED, 0);
       else for (i=0; i<del->nreceipients; i++)
              ctlfile_append_reply(ctf,
                     (unsigned)atol(del->receipients[i*2]), msg,
                     COMCTLFILE_DELDEFERRED, 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static const char * start_esmtpauth ( const char *  method,
const char *  arg,
void *  voidp 
) [static]

Definition at line 2972 of file esmtpclient.c.

{
       if (arg && !*arg)
              arg="=";

       if (dowritestr("AUTH ") || dowritestr(method) ||
                     (arg && (dowritestr(" ") || dowritestr(arg))) ||
                     dowritestr("\r\n") ||
              writeflush())
              return (0);

       return (getresp((struct esmtpauthinfo *)voidp));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int starttls ( struct moduledel del,
struct ctlfile ctf,
const char *  hostname 
) [static]

Definition at line 1537 of file esmtpclient.c.

{
       const char *p;
       int    pipefd[2];
       int rc;
       const char *sec;
       struct couriertls_info cinfo;
       char   *verify_domain=0;
       char   localfd_buf[NUMBUFSIZE+30];
       char   remotefd_buf[NUMBUFSIZE+30];
       char   miscbuf[NUMBUFSIZE];

       static char *trustcert_buf=0;
       static char *origcert_buf=0;

       char *argvec[10];

       int restore_origcert=0;
       int n;

       const char *tls_error_handle=getenv("TLS_ERROR_HANDLE");

       if (!tls_error_handle)
              tls_error_handle="";

       if (libmail_streampipe(pipefd))
       {
              perror("libmail_streampipe");
              return (-1);
       }

       if (dowritestr("STARTTLS\r\n") || writeflush() ||
              (p=readline()) == 0)
       {
              talking(del, ctf);
              connect_error(del, ctf);
              close(pipefd[0]);
              close(pipefd[1]);

              report_broken_starttls("(none)");

              return (1);
       }

       if (*p != '1' && *p != '2' && *p != '3')
       {
              talking(del, ctf);
              sent(del, ctf, "STARTTLS");
              smtp_msg(del, ctf);
              close(pipefd[0]);
              close(pipefd[1]);

              report_broken_starttls(p);

              while (!ISFINALLINE(p))
              {
                     reply(del, ctf, p);
                     if ((p=readline()) == 0)
                            break;
              }

              if (*tls_error_handle == 'i')
                     return 0;

              smtp_error(del, ctf, p, *tls_error_handle == 's' ? '4':0);
              return (-1);
       }

       sec=want_security(ctf);

       couriertls_init(&cinfo);

       /*
       ** Make sure that our side of the pipe is closed when couriertls
       ** is execed by the child process.
       */

       fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);

       strcat(strcpy(localfd_buf, "-localfd="),
              libmail_str_size_t(pipefd[1], miscbuf));
       strcat(strcpy(remotefd_buf, "-remotefd="),
              libmail_str_size_t(sockfd, miscbuf));

       p=getenv("ESMTP_TLS_VERIFY_DOMAIN");

       if (sec != 0)
       {
              char *q, *r;

              /*
              ** Replace TLS_TRUSTCERTS with TLS_TRUSTSECURITYCERTS,
              ** until couriertls is execed.
              */

              q=getenv("TLS_TRUSTCERTS");

              r=courier_malloc(strlen(q ? q:"")+40);
              strcat(strcpy(r, "TLS_TRUSTCERTS="), q ? q:"");

              if (origcert_buf)
                     free(origcert_buf);
              origcert_buf=r;
              restore_origcert=1;

              p=getenv("TLS_TRUSTSECURITYCERTS");
              if (!p || !*p)
              {
                     static const char fail[]=
                            "500 Unable to set minimum security"
                            " level.\n";

                     talking(del, ctf);
                     sent(del, ctf, "STARTTLS");
                     smtp_msg(del, ctf);
                     smtp_error(del, ctf, fail, 0);
                     sox_close(sockfd);
                     sockfd= -1;
                     close(pipefd[0]);
                     close(pipefd[1]);
                     return (-1);
              }

              q=courier_malloc(strlen(p)+40);

              strcat(strcpy(q, "TLS_TRUSTCERTS="), p);
              putenv(q);
              p="1";

              if (trustcert_buf)
                     free(trustcert_buf);
              trustcert_buf=q;
       }

       if (p && atoi(p))
       {
              verify_domain=courier_malloc(sizeof("-verify=")
                                        +strlen(hostname));
              strcat(strcpy(verify_domain, "-verify="), hostname);
       }


       n=0;

       argvec[n++]=localfd_buf;
       argvec[n++]=remotefd_buf;
       if (verify_domain)
       {
              argvec[n++]=verify_domain;
       }
       argvec[n]=0;

       n=couriertls_start(argvec, &cinfo);

       if (restore_origcert)
              putenv(origcert_buf);
       if (verify_domain)
              free(verify_domain);

       close(sockfd);
       sockfd=pipefd[0];
       close(pipefd[1]);

       if (!n && fcntl(sockfd, F_SETFL, O_NONBLOCK))
       {
              perror("fcntl");
              n= -1;
              strcpy(cinfo.errmsg, "fcntl() failed");
       }

       if (n)
       {
              char tmperrbuf[sizeof(cinfo.errmsg)+10];

              talking(del, ctf);
              sent(del, ctf, "STARTTLS");

              smtp_msg(del, ctf);
              strcat(strcpy(tmperrbuf,
                           *tls_error_handle == 's' ? "400 ":"500 "),
                     cinfo.errmsg);
              smtp_error(del, ctf, tmperrbuf, 0);
              sox_close(sockfd);
              sockfd= -1;
              couriertls_destroy(&cinfo);
              return (-1);
       }
       couriertls_destroy(&cinfo);

       /* Reset the socket buffer structure given the new filedescriptor */

       mybuf_init(&sockbuf, sockfd);
       writebufptr=writebuf;
       writebufleft=sizeof(writebuf);

       /* Ask again for an EHLO, because the capabilities may differ now */

       rc=hello2(del, ctf, 1);

       if (rc > 0)
              connection_closed(del, ctf);       /* Make sure to log it */
       else
              is_secure_connection= sec != 0;
       return (rc);

}

Here is the call graph for this function:

Here is the caller graph for this function:

static void swallow ( unsigned  l) [static]

Definition at line 1116 of file esmtpclient.c.

{
       burp(mybuf_ptr( &sockbuf ), l);

       mybuf_ptr( &sockbuf ) += l;
       mybuf_ptrleft( &sockbuf ) -= l;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void talking ( struct moduledel del,
struct ctlfile ctf 
) [static]

Definition at line 835 of file esmtpclient.c.

{
       talking2(del, ctf, -1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void talking2 ( struct moduledel del,
struct ctlfile ctf,
int  n 
) [static]

Definition at line 812 of file esmtpclient.c.

{
char   buf[RFC1035_NTOABUFSIZE];
unsigned i;
char   *p;

       sockipname(buf);
       p=courier_malloc(strlen(sockfdaddrname)+strlen(buf)+
              sizeof(" []"));
       strcat(strcat(strcat(strcpy(p, sockfdaddrname), " ["),
              buf), "]");

       if (n >= 0)
              ctlfile_append_connectioninfo(ctf,
                     (unsigned)atol(del->receipients[n*2]),
                     COMCTLFILE_DELINFO_PEER, p);
       else for (i=0; i<del->nreceipients; i++)
              ctlfile_append_connectioninfo(ctf,
                     (unsigned)atol(del->receipients[i*2]),
                     COMCTLFILE_DELINFO_PEER, p);
       free(p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int wait_read ( ) [static]

Definition at line 957 of file esmtpclient.c.

{
int    flag;

       wait_rw(&flag, 0);
       return (flag ? 0:-1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void wait_rw ( int *  waitr,
int *  waitw 
) [static]

Definition at line 912 of file esmtpclient.c.

{
fd_set fdr, fdw;
struct timeval       tv;
time_t current_time;

       time( & current_time );
       if (waitr)    *waitr=0;
       if (waitw)    *waitw=0;

       if (current_time >= timeout_time || sockfd < 0)
       {
              errno=ETIMEDOUT;
              if (sockfd >= 0)
                     sox_close(sockfd);
              sockfd= -1;
              return;
       }

       FD_ZERO(&fdr);
       FD_ZERO(&fdw);

       if (waitr)
              FD_SET(sockbuf.fd, &fdr);

       if (waitw)
              FD_SET(sockbuf.fd, &fdw);

       tv.tv_sec= timeout_time - current_time;
       tv.tv_usec=0;

       if ( sox_select(sockbuf.fd+1, &fdr, &fdw, 0, &tv) > 0)
       {
              if (waitw && FD_ISSET(sockbuf.fd, &fdw))
                     *waitw=1;
              if (waitr && FD_ISSET(sockbuf.fd, &fdr))
                     *waitr=1;
              return;
       }

       errno=ETIMEDOUT;
       sox_close(sockfd);
       sockfd= -1;
}

Here is the caller graph for this function:

static int wait_write ( ) [static]

Definition at line 965 of file esmtpclient.c.

{
int    flag;

       wait_rw(0, &flag);
       return (flag ? 0:-1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static const char* want_security ( struct ctlfile ctf) [static]

Definition at line 282 of file esmtpclient.c.

{
       const char *sec;

       if (smtproutes_flags & ROUTE_NOSECURITY)
              return (0);

       if (smtproutes_flags & ROUTE_STARTTLS)
              return ("STARTTLS");

       sec=ctlfile_security(ctf);

       if (!sec)
              return (0);
       if (strcmp(sec, "STARTTLS") == 0)
              return (sec);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int writeflush ( ) [static]

Definition at line 1106 of file esmtpclient.c.

{
       while (writebufptr > writebuf && sockfd >= 0)
              doflush();
       if (sockfd < 0)      return (-1);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

char* auth_key = 0 [static]

Definition at line 253 of file esmtpclient.c.

char* authsasllist = 0 [static]

Definition at line 262 of file esmtpclient.c.

time_t cmd_timeout [static]

Definition at line 76 of file esmtpclient.c.

time_t connect_timeout [static]

Definition at line 75 of file esmtpclient.c.

time_t data_timeout [static]

Definition at line 79 of file esmtpclient.c.

time_t esmtpkeepaliveping [static]

Definition at line 74 of file esmtpclient.c.

int has8bitmime [static]

Definition at line 266 of file esmtpclient.c.

int hascourier [static]

Definition at line 266 of file esmtpclient.c.

int hasdsn [static]

Definition at line 266 of file esmtpclient.c.

int hasexdata [static]

Definition at line 266 of file esmtpclient.c.

int haspipelining [static]

Definition at line 266 of file esmtpclient.c.

int hassecurity_starttls [static]

Definition at line 266 of file esmtpclient.c.

int hassize [static]

Definition at line 266 of file esmtpclient.c.

int hasstarttls [static]

Definition at line 266 of file esmtpclient.c.

int hasverp [static]

Definition at line 266 of file esmtpclient.c.

time_t helo_timeout [static]

Definition at line 77 of file esmtpclient.c.

char* host [static]

Definition at line 261 of file esmtpclient.c.

int is_secure_connection = 0 [static]

Definition at line 263 of file esmtpclient.c.

RFC1035_ADDR laddr [static]

Definition at line 1138 of file esmtpclient.c.

struct mybuf [static]

Definition at line 254 of file esmtpclient.c.

int net_error [static]

Definition at line 106 of file esmtpclient.c.

time_t net_timeout [static]

Definition at line 101 of file esmtpclient.c.

time_t quit_timeout [static]

Definition at line 78 of file esmtpclient.c.

void(* rewrite_func)(struct rw_info *, void(*)(struct rw_info *)) [static]

Definition at line 124 of file esmtpclient.c.

int smtproutes_flags = 0 [static]

Definition at line 264 of file esmtpclient.c.

int sockfd [static]

Definition at line 110 of file esmtpclient.c.

RFC1035_ADDR sockfdaddr [static]

Definition at line 251 of file esmtpclient.c.

char* sockfdaddrname = 0 [static]

Definition at line 252 of file esmtpclient.c.

char socklinebuf[sizeof(sockbuf.buffer)+1] [static]

Definition at line 259 of file esmtpclient.c.

unsigned socklinesize [static]

Definition at line 260 of file esmtpclient.c.

time_t timeout_time [static]

Definition at line 258 of file esmtpclient.c.

char writebuf[BUFSIZ] [static]

Definition at line 255 of file esmtpclient.c.

unsigned writebufleft [static]

Definition at line 257 of file esmtpclient.c.

char* writebufptr [static]

Definition at line 256 of file esmtpclient.c.