/***************************************************************************
 Name     :     RECVFR.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_RECVFR, m)
#define FILEID          FILEID_RECVFR






USHORT FindMSNSx(PThrdGlbl pTG, NPRFS npRecvd)
{
        USHORT  i;

        for(i=0; i<npRecvd->uNumFrames; i++)
        {
                BG_CHK(i < MAXFRAMES);
                if(IsAtWorkNSx(npRecvd->rglpfr[i]->fif, npRecvd->rglpfr[i]->cb))
                {
                        faxTlog((SZMOD "Found MS NSx!!\r\n"));
                        return i+1;
                }
        }
        return 0;
}





void GotRecvFrames(PThrdGlbl pTG, IFR ifr, NPRFS npRecvd, NPDIS npdis, LPBYTE lpbRecvdID,
                                        LPBYTE lpbRecipSubAddr, BCTYPE bctype, NPBC npbc, USHORT wBCSize,
                                        NPLLPARAMS npll)
{
        USHORT          uRet1=0, uRet2=0;

        InitBC(npbc, wBCSize, bctype);

        // RSL remove NSF processing.
        uRet1 = 0;

        if(npRecvd->uNumFrames) // recvd some NSXs
        {
                // scope out NSXs
                if(uRet1)                  // RSL = FindMSNSx(pTG, npRecvd))
                {
                        // found MS NSXs

                        BG_CHK((ifr!=ifrNSF) ? (pTG->ProtInst.llSendCaps.fECM && uRet1==1) : TRUE);
                        // if we got MS NSCs or NSSs then we must be able to do ECM
                        // and we can't get can't get other peoples NSSs/NSCs at same time

                        // setup BC first
                        npbc->bctype = bctype;

                        // all short ptrs into DGROUP get correctly cast to LPs we hope...
                        if(uRet2 = NSX_TO_BC(pTG, ifr, npRecvd->rglpfr, npRecvd->uNumFrames, npbc, wBCSize))
                        {
                                (MyDebugPrint(pTG,  LOG_ERR,  "<<ERROR>> got error %d parsing NSX\r\n", uRet2));
                                // forget we got an NSX
                                // zero out BC again
                                InitBC( npbc, wBCSize, bctype);
                                uRet1 = 0;
                        }
#ifndef NOCHALL
                        else
                        {
                                if(ifr==ifrNSF)
                                {
                                        USHORT uChallLen;
                                        // Poll challenge string is the first POLL_CHALLENGE_LEN
                                        // bytes (following the B5 00 76 signature) of the first
                                        // MS NSF _received_ or the whole thing if it is shorter
                                        // than that
                                        BG_CHK(npRecvd->rglpfr[uRet1-1]->cb > 3);
                                        uChallLen = min(npRecvd->rglpfr[uRet1-1]->cb-3, POLL_CHALLENGE_LEN);
                                        AppendToBCLen( npbc, wBCSize, npRecvd->rglpfr[uRet1-1]->fif+3,
                                                                uChallLen, wChallenge, wChallengeLen);
                                }
                                else if(ifr==ifrNSC)
                                {
                                        // for NSC append _our_ challenge string, i.e.
                                        // first POLL_CHALLENGE_LEN bytes (following the B5 00 76
                                        // signature) of the first MS NSF that _we_sent_out
                                        // or the whole thing if it is shorter than that

                                        AppendToBCLen(npbc, wBCSize, pTG->bSavedChallenge,
                                                pTG->uSavedChallengeLen, wChallenge, wChallengeLen);
                                }
                                // for NSS wChallenge==NULL
                        }
#endif //!NOCHALL
                }
#ifdef OEMNSF
                else if(wOEMFlags && lpfnOEMNSxToBC)
                {
#pragma message("WARNING: OEMNsxToBC: The code here for removing and restoring the FCS bytes hasn't been tested!!!")
                        USHORT uRet3;
         USHORT iFrame;
                        // OEM NSX DLL exists --> do something  for(iFrame=0; iFrame<wNumFrame; iFrame++)

              for(iFrame=0; iFrame < npRecvd->uNumFrames; iFrame++)
                      npRecvd->rglpfr[iFrame]->cb -= 2;     // Subtract 2 to lop off the FCS

                        if(!(uRet3 = lpfnOEMNSxToBC(ifr, npRecvd->rglpfr, npRecvd->uNumFrames, npbc, wBCSize, npll)))
                        {
            //It might be a modem that doesn't pass us the FCS, try again
            for(iFrame=0; iFrame < npRecvd->uNumFrames; iFrame++)
                         npRecvd->rglpfr[iFrame]->cb += 2;     // Put  last two bytes back on
                                // zero out BC again
                                InitBC(pTG, npbc, wBCSize, bctype);
            if(!(uRet3 = lpfnOEMNSxToBC(ifr, npRecvd->rglpfr, npRecvd->uNumFrames, npbc, wBCSize, npll)))
                           {
               (MyDebugPrint(pTG,  LOG_ERR,  "<<ERROR>> got error parsing OEM NSF\r\n"));
                                   // zero out BC again
                                   InitBC(pTG, npbc, wBCSize, bctype);
            }
                        }
                        else
                        {
                                faxTlog((SZMOD "Using OEM Protocol\r\n"));
                                fUsingOEMProt = TRUE;
                                if(uRet3 & OEMNSF_IGNORE_DIS)
                                        npdis = NULL;
                                if(uRet3 & OEMNSF_IGNORE_CSI)
                                        lpbRecvdID = NULL;
                        }
                }
#endif
        }

        if(npdis)
        {
                // extract DIS caps     into BC and LL
                ParseDISorDCSorDTC(pTG, npdis, &(npbc->Fax), npll, (ifr==ifrNSS ? TRUE : FALSE));
        }

        // If an ID is recvd in NSF/NSS/NSC the CSI/TSI/CIG should NOT overwrite it
        if(lpbRecvdID && !HasTextId(npbc))
        {
                PutTextId(npbc, wBCSize, lpbRecvdID, (int)_fstrlen(lpbRecvdID), TEXTCODE_ASCII);
                //PutNumId(npbc, wBCSize, lpbRecvdID, (int) _fstrlen(lpbRecvdID), TEXTCODE_ASCII);
        }

        // If a subaddress is recvd in NSF/NSS/NSC the SUB frame should NOT overwrite it
        if(lpbRecipSubAddr && !HasRecipSubAddr( npbc))
        {
                PutRecipSubAddr( npbc, wBCSize, lpbRecipSubAddr, (int)_fstrlen(lpbRecipSubAddr));
        }


        if(uRet1 > 0)
        {
                npll->fECM = TRUE;      // ignore ECM bit in DIS, if MS NSF present
        }
}







BOOL AwaitSendParamsAndDoNegot(PThrdGlbl pTG, BOOL fSleep)
{
        // This does actual negotiation & gets SENDPARAMS. It could potentially
        // return SEND_POLLREQ instead.
        if(!ProtGetBC(pTG, SEND_PARAMS, fSleep))
        {
                if(fSleep)
                {
                        // ICommFailureCode already set
                        MyDebugPrint(pTG, LOG_ALL, "ATTENTION: AwaitSendParamsAndDoNegot pTG->ProtInst.fAbort = TRUE\n");
                        pTG->ProtInst.fAbort = TRUE;
                }
                return FALSE;
        }

        // negotiate low-level params here. (a) because this is where
        // high-level params are negotiated (b) because it's inefficient to
        // do it on each DCS (c) because RTN breaks otherwise--see bug#731

        // llRecvCaps and llSendParams are set only at startup
        // SendParams are set in ProtGetBC just above
        // llNegot is the return value. So this can be called
        // only at the end of this function

        // negot lowlevel params if we are sending and not polling
        if(!pTG->ProtInst.fAbort && pTG->ProtInst.fSendParamsInited)
        {
                NegotiateLowLevelParams(pTG, &pTG->ProtInst.llRecvCaps, &pTG->ProtInst.llSendParams,
                                                        pTG->ProtInst.SendParams.Fax.AwRes,
                                                        pTG->ProtInst.SendParams.Fax.Encoding,
                                                        &pTG->ProtInst.llNegot);
                pTG->ProtInst.fllNegotiated = TRUE;

                // This chnages llNegot->Baud according to the MaxSpeed settings
                EnforceMaxSpeed(pTG);
        }
        return TRUE;
}













void GotRecvCaps(PThrdGlbl pTG)
{
        BG_CHK(pTG->ProtInst.fRecvdDIS);

        if(!pTG->ProtInst.llSendParams.fECM)
        {
                // if we can't do ECM on send, ignore the received NSFs
                // zap the ECM bits of the received DTC
                pTG->ProtInst.RemoteDIS.ECM = 0;
                pTG->ProtInst.RemoteDIS.SmallFrame = 0;
        }

        GotRecvFrames(pTG, ifrNSF, &pTG->ProtInst.RecvdNS,
                (pTG->ProtInst.fRecvdDIS ? &pTG->ProtInst.RemoteDIS : NULL),
                (pTG->ProtInst.fRecvdID  ?  pTG->ProtInst.bRemoteID : NULL),
                (pTG->ProtInst.fRecvdSUB ?  pTG->ProtInst.bRecipSubAddr : NULL),
                RECV_CAPS, (NPBC)&pTG->ProtInst.RecvCaps, sizeof(pTG->ProtInst.RecvCaps),
                &pTG->ProtInst.llRecvCaps);

        pTG->ProtInst.fRecvCapsGot = TRUE;
        pTG->ProtInst.fllRecvCapsGot = TRUE;

#ifdef FILET30
        // Send up raw caps.
        ICommRawCaps(
                pTG,
                (LPBYTE) (pTG->ProtInst.fRecvdID ?  pTG->ProtInst.bRemoteID: NULL),
                (LPBYTE) (pTG->ProtInst.fRecvdDIS ? (LPBYTE) (&(pTG->ProtInst.RemoteDIS)):NULL),
                (USHORT) (pTG->ProtInst.fRecvdDIS ? pTG->ProtInst.uRemoteDISlen:0),
                (LPFR FAR *) (pTG->ProtInst.RecvdNS.uNumFrames ? pTG->ProtInst.RecvdNS.rglpfr:NULL),
                (USHORT) (pTG->ProtInst.RecvdNS.uNumFrames)
        );

#endif

        // send off BC struct to higher level
        if(!ICommRecvCaps(pTG, (LPBC)&pTG->ProtInst.RecvCaps))
        {
                // ICommFailureCode already set
                MyDebugPrint(pTG, LOG_ALL, "ATTENTION: GotRecvCaps pTG->ProtInst.fAbort = TRUE\n");
                pTG->ProtInst.fAbort = TRUE;
        }

        // This need to be moved into whatnext.NodeA so that we can set
        // param to FALSE (no sleep) and do the stall thing
        AwaitSendParamsAndDoNegot(pTG, TRUE);
}
















void GotPollReq(PThrdGlbl pTG)
{
        BG_CHK(pTG->ProtInst.fRecvdDTC);

        if(!pTG->ProtInst.llSendParams.fECM)
        {
                // if we can't do ECM on send, ignore the received NSFs
                // zap the ECM bits of the received DTC
                pTG->ProtInst.RemoteDTC.ECM = 0;
                pTG->ProtInst.RemoteDTC.SmallFrame = 0;
        }

        GotRecvFrames(pTG, ifrNSC, &pTG->ProtInst.RecvdNS,
                (pTG->ProtInst.fRecvdDTC ? &pTG->ProtInst.RemoteDTC : NULL),
                (pTG->ProtInst.fRecvdID  ?  pTG->ProtInst.bRemoteID : NULL),
                (pTG->ProtInst.fRecvdSUB ?  pTG->ProtInst.bRecipSubAddr : NULL),
                RECV_POLLREQ, (NPBC)&pTG->ProtInst.RecvPollReq, sizeof(pTG->ProtInst.RecvPollReq),
                &pTG->ProtInst.llRecvCaps);

        pTG->ProtInst.fRecvPollReqGot = TRUE;
        pTG->ProtInst.fllRecvCapsGot = TRUE;

        // send off BC struct to higher level
        if(!ICommRecvPollReq(pTG, (LPBC)&pTG->ProtInst.RecvPollReq))
        {
                // ICommFailureCode already set
                MyDebugPrint(pTG, LOG_ALL, "ATTENTION: GetPollReq pTG->ProtInst.fAbort = TRUE\n");
                pTG->ProtInst.fAbort = TRUE;
        }


        //
        // This need to be moved into whatnext.NodeA so that we can set
        // param to FALSE (no sleep) and do the stall thing
        AwaitSendParamsAndDoNegot(pTG, TRUE);
}









void GotRecvParams(PThrdGlbl pTG)
{
        GotRecvFrames(pTG, ifrNSS, &pTG->ProtInst.RecvdNS,
                (pTG->ProtInst.fRecvdDCS ? (&pTG->ProtInst.RemoteDCS) : NULL),
                (pTG->ProtInst.fRecvdID ? pTG->ProtInst.bRemoteID : NULL),
                (pTG->ProtInst.fRecvdSUB ?  pTG->ProtInst.bRecipSubAddr : NULL),
                RECV_PARAMS, (NPBC)&pTG->ProtInst.RecvParams, sizeof(pTG->ProtInst.RecvParams),
                &pTG->ProtInst.llRecvParams);

        // If DCS has fECM set then we must've said we could do ECM
        BG_CHK(pTG->ProtInst.llRecvParams.fECM ? pTG->ProtInst.llSendCaps.fECM : 1);

        pTG->ProtInst.fRecvParamsGot = TRUE;
        pTG->ProtInst.fllRecvParamsGot = TRUE;

        if(!ICommRecvParams(pTG, (LPBC)&pTG->ProtInst.RecvParams)) {
                MyDebugPrint(pTG, LOG_ALL, "ATTENTION: GotRecvParams pTG->ProtInst.fAbort = TRUE\n");
                pTG->ProtInst.fAbort = TRUE;
        }

        ICommSetRecvMode(pTG, ProtReceivingECM(pTG));
}

