/***************************************************************************
 *                                                                         *
 *   CSEFU.C                                                               *
 *                                                                         *
 *   Copyright (c) 1988-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Client/Server E-mail and Forums utilities and common functions.       *
 *                                                                         *
 *                                                - J. Alvrus 10/20/94     *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "gcspsrv.h"
#include "gme.h"
#include "filexfer.h"
#include "galtext.h"
#include "galmsg.h"
#include "emlfor.h"
#include "csef.h"

#define FILREV "$Revision: 21 $"

INT wrmpool,                       /* E-mail/Forums write msg pool handle  */
    csmaxcc;                       /* max # cc:s for C/S users             */

struct rqinfo *rqiptr;             /* E-mail/Forums per-request memory     */
struct wrtbuf *wrtbuf;             /* current message writing buffer       */

struct flddef globidFDA[]={        /* global ID FDA                        */
     {CVTFLD_LONG,2,fldoff(globid,sysid),NULL},
     {CVTFLD_END ,0,0                   ,NULL}
};

struct flddef newdpkFDA[]={        /* new message dynapak FDA              */
     {CVTFLD_SHORT ,2         ,fldoff(newdpk,orgfor) ,NULL     },
     {CVTFLD_LONG  ,1         ,fldoff(newdpk,msgid)  ,NULL     },
     {CVTFLD_STRUCT,1         ,fldoff(newdpk,gmid)   ,globidFDA},
     {CVTFLD_LONG  ,1         ,fldoff(newdpk,thrid)  ,NULL     },
     {CVTFLD_CHAR  ,GCMAXFNM-1,fldoff(newdpk,attname),NULL     },
     {CVTFLD_SHORT ,1         ,fldoff(newdpk,flags)  ,NULL     },
     {CVTFLD_CHAR  ,0         ,fldoff(newdpk,info)   ,NULL     },
     {CVTFLD_END   ,0         ,0                     ,NULL     }
};

struct flddef wrterrFDA[]={        /* write-message response FDA           */
     {CVTFLD_SHORT,2,fldoff(wrterr,flags),NULL},
     {CVTFLD_END  ,0,0                   ,NULL}
};

struct flddef msgdpkFDA[]={        /* read message dynapak FDA             */
     {CVTFLD_SHORT ,1         ,fldoff(msgdpk,forum)   ,NULL},
     {CVTFLD_CHAR  ,1+FORNSZ-1,fldoff(msgdpk,axes)    ,NULL},
     {CVTFLD_LONG  ,1         ,fldoff(msgdpk,msgid)   ,NULL},
     {CVTFLD_STRUCT,1         ,fldoff(msgdpk,gmid)    ,globidFDA},
     {CVTFLD_LONG  ,1         ,fldoff(msgdpk,thrid)   ,NULL},
     {CVTFLD_CHAR  ,GCMAXFNM-1,fldoff(msgdpk,attname) ,NULL},
     {CVTFLD_DOUBLE,1         ,fldoff(msgdpk,crdatim) ,NULL},
     {CVTFLD_STRUCT,1         ,fldoff(msgdpk,rplto)   ,globidFDA},
     {CVTFLD_SHORT ,2         ,fldoff(msgdpk,nrpl)    ,NULL},
     {CVTFLD_CHAR  ,0         ,fldoff(msgdpk,info)    ,NULL},
     {CVTFLD_END   ,0         ,0                      ,NULL}
};

static VOID csefcon(VOID);
static VOID csefdisc(VOID);
static GBOOL cscflchk(VOID *work,USHORT forum,LONG msgid);
static GBOOL rsvwrtb(VOID);
static VOID dowrite(GBOOL isreply);
static GBOOL txtpfn(CHAR *txt,USHORT forum);
static GBOOL pfnerr(CHAR *str,USHORT forum);
static VOID rejwrt(struct wrterr *err);
static GBOOL hdlatt(VOID);
static VOID gocpyatt(VOID);
static VOID ccpyatt(VOID);
static VOID cstrtsnd(VOID);
static VOID startsnd(VOID);
static VOID cswrtcbk(INT evt,INT rc);
static VOID csndnew(VOID);
static VOID sndnew(VOID);
static VOID csndrpl(VOID);
static VOID sndrpl(VOID);
static GBOOL ndpk2msg(struct newdpk *dpk,struct message *msg,CHAR *text,
                      CHAR *filatt);
static VOID crd4fwd(VOID);
static VOID rd4fwd(VOID);
static VOID ccsfwdit(VOID);
static VOID csfwdit(VOID);
static VOID crd4cpy(VOID);
static VOID rd4cpy(VOID);
static VOID ccscpyit(VOID);
static VOID cscpyit(VOID);
static VOID rejcfwd(LONG rc);
static CHAR *addcmt(CHAR *txt,CHAR *cmt,CHAR *buf);

VOID
inics(VOID)                        /* initialize Client/Server stuff       */
{
     UINT wrmsiz;

     ASSERT(sizeof(struct grprqi) <= GMEWRKSZ);
     dclmrq(sizeof(struct rqinfo));
     dclvda(sizeof(struct message)+TXTLEN);
     dclvda(ACPYSIZ);
     dclvda(grprlen(gmeMaxGrpFor()));
     dclvda(sizeof(struct fordef));
     csmaxcc=numopt(CSMAXCC,0,32767);
     hook_connect(csefcon);
     hook_disconnect(csefdisc);
     wrmsiz=fldoff(wrtbuf,text)+TXTLEN;
     wrmsiz=max(wrmsiz,sizeof(struct fordsk)+MAXFDV);
     wrmsiz=max(wrmsiz,grprlen(gmeMaxGrpFor()));
     wrmpool=newpool(wrmsiz,2*nterms,nterms/numopt(CHNPBUF,1,256)+1);
     inicseml();
     inicsfor();
     setcfl(cscflchk);
}

VOID
cssetup(VOID)                      /* set up stuff for C/S E-mail/Forums   */
{
     setmbk(efmb);
     rqiptr=(struct rqinfo *)mrqptr;
     efwork=rqiptr->u.work;
     qsptr=myqsptr();
}

VOID
efcurreq(                          /* set current request for E-mail/Forums*/
INT reqid)                         /*   request ID to set to               */
{
     curreq(reqid);
     cssetup();
}

static VOID
csefcon(VOID)                      /* C/S E-mail/Forums connect handler    */
{
     struct qscfg *qsc;

     qsc=myqsptr();
     if (!sameas(qsc->userid,usaptr->userid)) {
          inigmeu();
     }
}

static VOID
csefdisc(VOID)                     /* C/S E-mail/Forums disconnect handler */
{
     if (sameas(myqsptr()->userid,usaptr->userid)) {
          clsgmeu();
     }
     peruflg[usrnum]=0;
     if (usrscn[usrnum] != NULL) {
          unrscan(usrnum);
          usrscn[usrnum]=NULL;
     }
     fordisc();
}

static GBOOL                       /*   returns TRUE if a conflict         */
cscflchk(                          /* C/S conflict checker                 */
VOID *work,                        /*   work area being used to read       */
USHORT forum,                      /*   forum ID w/possible conflict       */
LONG msgid)                        /*   message ID w/possible conflict     */
{
     SHORT i,j,rqid;
     struct rqinfo *tmprqi;
     struct wrtbuf *tmpwrt;

     if (msgid == 0L) {
          for (i=0 ; i < nterms; ++i) {
               if (usroff(i)->flags&ISGCSU) {
                    for (j=0 ; j < MAXREQS; ++j) {
                         rqid=srvrqid(i,j);
                         if (ismyreq(rqid,EMLAPID) || ismyreq(rqid,FORAPID)) {
                              tmprqi=(struct rqinfo *)mrqoff(rqid);
                              if (sameto(EMLATT,tmprqi->dpknam.suffix)
                               || sameto(FORATT,tmprqi->dpknam.suffix)) {
                                   if (forintg(tmprqi->u.tag) == forum) {
                                        return(TRUE);
                                   }
                              }
                              else if (work != tmprqi->u.work) {
                                   if (sameas(tmprqi->dpknam.suffix,WRTNEW)
                                    || sameas(tmprqi->dpknam.suffix,WRTRPL)) {
                                        tmpwrt=areaptr(wrmpool,tmprqi->wrthdl);
                                        if (tmpwrt->msg.forum == forum) {
                                             return(TRUE);
                                        }
                                   }
                                   else if (gmerqopn(&tmprqi->u.work)
                                    && chkmycfl(&tmprqi->u.work,forum,msgid)) {
                                        return(TRUE);
                                   }
                              }
                         }
                    }
               }
          }
          return(FALSE);
     }
     for (i=0 ; i < nterms; ++i) {
          if (usroff(i)->flags&ISGCSU) {
               for (j=0 ; j < MAXREQS; ++j) {
                    rqid=srvrqid(i,j);
                    if (ismyreq(rqid,EMLAPID) || ismyreq(rqid,FORAPID)) {
                         tmprqi=(struct rqinfo *)mrqoff(rqid);
                         if (sameto(EMLATT,tmprqi->dpknam.suffix)
                          || sameto(FORATT,tmprqi->dpknam.suffix)) {
                              if (msgintg(tmprqi->u.tag) == msgid) {
                                   return(TRUE);
                              }
                         }
                         else if (work != tmprqi->u.work
                          && gmerqopn(&tmprqi->u.work)
                          && chkmycfl(&tmprqi->u.work,forum,msgid)) {
                              return(TRUE);
                         }
                    }
               }
          }
     }
     return(FALSE);
}

VOID
crd4att(VOID)                      /* cycled read message for att dl       */
{
     cssetup();
     rd4att();
}

VOID
rd4att(VOID)                       /* read message in prep for att dl      */
{
     CHAR tmptag[TSLENG];

     msg=(struct message *)vdatmp;
     switch (readmsgf(efwork,msg,(CHAR *)rsptmp)) {
     case GMEAGAIN:
          cycleme(crd4att);
          return;
     case GMEOK:
          rqiptr->stt=1;
          if (tagatt(efwork,msg,tmptag) == GMEOK) {
               clsgmerq(efwork);
               movmem(tmptag,rqiptr->u.tag,TSLENG);
               stlcpy((CHAR *)rsptmp,dlname(msg),GCMAXPTH);
               strcat((CHAR *)rsptmp,";");
               stlcat((CHAR *)rsptmp,msg->attname,GCMAXPTH+GCMAXFNM);
               if (!forreal() || dlstart(rqiptr->u.tag)) {
                    rsp2read(&rqiptr->dpknam,STGLEN,rsptmp,NULL);
                    return;
               }
          }
          else {
               clsgmerq(efwork);
          }
          break;
     default:
          clsgmerq(efwork);
          break;
     }
     rejectreq();
}

VOID
wrtrpl(                            /* C/S write new message handler        */
struct saunam *dpknam,             /*   dynapak name in use                */
struct newdpk *newdpk)             /*   new message dynapak                */
{
     SHORT rc,pflvl;
     struct message *tmpmsg;

     if (rsvwrtb()) {
          if (!ndpk2msg(newdpk,msg,msgtxt,filatt)) {
               peruflg[usrnum]&=~WRTIPG;
               unrarea(wrmpool,rqiptr->wrthdl);
               rsp2write(FALSE,0,NULL,NULL);
               return;
          }
          rqiptr->dpknam=*dpknam;
          inigmerq(efwork);
          if ((msg->forum != EMLID && !fidxst(msg->forum))
           || (newdpk->orgfor != EMLID && !fidxst(newdpk->orgfor))) {
               ((struct wrterr *)rsptmp)->flags=FORUM;
               ((struct wrterr *)rsptmp)->rc=GMENFND;
               rejwrt((struct wrterr *)rsptmp);
               return;
          }
          inormrd(efwork,usaptr->userid,newdpk->orgfor,newdpk->msgid);
          tmpmsg=(struct message *)vdatmp;
          rc=readmsgf(efwork,tmpmsg,(CHAR *)vdatmp+sizeof(struct message));
          ASSERT(rc != GMEAGAIN);
          if (rc == GMEOK) {
               msg->gmid=tmpmsg->gmid;
               msg->thrid=tmpmsg->thrid;
               stlcpy(msg->history,tmpmsg->history,HSTSIZ);
               if (msg->forum == EMLID) {
                    stlcpy(msg->to,tmpmsg->from,MAXADR);
               }
               else if (!sameas(tmpmsg->from,msg->to)) {
                    pflvl=getdefp(msg->forum)->pfnlvl;
                    if (pflvl == DFTPFN) {
                         pflvl=pfceil;
                    }
                    if (!haskey(syskey) && profan(msg->to) > 3-pflvl) {
                         ((struct wrterr *)rsptmp)->flags=ADDRESS;
                         ((struct wrterr *)rsptmp)->rc=PFNERR;
                         rejwrt((struct wrterr *)rsptmp);
                         return;
                    }
               }
          }
          dowrite(TRUE);
     }
}

VOID
wrtnew(                            /* C/S write new message handler        */
struct saunam *dpknam,             /*   dynapak name in use                */
struct newdpk *newdpk)             /*   new message dynapak                */
{
     if (rsvwrtb()) {
          if (!ndpk2msg(newdpk,msg,msgtxt,filatt)) {
               peruflg[usrnum]&=~WRTIPG;
               unrarea(wrmpool,rqiptr->wrthdl);
               rsp2write(FALSE,0,NULL,NULL);
               return;
          }
          rqiptr->dpknam=*dpknam;
          inigmerq(efwork);
          if (msg->forum != EMLID && !fidxst(msg->forum)) {
               ((struct wrterr *)rsptmp)->flags=FORUM;
               ((struct wrterr *)rsptmp)->rc=GMENFND;
               rejwrt((struct wrterr *)rsptmp);
               return;
          }
          dowrite(FALSE);
     }
}

static GBOOL                       /*   returns TRUE if able to reserve buf*/
rsvwrtb(VOID)                      /* reserve a write buffer               */
{
     if (peruflg[usrnum]&WRTIPG) {
          ((struct wrterr *)rsptmp)->flags=0;
          ((struct wrterr *)rsptmp)->rc=WRTBUSY;
          rsp2write(FALSE,sizeof(struct wrterr),rsptmp,wrterrFDA);
          return(FALSE);
     }
     rqiptr->wrthdl=rsvarea(wrmpool);
     if (rqiptr->wrthdl == NOHDL) {
          ((struct wrterr *)rsptmp)->flags=0;
          ((struct wrterr *)rsptmp)->rc=WRTBUSY;
          rsp2write(FALSE,sizeof(struct wrterr),rsptmp,wrterrFDA);
          return(FALSE);
     }
     rqiptr->flags|=BUFINU;
     cswrtup();
     peruflg[usrnum]|=WRTIPG;
     return(TRUE);
}

static VOID
dowrite(                           /* C/S write a message handler          */
GBOOL isreply)                     /*   is this message a reply            */
{
     if (isreply) {
          rqiptr->flags|=ISREPLY;
     }
     ((struct wrterr *)rsptmp)->rc=PFNERR;
     if (pfnerr(msg->topic,msg->forum) || txtpfn(msgtxt,msg->forum)) {
          ((struct wrterr *)rsptmp)->flags=THEMSG;
          rejwrt((struct wrterr *)rsptmp);
          return;
     }
     if ((msg->flags&FILATT) && pfnerr(msg->attname,msg->forum)) {
          ((struct wrterr *)rsptmp)->flags=(SHORT)FILATT;
          rejwrt((struct wrterr *)rsptmp);
          return;
     }
     if ((msg->flags&FILATT) && !valfnm(msg->attname)) {
          ((struct wrterr *)rsptmp)->rc=GMEERR;
          ((struct wrterr *)rsptmp)->flags=(SHORT)FILATT;
          rejwrt((struct wrterr *)rsptmp);
          return;
     }
     wrtbuf->cclist=NULL;
     if (msg->flags&CCEXP) {
          if (!alwcpy || wrtany() == VALACC
           || (csmaxcc == 0 && !(usrptr->flags&MASTER))) {
               ((struct wrterr *)rsptmp)->flags=CCOPY;
               ((struct wrterr *)rsptmp)->rc=GMEERR;
               rejwrt((struct wrterr *)rsptmp);
               return;
          }
     }
     if (msg->forum != EMLID && foracc(msg->forum) < WRAXES) {
          ((struct wrterr *)rsptmp)->flags=FORUM;
          ((struct wrterr *)rsptmp)->rc=GMEACC;
          rejwrt((struct wrterr *)rsptmp);
          return;
     }
     stlcpy(msg->from,usaptr->userid,MAXADR);
     ((struct wrterr *)rsptmp)->rc=val2gme(valadr(efwork,msg->from,msg->to,
                                                  msg->forum));
     if (((struct wrterr *)rsptmp)->rc != GMEOK) {
          ((struct wrterr *)rsptmp)->flags=ADDRESS;
          rejwrt((struct wrterr *)rsptmp);
          return;
     }
     if (msg->flags&FILATT) {
          if (*filatt != '\0') {
               rqiptr->flags|=SRVATT;
               ((struct wrterr *)rsptmp)->flags=(SHORT)FILIND;
               if (!haskey(fprlock)) {
                    ((struct wrterr *)rsptmp)->rc=GMEACC;
                    rejwrt((struct wrterr *)rsptmp);
                    return;
               }
               if (!fexist(filatt)) {
                    ((struct wrterr *)rsptmp)->rc=GMEIVA;
                    rejwrt((struct wrterr *)rsptmp);
                    return;
               }
          }
          else {
               stlcpy(filatt,ulname(msg),GCMAXPTH);
          }
          ((struct wrterr *)rsptmp)->rc=val2gme(valatt(efwork,msg->from,
                                                       msg->to,msg->forum));
          if (((struct wrterr *)rsptmp)->rc != GMEOK) {
               ((struct wrterr *)rsptmp)->flags=(SHORT)FILATT;
               rejwrt((struct wrterr *)rsptmp);
               return;
          }
     }
     if (msg->flags&RECREQ) {
          ((struct wrterr *)rsptmp)->rc=val2gme(valrrr(efwork,msg->from,
                                                       msg->to,msg->forum));
          if (((struct wrterr *)rsptmp)->rc == GMEERR) {
               msg->flags&=~RECREQ;
          }
          else if (((struct wrterr *)rsptmp)->rc != GMEOK) {
               ((struct wrterr *)rsptmp)->flags=(SHORT)PRIMSG;
               rejwrt((struct wrterr *)rsptmp);
               return;
          }
     }
     if (msg->flags&PRIMSG) {
          ((struct wrterr *)rsptmp)->rc=val2gme(valpri(efwork,msg->from,
                                                       msg->to,msg->forum));
          if (((struct wrterr *)rsptmp)->rc == GMEERR) {
               msg->flags&=~PRIMSG;
          }
          else if (((struct wrterr *)rsptmp)->rc != GMEOK) {
               ((struct wrterr *)rsptmp)->flags=(SHORT)PRIMSG;
               rejwrt((struct wrterr *)rsptmp);
               return;
          }
     }
     if (msg->flags&CCEXP) {
          rqiptr->stt=WAIT4CC;
          return;
     }
     if (hdlatt()) {
          startsnd();
     }
}

static GBOOL                       /*   returns TRUE if contains profanity */
txtpfn(                            /* check text of message for profanity  */
CHAR *txt,                         /*   message text                       */
USHORT forum)                      /*   forum to use for profanity level   */
{
     if (isfmtted(txt)) {
          if (stripfmt(txt,vdatmp,TXTLEN)) {
               txt=vdatmp;
          }
     }
     return(pfnerr(txt,forum));
}

static GBOOL
pfnerr(                            /* is string too profane?               */
CHAR *str,                         /*   string to check                    */
USHORT forum)                      /*   forum to use for profanity level   */
{
     SHORT maxpfn;

     if (haskey(syskey)) {
          return(FALSE);
     }
     if (forum == EMLID) {
          maxpfn=3-pfceil;
     }
     else {
          maxpfn=getdefp(forum)->pfnlvl;
          if (maxpfn == DFTPFN) {
               maxpfn=3-pfceil;
          }
          else {
               maxpfn=3-maxpfn;
          }
     }
     return(profan(str) > maxpfn);
}

static VOID
rejwrt(                            /* reject write request with error code */
struct wrterr *err)                /*   error structure to return          */
{
     peruflg[usrnum]&=~WRTIPG;
     unrarea(wrmpool,rqiptr->wrthdl);
     clsgmerq(efwork);
     rsp2write(FALSE,sizeof(struct wrterr),err,wrterrFDA);
}

VOID
gcclst(                            /* got cc: list for message             */
struct saunam *dpknam,             /*   dynapak name in use                */
CHAR *cclist)                      /*   ';'-deliminated list of cc:s       */
{
     SHORT ncc,tmprq,othrq;
     USHORT forum;
     CHAR *cp,*tmpadr;
     struct wrterr *err;
     struct rqinfo *tmprqi;

     ASSERT(sameto(CCLSFX,dpknam->suffix));
     tmprq=s2rq(&dpknam->suffix[sizeof(CCLSFX)-1]);
     if (tmprq >= 0) {
          othrq=srvrqid(usrnum,tmprq);
          if (ismyreq(othrq,dpknam->appid)) {
               tmprqi=(struct rqinfo *)mrqoff(othrq);
               if ((sameas(tmprqi->dpknam.suffix,WRTNEW)
                 || sameas(tmprqi->dpknam.suffix,WRTRPL))
                 && tmprqi->stt == WAIT4CC) {
                    err=(struct wrterr *)rsptmp;
                    if (*cclist != '\0') {
                         wrtbuf=areaptr(wrmpool,tmprqi->wrthdl);
                         forum=wrtbuf->msg.forum;
                         setmem(vdatmp,GMEWRKSZ,0);
                         tmpadr=vdatmp+GMEWRKSZ;
                         ncc=0;
                         cp=cclist;
                         do {
                              cp=parscc(tmpadr,cp);
                              if (ncc >= csmaxcc && !(usrptr->flags&MASTER)) {
                                   err->flags=-1;
                                   err->rc=TOOMNY;
                                   rsp2write(FALSE,sizeof(struct wrterr),err,wrterrFDA);
                                   return;
                              }
                              inigmerq(vdatmp);
                              err->rc=valadr(vdatmp,usaptr->userid,tmpadr,forum);
                              clsgmerq(vdatmp);
                              if (err->rc == VALNO || err->rc == VALACC) {
                                   err->flags=ncc;
                                   err->rc=val2gme(err->rc);
                                   rsp2write(FALSE,sizeof(struct wrterr),err,wrterrFDA);
                                   return;
                              }
                              ++ncc;
                         } while (cp != NULL);
                         cp=strdup(cclist);
                         if (cp == NULL) {
                              err->flags=-1;
                              err->rc=GMEMEM;
                              rsp2write(FALSE,sizeof(struct wrterr),err,wrterrFDA);
                              return;
                         }
                         wrtbuf->cclist=cp;
                    }
                    rsp2write(TRUE,0,NULL,NULL);
                    efcurreq(othrq);
                    cswrtup();
                    if (hdlatt()) {
                         startsnd();
                    }
                    return;
               }
          }
     }
     rsp2write(FALSE,0,NULL,NULL);
}

VOID
uplatt(                            /* upload an attachment to a new msg    */
struct saunam *dpknam,             /*   dynapak name in use                */
struct filinf *finfo)              /*   file dynapak info structure        */
{
     SHORT tmprq;
     struct rqinfo *tmprqi;

     ASSERT(sameto(UPLATT,dpknam->suffix));
     tmprq=s2rq(&dpknam->suffix[sizeof(UPLATT)-1]);
     if (tmprq >= 0) {
          rqiptr->u.uplinf.othrqid=srvrqid(usrnum,tmprq);
          if (ismyreq(rqiptr->u.uplinf.othrqid,dpknam->appid)) {
               tmprqi=(struct rqinfo *)mrqoff(rqiptr->u.uplinf.othrqid);
               if (sameas(tmprqi->dpknam.suffix,WRTNEW)
             || sameas(tmprqi->dpknam.suffix,WRTRPL)) {
                    if (tmprqi->stt == WAIT4ATT) {
                         rqiptr->dpknam=*dpknam;
                         rqiptr->u.uplinf.date=finfo->date;
                         rqiptr->u.uplinf.time=finfo->time;
                         wrtbuf=areaptr(wrmpool,tmprqi->wrthdl);
                         stlcpy(rqiptr->u.uplinf.attpath,wrtbuf->filatt,
                                GCMAXPTH);
                         tmprqi->stt=UPINGATT;
                ok2write(wrtbuf->filatt);
                         return;
                    }
               }
          }
     }
     rsp2write(FALSE,0,NULL,NULL);
}

VOID
uladone(VOID)                      /* done uploading attachment to message */
{
     struct rqinfo *tmprqi;

     if (ismyreq(rqiptr->u.uplinf.othrqid,rqiptr->dpknam.appid)) {
          tmprqi=(struct rqinfo *)mrqoff(rqiptr->u.uplinf.othrqid);
          if (tmprqi->stt == UPINGATT) {
               setFileTm(rqiptr->u.uplinf.attpath,rqiptr->u.uplinf.time,
                      rqiptr->u.uplinf.date);
               rsp2write(TRUE,0,NULL,NULL);
               efcurreq(rqiptr->u.uplinf.othrqid);
               cswrtup();
               startsnd();
               return;
          }
     }
     unlink(rqiptr->u.uplinf.attpath);
     rsp2write(FALSE,0,NULL,NULL);
}

VOID
uplabt(VOID)                       /* attachment upload aborted            */
{
     struct rqinfo *tmprqi;

     unlink(rqiptr->u.uplinf.attpath);
     if (ismyreq(rqiptr->u.uplinf.othrqid,rqiptr->dpknam.appid)) {
          tmprqi=(struct rqinfo *)mrqoff(rqiptr->u.uplinf.othrqid);
          if (tmprqi->stt == UPINGATT) {
               tmprqi->stt=WAIT4ATT;
          }
     }
}

static GBOOL                       /*   returns TRUE if OK to start sending*/
hdlatt(VOID)                       /* handle attachment for C/S write      */
{
     if (msg->flags&FILATT) {
          if (rqiptr->flags&SRVATT) {
               if (!(msg->flags&FILIND)) {
                    gocpyatt();
                    return(FALSE);
               }
          }
          else {
               rqiptr->stt=WAIT4ATT;
               return(FALSE);
          }
     }
     return(TRUE);
}

static VOID
gocpyatt(VOID)                     /* begin copying attachment             */
{
     rqiptr->stt=CPYNGATT;
     ((struct wrterr *)rsptmp)->rc=GMENOAT;
     ((struct wrterr *)rsptmp)->flags=(int)FILIND;
     if ((rqiptr->ifp=fopen(filatt,FOPRB)) == NULL) {
          rejwrt((struct wrterr *)rsptmp);
          return;
     }
     stlcpy(filatt,ulname(msg),GCMAXPTH);
     if ((rqiptr->ofp=fopen(filatt,FOPWB)) == NULL) {
          fclose(rqiptr->ifp);
          rejwrt((struct wrterr *)rsptmp);
          return;
     }
     cycleme(ccpyatt);
}

static VOID
ccpyatt(VOID)                      /* cycled attachment copy process       */
{
     INT siz;
     ULONG numtck,begtck;

     cssetup();
     numtck=iotck();
     begtck=hrtval();
     do {
          if ((siz=(INT)fread(vdatmp,1,ACPYSIZ,rqiptr->ifp)) > 0) {
               fwrite(vdatmp,1,siz,rqiptr->ofp);
          }
     } while (siz == ACPYSIZ && hrtval()-begtck < numtck);
     if (ferror(rqiptr->ofp) || ferror(rqiptr->ifp)) {
          fclose(rqiptr->ifp);
          fclose(rqiptr->ofp);
          cswrtup();
          unlink(filatt);
          ((struct wrterr *)rsptmp)->rc=GMENOAT;
          ((struct wrterr *)rsptmp)->flags=(INT)FILIND;
          rejwrt((struct wrterr *)rsptmp);
     }
     if (feof(rqiptr->ifp)) {
          fclose(rqiptr->ifp);
          rqiptr->ifp=NULL;
          fclose(rqiptr->ofp);
          rqiptr->ofp=NULL;
          cstrtsnd();
     }
}

static VOID
cstrtsnd(VOID)                     /* start sending after doing a cycle    */
{
     cssetup();
     cswrtup();
     startsnd();
}

VOID
wrtabt(VOID)                       /* message write request aborted        */
{
     cswrtup();
     clsgmerq(efwork);
     if (wrtbuf->cclist != NULL) {
          free(wrtbuf->cclist);
     }
     switch (rqiptr->stt) {
     case CPYNGATT:
          fclose(rqiptr->ifp);
          fclose(rqiptr->ofp);
     case SENDING:
          unlink(filatt);
     }
     unrarea(wrmpool,rqiptr->wrthdl);
     peruflg[usrnum]&=~WRTIPG;
}

VOID
cswrtup(VOID)                      /* set global ptrs to current write buf */
{
     ASSERT(rqiptr->wrthdl != NOHDL);
     wrtbuf=areaptr(wrmpool,rqiptr->wrthdl);
     msg=&wrtbuf->msg;
     msgtxt=wrtbuf->text;
     filatt=wrtbuf->filatt;
}

static VOID
startsnd(VOID)                     /* start sending message                */
{
     setgmecb(efwork,cswrtcbk);
     rqiptr->stt=SENDING;
     wrtbuf->primsg=0L;
     if (rqiptr->flags&ISREPLY) {
          sndrpl();
     }
     else {
          sndnew();
     }
}

static VOID
cswrtcbk(                          /* write message callback for C/S       */
INT evt,                         /*   current event                      */
INT rc)                          /*   result of last write operation     */
{
     switch (evt) {
     case EVTDSTS:
          rqiptr->flags|=WDSTING;
          break;
     case EVTDSTD:
          rqiptr->flags&=~WDSTING;
          break;
     case EVTCCST:
          rqiptr->flags|=WCCING;
          break;
     case EVTDONE:
          if (wrtbuf->primsg == 0L) {
               wrtbuf->primsg=msg->msgid;
          }
          if (rc > GMEAGAIN) {
               if (rqiptr->flags&WCCING) {
                    if (rc == GMEAFWD) {
                         cpynot(gmexinf());
                    }
                    else {
                         cpynot(msg->to);
                    }
               }
               else {
                    if (rc == GMEAFWD) {
                         wrtnot(gmexinf(),msg);
                    }
                    else {
                         wrtnot(msg->to,msg);
                    }
               }
          }
          else if ((rqiptr->flags&WCCING) && !(rqiptr->flags&WDSTING)) {
               if (qroom(usrnum,NORMAL)) {
                    *namtmp=rqiptr->dpknam;
                    strcpy(namtmp->suffix,"wrtccerr ");
                    stlcat(namtmp->suffix,spr("%d",rc),SFXSIZ);
                    senddpk(usrnum,rqiptr->dpknam.appid,NORMAL,namtmp,
                            STGLEN,msg->to,rtextFDA);
               }
          }
          break;
     }
}

static VOID
csndnew(VOID)                      /* cycled send a new message process    */
{
     cssetup();
     cswrtup();
     sndnew();
}

static VOID
sndnew(VOID)                       /* send a new message                   */
{
     struct wrterr err;

     switch (err.rc=gmeSendMsg(efwork,msg,msgtxt,filatt,wrtbuf->cclist)) {
     case GMEAGAIN:
          cycleme(csndnew);
          return;
     case GMEAFWD:
     case GMEOK:
          if (!(rqiptr->flags&(WDSTING|WCCING))) {
               if (err.rc == GMEAFWD) {
                    wrtnot(gmexinf(),msg);
               }
               else {
                    wrtnot(msg->to,msg);
               }
          }
          if (wrtbuf->primsg == 0L) {
               rsp2write(TRUE,sizeof(LONG),&msg->msgid,longFDA);
          }
          else {
               rsp2write(TRUE,sizeof(LONG),&wrtbuf->primsg,longFDA);
          }
          break;
     default:
          err.flags=THEMSG;
          rsp2write(FALSE,sizeof(struct wrterr),&err,wrterrFDA);
          break;
     }
     if (wrtbuf->cclist != NULL) {
          free(wrtbuf->cclist);
     }
     unrarea(wrmpool,rqiptr->wrthdl);
     peruflg[usrnum]&=~WRTIPG;
}

static VOID
csndrpl(VOID)                      /* cycled send a reply process          */
{
     cssetup();
     cswrtup();
     sndrpl();
}

static VOID
sndrpl(VOID)                       /* send a reply                         */
{
     struct wrterr err;

     switch (err.rc=reply(efwork,msg,msgtxt,filatt,wrtbuf->cclist)) {
     case GMEAGAIN:
          cycleme(csndrpl);
          return;
     case GMEAFWD:
     case GMEOK:
          if (!(rqiptr->flags&(WDSTING|WCCING))) {
               if (err.rc == GMEAFWD) {
                    wrtnot(gmexinf(),msg);
               }
               else {
                    wrtnot(msg->to,msg);
               }
          }
          if (wrtbuf->primsg == 0L) {
               rsp2write(TRUE,sizeof(LONG),&msg->msgid,longFDA);
          }
          else {
               rsp2write(TRUE,sizeof(LONG),&wrtbuf->primsg,longFDA);
          }
          break;
     default:
          err.flags=THEMSG;
          rsp2write(FALSE,sizeof(struct wrterr),&err,wrterrFDA);
          break;
     }
     if (wrtbuf->cclist != NULL) {
          free(wrtbuf->cclist);
     }
     unrarea(wrmpool,rqiptr->wrthdl);
     peruflg[usrnum]&=~WRTIPG;
}

static GBOOL                       /*   returns TRUE if dpk valid          */
ndpk2msg(                          /* convert new msg dpk to msg struct    */
struct newdpk *dpk,                /*   new message dynapak structure      */
struct message *msg,               /*   message header structure           */
CHAR *text,                        /*   text buffer                        */
CHAR *filatt)                      /*   file attachment (if indirect)      */
{
     CHAR *scp,*ecp;

     ASSERT(dpk != NULL);
     ASSERT(msg != NULL);
     ASSERT(text != NULL);
     ASSERT(filatt != NULL);
     setmem(msg,sizeof(struct message),0);
     msg->forum=(USHORT)dpk->forum;
     msg->msgid=dpk->msgid;
     msg->gmid=dpk->gmid;
     msg->thrid=dpk->thrid;
     b2ccpy(msg->attname,dpk->attname,GCMAXFNM);
     msg->flags=(LONG)dpk->flags;
     scp=unpad(dpk->info);
     ecp=strchr(scp,FLDSEP);
     if (ecp == NULL) {
          return(FALSE);
     }
     *ecp='\0';
     stlcpy(filatt,scp,GCMAXPTH);
     scp=ecp+1;
     ecp=strchr(scp,FLDSEP);
     if (ecp == NULL) {
          return(FALSE);
     }
     *ecp='\0';
     stlcpy(msg->to,scp,MAXADR);
     scp=ecp+1;
     ecp=strchr(scp,FLDSEP);
     if (ecp == NULL) {
          return(FALSE);
     }
     *ecp='\0';
     stlcpy(msg->topic,scp,TPCSIZ);
     scp=ecp+1;
     ecp=strchr(scp,FLDSEP);
     if (ecp == NULL) {
          return(FALSE);
     }
     *ecp='\0';
     stlcpy(msg->history,scp,HSTSIZ);
     if (isfmtted(ecp+1)) {
          stlcpy(text,ecp+1,TXTLEN);
     }
     else {
          text[0]='\r';
          stlcpy(&text[1],ecp+1,TXTLEN-1);
     }
     ecp=text+strlen(text);
     while (ecp > text && *ecp <= ' ') {
          *ecp--='\0';
     }
     return(TRUE);
}

VOID
csfwd(                             /* C/S common forward-message function  */
struct saunam *dpknam,             /*   dynapak name in use                */
CHAR *fwdinf)                      /*   address to fwd to/comments         */
{
     rqiptr->wrthdl=rsvarea(wrmpool);
     if (rqiptr->wrthdl == NOHDL) {
          *(LONG *)rsptmp=(LONG)WRTBUSY;
          rsp2write(FALSE,sizeof(LONG),rsptmp,longFDA);
          return;
     }
     rqiptr->flags|=BUFINU;
     cswrtup();
     rqiptr->dpknam=*dpknam;
     stlcpy(msgtxt,fwdinf,TXTLEN);
     rd4fwd();
}

static VOID
crd4fwd(VOID)                      /* cycled read message for forward      */
{
     cssetup();
     cswrtup();
     rd4fwd();
}

static VOID
rd4fwd(VOID)                       /* read message in prep for forward     */
{
     SHORT rc,maxpfn;
     CHAR *cp;

     switch (rc=readmsgf(efwork,msg,(CHAR *)rsptmp)) {
     case GMEAGAIN:
          cycleme(crd4fwd);
          return;
     case GMEOK:
          stlcpy((CHAR *)vdatmp,msgtxt,TXTLEN);
          cp=strchr(vdatmp,FLDSEP);
          if (cp != NULL) {
               *cp++='\0';
               if (msg->forum == EMLID) {
                    maxpfn=3-pfceil;
               }
               else {
                    maxpfn=getdefp(msg->forum)->pfnlvl;
                    if (maxpfn == DFTPFN) {
                         maxpfn=3-pfceil;
                    }
                    else {
                         maxpfn=3-maxpfn;
                    }
               }
               if (profan(cp) > maxpfn) {
                    rejcfwd(PFNERR);
                    break;
               }
          }
          if (msg->forum != EMLID) {
               forctx(efwork,msg->forum,FSQFOR);
          }
          msg->forum=EMLID;
          stlcpy(msg->to,(CHAR *)vdatmp,MAXADR);
          rc=val2gme(vfwdadr(efwork,usaptr->userid,msg->to,EMLID));
          if (rc != GMEOK) {
               rejcfwd(rc == GMEERR ? BADADR : rc);
               break;
          }
          if (msg->flags&FILATT) {
               rc=val2gme(vfwdatt(efwork,usaptr->userid,msg->to,EMLID));
               if (rc != GMEOK) {
                    rejcfwd(rc == GMEERR ? GMEIVA : rc);
                    break;
               }
          }
          if ((msg->flags&PRIMSG)
           && vfwdpri(efwork,usaptr->userid,msg->to,EMLID) != VALYES) {
               msg->flags&=~PRIMSG;
          }
          ASSERT(!(msg->flags&RECREQ));
          if (addcmt((CHAR *)rsptmp,cp,msgtxt) == NULL) {
               rejcfwd(CMTERR);
               break;
          }
          csfwdit();
          break;
     default:
          rejcfwd(rc);
          break;
     }
}

static VOID
ccsfwdit(VOID)                     /* cycled C/S forward message process   */
{
     cssetup();
     cswrtup();
     csfwdit();
}

static VOID
csfwdit(VOID)                      /* C/S forward a message process        */
{
     SHORT rc;

     switch (rc=fwdmsg(efwork,msg,msgtxt)) {
     case GMEAGAIN:
          cycleme(ccsfwdit);
          return;
     case GMEOK:
     case GMEAFWD:
          rsp2write(TRUE,sizeof(LONG),&msg->msgid,longFDA);
          break;
     default:
          *(LONG *)rsptmp=(LONG)rc;
          rsp2write(FALSE,sizeof(LONG),rsptmp,longFDA);
          break;
     }
     clsgmerq(efwork);
     unrarea(wrmpool,rqiptr->wrthdl);
}

VOID
cscopy(                            /* C/S common copy-message function     */
struct saunam *dpknam,             /*   dynapak name in use                */
CHAR *cpyinf)                      /*   address to copy to/comments        */
{
     rqiptr->wrthdl=rsvarea(wrmpool);
     if (rqiptr->wrthdl == NOHDL) {
          *(LONG *)rsptmp=(LONG)WRTBUSY;
          rsp2write(FALSE,sizeof(LONG),rsptmp,longFDA);
          return;
     }
     rqiptr->flags|=BUFINU;
     cswrtup();
     rqiptr->dpknam=*dpknam;
     stlcpy(msgtxt,cpyinf,TXTLEN);
     rd4cpy();
}

static VOID
crd4cpy(VOID)                      /* cycled read message for copy         */
{
     cssetup();
     cswrtup();
     rd4cpy();
}

static VOID
rd4cpy(VOID)                       /* read message in prep for copy        */
{
     SHORT rc,maxpfn;
     CHAR *cp;

     switch (rc=readmsgf(efwork,msg,(CHAR *)rsptmp)) {
     case GMEAGAIN:
          cycleme(crd4cpy);
          return;
     case GMEOK:
          stlcpy((CHAR *)vdatmp,msgtxt,TXTLEN);
          cp=strchr(vdatmp,FLDSEP);
          if (cp != NULL) {
               *cp++='\0';
               if (msg->forum == EMLID) {
                    maxpfn=3-pfceil;
               }
               else {
                    maxpfn=getdefp(msg->forum)->pfnlvl;
                    if (maxpfn == DFTPFN) {
                         maxpfn=3-pfceil;
                    }
                    else {
                         maxpfn=3-maxpfn;
                    }
               }
               if (profan(cp) > maxpfn) {
                    rejcfwd(PFNERR);
                    break;
               }
          }
          stlcpy(msg->to,(CHAR *)vdatmp,MAXADR);
          rc=val2gme(valadr(efwork,usaptr->userid,msg->to,EMLID));
          if (rc != GMEOK) {
               rejcfwd(rc == GMEERR ? BADADR : rc);
               break;
          }
          if (msg->flags&FILATT) {
               rc=val2gme(valatt(efwork,usaptr->userid,msg->to,EMLID));
               if (rc != GMEOK) {
                    rejcfwd(rc == GMEERR ? GMEIVA : rc);
                    break;
               }
          }
          if ((msg->flags&PRIMSG)
           && valpri(efwork,usaptr->userid,msg->to,EMLID) != VALYES) {
               msg->flags&=~PRIMSG;
          }
          ASSERT(!(msg->flags&RECREQ));
          if (addcmt((CHAR *)rsptmp,cp,msgtxt) == NULL) {
               rejcfwd(CMTERR);
               break;
          }
          msg->forum=EMLID;
          cscpyit();
          break;
     default:
          rejcfwd(rc);
          break;
     }
}

static VOID
ccscpyit(VOID)                     /* cycled C/S forward message process   */
{
     cssetup();
     cswrtup();
     cscpyit();
}

static VOID
cscpyit(VOID)                      /* C/S forward a message process        */
{
     SHORT rc;

     switch (rc=copymsg(efwork,msg,msgtxt)) {
     case GMEAGAIN:
          cycleme(ccscpyit);
          return;
     case GMEOK:
     case GMEAFWD:
          rsp2write(TRUE,sizeof(LONG),&msg->msgid,longFDA);
          break;
     default:
          *(LONG *)rsptmp=(LONG)rc;
          rsp2write(FALSE,sizeof(LONG),rsptmp,longFDA);
          break;
     }
     clsgmerq(efwork);
     unrarea(wrmpool,rqiptr->wrthdl);
}

static VOID
rejcfwd(                           /* reject copy or forward request       */
LONG rc)                           /*   error code to return               */
{
     unrarea(wrmpool,rqiptr->wrthdl);
     clsgmerq(efwork);
     rsp2write(FALSE,sizeof(LONG),&rc,longFDA);
}

static CHAR *                      /*   returns pointer to destination buf */
addcmt(                            /* add comments to message text         */
CHAR *txt,                         /*   buffer containing text             */
CHAR *cmt,                         /*   buffer containing comments         */
CHAR *buf)                         /*   destination buffer                 */
{
     LONG avlspc;

     avlspc=TXTLEN-strlen(txt)-strlen(abvcmt)-strlen(blwcmt)-2*UIDSIZ;
     if (cmt != NULL && cmt[0] != '\r' && cmt[0] != '\n') {
          --avlspc;
     }
     if (cmt == NULL || *cmt == '\0' || avlspc <= 0L) {
          stlcpy(buf,txt,TXTLEN);
     }
     else {
          sprintf(buf,abvcmt,usaptr->userid);
          if (cmt[0] != '\r' && cmt[0] != '\n') {
               stlcat(buf,"\r",(UINT)avlspc);
          }
          stlcat(buf,cmt,(UINT)avlspc);
          sprintf(buf+strlen(buf),blwcmt,usaptr->userid);
          if (isfmtted(txt)) {
               if (buf[0] == '\r' || buf[0] == '\n') {
                    movmem(buf+1,buf,strlen(buf));
               }
               stlcat(buf,"\r",TXTLEN);
               if (!insasc(FALSE,buf,txt,TXTLEN)) {
                    return(NULL);
               }
               stlcpy(buf,txt,TXTLEN);
          }
          else {
               stlcat(buf,txt,TXTLEN);
          }
     }
     return(buf);
}

SHORT                              /*   returns GME status code            */
readir(                            /* read E-mail with direction           */
INT dir,                           /*   direction to read                  */
VOID *work,                        /*   GME work area                      */
struct message *msg,               /*   message header buffer              */
CHAR *text)                        /*   message text buffer                */
{
     switch (dir) {
     case 0:
          return(readmsgf(work,msg,text));
     case 1:
          return(nextmsgf(work,msg,text));
     case -1:
          return(prevmsgf(work,msg,text));
     default:
          ASSERT(FALSE);
     }
     return(GMEERR);
}

ULONG
iotck(VOID)                        /* get # hrtval() tcks to use for I/O   */
{
     ULONG rval;

     rval=655360L/nliniu()/(2*rsptim);
     if (rval > 3277) {       /* 50 ms */
          rval=3277;
     }
     else if (rval < 66) {    /* 1 ms */
          rval=66;
     }
     return(rval);
}

VOID
vdamsg(VOID)                       /* set msg and msgtxt to point at vdatmp*/
{
     msg=(struct message *)vdatmp;
     msgtxt=(CHAR *)vdatmp+sizeof(struct message);
}

LONG
s2mn(                              /* converts string to msg# w/ error chk */
CHAR *s)                           /*   string to convert                  */
{
     LONG n;

     if (!alldgs(s)) {
          return(-1L);
     }
     n=atol(s);
     if (n == 0L && s[0] != '0') {
          return(-1L);
     }
     return(n);
}

INT
s2rq(                              /* converts string to reqid w/error chk */
CHAR *s)                           /*   string to convert                  */
{
     INT n;

     if (!alldgs(s)) {
          return(-1);
     }
     n=atoi(s);
     if (n == 0L && s[0] != '0') {
          return(-1);
     }
     return(n);
}

CHAR *                             /*   returns pointer to static buffer   */
longstr(                           /* convert long int to left-padded str  */
LONG n)                            /*   number to convert                  */
{
     static CHAR s[11];

     sprintf(s,"%010lu",(ULONG)n);
     return(s);
}

CHAR *                             /*   copy of pointer to destination     */
chrcat(                            /* concatenate a character onto a string*/
CHAR *s,                           /*   string to add to                   */
CHAR c)                            /*   character to add                   */
{
     register CHAR *ptr;

     ptr=s+strlen(s);
     *ptr++=c;
     *ptr='\0';
     return(s);
}

struct msgdpk *                    /*   returns copy of pointer to dest    */
msg2dpk(                           /* copy message to dynapak form         */
struct message *msg,               /*   message header                     */
CHAR *text,                        /*   message text                       */
struct msgdpk *dpk,                /*   message dynapak buffer             */
GBOOL incltxt)                     /*   include message text in dpk?      */
{
     CHAR *cp;

     dpk->forum=msg->forum;
     if (msg->forum == EMLID) {
          setmem(dpk->fornam,FORNSZ-1,' ');
     }
     else {
          c2bcpy(dpk->fornam,getfnm(msg->forum),FORNSZ-1);
     }
     dpk->msgid=msg->msgid;
     dpk->gmid=msg->gmid;
     dpk->thrid=msg->thrid;
     c2bcpy(dpk->attname,msg->attname,GCMAXFNM-1);
     dpk->crdatim=d2vdat(msg->crdate,msg->crtime);
     dpk->rplto=msg->rplto;
     dpk->nrpl=msg->nrpl;
     dpk->flags=(SHORT)msg->flags;
     stlcpy(dpk->info,msg->from,MAXADR);
     cp=dpk->info+strlen(dpk->info);
     *cp++=FLDSEP;
     stlcpy(cp,msg->to,MAXADR);
     cp+=strlen(cp);
     *cp++=FLDSEP;
     stlcpy(cp,msg->topic,TPCSIZ);
     cp+=strlen(cp);
     *cp++=FLDSEP;
     stlcpy(cp,msg->history,HSTSIZ);
     if (incltxt) {
          cp+=strlen(cp);
          *cp++=FLDSEP;
          if (!isfmtted(text)) {
               lf2cr(text);
               if (text[0] == '\r') {
                    ++text;
               }
               stpans(text);
          }
          stlcpy(cp,text,TXTLEN);
     }
     ASSERT(sizeof(struct msgdpk)+strlen(dpk->info) <= MAXDPKV);
     return(dpk);
}

GBOOL
valtpc(                            /* is this an acceptible topic string?  */
const CHAR *topic)                 /*   topic string                       */
{
     register CHAR const *cp;

     for (cp=topic ; *cp != '\0' ; ++cp) {
          if (*cp < ' ') {
               return(FALSE);
          }
     }
     return(TRUE);
}

VOID
getlex(                            /* get spelling checker file            */
struct saunam *dpknam)             /*   dpk name in use                    */
{
     char filnam[GCMAXFNM];

     ASSERT(sameto(LEXDPK,dpknam->suffix));
     stlcpy(filnam,dpknam->suffix+sizeof(LEXDPK)-1,GCMAXFNM);
     if (valfnm(filnam)) {
          rsp2read(dpknam,STGLEN,stlcat(strcpy(rsptmp,LEXDIR),filnam,GCMAXPTH),NULL);
     }
     else {
          rejectreq();
     }
}
