--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Implement all routine to manage SMTP low level */
+/* exchange. */
+/* */
+/********************************************************/
+#include <arpa/inet.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "subrou.h"
+#include "unieml.h"
+#include "devlog.h"
+#include "gestcp.h"
+#include "geseml.h"
+#include "lvleml.h"
+
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to free memory used by contact */
+/* */
+/********************************************************/
+static CONTYP *freecontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:freecontact"
+
+if (contact!=(CONTYP *)0) {
+ contact->sqlptr=sql_closesql(contact->sqlptr);
+ contact->logptr=log_closelog(contact->logptr);
+ contact->recipients=(RCPTYP **)rou_freelist((void **)contact->recipients,
+ (genfree_t)eml_freerecipient);
+ contact->mailfrom=rou_freestr(contact->mailfrom);
+ contact->cursesid=rou_freestr(contact->cursesid);
+ contact->mainsesid=rou_freestr(contact->mainsesid);
+ contact->fqdn=rou_freestr(contact->fqdn);
+ contact->peername=rou_freestr(contact->peername);
+ contact->peerip=rou_freestr(contact->peerip);
+ contact->locserv=rou_freestr(contact->locserv);
+ contact->locip=rou_freestr(contact->locip);
+ contact->locname=rou_freestr(contact->locname);
+ (void) free(contact);
+ contact=(CONTYP *)0;
+ }
+return contact;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to get the domain code */
+/* */
+/********************************************************/
+static _Bool setlocdom(CONTYP *contact,RCPTYP *rcpt)
+
+{
+#define OPEP "lvleml.c:setlocdom,"
+
+char done;
+int phase;
+_Bool proceed;
+
+done=true;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d' parm=<%s>",OPEP,phase,parameter);
+ switch (phase) {
+ case 0 : //is RCPT ok;
+ if ((rcpt==(RCPTYP *)0)||(rcpt->domain==(char *)0)) {
+ (void) rou_alert(0,"%s Recipient is NULL (Bug!?)",OPEP);
+ done=false;
+ phase=999;
+ }
+ break;
+ case 1 : //check about local domain, TEMPORARY code
+ int status;
+
+ status=dns_is_domain_local(rcpt->domain,tls_get_bind_afn());
+ switch (status) {
+ case dns_nomx :
+ done=false;
+ break;
+ case dns_local :
+ rcpt->code='L'; //domain is local
+ break;
+ case dns_remote :
+ rcpt->code='R'; //domain is remote
+ break;
+ default :
+ (void) rou_alert(0,"%s Unexpected status='%d' for domain<%s>",
+ OPEP,status,rcpt->domain);
+ break;
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to transmit a string to the remot peer*/
+/* */
+/********************************************************/
+static void transmit(CONTYP *contact,const char *fmt,...)
+
+{
+va_list args;
+char *line;
+
+va_start(args,fmt);
+line=(char *)0;
+if (rou_vasprintf(&line,fmt,args)>0) {
+ (void) log_fprintlog(contact->logptr,true,"%s",line);
+ (void) tcp_write(contact->socptr,line);
+ (void) free(line);
+ }
+va_end(args);
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send the signon once the contact */
+/* with peer is detected. */
+/* */
+/********************************************************/
+static void signon(CONTYP *contact)
+
+{
+#define FMT "%d %s, ESMTP (%s) %s-%s; %s"
+
+if (contact!=(CONTYP *)0) {
+ const char *mode;
+ char signon[100];
+
+ mode=soc_getstrmode(contact->socptr);
+ (void) snprintf(signon,sizeof(signon),FMT,
+ SIGNON,contact->locname,
+ mode,
+ appname,
+ rou_getversion(),
+ rou_ascsysstamp(time((time_t *)0)));
+ (void) transmit(contact,"%s",signon);
+ }
+#undef FMT
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send ready link information */
+/* is a correct one */
+/* */
+/********************************************************/
+static void linkready(CONTYP *contact,_Bool suite)
+
+{
+const char *mode;
+char sepa;
+
+sepa=' ';
+if (suite==true)
+ sepa='-';
+mode=soc_getstrmode(contact->socptr);
+(void) transmit(contact,"%d%c%s, link (%s) ready, your IP/FQDN=[%s/%s]",
+ CMDOK,sepa,contact->locname,mode,
+ contact->peerip,contact->peername);
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to add received information to */
+/* the email contents. */
+/* */
+/********************************************************/
+static _Bool addreceived(CONTYP *contact,FILE *data)
+
+{
+_Bool status;
+time_t curtime;
+int phase;
+_Bool proceed;
+
+status=true;
+curtime=time((time_t *)0);
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //Inserting the remote information
+ (void) fprintf(data,"Received: from %s (IP=[%s], originator=<%s>)\n",
+ contact->peername,contact->peerip,contact->mailfrom);
+ break;
+ case 1 : //Inserting the Receive information
+ (void) fprintf(data,"\tby %s ([%s:%s]/%s-%s) with ESMTP\n",
+ contact->locname,contact->locip,contact->locserv,
+ appname,rou_getversion());
+ break;
+ case 2 : //Inserting TLS information
+ if (soc_iscrypted(contact->socptr)==true) {
+ (void) fprintf(data,"\t(%s)\n",soc_getcipherid(contact->socptr));
+ }
+ break;
+ case 3 : //Inserting ID information
+ (void) fprintf(data,"\tid <%s@%s>;\n",
+ contact->cursesid,contact->locname);
+ break;
+ case 4 : //date information
+ (void) fprintf(data,"\t%s\n",rou_ascsysstamp(curtime));
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return status;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to check if helo or ehlo paratmeter */
+/* is a correct one */
+/* */
+/********************************************************/
+static _Bool isgoodfqdn(CONTYP *contact,char *parameter)
+
+{
+#define OPEP "lvleml.c:isgoodfqdn"
+
+_Bool done;
+int phase;
+_Bool proceed;
+
+done=false;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d' parm=<%s>",OPEP,phase,parameter);
+ switch (phase) {
+ case 0 : //checking if we have a parameter
+ if ((parameter==(char *)0)||(strlen(parameter)==0))
+ phase=999; //no parameter
+ break;
+ case 1 : //seems to be a good fqdn
+ contact->fqdn=rou_freestr(contact->fqdn);
+ contact->fqdn=strdup(parameter);
+ done=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to set create the sessid count*/
+/* file. This file is used to keep track */
+/* of the number of the sessionid|(rcpt) */
+/* used to send email to all recipient. */
+/* */
+/************************************************/
+static _Bool setcountfile(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:setcountfile,"
+
+_Bool status;
+int num;
+FILE *qfile;
+int phase;
+_Bool proceed;
+
+status=false;
+num=0;
+qfile=(FILE *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //is contact good
+ if (contact==(CONTYP *)0) {
+ (void) rou_alert(0,"%s contact pointer is NULL (bug?)",OPEP);
+ phase=999;
+ }
+ break;
+ case 1 : //counting recipient number
+ if ((num=rou_nbrlist((void **)contact->recipients))==0)
+ phase=999; //No recipient!
+ break;
+ case 2 : //creating the count file
+ if ((qfile=eml_createqfile(contact->cursesid,EXTCNT))==(FILE *)0) {
+ (void) rou_alert(0,"%s Unable to open 'count' qfile <%s> (error=<%s>)",
+ OPEP,contact->cursesid,strerror(errno));
+ phase=999;
+ }
+ break;
+ case 3 : //inserting number of receipient
+ if (fprintf(qfile,"%d\n",num)<1) {
+ (void) rou_alert(0,"%s Unable to set 'count' in qfile <%s> (error=<%s>)",
+ OPEP,contact->cursesid,strerror(errno));
+ (void) fclose(qfile);
+ phase=999; //trouble trouble
+ }
+ break;
+ case 4 : //closing count file
+ if (fclose(qfile)!=0) {
+ (void) rou_alert(0,"%s Unable to close qfile <%s> (error=<%s>)",
+ OPEP,contact->cursesid,strerror(errno));
+ phase=999; //trouble trouble
+ }
+ break;
+ case 5 : //everything fine
+ status=true;
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return status;
+
+
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to set RCPT directive to */
+/* forward email to SMTP peers. */
+/* */
+/************************************************/
+static _Bool setdirectives(CONTYP *contact,char *ext)
+
+{
+#define OPEP "lvleml.c:setdirectives,"
+
+_Bool status;
+FILE *trans;
+int phase;
+_Bool proceed;
+
+status=false;
+trans=(FILE *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //Creating the file
+ if ((trans=eml_createqfile(contact->cursesid,ext))==(FILE *)0)
+ phase=999; //trouble trouble
+ break;
+ case 1 : //write data to trans file;
+ if (eml_mktransfile(contact,trans)==false) {
+ (void) eml_closeqfile(trans);
+ phase=999; //Trouble trouble
+ }
+ break;
+ case 2 : //closing transfile
+ if (eml_closeqfile(trans)<0)
+ phase=999; //Trouble trouble
+ break;
+ case 3 : //everythin fine
+ status=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+#undef OPEP
+return status;
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to send a simple SMTP ccommand*/
+/* (no need to have the response wording) */
+/* */
+/************************************************/
+static int simple_smtp_command(RMTTYP *rmt,char *fmt,...)
+
+{
+va_list args;
+char strloc[300];
+
+va_start(args,fmt);
+(void) vsnprintf(strloc,sizeof(strloc),fmt,args);
+va_end(args);
+return tcp_smtp_command(rmt,(char ***)0,strloc);
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to accept EMAIL contents from */
+/* SMTP peers. */
+/* Return true, if everything is fine */
+/* */
+/************************************************/
+static _Bool getdata(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:getdata,"
+#define EXTMP "tmp"
+
+_Bool done;
+FILE *queue;
+_Bool completed;
+int total;
+TIMESPEC start;
+int phase;
+_Bool proceed;
+
+done=false;
+queue=(FILE *)0;
+completed=false;
+total=0;
+phase=0;
+proceed=setdirectives(contact,EXTMP);
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //checking if we have recipient
+ if (rou_nbrlist((void **)contact->recipients)==0) {
+ char *cmt;
+
+ cmt="RCPT first. transaction protocol command out of sequence";
+ (void) transmit(contact,"%d 5.5.0 %s",BADSEQ,cmt);
+ done=true; //lets say DATA will be issued
+ proceed=false; //No recipients
+ }
+ break;
+ case 1 : //opening the queue email
+ if ((queue=eml_createqfile(contact->cursesid,""))==(FILE *)0)
+ phase=999; //trouble trouble
+ break;
+ case 2 : //adding received stamp to file
+ if (addreceived(contact,queue)==false)
+ phase=999; //trouble trouble
+ break;
+ case 3 : //sending 'go ahead' to remote
+ (void) clock_gettime(CLOCK_REALTIME,&start);
+ (void) transmit(contact,"%d 3.5.0 %s",
+ DATAOK,"End data with <CR><LF>.<CR><LF>");
+ break;
+ case 4 : //get incoming line, detect 'single dot' as end
+ while (completed==false) {
+ int got;
+ char *line;
+
+ completed=false;
+ got=tcp_getline(contact->socptr,WAITRMT,&line);
+ if (got<0) { //data timeout
+ phase=999; //trouble trouble
+ break; //exiting loop
+ }
+ total+=got;
+ if (strcmp(line,".")==0) {
+ completed=true;
+ }
+ else {
+ if ((strlen(line)>1)&&(line[0]=='.'))
+ (void) memmove(line,line+1,strlen(line));
+ (void) fprintf(queue,"%s\n",line);
+ }
+ line=rou_freestr(line);
+ }
+ break;
+ case 5 : //got all data
+ if (eml_closeqfile(queue)<0)
+ phase=999; //Trouble trouble
+ break;
+ case 6 : //creating the count file
+ if (setcountfile(contact)==false)
+ phase=999; //Unable to create count file???
+ break;
+ case 7 : //renameing directive
+ if (eml_renameqfile(contact->cursesid,EXTMP,EXTRANS)==false)
+ phase=999; //Trouble trouble
+ break;
+ case 8 : //everything fine
+ const char *fmt;
+ unsigned int delta;
+
+ total+=1023;
+ total/=1024; //KBytes
+ delta=rou_getdifftime(&start);
+ fmt="%d 3.5.3 Message accepted for delivery (Session ID=<%s>)";
+ (void) transmit(contact,fmt,CMDOK,contact->cursesid);
+ fmt="(DATA stream received: %d Kbytes within %d.%03d seconds)";
+ (void) log_fprintlog(contact->logptr,false,fmt,total,delta/1000,delta%1000);
+ done=true;
+ proceed=false; //task done
+ break;
+ default : //SAFE guard
+ (void) transmit(contact,"%d 5.5.4 %s",
+ DATRJC,"Server does not accept mail");
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+
+#undef EXTMP
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to send an "HELO" message */
+/* if EHLO message is not accepted. */
+/* */
+/************************************************/
+static _Bool dohelo(CONTYP *contact,char *parameter)
+
+{
+#define OPEP "lvleml.c:dohelo"
+#define DETAIL "HELO argument is mandatory, closing connection"
+
+_Bool done;
+
+if ((done=isgoodfqdn(contact,parameter))==false)
+ (void) transmit(contact,"%d 5.5.4 %s.",BADPAR,DETAIL);
+else
+ (void) linkready(contact,false);
+return done;
+#undef DETAIL
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to send an "HELO" message */
+/* if EHLO message is not accepted. */
+/* */
+/************************************************/
+static _Bool doehlo(CONTYP *contact,char *parameter)
+
+{
+static char *ehlostr[]= {
+ "-STARTTLS",
+ "-8BITMIME",
+ "-ENHANCEDSTATUSCODES",
+ "-AUTH PLAIN LOGIN",
+ " HELP",
+ (char *)0
+ };
+
+#define OPEP "lvleml.c:doehlo"
+#define DETAIL "syntax error (domain part missing), closing connection"
+
+_Bool done;
+int strstart;
+int phase;
+_Bool proceed;
+
+done=false;
+strstart=0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //Do we have a parameter
+ if ((done=isgoodfqdn(contact,parameter))==false) {
+ (void) transmit(contact,"%d 5.5.4 %s.",BADPAR,DETAIL);
+ phase=999; //Trouble trouble
+ }
+ break;
+ case 1 : //thereis an FQDN
+ (void) linkready(contact,true);
+ (void) transmit(contact,"%d-SIZE %ld",CMDOK,MXMSIZE);
+ if (soc_iscrypted(contact->socptr)==true)
+ strstart++;
+ for (int i=strstart;ehlostr[i]!=(char *)0;i++) {
+ (void) transmit(contact,"%d%s",CMDOK,ehlostr[i]);
+ }
+ done=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+#undef DETAIL
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to manage a "MAIL FROM:" */
+/* ommand from the SMTP client. */
+/* */
+/************************************************/
+static _Bool checkfrom(CONTYP *contact,char *mailfrom)
+
+{
+_Bool success;
+_Bool proceed;
+int phase;
+
+success=false;
+proceed=true;
+phase=0;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //do we have an originator
+ if ((mailfrom==(char *)0)||(strlen(mailfrom)<3)) {
+ (void) transmit(contact,"%d 5.5.0 <%s> originator not specified",
+ BADPAR,mailfrom);
+ phase=999; //no need to go further
+ }
+ break;
+ case 1 : //do we have already a from
+ if (contact->mailfrom!=(char *)0) {
+ (void) transmit(contact,"%d 5.5.1 '%s' %s",
+ BADPAR,contact->mailfrom,
+ "was previously defined as originator"
+ );
+ phase=999; //no need to go further
+ }
+ break;
+ case 2 : //check from format
+ if ((mailfrom[0]!='<')||(mailfrom[strlen(mailfrom)-1]!='>')) {
+ (void) transmit(contact,"%d 5.5.2 '%s' bad Format error",
+ BADPAR,mailfrom);
+ phase=999; //no need to go further
+ }
+ mailfrom[strlen(mailfrom)-1]='\000';
+ (void) memmove(mailfrom,mailfrom+1,strlen(mailfrom));
+ break;
+ case 3 : //everything ok
+ contact->mailfrom=strdup(mailfrom);
+ (void) transmit(contact,"%d 2.1.3 %s.. sender ok",
+ CMDOK,contact->mailfrom);
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return success;
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to manage a "RCPT TO:" */
+/* command from the SMTP client. */
+/* */
+/************************************************/
+static _Bool checkto(CONTYP *contact,char *rcptto)
+
+{
+#define OPEP "lvleml.c:checkto,"
+_Bool success;
+RCPTYP *neu;
+const char *detail;
+char *report;
+_Bool proceed;
+int phase;
+
+success=false;
+neu=(RCPTYP *)0;
+detail="Address accepted";
+report=(char *)0;
+proceed=true;
+phase=0;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d' rcptto=<%s>",OPEP,phase,rcptto);
+ switch (phase) {
+ case 0 : //do we have an originator
+ if ((rcptto==(char *)0)||(strlen(rcptto)==0)) {
+ (void) transmit(contact,"%d 5.6.0 <%s> recipient not specified",
+ BADPAR,rcptto);
+ phase=999; //no need to go further
+ }
+ break;
+ case 1 : //check rcpt format
+ if ((rcptto[0]!='<')||(rcptto[strlen(rcptto)-1]!='>')) {
+ (void) transmit(contact,"%d 5.6.1 '%s' bad Format error",
+ BADPAR,rcptto);
+ phase=999; //no need to go further
+ }
+ rcptto[strlen(rcptto)-1]='\000';
+ (void) memmove(rcptto,rcptto+1,strlen(rcptto));
+ break;
+ case 2 : //checking rcptto format
+ neu=eml_isemailok(rcptto,&report);
+ if (neu==(RCPTYP *)0) {
+ (void) transmit(contact,"%d 5.6.2 %s",NOTEML,report);
+ report=rou_freestr(report);
+ phase=999; //no need to go further
+ }
+ break;
+ case 3 : //Do we have a domain MX
+ if (setlocdom(contact,neu)==false) {
+ (void) transmit(contact,"%d 5.6.3 %s (domain=%s)",
+ MISSMX,
+ "No valid MX found for recipient domain name",
+ neu->domain);
+ neu=eml_freerecipient(neu); //free recipient
+ phase=999; //no need to go further
+ }
+ break;
+ case 4 : //Storing rcpt to
+ if (eml_addrecipient(&(contact->recipients),neu)==false) {
+ detail="duplicate recipients will be consolidated";
+ neu=eml_freerecipient(neu);
+ }
+ break;
+ case 5 : //everything ok
+ (void) transmit(contact,"%d 2.6.4 %s",CMDOK,detail);
+ success=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return success;
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to reset the current session */
+/* */
+/************************************************/
+static _Bool doreset(CONTYP *contact,char *parameter)
+
+{
+#define LOCSEQ "2.1.0"
+
+(void) transmit(contact,"%d-%s flushed session %s",
+ CMDOK,LOCSEQ,contact->cursesid);
+contact->numreset++;
+contact->recipients=(RCPTYP **)rou_freelist((void **)(contact->recipients),
+ (genfree_t)eml_freerecipient);
+contact->mailfrom=rou_freestr(contact->mailfrom);
+contact->cursesid=rou_freestr(contact->cursesid);
+contact->cursesid=eml_getcursesid(contact->mainsesid,contact->numreset);
+(void) transmit(contact,"%d %s opening new session %s",
+ CMDOK,LOCSEQ,contact->cursesid);
+return true;
+
+#undef LOCSEQ
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to to send ehlo (or helo) to remote */
+/* MX server. */
+/* Return true if succesfull */
+/* */
+/********************************************************/
+static _Bool greetings_rmt(RMTTYP *rmt)
+
+{
+#define OPEP "lvleml.c:greetings_rmt,"
+
+_Bool done;
+int phase;
+_Bool proceed;
+
+done=false;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ int rspcode;
+
+ rspcode=ERRPROC;
+ switch (phase) {
+ case 0 : //Sending EHLO
+ rspcode=simple_smtp_command(rmt,"EHLO %s",rmt->orgdomain);
+ switch (rspcode) {
+ case CMDOK : //So fare, so good
+ break;
+ default : //Trouble
+ (void) rou_alert(0,"%s EHLO Remote <%s> unexpected answer code '%d'",
+ OPEP,rmt->curmx,rspcode);
+ phase++; //No STARTTLS available
+ break;
+ }
+ break;
+ case 1 : //Stating starttls
+ phase=999; //No need to go futher
+ rspcode=simple_smtp_command(rmt,"STARTTLS",rmt->orgdomain);
+ switch (rspcode) {
+ case SIGNON : //link is now encrypted
+ done=soc_starttls(rmt->socptr,false);
+ switch (done) {
+ case true :
+ (void) log_fprintlog(rmt->logptr,false,"crypted link is now set");
+ break;
+ case false :
+ (void) log_fprintlog(rmt->logptr,false,"Unable to set crypted link");
+ break;
+ }
+ phase=999; //link is now established
+ break;
+ default : //Trouble
+ (void) rou_alert(0,"%s Unable to establish crypted link with <%s>",
+ OPEP,rmt->curmx);
+ break;
+ }
+ break;
+ case 2 : //Sending HELO
+ rspcode=simple_smtp_command(rmt,"HELO %s",rmt->orgdomain);
+ switch (rspcode) {
+ case CMDOK : //So fare, so good
+ done=true;
+ phase=999;
+ break;
+ default : //Trouble
+ (void) rou_alert(0,"%s, HELO Remote <%s> unexpected answer code '%d'",
+ OPEP,rmt->curmx,rspcode);
+ break;
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to connect to the remote SMTP server */
+/* */
+/********************************************************/
+static _Bool connect_to_mx(RMTTYP *rmt)
+
+{
+#define OPEP "lvleml.c:connect_to_mx,"
+
+_Bool done;
+int phase;
+int proceed;
+
+done=false;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //do we have MX
+ if (rmt->mxs==(MXTYP **)0) {
+ (void) log_fprintlog(rmt->logptr,false,"NO MX found for domain <%s>",
+ rmt->dstdomain);
+ phase=999;
+ }
+ break;
+ case 1 : //Trying to connect
+ MXTYP **mxs;
+ const char *srcip;
+
+ mxs=rmt->mxs;
+ srcip=(const char *)0;
+ while (*mxs!=(MXTYP *)0) {
+ rmt->curmx=*mxs;
+ (void) rou_alert(0,"%s JMPDBG trying connect to <%s>",
+ OPEP,rmt->curmx->mxname);
+ rmt->socptr=soc_openfeedsock(pro_smtp,srcip,rmt->curmx->mxname,EMLPORT);
+ if (rmt->socptr!=(SOCPTR *)0) {
+ char cmt[100];
+
+ (void) snprintf(cmt,sizeof(cmt),"Now Connected to MX <%s>",
+ rmt->curmx->mxname);
+ (void) log_fprintlog(rmt->logptr,false,cmt);
+ break;
+ }
+ mxs++;
+ }
+ if (rmt->socptr==(SOCPTR *)0)
+ phase=999;
+ break;
+ case 2 : //waiting for signon
+ int res;
+
+ res=tcp_get_smtp_reply(rmt,WAITRMT,(char ***)0);
+ switch (res) {
+ case SIGNON : //everything fine
+ break;
+ default : //not getting the right signon
+ phase=999; //No need to go further
+ break;
+ }
+ break;
+ case 3 : //send greetings
+ if ((done=greetings_rmt(rmt))==false)
+ phase=999; //greeting not successful!
+ break;
+ case 4 : //send greetings
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send the data to the remote server */
+/* */
+/********************************************************/
+static void senddata(RMTTYP *rmt,TRATYP **tosend,const char *sessid)
+
+{
+#define OPEP "lvleml.c:senddata,"
+
+int rspcode;
+int sent;
+TIMESPEC start;
+int phase;
+_Bool proceed;
+
+rspcode=0;
+sent=0;
+phase=0;
+proceed=true;
+(void) clock_gettime(CLOCK_REALTIME,&start);
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //Sendig data request
+ rspcode=simple_smtp_command(rmt,"DATA");
+ switch (rspcode) {
+ case DATAOK : //data accepted
+ break;
+ default : //Unexpected return code
+ phase=999; //Not accepting data
+ break;
+ }
+ break;
+ case 1 : //sending session data
+ sent=tcp_send_smtp_data(rmt,sessid);
+ if (sent<0)
+ phase=999; //No need to wait form response code
+ break;
+ case 2 : //send the text termination
+ (void) tcp_write(rmt->socptr,".");
+ rspcode= tcp_get_smtp_reply(rmt,WAITRMT,(char ***)0);
+ break;
+ case 3 : //sending session data
+ const char *fmt;
+ unsigned int delta;
+
+ sent+=1023;
+ sent/=1024; //Sent now in KByes
+ fmt="Data stream Sent: %d Kbytes within %d.%03d seconds";
+ delta=rou_getdifftime(&start);
+ (void) log_fprintlog(rmt->logptr,false,fmt,sent,delta/1000,delta%1000);
+ switch (rspcode) {
+ case CMDOK :
+ const char *cmt;
+
+ cmt="Transmission completed successfully";
+ (void) log_fprintlog(rmt->logptr,false,cmt);
+ break;
+ case MALABRT : //Data rejected
+ break;
+ default : //Unexpected return code
+ break;
+ }
+ break;
+ case 4 : //Updating sending
+ TRATYP **dest;
+
+ dest=tosend;
+ while (*dest!=(TRATYP *)0) {
+ switch ((*dest)->sendcode) {
+ case CMDOK :
+ if (rspcode==CMDOK) {
+ (*dest)->code='C'; //Data was sent properly
+ }
+ break;
+ case UKNUSER : //NO BREAK
+ case BADPAR :
+ break;
+ default :
+ (void) rou_alert(0,"%s sessid=<%s>, Unexpected code='%d' (Bug?)",
+ OPEP,sessid,rspcode);
+ break;
+ }
+ dest++;
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send the whole email transaction */
+/* */
+/********************************************************/
+static void sending_email(char *orgdomain,char *dstdomain,char *sessid,TRATYP **tra)
+
+{
+#define OPEP "lvleml.c:sending_email,"
+
+time_t isnow;
+RMTTYP rmt;
+int tobesend;
+TRATYP **tosend;
+int phase;
+_Bool proceed;
+
+isnow=time((time_t *)0);
+(void) memset(&rmt,'\000',sizeof(rmt));
+rmt.mxs=dns_getmx(dstdomain);
+rmt.dstdomain=dstdomain;
+rmt.orgdomain=orgdomain;
+tosend=(TRATYP **)0;
+tobesend=0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //process completed?
+ if ((*tra)==(TRATYP *)0)
+ phase=999; //all scanning done
+ break;
+ case 1 : //collecting email to be sent
+ rmt.logptr=log_closelog(rmt.logptr);
+ while (*tra!=(TRATYP *)0) {
+ if (strcmp((*tra)->sessid,sessid)!=0) {
+ sessid=(*tra)->sessid;
+ break;
+ }
+ if (((*tra)->date+(*tra)->delay)<=isnow) {
+ switch ((*tra)->code) {
+ case 'R' : //remote email (MX is remote)
+ (void) eml_add_delay(isnow,*tra);
+ tosend=(TRATYP **)rou_addlist((void **)tosend,(void *)(*tra));
+ break;
+ default : //Status is not to be send
+ (void) rou_alert(0,"%s Directive is not! remote email (Bug?)",OPEP);
+ break;
+ }
+ }
+ tra++;
+ }
+ break;
+ case 2 : //Checking if we have email to be sent
+ if (tosend==(TRATYP **)0)
+ phase=-1; //lets continue to see other email
+ break;
+ case 3 : { //checking if connection is open
+ char cmt[100];
+
+ (void) snprintf(cmt,sizeof(cmt),"session-id=%s",sessid);
+ rmt.logptr=log_openlog(sessid,false,cmt);
+ if (rmt.socptr!=(SOCPTR *)0) { //reset the connection
+ phase++; //NO need to open connection
+ }
+ break;
+ }
+ case 4 : //Opening connection if not open
+ if (connect_to_mx(&rmt)==false) {
+ char cmt[100];
+
+ (void) snprintf(cmt,sizeof(cmt),"Unable to contact ANY MX for domain <%s>",
+ dstdomain);
+ (void) log_fprintlog(rmt.logptr,false,cmt);
+ if (tosend!=(TRATYP **)0) {
+ TRATYP **ptr;
+ char note[150];
+
+ (void) snprintf(note,sizeof(note),"%d %s",NOANSWR,cmt);
+ ptr=tosend;
+ while (*ptr!=(TRATYP *)0) {
+ (void) eml_freetra_resp(*ptr);
+ (*ptr)->resp=(char **)rou_addlist((void **)(*ptr)->resp,
+ (void *)strdup(note));
+ ptr++;
+ }
+ (void) free(tosend);
+ }
+ phase=999; //No need to go further
+ }
+ break;
+ case 5 : { //sending originator
+ int rspcode;
+
+ rspcode=simple_smtp_command(&rmt,"MAIL FROM: <%s>",(*tosend)->mailfrom);
+ switch (rspcode) {
+ case CMDOK : //originator accepted
+ break;
+ default : //unexpected answer
+ (void) rou_alert(0,"%s JMPDBG unexpected response code='%d'",
+ OPEP,rspcode);
+ phase+=2; //not sending data
+ break;
+ }
+ break;
+ }
+ case 6 : { //sending recipient list
+ int rspcode;
+ TRATYP **dest;
+
+ tobesend=0;
+ dest=tosend;
+ while (*dest!=(TRATYP *)0) {
+ char ***resp;
+
+ (void) eml_freetra_resp(*dest);
+ resp=&((*dest)->resp);
+ rspcode=tcp_smtp_command(&rmt,resp,"RCPT TO: <%s>",(*dest)->rcptto);
+ switch (rspcode) {
+ case CMDOK : //originator accepted
+ tobesend++;
+ (*dest)->sendcode=rspcode;
+ break;
+ case UKNUSER : //recipient is unknown
+ case NORELAY : //email no relayed
+ (*dest)->code='W'; //Need to send a Warning
+ (*dest)->sendcode=rspcode;
+ break;
+ default : //Not accepted recipient
+ (void) rou_alert(0,"%s sessid=<%s>, unknwon code='%d'",
+ OPEP,sessid,rspcode);
+ (*dest)->code='C'; //completed (Temporary JMPDBG);
+ (*dest)->sendcode=BADPAR;
+ break;
+ }
+ dest++;
+ }
+ if (tobesend>=0)
+ (void) senddata(&rmt,tosend,sessid);
+ break;
+ }
+ case 8 : //cleaning recipient list
+ (void) free(tosend);
+ tosend=(TRATYP **)0;
+ phase=0; //Lets see if we have other recipient
+ break;
+ default : //SAFE Guard
+ rmt.logptr=log_closelog(rmt.logptr);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+rmt.mxs=dns_freemxlist(rmt.mxs);
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to proceed with peer exchange */
+/* 5 return values: */
+/* 1 exiting via "quit" */
+/* 0 contact timeout */
+/* -1 signal received */
+/* -2 remote disconnected */
+/* -3 BUG! */
+/* */
+/********************************************************/
+PUBLIC int eml_docontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:eml_docontact"
+
+int status;
+int got;
+int delay;
+int penalty;
+_Bool proceed;
+
+status=1;
+got=0;
+delay=300; //5 minutes standard delay
+penalty=1;
+if (debug>1)
+ delay/=10; //30 sec in debug mode
+proceed=true;
+(void) signon(contact);
+while (proceed==true) {
+ char *line;
+ CODTYP code;
+
+ line=(char *)0;
+ got=tcp_getline(contact->socptr,delay,&line);
+ if (got<=0) { //timeout or trouble?
+ char str[100];
+
+ switch (got) {
+ case 0 : //timeout
+ (void) snprintf(str,sizeof(str),"No data from remote within %d sec",delay);
+ break;
+ case -1 : //signal received
+ (void) snprintf(str,sizeof(str),"Signal Received");
+ break;
+ case -2 : //contact lost
+ (void) snprintf(str,sizeof(str),"Lost link with remote");
+ break;
+ default :
+ (void) snprintf(str,sizeof(str),"Unexpected status='%d' (Bug?)",status);
+ status=-3;
+ break;
+ }
+ (void) log_fprintlog(contact->logptr,false,"Contact terminated; "
+ "condition=<%s>",str);
+ //(void) rou_alert(0,"%s exit status='%d'",OPEP,status);
+ break; //no need to go further
+
+ }
+ (void) log_fprintlog(contact->logptr,false,"%s",line);
+ code=eml_getcode(line);
+ switch (code) {
+ case c_data : //Peer request to transfer email corps.
+ proceed=getdata(contact);
+ break;
+ case c_helo : //HELO SMTP protocol
+ proceed=dohelo(contact,line);
+ break;
+ case c_ehlo : //EHLO SMTP protocol
+ proceed=doehlo(contact,line);
+ break;
+ case c_noop : //No Operation
+ (void) transmit(contact,"%d 2.0.0 OK, %s",
+ CMDOK,contact->mainsesid);
+ break;
+ case c_quit : //QUIT SMTP protocol
+ (void) transmit(contact,"%d 2.0.0 Bye, closing connection CNT=%s",
+ QUITOK,contact->mainsesid);
+ status=1; //every thing fine
+ proceed=false;
+ break;
+ case c_mail : //MAIL FROM: checking originator
+ (void) checkfrom(contact,line);
+ break;
+ case c_rcpt : //Doing rpt scanning
+ if (checkto(contact,line)==false) {
+ (void) sleep(penalty); //relaxing bad guys
+ penalty*=2;
+ }
+ break;
+ case c_rset : //Doing session reset
+ proceed=doreset(contact,line);
+ break;
+ case c_starttls : //EHLO start encrypted link in server mode
+ switch (soc_starttls(contact->socptr,true)) {
+ case true : //link now in TLS crypted mode
+ (void) transmit(contact,"%d Link now encrypted (cipher=<%s>)",
+ CMDOK,soc_get_cipher_name(contact->socptr));
+ break;
+ case false : //unable to establish link
+ (void) transmit(contact,"%d 5.3.3 command starttls not successful",
+ CMDBAD);
+ status=-1;
+ proceed=false;
+ break;
+ }
+ break;
+ case c_unknown : //unknown keyword
+ (void) rou_alert(0,"SMTP Command <%s> from [%s] is unknown (config?)",
+ line,contact->peerip);
+ (void) transmit(contact,"%d-5.5.1 Unrecognized command, see RFC 5321",CMDBAD);
+ (void) transmit(contact,"%d-5.5.1 https://www.rfc-editor.org",CMDBAD);
+ (void) transmit(contact,"%d 5.5.1 session %s is still running",
+ CMDBAD,contact->mainsesid);
+ break;
+ default :
+ (void) rou_alert(0,"%s Unable to find entry for code='%d' (Bug?)",OPEP,code);
+ (void) transmit(contact,"%d-5.5.1 Unrecognized command, see RFC 5321",CMDBAD);
+ (void) transmit(contact,"%d 2.0.0 Bug!, closing connection Immediatly (%s)",
+ QUITOK,contact->mainsesid);
+ status=-1; //remote is a trouble maker
+ status=-3;
+ proceed=false;
+ break;
+ }
+ line=rou_freestr(line);
+ }
+return status;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to wait for a remote client. */
+/* return all reference to the established contact.*/
+/* */
+/********************************************************/
+PUBLIC CONTYP *eml_getcontact(SOCPTR *socptr,int pos)
+
+{
+#define OPEP "lvleml.c:eml_getcontact"
+#define MXCARIN 200 //maximun number of char
+ //within carpile
+
+CONTYP *contact;
+int phase;
+_Bool proceed;
+
+contact=(CONTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase){
+ case 0 : //check for binding
+ if (socptr==(SOCPTR *)0) {
+ (void) rou_alert(0,"%s socket pointer is NULL (Bug!?)",OPEP);
+ phase=999; //not going further
+ }
+ break;
+ case 1 : //connecting to database
+ contact=(CONTYP *)calloc(1,sizeof(CONTYP));
+ contact->sqlptr=sql_opensql();
+ if (contact->sqlptr==(SQLPTR *)0) {
+ (void) rou_alert(0,"%s Unable to contact database",OPEP);
+ (void) sleep(2);//delay to avoid avalanche
+ (void) free(contact);
+ contact=(CONTYP *)0;
+ phase=999; //no contact possible.
+ }
+ break;
+ case 2 : //waiting from contact
+ if ((contact->socptr=soc_accept(socptr,pos))==(SOCPTR *)0) {
+ (void) rou_alert(3,"%s Unable to open contact",OPEP);
+ contact=freecontact(contact);
+ phase=999; //no contact
+ }
+ break;
+ case 3 : //Preparing contact
+ contact->mainsesid=eml_getmainsesid();
+ contact->cursesid=eml_getcursesid(contact->mainsesid,contact->numreset);
+ contact->locname=soc_getaddrinfo(contact->socptr,true,true);
+ contact->locip=soc_getaddrinfo(contact->socptr,true,false);
+ if (contact->locip!=(char *)0) {
+ char *ptr;
+
+ //extracting service port number
+ if ((ptr=strrchr(contact->locip,':'))!=(char *)0) {
+ *ptr='\000';
+ contact->locserv=strdup(ptr+1);
+ }
+ }
+ contact->peername=soc_getaddrinfo(contact->socptr,false,true);
+ contact->peerip=soc_getaddrinfo(contact->socptr,false,false);
+ contact->logptr=log_openlog(contact->mainsesid,true,(const char *)0);
+ (void) rou_alert(0,"Contact from peer <%s> to port <%s> started",
+ contact->peerip,contact->locserv);
+ break;
+ case 4 : //check contact validity
+ if ((contact->locname==(char *)0)||(contact->peerip==(char *)0)) {
+ (void) rou_alert(0,"%s Unable to establish contact entities",OPEP);
+ contact=freecontact(contact);
+ phase=999; //no identity
+ }
+ break;
+ case 5 : //contact is good, then sending a signon
+ (void) log_fprintlog(contact->logptr,false,"opening connection CNT=%s",
+ contact->mainsesid);
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return contact;
+#undef MXCARIN
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to wait for a remote client. */
+/* return the frreed memory contact (NULL pointer) */
+/* */
+/********************************************************/
+PUBLIC CONTYP *eml_dropcontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:eml_dropcontact"
+
+int phase;
+_Bool proceed;
+
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase){
+ case 0 : //check for binding
+ if (contact==(CONTYP *)0) {
+ (void) rou_alert(0,"%s Contact pointer is NULL (Bug!?)",OPEP);
+ phase=999; //not going further
+ }
+ break;
+ case 1 : //properly closing remote contact
+ (void) rou_alert(0,"Contact from peer <%s> to port <%s> terminated",
+ contact->peerip,contact->locserv);
+ contact->socptr=soc_release(contact->socptr);
+ //(void) kill(getppid(),SIGCHLD);
+ //(void) rou_alert(0,"%s JMPDBG signal SIGCHLD sent to='%d'",OPEP,getppid());
+ break;
+ case 2 : //freeing contact memory
+ contact=freecontact(contact);
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return contact;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to generate transfile contents */
+/* return all reference to contact. */
+/* */
+/********************************************************/
+PUBLIC _Bool eml_mktransfile(CONTYP *contact,FILE *qfile)
+
+{
+#define OPEP "lvleml.c:eml_mktrans"
+
+_Bool status;
+
+status=true;
+if ((contact!=(CONTYP *)0)&&(contact->recipients!=(RCPTYP **)0)) {
+ RCPTYP **ptr;
+ TRATYP **tralist;
+ time_t isnow;
+
+ ptr=contact->recipients;
+ tralist=(TRATYP **)0;
+ isnow=time((time_t *)0);
+ while (*ptr!=(RCPTYP *)0) {
+ TRATYP *tra;
+ char data[300];
+
+
+ (void) snprintf(data,sizeof(data),"%s@%s",(*ptr)->userid,(*ptr)->domain);
+ tra=(TRATYP *)calloc(1,sizeof(TRATYP));
+ tra->code=(*ptr)->code;
+ tra->date=isnow;
+ tra->delay=0;
+ tra->sessid=strdup(contact->cursesid);
+ tra->mailfrom=strdup(contact->mailfrom);
+ tra->rcptto=strdup(data);
+ tralist=(TRATYP **)rou_addlist((void **)tralist,(void *)tra);
+ ptr++;
+ }
+ (void) eml_dump_list_tra(qfile,tralist);
+ tralist=(TRATYP **)rou_freelist((void **)tralist,(genfree_t)eml_freetra);
+ }
+return status;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to store local email (MX local) within*/
+/* the serveur right directory. */
+/* */
+/********************************************************/
+PUBLIC void eml_local_email(TRATYP **tra)
+
+{
+#define OPEP "lvleml.c:eml_local_email,"
+
+time_t isnow;
+
+isnow=time((time_t *)0);
+while (*tra!=(TRATYP *)0) {
+ if (((*tra)->date+(*tra)->delay)>isnow)
+ continue;
+ (void) eml_add_delay(isnow,*tra);
+ switch ((*tra)->code) {
+ case 'L' : //local email (MX is local)
+ (*tra)->code='C';
+ if (eml_store_email(*tra)==false) {
+ (*tra)->code='L'; //Will try to deliver later one
+ (void) rou_alert(0,"%s Unable to deliver local email <%s> to <%s>",
+ OPEP,(*tra)->sessid,(*tra)->rcptto);
+ }
+ break;
+ default : //Unexpected local? email??
+ (void) rou_alert(0,"%s Directive is not! local email (Bug?)",OPEP);
+ (void) rou_alert(0,"%s TRA=<%cs %lu %04u %s %s %s",OPEP,
+ (*tra)->code,
+ (*tra)->date,
+ (*tra)->delay,
+ (*tra)->sessid,
+ (*tra)->mailfrom,
+ (*tra)->rcptto);
+ break;
+ }
+ tra++;
+ }
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send email to remote recipient */
+/* */
+/********************************************************/
+PUBLIC void eml_remote_email(TRATYP **tra)
+
+{
+#define OPEP "lvleml.c:eml_remote_email,"
+
+char *orgdomain;
+char *dstdomain;
+char *sessid;
+int phase;
+_Bool proceed;
+
+orgdomain=(char *)0;
+dstdomain=(char *)0;
+sessid=(char *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //Check if we have tra
+ if (tra==(TRATYP **)0) {
+ (void) rou_alert(0,"%s Transaction pointer is NULL (Bug?)",OPEP);
+ phase=999;
+ }
+ break;
+ case 1 : //set originator domain
+ if ((orgdomain=strrchr((*tra)->mailfrom,'@'))!=(char *)0)
+ orgdomain++;
+ if (orgdomain==(char *)0) {
+ (void) rou_alert(0,"%s Originator address <%s> without domain? (Bug?)",
+ OPEP,(*tra)->mailfrom);
+ phase=999;
+ }
+ break;
+ case 2 : //detecting remote domain
+ if ((dstdomain=strrchr((*tra)->rcptto,'@'))!=(char *)0)
+ dstdomain++;
+ if (dstdomain==(char *)0) {
+ (void) rou_alert(0,"%s Recipient address <%s> without domain? (Bug?)",
+ OPEP,(*tra)->rcptto);
+ phase=999;
+ }
+ break;
+ case 3 : //checking if we have a session ID
+ sessid=(*tra)->sessid;
+ if (sessid==(char *)0) {
+ (void) rou_alert(0,"%s Session ID is NULL (Bug?)",OPEP);
+ sessid="0000-0000";
+ }
+ break;
+ case 4 : //sending the whole transaction to remote server
+ (void) sending_email(orgdomain,dstdomain,sessid,tra);
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to rebounce an email which was NOT */
+/* deliverable. */
+/* */
+/********************************************************/
+PUBLIC void eml_rebounce_email(TRATYP *tra)
+
+{
+char *tmp;
+
+(void) rou_alert(0,"JMPDG rebounce");
+tmp=tra->mailfrom;
+tra->mailfrom=tra->rcptto;
+tra->mailfrom=tmp;
+tra->code='L';
+}
+