/*----------------------------------------------------------------------
    Routines used to hand off messages to local agents for sending/posting

 The two exported routines are:

    1) smtp_command()  -- used to get local transport agent to invoke
    2) post_handoff()  -- used to pass messages to local posting agent

 ----*/



/*
 * Protos for "sendmail" internal functions
 */
static char *mta_parse_post PROTO((METAENV *, BODY *, char *, char *));
static long  pine_pipe_soutr_nl PROTO((void *, char *));



/* ----------------------------------------------------------------------
   Figure out command to start local SMTP agent

  Args: errbuf   -- buffer for reporting errors (assumed non-NULL)

  Returns an alloc'd copy of the local SMTP agent invocation or NULL

  ----*/
char *
smtp_command(errbuf)
    char *errbuf;
{
#if	defined(SENDMAIL) && defined(SENDMAILFLAGS)
    char tmp[256];

    sprintf(tmp, "%s %s", SENDMAIL, SENDMAILFLAGS);
    return(cpystr(tmp));
#else
    strcpy(errbuf, "No default posting command.");
    return(NULL);
#endif
}



/*----------------------------------------------------------------------
   Hand off given message to local posting agent

  Args: envelope -- The envelope for the BCC and debugging
        header   -- The text of the message header
        errbuf   -- buffer for reporting errors (assumed non-NULL)
     
   ----*/
int
mta_handoff(header, body, errbuf)
    METAENV    *header;
    BODY       *body;
    char       *errbuf;
{
    char cmd_buf[256], *cmd = NULL;

    /*
     * A bit of complicated policy implemented here.
     * There are two posting variables sendmail-path and smtp-server.
     * Precedence is in that order.
     * They can be set one of 4 ways: fixed, command-line, user, or globally.
     * Precedence is in that order.
     * Said differently, the order goes something like what's below.
     * 
     * NOTE: the fixed/command-line/user precendence handling is also
     *	     indicated by what's pointed to by ps_global->VAR_*, but since
     *	     that also includes the global defaults, it's not sufficient.
     */

    if(ps_global->FIX_SENDMAIL_PATH
       && ps_global->FIX_SENDMAIL_PATH[0]){
	cmd = ps_global->FIX_SENDMAIL_PATH;
    }
    else if(!(ps_global->FIX_SMTP_SERVER
	      && ps_global->FIX_SMTP_SERVER[0])){
	if(ps_global->COM_SENDMAIL_PATH
	   && ps_global->COM_SENDMAIL_PATH[0]){
	    cmd = ps_global->COM_SENDMAIL_PATH;
	}
	else if(!(ps_global->COM_SMTP_SERVER
		  && ps_global->COM_SMTP_SERVER[0])){
	    if(ps_global->USR_SENDMAIL_PATH
	       && ps_global->USR_SENDMAIL_PATH[0]){
		cmd = ps_global->USR_SENDMAIL_PATH;
	    }
	    else if(!(ps_global->USR_SMTP_SERVER
		      && ps_global->USR_SMTP_SERVER[0])){
		if(ps_global->GLO_SENDMAIL_PATH
		   && ps_global->GLO_SENDMAIL_PATH[0]){
		    cmd = ps_global->GLO_SENDMAIL_PATH;
		}
#ifdef	DF_SENDMAIL_PATH
		/*
		 * This defines the default method of posting.  So,
		 * unless we're told otherwise use it...
		 */
		else if(!(ps_global->GLO_SMTP_SERVER
			  && ps_global->GLO_SMTP_SERVER[0])){
		    strcpy(cmd = cmd_buf, DF_SENDMAIL_PATH);
		}
#endif
	    }
	}
    }

    *errbuf = '\0';
    if(cmd){
	dprint(4, (debugfile, "call_mailer via cmd: %s\n", cmd));

	(void) mta_parse_post(header, body, cmd, errbuf);
	return(1);
    }
    else
      return(0);
}



/*----------------------------------------------------------------------
   Hand off given message to local posting agent

  Args: envelope -- The envelope for the BCC and debugging
        header   -- The text of the message header
        errbuf   -- buffer for reporting errors (assumed non-NULL)
     
  Fork off mailer process and pipe the message into it
  Called to post news via Inews when NNTP is unavailable
  
   ----*/
char *
post_handoff(header, body, errbuf)
    METAENV    *header;
    BODY       *body;
    char       *errbuf;
{
    char *err = NULL;
#ifdef	SENDNEWS
    char *s;

    if(s = strstr(header->env->date," (")) /* fix the date format for news */
      *s = '\0';

    if(err = mta_parse_post(header, body, SENDNEWS, errbuf))
      sprintf(err = errbuf, "News not posted: \"%s\": %s", SENDNEWS, err);

    if(s)
      *s = ' ';				/* restore the date */

#else /* !SENDNEWS */  /* this is the default case */
    sprintf(err = errbuf, "Can't post, NNTP-server must be defined!");
#endif /* !SENDNEWS */
    return(err);
}



/*----------------------------------------------------------------------
   Hand off message to local MTA; it parses recipients from 822 header

  Args: header -- struct containing header data
        body  -- struct containing message body data
	cmd -- command to use for handoff (%s says where file should go)
	errs -- pointer to buf to hold errors

   ----*/
static char *
mta_parse_post(header, body, cmd, errs)
    METAENV *header;
    BODY    *body;
    char    *cmd;
    char    *errs;
{
    char c, *p, *result = NULL;
    int  rv;
    PIPE_S *pipe;

    dprint(1, (debugfile, "=== mta_parse_post(%s) ===\n", cmd));

    /* tie off cmd */
    for(p = cmd; (c = *p) && !isspace(*p); p++)
      ;

    *p = *errs = '\0';
    rv = can_access(cmd, EXECUTE_ACCESS);
    *p = c;
    if(!rv){
	if(pipe = open_system_pipe(cmd, &result, NULL,
			PIPE_STDERR | PIPE_WRITE | PIPE_PROT | PIPE_NOSHELL)){
	    if(!pine_rfc822_output(header, body, pine_pipe_soutr_nl,
				   (TCPSTREAM *) pipe))
	      strcpy(errs, "Error posting.");

	    if(close_system_pipe(&pipe) && !*errs){
		sprintf(errs, "Posting program %s returned error", cmd);
		if(result)
		  display_output_file(result, "POSTING ERRORS", errs);
	    }
	}
	else
	  sprintf(errs, "Error running cmd: %s", cmd);

	if(result){
	    unlink(result);
	    fs_give((void **)&result);
	}
    }
    else
      sprintf(errs, "Error with \"%s\" : %s", cmd,
	      (errno > 0) ? error_description(errno) : "not executable");

    return(*errs ? errs : NULL);
}


/* 
 * pine_pipe_soutr - Replacement for tcp_soutr that writes one of our
 *		     pipes rather than a tcp stream
 */
static long
pine_pipe_soutr_nl (stream,s)
     void *stream;
     char *s;
{
    long    rv = T;
    char   *p;
    size_t  n;

    while(*s && rv){
	/* map CR LF ? */
	if(n = (p = strstr(s, "\015\012")) ? p - s : strlen(s))
	  do
	    rv = fwrite(s, n, (size_t) 1, ((PIPE_S *)stream)->ofilep);
	  while(!rv && ferror(((PIPE_S *)stream)->ofilep) && errno == EINTR);

	if(p && rv){
	    s = p + 2;
	    do					/* write UNIX EOL */
	      rv = fwrite("\n", (size_t)1, (size_t)1,
			  ((PIPE_S *)stream)->ofilep);
	    while(!rv && ferror(((PIPE_S *)stream)->ofilep)
		  && errno == EINTR);
	}
	else
	  break;
    }

    return(rv);
}
