/***************************************************************************
 Name     :     SENDFR.C
 Comment  :
 Functions:     (see Prototypes just below)

        Copyright (c) 1993 Microsoft Corp.

 Revision Log
 Date     Name  Description
 -------- ----- ---------------------------------------------------------
***************************************************************************/

#include "prep.h"

#include "efaxcb.h"

#include "protocol.h"

///RSL
#include "glbproto.h"

#define faxTlog(m)      DEBUGMSG(ZONE_SENDFR, m)
#define FILEID          FILEID_SENDFR








VOID BCtoNSFCSIDIS(PThrdGlbl pTG, NPRFS npfs, NPBC npbc, NPLLPARAMS npll)
{
        // Use bigger buf. Avoid truncating Id before stripping alphas
        char    szCSI[MAXTOTALIDLEN + 2];

        //BG_CHK(npbc->bctype==SEND_CAPS);
        //BG_CHK(npbc->wTotalSize >= sizeof(BC));

        ZeroRFS(pTG, npfs);

        // extract ID
        // GetTextId(npbc, szCSI, MAXTOTALIDLEN+1);

        if (pTG->LocalID) {
            strcpy (szCSI, pTG->LocalID);
        }


#ifdef OEMNSF
        CreateOEMFrames(pTG, ifrNSF, OEMNSF_POSBEFORE, npbc, npll, npfs);
#endif

        // RSL no NSF
#if 0
        // Send MS NSFs IFF ECM is enabled
        if (1) /// RSL (pTG->ProtInst.llSendCaps.fECM)
        {
                // Now create MS NSx
                CreateNSForNSCorNSS(pTG, ifrNSF, npfs, npbc, FALSE); // NO id in NSF
        }
        else
        {
                // zap MMR out of our DIS
                npbc->Fax.Encoding &= (~MMR_DATA);
        }
#endif

#ifdef OEMNSF
        CreateOEMFrames(pTG, ifrNSF, OEMNSF_POSAFTER, npbc, npll, npfs);
#endif


        if(_fstrlen(szCSI))
                CreateIDFrame(pTG, ifrCSI, npfs, szCSI, FALSE); // RSL: DON'T strip non-numerics for CSI

        CreateDISorDTC(pTG, ifrDIS, npfs, &npbc->Fax, npll);
}








VOID BCtoNSCCIGDTC(PThrdGlbl pTG, NPRFS npfs, NPBC npbc, NPLLPARAMS npll)
{
        // Use bigger buf. Avoid truncating Id before stripping alphas
        char    szCIG[MAXTOTALIDLEN + 2];
        BOOL    fSkipDTC;
        BOOL    fSkipCIG;

        BG_CHK(npbc->bctype==SEND_POLLREQ);
        BG_CHK(npbc->wTotalSize >= sizeof(BC));

        ZeroRFS(pTG, npfs);

        fSkipDTC = 0;
        fSkipCIG = 0;

        // extract ID
        GetTextId(npbc, szCIG, MAXTOTALIDLEN+1);

#ifdef OEMNSF
        if(fUsingOEMProt)
        {
                WORD    wFlags;

                BG_CHK(wOEMFlags);
                wFlags = CreateOEMFrames(pTG, ifrNSC, OEMNSF_POSBEFORE, npbc, npll, npfs);

                fSkipDTC = ((wFlags & OEMNSF_DONTSEND_DCS) != 0);
                fSkipCIG = ((wFlags & OEMNSF_DONTSEND_TSI) != 0);
        }
        else
#endif
        {
                if(npbc->wNumPollReq)
                {
                        // if we have NSC poll reqs send NSC _with_ our ID. This is reqd
                        // for return addressing of response. See bug#6224 and 6675. In
                        // this case CIG is redundant so dont send it.
                        // NOTE: The real check we want to do is to see if we are polling
                        // another AtWork amchine or a G3. This test is just a proxy. The
                        // result is a residual bug that G3/blind-polls from IFAX-to-IFAX
                        // will NOT be routed correctly, even though they could/should.
                        // G3/Blind-polls from IFAX-to-G3 will never be routed correctly
                        // so long as we rely on the pollee to do the routing, but IFAX
                        // to G3 blind polls wil work if we replace the
                        //              if(wNumPollReq)
                        // test with a
                        //              if(pollee is AtWork)
                        //
                        CreateNSForNSCorNSS(pTG, ifrNSC, npfs, npbc, TRUE);  // ID in NSC with poll req
                        fSkipCIG = TRUE;
                }
                else
                {
                        // no NSC poll reqs, so only send our basic NSC
                        // (ie. to advert capabilities) if we have ECM
                        // Dont send our ID in this case. CIG is good enough
                        if(pTG->ProtInst.llSendCaps.fECM)
                                CreateNSForNSCorNSS(pTG, ifrNSC, npfs, npbc, FALSE); // no id in NSC w/o poll req
                }
        }

        if(!pTG->ProtInst.llSendCaps.fECM)
        {
                // zap MMR out of our DTC
                npbc->Fax.Encoding &= (~MMR_DATA);
        }

        if(!fSkipCIG && _fstrlen(szCIG))
                CreateIDFrame(pTG, ifrCIG, npfs, szCIG, TRUE);
        // Strip non-numerics for CIG. Our FULL ID (used for addressing the
        // response) is sent in the NSC if we have NSC poll requests, so the
        // CIG is only for G3 display purposes. Strip alphas to conform
        // to spec & cut it down to size

        if(!fSkipDTC)
                CreateDISorDTC(pTG, ifrDTC, npfs, &npbc->Fax, npll);
}











void CreateNSForNSCorNSS(PThrdGlbl pTG, IFR ifr, NPRFS npfs, NPBC npbc, BOOL fSendID)
{
        WORD    wNumFrames;
        USHORT  uRet;
        int     i;
        // be sure to init these to zero
        WORD    wsz=0, wEnc=0, wLen=0;

#ifdef DEBUG
        // check BCtype first
        switch(ifr)
        {
          case ifrNSF:  /* RSL BG_CHK(npbc->bctype == SEND_CAPS); */ break;
          case ifrNSS:  BG_CHK(npbc->bctype == SEND_PARAMS); break;
          case ifrNSC:  BG_CHK(npbc->bctype == SEND_POLLREQ); break;
        }
#endif //DEBUG
        // RSL BG_CHK(npbc->wTotalSize >= sizeof(BC));


        if(!fSendID)
        {
                // if we dont want to send the ID, save the ptrs/params of text id
                // and zap it out of the BC struct before calling AWNSF
                // We restore everything before exiting this function
                wsz = npbc->wszTextId;
                wLen = npbc->wTextIdLen;
                wEnc = npbc->wTextEncoding;
                npbc->wszTextId = npbc->wTextIdLen = npbc->wTextEncoding = 0;
        }

        if(uRet = BC_TO_NSX(pTG, ifr, npbc, fsFreePtr(pTG, npfs), (WORD) fsFreeSpace(pTG, npfs), &wNumFrames))
        {
                (MyDebugPrint(pTG,  LOG_ERR,  "<<ERROR>> BCtoNSx returned error %d\r\n", uRet));
                // go restore pointers if neccesary
                goto done;
        }
        else if(wNumFrames)
        {
                LPLPFR rglpfr = (LPLPFR)fsFreePtr(pTG, npfs);
                LPBYTE lpbLim = (LPBYTE)fsFreePtr(pTG, npfs);

                for(i=0; i<(int)wNumFrames; i++)
                {
                        (MyDebugPrint(pTG, LOG_ALL,  "Created NSF/NSC, len=%d\r\n", rglpfr[i]->cb));
                        BG_CHK((LPBYTE)(rglpfr[i]) >= fsStart(pTG, npfs));
                        BG_CHK(rglpfr[i]->fif+rglpfr[i]->cb <= fsLim(pTG, npfs));

#ifndef NOCHALL
                        if(ifr==ifrNSF && i==0)
                        {
                                BG_CHK(rglpfr[i]->cb > 3);
                                pTG->uSavedChallengeLen = min(rglpfr[i]->cb-3, POLL_CHALLENGE_LEN);
                                _fmemcpy(pTG->bSavedChallenge, rglpfr[i]->fif+3, pTG->uSavedChallengeLen);
                        }
#endif //!NOCHALL

                        if(npfs->uNumFrames < MAXFRAMES)
                        {
                                npfs->rglpfr[npfs->uNumFrames++] = rglpfr[i];
                                lpbLim = max(lpbLim, rglpfr[i]->fif+rglpfr[i]->cb);
                        }
                        else { BG_CHK(FALSE); break; }
                }
                npfs->uFreeSpaceOff = (USHORT)(lpbLim - ((LPBYTE)(npfs->b)));
                BG_CHK(npfs->uFreeSpaceOff <= fsSize(pTG, npfs) && npfs->uNumFrames <= MAXFRAMES);
        }
        else { BG_CHK(FALSE); }

done:
        // restore TextId in BC, if we had zapped it out!
        if(wsz)  npbc->wszTextId         = wsz;
        if(wLen) npbc->wTextIdLen        = wLen;
        if(wEnc) npbc->wTextEncoding = wEnc;
        return;
}









void CreateIDFrame(PThrdGlbl pTG, IFR ifr, NPRFS npfs, LPSTR szId, BOOL fStrip)
{
        BYTE szTemp[IDFIFSIZE+2];
        USHORT i, j;
        NPFR    npfr;

        npfr = (NPFR) fsFreePtr(pTG, npfs);
        if( fsFreeSpace(pTG, npfs) <= (sizeof(FRBASE)+IDFIFSIZE) ||
                npfs->uNumFrames >= MAXFRAMES)
        {
                BG_CHK(FALSE);
                return;
        }

if(fStrip)
{
        // CreateID strips non-numeric parts. Must send TSI when
        // we do EFAX-to-EFAX in G3 mode. See bug#771

        for(i=0, j=0; szId[i] && j<IDFIFSIZE; i++)
        {
                // copy over all numerics and NON-LEADING blanks
                // throw away all leading blanks
                if( (szId[i] >= '0' && szId[i] <= '9') ||
                        (szId[i] == ' ' && j != 0))
                {
                        szTemp[j++] = szId[i];
                }
                // send + and - as space. At other end, when we get a
                // single leading space convert that to +. Leave other spaces
                // unmolested. This is so that EFAX-to-EFAX in G3 mode
                // with canonical numbers, reply will work correctly
                // see bug#771
                if(szId[i] == '+' || szId[i] == '-')
                {
                        szTemp[j++] = ' ';
                }
        }
        szTemp[j++] = 0;
}
else
{
        _fmemcpy(szTemp, szId, IDFIFSIZE);
        szTemp[IDFIFSIZE] = 0;
}

        (MyDebugPrint(pTG,  LOG_ALL, "CreateID: Got<%s> Sent<%s>\r\n", (LPSTR)szId, (LPSTR)szTemp));

        if(_fstrlen(szTemp))
        {
                CreateStupidReversedFIFs(pTG, npfr->fif, szTemp);

                npfr->ifr = ifr;
                npfr->cb = IDFIFSIZE;
                npfs->rglpfr[npfs->uNumFrames++] = npfr;
                npfs->uFreeSpaceOff += IDFIFSIZE+sizeof(FRBASE);
                BG_CHK(npfs->uFreeSpaceOff <= fsSize(pTG, npfs) && npfs->uNumFrames <= MAXFRAMES);
        }
        else
        {
                (MyDebugPrint(pTG, LOG_ALL,  "WARNING: %s ID is EMPTY. Not sending\r\n", (LPSTR)(fStrip ? "STRIPPED" : "ORIGINAL") ));
        }
}


















void CreateDISorDTC(PThrdGlbl pTG, IFR ifr, NPRFS npfs, NPBCFAX npbcFax, NPLLPARAMS npll)
{
        USHORT  uLen;
        NPFR    npfr;

        if( fsFreeSpace(pTG, npfs) <= (sizeof(FRBASE)+sizeof(DIS)) ||
                npfs->uNumFrames >= MAXFRAMES)
        {
                BG_CHK(FALSE);
                return;
        }
        npfr = (NPFR) fsFreePtr(pTG, npfs);

        uLen = SetupDISorDCSorDTC(pTG, (NPDIS)npfr->fif, npbcFax, npll, 0, npll->fECM64);
        BG_CHK(uLen >= 3 && uLen <= 8);
        // BG_CHK(npfr->fif[uLen-1] == 0);      // send a final 0 byte

        npfr->ifr = ifr;
        npfr->cb = (BYTE) uLen;
        npfs->rglpfr[npfs->uNumFrames++] = npfr;
        npfs->uFreeSpaceOff += uLen+sizeof(FRBASE);
        BG_CHK(npfs->uFreeSpaceOff <= fsSize(pTG, npfs) && npfs->uNumFrames <= MAXFRAMES);
}






















VOID CreateNSSTSIDCS(PThrdGlbl pTG, NPPROT npProt, NPRFS npfs, USHORT uWhichDCS)
{

        // uWhichDCS:: 0==1st DCS  1==after NoReply  2==afterFTT

        NPBC    npbc = (NPBC)&(npProt->SendParams);
        BOOL    fEfax;
        // Use bigger buf. Avoid truncating Id before stripping alphas
        char    szTSI[MAXTOTALIDLEN + 2];


        BG_CHK(npProt->fSendParamsInited);
        BG_CHK(npbc->bctype==SEND_PARAMS);
        BG_CHK(npbc->wTotalSize >= sizeof(BC));

        BG_CHK(npProt->fllRecvCapsGot);
        BG_CHK(npProt->fllSendParamsInited);
        BG_CHK(npProt->fHWCapsInited);

/********** moved to the RECVCAPS point. see bug#731 ********************
        if(uWhichDCS==0)                        // don't renegotiate after NoRely or FTT
        {
                NegotiateLowLevelParams(&npProt->llRecvCaps, &npProt->llSendParams,
                        npbc->Fax.AwRes, npbc->Fax.Encoding, &npProt->llNegot);
                npProt->fllNegotiated = TRUE;
                EnforceMaxSpeed(npProt);
        }
*************************************************************************/

        BG_CHK(npProt->fllNegotiated);

        // don't print -- too slow
        // (MyDebugPrint(pTG,  "In CreateNSSTSIDCS after negotiation\r\n"));
        // D_PrintBC(npbc, &npProt->llNegot);

        ZeroRFS(pTG, npfs);

        // Send only TSI-DCS or NSS-DCS. Never a need to send TSI with NSS
        // (can bundle ID into message)

        // extract ID
        // BUGBUG RSL need to get from the Registry.

        // GetTextId(npbc, szTSI, MAXTOTALIDLEN+1);
        if (pTG->LocalID) {
            strcpy (szTSI, pTG->LocalID);
        }


#ifdef OEMNSF
        if(fUsingOEMProt)       // using OEM, not MS At Work NSSs
        {
                WORD wFlags;

                BG_CHK(wOEMFlags);

                wFlags = CreateOEMFrames(pTG, ifrNSS, 0, npbc, &npProt->llNegot, npfs);
                BG_CHK(wFlags);

                if(!(wFlags & OEMNSF_DONTSEND_TSI))
                        CreateIDFrame(pTG, ifrTSI, npfs, szTSI, TRUE); //STRIP alphas in TSI

                if(!(wFlags & OEMNSF_DONTSEND_DCS))
                        CreateDCS(pTG, npfs, &(npbc->Fax), &npProt->llNegot);
        }
        else
#endif //OEMNSF
        {
                fEfax = (npbc->NSS.vMsgProtocol != 0);

                // RSL no NSF
                if(0)
                {
                        // must be TRUE otheriwse we have negotaited ourselves into a corner here
                        BG_CHK(npProt->llNegot.fECM);
                        CreateNSForNSCorNSS(pTG, ifrNSS, npfs, npbc, FALSE); // no ID in NSS
                }
                else
                {
                        // CreateID strips non-numeric parts. Must send TSI when
                        // we do EFAX-to-EFAX in G3 mode. See bug#771
                        if(_fstrlen(szTSI))
                        {
                                // This is for Snowball, as per bug#771
                                CreateIDFrame(pTG, ifrTSI, npfs, szTSI, FALSE); //RSL: DON'T STRIP alphas in TSI
                        }
                }

                CreateDCS(pTG, npfs, &(npbc->Fax), &npProt->llNegot);

                BG_CHK((npbc->NSS.vMsgProtocol == 0) ||
                                (!npbc->Fax.AwRes && !npbc->Fax.Encoding));
        }
}











void CreateDCS(PThrdGlbl pTG, NPRFS npfs, NPBCFAX npbcFax, NPLLPARAMS npll)
{
        USHORT  uLen;
        NPFR    npfr;

        if( fsFreeSpace(pTG, npfs) <= (sizeof(FRBASE)+sizeof(DIS)) ||
                npfs->uNumFrames >= MAXFRAMES)
        {
                BG_CHK(FALSE);
                return;
        }
        npfr = (NPFR) fsFreePtr(pTG, npfs);

        BG_CHK(npbcFax->fPublicPoll==0);
        npbcFax->fPublicPoll = 0;
                // the G3Poll bit *has* to be 0 in DCS
                // else the OMNIFAX G77 and GT croak
                // the PWD/SEP/SUB bits *have* to be 0 in DCS
                // Baud rate, ECM and ECM frame size according to lowlevel negotiation
                // everything else according to high level negotiation

        uLen = SetupDISorDCSorDTC(pTG, (NPDIS)npfr->fif, npbcFax,
                                                                npll, npll->fECM, npll->fECM64);

        BG_CHK(uLen >= 3 && uLen <= 8);
        // BG_CHK(npfr->fif[uLen-1] == 0);      // send a final 0 byte
        // make sure that DCS we send is no longer than the DIS we receive.
        // This should automatically be so
        BG_CHK(pTG->ProtInst.uRemoteDISlen ? (uLen-1 <= pTG->ProtInst.uRemoteDISlen) : TRUE);
        BG_CHK(pTG->ProtInst.uRemoteDTClen ? (uLen-1 <= pTG->ProtInst.uRemoteDTClen) : TRUE);

        // If DCS is longer than the recvd DIS truncate the DCS to the same
        // length as the DIS. (It should never be more than 1byte longer --
        // because of the extra 0).

        if(pTG->ProtInst.uRemoteDISlen && (pTG->ProtInst.uRemoteDISlen < uLen))
                uLen = pTG->ProtInst.uRemoteDISlen;
        else if(pTG->ProtInst.uRemoteDTClen && (pTG->ProtInst.uRemoteDTClen < uLen))
                uLen = pTG->ProtInst.uRemoteDTClen;

        npfr->ifr = ifrDCS;
        npfr->cb = (BYTE) uLen;
        npfs->rglpfr[npfs->uNumFrames++] = npfr;
        npfs->uFreeSpaceOff += uLen+sizeof(FRBASE);
        BG_CHK(npfs->uFreeSpaceOff <= fsSize(pTG, npfs) && npfs->uNumFrames <= MAXFRAMES);
}

#ifdef NSF_TEST_HOOKS

#pragma message("<<WARNING>> INCLUDING NSF TEST HOOKS")









BOOL NSFTestGetNSx (PThrdGlbl pTG, IFR ifr, LPBC lpbcIn,
                      LPBYTE lpbOut, WORD wMaxOut, LPWORD lpwNumFrame)
{
        BOOL fRet=FALSE;
        DWORD_PTR dwKey=ProfileOpen(DEF_BASEKEY, szNSFTEST, fREG_READ);
        char rgchTmp32[32];
        LPSTR lpsz=NULL;
        UINT ucb,ucb0;
        if (!dwKey) goto end;

        switch(ifr)
        {
          case ifrNSF:  lpsz = "NSF";   break;
          case ifrNSS:  lpsz = "NSS";   break;
          case ifrNSC:  lpsz = "NSC";   break;
          default:      BG_CHK(FALSE);          goto end;
        }

        wsprintf(rgchTmp32, "Send%sFrameCount", (LPSTR) lpsz);
        *lpwNumFrame = (WORD) ProfileGetInt(dwKey, rgchTmp32, 0, NULL);

        if(!*lpwNumFrame) goto end;

        // Save space for frame pointer array
        ucb=sizeof(LPFR) * *lpwNumFrame;
        if (wMaxOut <= ucb) goto end;

        wsprintf(rgchTmp32, "Send%sFrames", (LPSTR) lpsz);
        ucb0=ProfileGetData(dwKey, rgchTmp32, lpbOut+ucb, wMaxOut-ucb);
        if (!ucb0) goto end;

#ifdef DEBUG
        {
                char rgchTmp64[64];
                UINT u,v;
                (MyDebugPrint(pTG,  LOG_ERR, "\r\nTEST-NSF: Dump  of %u send frame(s):\r\n",
                                        (unsigned) *lpwNumFrame));
                rgchTmp64[0]=0;
                for (u=0,v=0;u<ucb0;u++)
                {
                  v += wsprintf(rgchTmp64+v, " %02x", (unsigned) lpbOut[ucb+u]);
                  if ((v+8) >= sizeof(rgchTmp64))
                  {
                        (MyDebugPrint(pTG,  LOG_ERR,  "\t%s\r\n", (LPSTR) rgchTmp64));
                        v=0;
                        rgchTmp64[0]=0;
                  }
                }
                (MyDebugPrint(pTG,  LOG_ERR,  "\t%s\r\n", (LPSTR) rgchTmp64));

        }
#endif
        // Initialize frame pointer array
        {
                UINT u;
                UINT ucbtot = ucb+ucb0;
                for (u=0;u<*lpwNumFrame;u++)
                {
                        LPFR lpfr = (LPFR) (lpbOut+ucb);
                        (MyDebugPrint(pTG,  LOG_ERR, "NSFTest: u=%lu, ifr=%lu, cb=%lu, ucb=%lu\r\n",
                                        (unsigned long) u,
                                        (unsigned long) lpfr->ifr,
                                        (unsigned long) lpfr->cb,
                                        (unsigned long) ucb));
                        if (lpfr->ifr!=ifr) goto bad_frames;
                        if (lpfr->cb>100) // awnsfapi.h says max frame size=70.
                                goto bad_frames;
                        if ((ucb+sizeof(FRBASE)+lpfr->cb)>ucbtot)
                                goto bad_frames;

                        ((LPFR *)(lpbOut))[u] = lpfr;
                        ucb+=sizeof(FRBASE)+lpfr->cb;
                }
        }

        fRet=TRUE;
        goto end;

bad_frames:
        (MyDebugPrint(pTG,  LOG_ERR, "TEST-NSF: Bad frames from registry\r\n"));
        // fall through..

end:
        if (dwKey) ProfileClose(dwKey);

        if (!fRet) {(MyDebugPrint(pTG,  LOG_ALL,  "WARNING: NSFTestGetNSx FAILS!\r\n"));}

        return fRet;
}


















BOOL NSFTestPutNSx(PThrdGlbl pTG, IFR ifr, LPLPFR rglpfr, WORD wNumFrame,
                                                LPBC lpbcOut, WORD wBCSize)
{
        BOOL fRet=FALSE;
        DWORD_PTR dwKey=ProfileOpen(DEF_BASEKEY, szNSFTEST, fREG_CREATE|fREG_WRITE);
        char rgchTmp32[32];
        char rgchTmp10[10];
        BYTE rgbTmp256[256];
        LPSTR lpsz=NULL;
        UINT    u;
        UINT ucb=0;

        if (!dwKey) goto end;

        switch(ifr)
        {
          case ifrNSF:  lpsz = "NSF";   break;
          case ifrNSS:  lpsz = "NSS";   break;
          case ifrNSC:  lpsz = "NSC";   break;
          default:      BG_CHK(FALSE);          goto end;
        }

        // Tack frames together...
        ucb=0;
        for(u=0; u<wNumFrame; u++)
        {
                UINT    uLen = sizeof(FRBASE)+rglpfr[u]->cb;

                if ((ucb+uLen) > sizeof(rgbTmp256))
                {
                        (MyDebugPrint(pTG,  LOG_ERR,  "<<WARNING>>NSFTEST: Out of space!\r\n"));
                        break;
                }
                _fmemcpy(rgbTmp256+ucb, (LPBYTE)rglpfr[u], uLen);
                ucb+=uLen;
        }

        if(u)
        {
                wsprintf(rgchTmp32, "Recvd%sFrames", (LPSTR) lpsz);
                if (!ProfileWriteData(dwKey, rgchTmp32, rgbTmp256, ucb)) goto end;
        }

        wsprintf(rgchTmp32, "Recvd%sFrameCount", (LPSTR) lpsz);
        wsprintf(rgchTmp10, "%u", (unsigned) (u&0xff));
        if (!ProfileWriteString(dwKey, rgchTmp32, rgchTmp10, FALSE)) goto end;


        fRet=TRUE;

end:
        if (dwKey) ProfileClose(dwKey);

        if (!fRet) {(MyDebugPrint(pTG,  LOG_ERR,  "NSFTestPutNSx FAILS!\r\n"));}

        return fRet;
}

#endif // NSF_TEST_HOOKS
