/***************************************************************************
 *                                                                         *
 *   WLMSGU.C                                                              *
 *                                                                         *
 *   Copyright (c) 1997 Galacticomm, Inc.         All Rights Reserved.     *
 *                                                                         *
 *   Worldlink Messaging transit message format utilities.                 *
 *                                                                         *
 *                                            - J. Alvrus   1/16/97        *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "gme.h"
#include "wlmutl.h"
#include "wlmstoru.h"
#include "wlmforu.h"
#include "wlmmsgu.h"

#define FILREV "$Revision: 1.3 $"

GBOOL wlMsgActive=FALSE;           /* have message utils been initialized? */
VOID *wlMsgBuf;                    /* temp buf for reading/writing msgs    */
CHAR *wlHdrBuf;                    /* temp WLM header buffer               */

struct flddef wlmSectHdrFDA[]={
     {CVTFLD_CHAR,WLMSECTLEN,0                     ,NULL},
     {CVTFLD_LONG,1         ,fldoff(wlmSectHdr,len),NULL},
     {CVTFLD_END ,0         ,0                     ,NULL}
};

static GBOOL findSect(size_t *sectPos,size_t *sectLen,const CHAR *sectName,
                      const VOID *src,size_t srcLen);

GBOOL
initMsgUtil(VOID)                  /* transit message utility init         */
{
     wlMsgBuf=alcmem(MSGBUFSIZ);
     wlHdrBuf=alcmem(WLMAXHDR);
     wlMsgActive=TRUE;
     return(TRUE);
}

VOID
closeMsgUtil(VOID)                 /* shut down transit message utility    */
{
     if (wlMsgActive) {
          free(wlMsgBuf);
          free(wlHdrBuf);
     }
     wlMsgActive=FALSE;
}

GBOOL                              /*   returns TRUE if successful         */
addMsg2Stor(                       /* generic add message to store         */
const CHAR *storFile,              /*   path+file name of store file to use*/
ULONG idxInit,                     /*   initial idx if store doesn't exist */
const VOID *msgBuf,                /*   buffer containing contents to store*/
size_t bufLen,                     /*   length of contents                 */
const CHAR *attDir,                /*   final resting place for attachment */
const CHAR *attFile)               /*   current attachment path+file name  */
{                                  /*   (NULL if none)                     */
     GBOOL flg;
     ULONG idx;
     STORFILE *sfp;
     CHAR tmpPath[GCMAXPTH];

     flg=isfile(storFile);
     if ((flg && (sfp=storOpen(storFile)) != NULL)
      || (!flg && (sfp=storCreate(storFile,idxInit)) != NULL)) {
          flg=storAddMsg(sfp,msgBuf,bufLen);
          storClose(sfp);
          idx=storLastIdx();
          if (flg) {
               if (attFile != NULL) {
                    rename(attFile,
                           makePath(tmpPath,attDir,makeAttName(idx),GCMAXPTH));
               }
               return(TRUE);
          }
     }
     return(FALSE);
}

size_t                             /*   returns # of bytes put in dst      */
makeTransitMsg(                    /* form transit-format message          */
VOID *dstBuf,                      /*   destination buffer                 */
size_t dstSiz,                     /*   size of destination buffer         */
const CHAR *forum,                 /*   forum name or NULL if email        */
const CHAR *to,                    /*   to address                         */
const CHAR *from,                  /*   from address in exporter format    */
const struct message *pmsg,        /*   GME message header                 */
const CHAR *text,                  /*   message body                       */
const CHAR *appInfo)               /*   application-defined info (if any)  */
{
     size_t used;
     const CHAR *hdr;
     CHAR *buf;

     buf=dstBuf;
     hdr=wlmHeader(forum,to,from,pmsg);
     used=0;
     used=wlmSetSectStr(buf,used,dstSiz,HDRSECT,hdr);
     if (!NULSTR(text)) {
          used=wlmSetSectStr(buf,used,dstSiz,TXTSECT,text);
     }
     if (!NULSTR(appInfo)) {
          used=wlmSetSectStr(buf,used,dstSiz,APPSECT,appInfo);
     }
     return(used);
}

GBOOL                              /*   returns FALSE if bad forum         */
xltTransitMsg(                     /* translate transit pmsg to GME format  */
VOID *srcBuf,                      /*   buffer containing transit pmsg      */
size_t srcLen,                     /*   length of transit message          */
struct message *pmsg,              /*   message header to fill in          */
CHAR *text,                        /*   buffer for text (must be TXTLEN)   */
CHAR *appinf,                      /*   buf for app info (must be TXTLEN)  */
GBOOL attFlag)                     /*   is there an attachment?            */
{
     CHAR numBuf[sizeof("-1234567890")];

     memset(pmsg,0,sizeof(struct message));
     wlmGetSectStr(vdatmp,WLMAXHDR,HDRSECT,srcBuf,srcLen);
     wlmGetSectStr(text,TXTLEN,TXTSECT,srcBuf,srcLen);
     wlmGetSectStr(appinf,TXTLEN,APPSECT,srcBuf,srcLen);
     if (*getWLHeader(pmsg->to,MAXADR,WLH_FORUM,"",vdatmp) != '\0') {
          if ((pmsg->forum=getWLForumID(pmsg->to)) == EMLID) {
               return(FALSE);
          }
     }
     getWLHeader(pmsg->from,MAXADR,WLH_FROM,"",vdatmp);
     getWLHeader(pmsg->to,MAXADR,WLH_TO,"",vdatmp);
     getWLHeader(pmsg->topic,TPCSIZ,WLH_TOPIC,"",vdatmp);
     getWLHeader(pmsg->history,HSTSIZ,WLH_HISTORY,"",vdatmp);
     if (pmsg->forum == EMLID) {
          if (atoi(getWLHeader(numBuf,sizeof(numBuf),WLH_PRIORITY,"0",vdatmp))) {
               pmsg->flags|=PRIMSG;
          }
          if (atoi(getWLHeader(numBuf,sizeof(numBuf),WLH_RETRCP,"0",vdatmp))) {
               pmsg->flags|=RECREQ;
          }
          if (atoi(getWLHeader(numBuf,sizeof(numBuf),WLH_ERRMSG,"0",vdatmp))) {
               pmsg->flags|=GMFERR;
          }
     }
     else {
          if (*pmsg->to == '\0') {
               strcpy(pmsg->to,ALLINF);
          }
          pmsg->thrid=atol(getWLHeader(numBuf,sizeof(numBuf),
                                      WLH_THRID,"0",vdatmp));
          getHdrGlobID(&pmsg->gmid,WLH_GLOBID,vdatmp);
          getHdrGlobID(&pmsg->rplto,WLH_RPLTO,vdatmp);
     }
     if (attFlag) {
          getWLHeader(pmsg->attname,GCMAXFNM,WLH_ATTNAME,DFTATT,vdatmp);
          pmsg->flags|=FILATT;
     }
     return(TRUE);
}

size_t                             /*   returns # of bytes used in buffer  */
wlmSetSect(                        /* put a section in a message buffer    */
VOID *buf,                         /*   buffer to add to                   */
size_t bufUsed,                    /*   # bytes currently used in buffer   */
size_t bufSiz,                     /*   total size of buffer               */
const CHAR *sectName,              /*   name of section                    */
const VOID *sect,                  /*   buffer containing section contents */
size_t sectLen)                    /*   length of contents                 */
{
     INT i;
     CHAR *sptr;
     size_t oldpos,oldlen;
     struct wlmSectHdr hdr;

     if (findSect(&oldpos,&oldlen,sectName,buf,bufUsed)) {
          oldlen+=WLMSHDRSIZ;
          sptr=((CHAR *)buf)+oldpos;
          memmove(sptr,sptr+oldlen,bufUsed-(oldpos+oldlen));
          bufUsed-=oldlen;
     }
     if (sectLen != 0) {
          memset(&hdr,0,sizeof(struct wlmSectHdr));
          for (i=0 ; i < WLMSECTLEN ; ++i) {
               if (*sectName != '\0') {
                    hdr.name[i]=tolower(*sectName++);
               }
               else {
                    hdr.name[i]=' ';
               }
          }
          sectLen=min(sectLen,(bufSiz-bufUsed)-WLMSHDRSIZ);
          hdr.len=(ULONG)sectLen;
          sptr=((CHAR *)buf)+bufUsed;
          i=cvtData(&hdr,sptr,sizeof(struct wlmSectHdr),wlmSectHdrFDA,
                    CVTSERVER,CVTWLM,CHAN_NUL);
          memcpy(sptr+i,sect,sectLen);
          bufUsed+=WLMSHDRSIZ+sectLen;
     }
     return(bufUsed);
}

size_t                             /*   returns # of bytes used in buffer  */
wlmSetSectStr(                     /* put a string section in a msg buffer */
VOID *buf,                         /*   buffer to add to                   */
size_t bufUsed,                    /*   # bytes currently used in buffer   */
size_t bufSiz,                     /*   total size of buffer               */
const CHAR *sectName,              /*   name of section                    */
const CHAR *sect)                  /*   section content string             */
{
     return(wlmSetSect(buf,bufUsed,bufSiz,sectName,sect,strlen(sect)));
}

size_t                             /*   returns # bytes put into dest      */
wlmGetSect(                        /* get a section from a message buffer  */
VOID *dst,                         /*   buffer to receive section          */
size_t dstSiz,                     /*   size of destination buffer         */
const CHAR *sectName,              /*   name of section                    */
const VOID *src,                   /*   buffer containing message          */
size_t srcLen)                     /*   length of message                  */
{
     size_t pos,len;

     len=0;
     if (findSect(&pos,&len,sectName,src,srcLen)) {
          len=min(dstSiz,len);
          memcpy(dst,((const CHAR *)src)+(pos+WLMSHDRSIZ),len);
     }
     return(len);
}

CHAR *                             /*   returns pointer to destination     */
wlmGetSectStr(                     /* get a string section from msg buffer */
CHAR *dst,                         /*   buffer to receive section          */
size_t dstSiz,                     /*   size of destination buffer         */
const CHAR *sectName,              /*   name of section                    */
const VOID *src,                   /*   buffer containing message          */
size_t srcLen)                     /*   length of message                  */
{
     dst[wlmGetSect(dst,dstSiz-1,sectName,src,srcLen)]='\0';
     return(dst);
}

static GBOOL                       /*   returns TRUE if section exists     */
findSect(                          /* find a section in a message buffer   */
size_t *sectPos,                   /*   buffer to receive section offset   */
size_t *sectLen,                   /*   buffer to receive section length   */
const CHAR *sectName,              /*   name of section                    */
const VOID *src,                   /*   buffer containing message          */
size_t srcLen)                     /*   length of message                  */
{
     size_t pos;
     CHAR testnam[WLMSECTLEN+1];
     struct wlmSectHdr hdr;

     for (pos=0 ; pos < srcLen ; pos+=WLMSHDRSIZ+(size_t)hdr.len) {
          cvtData(((CHAR *)src)+pos,&hdr,WLMSHDRSIZ,wlmSectHdrFDA,
                  CVTWLM,CVTSERVER,CHAN_NUL);
          memcpy(testnam,hdr.name,WLMSECTLEN);
          testnam[WLMSECTLEN]='\0';
          if (sameas(unpad(testnam),sectName)) {
               *sectLen=(size_t)hdr.len;
               *sectPos=pos;
               return(TRUE);
          }
     }
     return(FALSE);
}

const CHAR *                       /*   returns pointer to temp buffer     */
wlmHeader(                         /* form header for WLM message          */
const CHAR *forum,                 /*   forum name or NULL if email        */
const CHAR *to,                    /*   to address                         */
const CHAR *from,                  /*   from address in exporter format    */
const struct message *pmsg)        /*   GME message header                 */
{
     GBOOL emlflg;

     *wlHdrBuf='\0';
     emlflg=FALSE;
     if (forum == NULL) {
          emlflg=TRUE;
          setWLHeader(wlHdrBuf,WLH_TO,to,WLMAXHDR);
          if (*pmsg->history != '\0') {
               setWLHeader(wlHdrBuf,WLH_HISTORY,pmsg->history,WLMAXHDR);
          }
     }
     else {
          setWLHeader(wlHdrBuf,WLH_FORUM,forum,WLMAXHDR);
          if (!sameas(ALLINF,to)) {
               setWLHeader(wlHdrBuf,WLH_TO,to,WLMAXHDR);
          }
     }
     setWLHeader(wlHdrBuf,WLH_FROM,from,WLMAXHDR);
     setWLHeader(wlHdrBuf,WLH_DATE,wlmDateStr(pmsg->crdate,pmsg->crtime),WLMAXHDR);
     setWLHeader(wlHdrBuf,WLH_TOPIC,pmsg->topic,WLMAXHDR);
     if (pmsg->flags&FILATT) {
          setWLHeader(wlHdrBuf,WLH_ATTNAME,pmsg->attname,WLMAXHDR);
     }
     if (emlflg) {
          if (pmsg->flags&RECREQ) {
               setWLHeader(wlHdrBuf,WLH_RETRCP,"1",WLMAXHDR);
          }
          if (pmsg->flags&PRIMSG) {
               setWLHeader(wlHdrBuf,WLH_PRIORITY,"1",WLMAXHDR);
          }
          if (pmsg->flags&GMFERR) {
               setWLHeader(wlHdrBuf,WLH_ERRMSG,"1",WLMAXHDR);
          }
     }
     else {
          setWLHeader(wlHdrBuf,WLH_THRID,l2as(pmsg->thrid),WLMAXHDR);
          setWLHeader(wlHdrBuf,WLH_GLOBID,wlmGlobIDStr(&pmsg->gmid),WLMAXHDR);
          if (pmsg->rplto.sysid != 0 && pmsg->rplto.msgid != 0) {
               setWLHeader(wlHdrBuf,WLH_RPLTO,wlmGlobIDStr(&pmsg->rplto),WLMAXHDR);
          }
     }
     return(wlHdrBuf);
}

CHAR *                             /*   returns pointer to destination     */
setWLHeader(                       /* add WLM header to buffer             */
CHAR *dst,                         /*   destination buffer                 */
const CHAR *kwd,                   /*   header keyword                     */
const CHAR *val,                   /*   header value                       */
size_t bufSiz)                     /*   size of destination buffer         */
{
     setConfigStr(NULL,kwd,val,dst,bufSiz);
     return(dst);
}

CHAR *                             /*   returns pointer to destination     */
getWLHeader(                       /* get a WLM header from a buffer       */
CHAR *dst,                         /*   destination buffer                 */
size_t dstSiz,                     /*   size of destination buffer         */
const CHAR *kwd,                   /*   header keyword to find             */
const CHAR *dftval,                /*   default value if keyword not found */
const CHAR *src)                   /*   source buffer                      */
{
     return(getConfigStr(NULL,kwd,dftval,dst,dstSiz,src));
}

const CHAR *                       /*   returns pointer to temp buffer     */
makeAttName(                       /* form attachment name                 */
ULONG msgIdx)                      /*   based on message index             */
{
     static CHAR retBuf[GCMAXFNM];

     sprintf(retBuf,"%08X.ATT",msgIdx);
     return(retBuf);
}

const CHAR *                       /*   returns pointer to temp buffer     */
wlmDateStr(                        /* generate WLM date string             */
USHORT date,                       /*   DOS date                           */
USHORT time)                       /*   DOS time                           */
{
     static CHAR retbuf[WLMDATESIZ];

     sprintf(retbuf,WLMDATEFMT,
             ddyear(date),ddmon(date),ddday(date),
             dthour(time),dtmin(time),dtsec(time));
     return(retbuf);
}

GBOOL                              /*   returns TRUE if successful         */
xltDateStr(                        /* translate WLM date string            */
const CHAR *dateStr,               /*   WLM-format date string             */
USHORT *date,                      /*   buffer to receive DOS date         */
USHORT *time)                      /*   buffer to receive DOS time         */
{
     INT year,mon,day,hour,min,sec;

     if (sscanf(dateStr,WLMDATEFMT,&year,&mon,&day,&hour,&min,&sec) == 6) {
          *date=dddate(mon,day,year);
          *time=dttime(hour,min,sec);
          return(TRUE);
     }
     return(FALSE);
}

const CHAR *                       /*   returns pointer to temp buffer     */
wlmGlobIDStr(                      /* generate GME global ID string        */
const struct globid *gid)          /*   global ID to convert               */
{
     static CHAR retbuf[sizeof("1234567890 1234567890")];

     sprintf(retbuf,"%010lu %010lu",gid->sysid,gid->msgid);
     return(retbuf);
}

VOID
getHdrGlobID(                      /* read a global ID from a msg header   */
struct globid *gid,                /*   buffer to take global ID           */
const CHAR *hdr,                   /*   name of header to read             */
const CHAR *src)                   /*   buffer containing headers          */
{
     CHAR tmpbuf[sizeof("1234567890 1234567890")];

     if (*getWLHeader(tmpbuf,sizeof(tmpbuf),hdr,"",src) == '\0'
      || !xltGlobIDStr(tmpbuf,gid)) {
          memset(gid,0,sizeof(struct globid));
     }
}

GBOOL                              /*   returns TRUE if successful         */
xltGlobIDStr(                      /* translate global ID string to struct */
const CHAR *idStr,                 /*   WL string format global ID         */
struct globid *gid)                /*   buffer to fill in                  */
{
     return(sscanf(idStr,"%lu %lu",&gid->sysid,&gid->msgid) == 2);
}


CHAR *                             /*   returns pointer to destination     */
formErrorMsg(                      /* form top of error message text       */
CHAR *dst,                         /*   destination buffer (TXTLEN long)   */
INT errmsg,                        /*   MCV number of message framework    */
INT reason,                        /*   MCV # of reason for error message  */
const CHAR *dateStr,               /*   WLM-format date string             */
const CHAR *recip,                 /*   intended recipient                 */
const CHAR *topic)                 /*   topic of message                   */
{                                  /*   (setmbk must be done by caller)    */
     CHAR *cp;
     USHORT date,time;
     GBOOL valDate;

     clrprf();
     prfmsg(reason);
     stlcpy(dst,prfbuf,TXTLEN);
     stpans(dst);
     if ((cp=strchr(dst,'\n')) != NULL) {
          *cp='\0';
     }
     if ((cp=strchr(dst,'\r')) != NULL) {
          *cp='\0';
     }
     clrprf();
     valDate=xltDateStr(dateStr,&date,&time);
     prfmsg(errmsg,valDate ? prndat(22,date,'-') : "Unknown",
            valDate ? prntim(14,time) : "",recip,topic,dst);
     dst[0]='\r';
     stlcpy(&dst[1],prfbuf,TXTLEN-1);
     clrprf();
     stpans(dst);
     return(dst);
}
