]> SAFE projects GIT repository - jmp/mailleur/commitdiff
Starting to implement procedure end_to_mx
authorJean-Marc Pigeon (Delson) <jmp@safe.ca>
Sat, 14 Jun 2025 13:56:09 +0000 (09:56 -0400)
committerJean-Marc Pigeon (Delson) <jmp@safe.ca>
Sat, 14 Jun 2025 13:56:09 +0000 (09:56 -0400)
lib/lvleml.c
lib/xx.c [new file with mode: 0644]

index ff46ec72412807634d9c78ff542c2b4ee89c6110..1f960dc71eee9d7d1a304f8cb3d617274e174fc5 100644 (file)
@@ -898,7 +898,7 @@ return done;
 /*     Procedure to connect to the remote SMTP server  */
 /*                                                      */
 /********************************************************/
-static _Bool connect_to_mx(RMTTYP *rmt)
+static _Bool connect_mx(RMTTYP *rmt)
 
 {
 #define OPEP    "lvleml.c:connect_to_mx,"
@@ -976,6 +976,47 @@ return done;
 */
 /********************************************************/
 /*                                                      */
+/*     Procedure to reset the remote session           */
+/*                                                      */
+/********************************************************/
+static _Bool reset_mx(RMTTYP *rmt)
+
+{
+_Bool ok;
+int phase;
+_Bool proceed;
+
+ok=false;
+phase=0;
+proceed=true;
+while (proceed==true) {
+  switch (phase) {
+      break;
+    default     :       //SAFE Guard
+      proceed=false;
+      break;
+    }
+  phase++;
+  }
+return ok;
+}
+/*
+^L
+*/
+/********************************************************/
+/*                                                      */
+/*     Procedure to close the remote connection with MX*/
+/*                                                      */
+/********************************************************/
+static void close_mx(RMTTYP *rmt)
+
+{
+}
+/*
+^L
+*/
+/********************************************************/
+/*                                                      */
 /*     Procedure to send the data to the remote server */
 /*                                                      */
 /********************************************************/
@@ -1073,6 +1114,40 @@ while (proceed==true) {
 */
 /********************************************************/
 /*                                                      */
+/*     Procedure to send one email session to intended */
+/*      recipient.                                      */
+/*                                                      */
+/********************************************************/
+static TRATYP **send_to_mx(RMTTYP *rmt,TRATYP **list)
+
+{
+TRATYP **tosend;
+char *sessid;
+int phase;
+_Bool proceed;
+
+tosend=(TRATYP **)0;
+sessid=(char *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+  switch (phase) {
+    case 3      :       //sending data
+      (void) senddata(rmt,tosend,sessid);
+      break;
+    default     :       //SAFE Guard
+      proceed=false;
+      break;
+    }
+  phase++;
+  }
+return list;
+}
+/*
+^L
+*/
+/********************************************************/
+/*                                                      */
 /*     Procedure to send the whole email transaction   */
 /*                                                      */
 /********************************************************/
@@ -1083,7 +1158,6 @@ static void sending_email(char *orgdomain,char *dstdomain,char *sessid,TRATYP **
 
 time_t isnow;
 RMTTYP rmt;
-int tobesend;
 TRATYP **tosend;
 int phase;
 _Bool proceed;
@@ -1094,7 +1168,6 @@ rmt.mxs=dns_getmx(dstdomain);
 rmt.dstdomain=dstdomain;
 rmt.orgdomain=orgdomain;
 tosend=(TRATYP **)0;
-tobesend=0;
 phase=0;
 proceed=true;
 while (proceed==true) {
@@ -1140,7 +1213,7 @@ while (proceed==true) {
       break;
       }
     case 4      :       //Opening connection if not open
-      if (connect_to_mx(&rmt)==false) {
+      if (connect_mx(&rmt)==false) {
         char cmt[100];
 
         (void) snprintf(cmt,sizeof(cmt),"Unable to contact ANY MX for domain <%s>",
@@ -1179,47 +1252,28 @@ while (proceed==true) {
       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++;
+        dest=send_to_mx(&rmt,dest);
+        if (*dest==(TRATYP *)0)
+          break;        //no more to send;
+        if (reset_mx(&rmt)==false) {
+          break;        //can not send more
+          }  
         }
-      if (tobesend>=0)
-        (void) senddata(&rmt,tosend,sessid);
       break;
       }
+    case 7      :      //closing current connection with MX
+      (void) close_mx(&rmt);
+      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;
     }
diff --git a/lib/xx.c b/lib/xx.c
new file mode 100644 (file)
index 0000000..ff46ec7
--- /dev/null
+++ b/lib/xx.c
@@ -0,0 +1,1685 @@
+// 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';
+}
+