/*
 * Copyright 2009 Funambol, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

#include <base/util/utils.h>
#include <spds/SyncMLProcessor.h>
#include <syncml/core/NextNonce.h>
#include <syncml/core/TagNames.h>
#include <syncml/core/SyncHdr.h>

#include "commontypes.h"
#include "Errors.h"
#include "Logger/LoggerMacroses.h"
#include "Utils.h"

#include "executionqueue/IExecutionQueue.h"
#include "treemanager/AlertCommand.h"
#include "treemanager/MOTreeAddCommand.h"
#include "treemanager/MOTreeAtomicCommand.h"
#include "treemanager/MOTreeCopyCommand.h"
#include "treemanager/MOTreeDeleteCommand.h"
#include "treemanager/MOTreeExecCommand.h"
#include "treemanager/MOTreeGetCommand.h"
#include "treemanager/MOTreeReplaceCommand.h"
#include "treemanager/MOTreeSequenceCommand.h"

#include "serverexchange/LOCollector.h"
#include "serverexchange/ResponseProcessor.h"
#include "serverexchange/ICommandsSink.h"
#include "serverexchange/IServerExchangeManager.h"
#include "serverexchange/wrappers/SCommandFactory.h"
#include "serverexchange/wrappers/SAlertCommand.h"
#include "serverexchange/wrappers/SStatusCommand.h"

#define HTTP_PREFIX     "http://"
#define HTTPS_PREFIX    "https://"


using namespace NS_DM_Client;
using namespace NS_DM_Client::NS_Communication;
using namespace NS_DM_Client::NS_SyncMLCommand;

static const char * c_LogName = "ResponseProcessor";


ResponseProcessor::ResponseProcessor(ConnectionInfo &ci, NS_SyncMLCommand::ICommandsSink *pCS, ProfileComponentsHolder *pPCH) :
    m_sessionFinished(false),
    m_checkForCred(false),
    m_changeAuthType(false),
    m_cServerID(NULL),
    m_responseCommandsCount(0),
    m_pConnInfo(&ci),
    m_pSyncML(NULL),
    m_pLOCollector(NULL),
    m_pPCH(pPCH)
{
    m_pCommandsSink = pCS;
}


ResponseProcessor::~ResponseProcessor()
{
    SAFE_DELETE_ARR(m_cServerID);
    SAFE_DELETE(m_pSyncML);
    SAFE_DELETE(m_pLOCollector);
}


ResponseProcessor::ProcessingStatus ResponseProcessor::Process(const char * xmlresponse, bool sumode)
{
GDLDEBUG("ENTER");

    if (!xmlresponse) return PS_InvalidParam;

    ProcessingStatus result = PS_Successful;
    Funambol::SyncMLProcessor processor;
    m_pSyncML = processor.processMsg(const_cast<char*>(xmlresponse));
    m_changeAuthType = m_checkForCred = false;
    m_sessionFinished = m_pConnInfo->state.connectionFinished = true;

    do
    {
        if (!m_pSyncML || !m_pSyncML->getSyncHdr() || !m_pSyncML->getSyncBody())
        {
            result = PS_MalformedMessage;
            break;
        }

        if (!sumode && !m_pSession->IsSendingLO())
        {
            if (m_pSession->State().ServerAuthenticated)
            {
                GDLINFO("Server authenticated in prev message, skip check");
            }
            else
            {
                if (m_pSession->IsServerCredValid(m_pSyncML->getSyncHdr()->getCred()))
                {
                    m_pSession->SetServerAuthenticated(true);
                    m_checkForCred = false;
                    GDLINFO("Server authenticated");
                }
                else
                {
                    GDLDEBUG("Server not authenticated (Cred info is absent or invalid)");

                    // TODO - review
                    if (!m_pSyncML->getSyncHdr()->getCred() ||
                        (m_pSyncML->getSyncHdr()->getCred() &&
                         strcmp(m_pSession->GetTypeName(), m_pSyncML->getSyncHdr()->getCred()->getType())))
                    {
                        m_changeAuthType = true;
                        m_checkForCred = true;
                    }
                    else if (m_pSession->AcceptsNonces())
                    {
                        m_pConnInfo->state.hasToResendLastCommands = true;
                        m_checkForCred = true;
                    }
                    else
                    {
                        result = PS_InvalidServerCred;
                        m_pConnInfo->state.connectionFinished = true;
                        m_pConnInfo->state.hasToResendLastCommands = false;
                        break;
                    }
                }
            }
        }

        Funambol::ArrayList *pCommands = m_pSyncML->getSyncBody()->getCommands();
        if (!pCommands || !pCommands->size())
        {
            result = PS_MalformedMessage; break;
        }

        processHeader();
        m_pConnInfo->SetLOMode(!m_pSyncML->isLastMessage());
        GDLDEBUG("Final tag is %s", m_pSyncML->isLastMessage() ? "set" : "not set");
        GDLDEBUG("");
        
        if (!m_pSyncML->isLastMessage() && !m_pConnInfo->state.hasLOSending)
        {
            if (!m_pLOCollector)
            {
                m_pLOCollector = new(std::nothrow) LOCollector();
                if(m_pLOCollector == (LOCollector*)NULL)
                {
                    GDLWARN("new LOCollector");
                }
                GDLDEBUG("Create LOCollector %x", m_pLOCollector);
            }
        }

        if (m_pConnInfo->IsWaitingForNextChunk())
        {
            // check whether alert status is ok
            checkForNextChunkData();
        }

        GDLDEBUG("Server response contains   %d command%s", pCommands->size(), pCommands->size()==1 ? "" : "s");

        initProcessing(sumode, pCommands->size());

        m_pConnInfo->state.repeatAuthentication = false;

        int statusCommandsCount = 0;
        for (int i=0; i<pCommands->size(); ++i)
        {
            Funambol::AbstractCommand *command = static_cast<Funambol::AbstractCommand*>(pCommands->get(i));
            if (command)
            {
                processCommand(command);
                if (!strcmp(STATUS_COMMAND_NAME, command->getName()))
                    statusCommandsCount++;
            }
        }

//      repeatAuthentication
        if (!sumode && !m_pSession->State().ServerAuthenticated && !m_pSession->CredentialsSent())
        {
            GDLDEBUG("repeat authentication");
            m_pConnInfo->state.repeatAuthentication = true;
            m_pConnInfo->state.connectionFinished = false;
        }
    } while (0);

    SAFE_DELETE(m_pSyncML);

GDLDEBUG("LEAVE");

    return result;
}


// Check received response for the status on the alert 1222.
void ResponseProcessor::checkForNextChunkData()
{
GDLDEBUG("ENTER");

    Funambol::ArrayList *pCommands = m_pSyncML->getSyncBody()->getCommands();
    for (int i=0; i<pCommands->size(); ++i)
    {
        Funambol::AbstractCommand *pCommand = static_cast<Funambol::AbstractCommand*>(pCommands->get(i));
        if (pCommand && !strcmp(STATUS_COMMAND_NAME, pCommand->getName()))
        {
            Funambol::Status *pStatus = (Funambol::Status*)pCommand;

            char bufOK[16];
            memset(bufOK, '\0', 16);
            __sprintf(bufOK, "%d", e_Ok);

            if (pStatus && pStatus->getCmd() && pStatus->getData() && pStatus->getData()->getData() &&
                !strcmp(ALERT_COMMAND_NAME, pStatus->getCmd()) &&
                !strcmp(bufOK, pStatus->getData()->getData()))
            {
                // message from server contains chunk with LO data
                m_pConnInfo->SetLOMode(true);
                return;
            }
        }
    }
    m_pConnInfo->SetLOMode(false);

GDLDEBUG("LEAVE");
}


bool ResponseProcessor::commandHasLOChunk(Funambol::ItemizedCommand *cmd)
{
    if (!cmd || !cmd->getItems())
        return false;

    Funambol::ArrayList *pItems = cmd->getItems();
    if (pItems->size() == 1)
    {
        Funambol::Item *pItem = (Funambol::Item *) pItems->get(0);
        return (pItem && pItem->getMoreData());
    }
    return false;
}


void ResponseProcessor::enqueueExCommand(ActionCommand &cmd)
{
GDLDEBUG("ENTER");

    if (m_pCommandsSink)
        cmd.SetCommandsSink(*m_pCommandsSink);
    if (!m_pPCH->GetExecutionQueue()->Add(cmd))
    {
        delete &cmd;
    }

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processCommand(Funambol::AbstractCommand *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;
    
    const char *name = cmd->getName();
    if (m_checkForCred && strcmp(name, STATUS_COMMAND_NAME))
    {
        m_pConnInfo->msgState.DecCommandsCount();
        return;
    }

    GDLDEBUG("process command '%s', id=%s cr only - %s", 
        name, 
        cmd->getCmdID() ? cmd->getCmdID()->getCmdID() : "[CmdID is absent in command's body]", 
        m_checkForCred ? "yes" : "no");

    if (m_pConnInfo->IsInLOMode() && (!strcmp(name, ADD_COMMAND_NAME) || !strcmp(name, REPLACE_COMMAND_NAME)))
    {
        GDLDEBUG("before process chunk in command '%s' Meta - %x", name, cmd->getMeta());
        Funambol::ItemizedCommand *pICmd = static_cast<Funambol::ItemizedCommand*>(cmd);
        if (pICmd && 0 <= processLOChunk(*pICmd))
        {
            GDLDEBUG("LO chunk processed");
            return;
        }
        // negative value means passed command does not carry chunked data
        // and should be processed in ordinal way
    }
    

    if (name && !strcmp(name, STATUS_COMMAND_NAME))
    {
        processStatus(static_cast<Funambol::Status*>(cmd));
    }
    else if (name && !strcmp(name, ALERT_COMMAND_NAME))
    {
        processAlert(static_cast<Funambol::Alert*>(cmd));
    }
    else if (name && !strcmp(name, ADD_COMMAND_NAME))
    {
        processAdd(static_cast<Funambol::Add*>(cmd));
    }
    else if (name && !strcmp(name, ATOMIC_COMMAND_NAME))
    {
        processAtomic(static_cast<Funambol::Atomic*>(cmd));
    }
    else if (name && !strcmp(name, COPY_COMMAND_NAME))
    {
        processCopy(static_cast<Funambol::Copy*>(cmd));
    }
    else if (name && !strcmp(name, DELETE_COMMAND_NAME))
    {
        processDelete(static_cast<Funambol::Delete*>(cmd));
    }
    else if (name && !strcmp(name, EXEC_COMMAND_NAME))
    {
        processExec(static_cast<Funambol::Exec*>(cmd));
    }
    else if (name && !strcmp(name, GET_COMMAND_NAME))
    {
        processGet(static_cast<Funambol::Get*>(cmd));
    }
    else if (name && !strcmp(name, REPLACE_COMMAND_NAME))
    {
        processReplace(static_cast<Funambol::Replace*>(cmd));
    }
    else if (name && !strcmp(name, RESULTS_COMMAND_NAME))
    {
        processResults(static_cast<Funambol::Results*>(cmd));
    }
    else if (name && !strcmp(name, SEQUENCE_COMMAND_NAME))
    {
        processSequence(static_cast<Funambol::Sequence*>(cmd));
    }

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processAlert(Funambol::Alert *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    int data = cmd->getData();
    if (AC_LO_REQUEST_NEXT_CHUNK == data)
    {
        // insert status with 200 on Alert into the 0 pos
        if (cmd->getCmdID())
            m_pConnInfo->SetNextChunkAlertCmdID(cmd->getCmdID()->getCmdID());
        m_pConnInfo->state.connectionFinished = false;
        m_pConnInfo->msgState.DecCommandsCount();
    }
    else if (AC_SESSION_ABORT == data)
    {
        GDLDEBUG("abort session with server");
        m_pConnInfo->state.abortConnection = true;
    }
    else
    {
        AlertPtr ptrAlert((Funambol::Alert*)cmd->clone());
        if(ptrAlert.get() == NULL)
        {
            GDLWARN("ptrAlert is NULL");
        }
        ActionCommand *pAlertCmd = new(std::nothrow) AlertCommand(m_pPCH, ptrAlert,
            m_pConnInfo->LastServerMessageID(), m_cServerID);
        if(pAlertCmd == (ActionCommand*)NULL)
        {
            GDLWARN("new AlertCommand");
        }
        enqueueExCommand(*pAlertCmd);
    }

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processAdd(Funambol::Add *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    AddPtr ptrAdd((Funambol::Add*)cmd->clone());
    if(ptrAdd.get() == NULL)
    {
        GDLWARN("ptrAdd is NULL");
    }
    ActionCommand *pAddCmd = new(std::nothrow) MOTreeAddCommand(m_pPCH, ptrAdd,
        m_pConnInfo->LastServerMessageID(), m_cServerID);
    if(pAddCmd == (ActionCommand*)NULL)
    {
        GDLWARN("new MOTreeAddCommand");
    }
    enqueueExCommand(*pAddCmd);

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processAtomic(Funambol::Atomic *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    if (cmd->getCommands())
        m_pConnInfo->msgState.IncCommandsCount(cmd->getCommands()->size());

    AtomicPtr ptrAtomic((Funambol::Atomic*)cmd->clone());
    if(ptrAtomic.get() == NULL)
    {
        GDLWARN("ptrAtomic is NULL");
    }
    ActionCommand *pAtomicCmd = new(std::nothrow) MOTreeAtomicCommand(m_pPCH, ptrAtomic,
        m_pConnInfo->LastServerMessageID(), m_cServerID);
    if(pAtomicCmd == (ActionCommand*)NULL)
    {
        GDLWARN("new MOTreeAtomicCommand");
    }
    enqueueExCommand(*pAtomicCmd);

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processCopy(Funambol::Copy *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    CopyPtr ptrGet((Funambol::Copy*)cmd->clone());
    if(ptrGet.get() == NULL)
    {
        GDLWARN("ptrGet is NULL");
    }
    ActionCommand *pCopyCmd = new(std::nothrow) MOTreeCopyCommand(m_pPCH, ptrGet,
        m_pConnInfo->LastServerMessageID(), m_cServerID);
    if(pCopyCmd == (ActionCommand*)NULL)
    {
        GDLWARN("new MOTreeCopyCommand");
    }
    enqueueExCommand(*pCopyCmd);

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processDelete(Funambol::Delete *cmd)
{
GDLDEBUG("ENTER");
    if (!cmd) return;

    DeletePtr ptrDelete((Funambol::Delete*)cmd->clone());
    if(ptrDelete.get() == NULL)
    {
        GDLWARN("ptrDelete is NULL");
    }
    ActionCommand *pDeleteCmd = new(std::nothrow) MOTreeDeleteCommand(m_pPCH, ptrDelete,
        m_pConnInfo->LastServerMessageID(), m_cServerID);
    if(pDeleteCmd == (ActionCommand*)NULL)
    {
        GDLWARN("new MOTreeDeleteCommand");
    }
    enqueueExCommand(*pDeleteCmd);
GDLDEBUG("LEAVE");
}


void ResponseProcessor::processExec(Funambol::Exec *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    ExecPtr ptrExec((Funambol::Exec*)cmd->clone());
    if(ptrExec.get() == NULL)
    {
        GDLWARN("ptrExec is NULL");
    }
    ActionCommand *pExecCmd = new(std::nothrow) MOTreeExecCommand(m_pPCH, ptrExec,
        m_pConnInfo->LastServerMessageID(), m_cServerID);
    if(pExecCmd == (ActionCommand*)NULL)
    {
        GDLWARN("new MOTreeExecCommand");
    }
    enqueueExCommand(*pExecCmd);

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processGet(Funambol::Get *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    GetPtr ptrGet((Funambol::Get*)cmd->clone());
    if(ptrGet.get() == NULL)
    {
        GDLWARN("ptrGet is NULL");
    }
    MOTreeGetCommand *pGetCmd = new(std::nothrow) MOTreeGetCommand(m_pPCH, ptrGet,
        m_pConnInfo->LastServerMessageID(), m_cServerID);
    if(pGetCmd == (ActionCommand*)NULL)
    {
        GDLWARN("new MOTreeGetCommand");
    }
    pGetCmd->SetMaxObjSize(m_pConnInfo->settings.MaxObjSize);
    enqueueExCommand(*pGetCmd);

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processHeader()
{
GDLDEBUG("ENTER");

    m_pConnInfo->SetLastServerMessageID(m_pSyncML->getSyncHdr()->getMsgID());
    Funambol::Meta *pMeta = m_pSyncML->getSyncHdr()->getMeta();
    if (pMeta)
    {
        m_pConnInfo->settings.MaxMsgSize = pMeta->getMaxMsgSize();
        m_pConnInfo->settings.MaxObjSize = pMeta->getMaxObjSize();
    }

GDLDEBUG("LEAVE");
}

void ResponseProcessor::processReplace(Funambol::Replace *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    ReplacePtr ptrReplace((Funambol::Replace*)cmd->clone());
    if(ptrReplace.get() == NULL)
    {
        GDLWARN("ptrReplace is NULL");
    }
    ActionCommand *pReplaceCmd = new(std::nothrow) MOTreeReplaceCommand(m_pPCH, ptrReplace,
        m_pConnInfo->LastServerMessageID(), m_cServerID);
    if(pReplaceCmd == (ActionCommand*)NULL)
    {
        GDLWARN("new MOTreeReplaceCommand");
    }
    enqueueExCommand(*pReplaceCmd);

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processResults(Funambol::Results *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    m_pConnInfo->msgState.DecCommandsCount();

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processSequence(Funambol::Sequence *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    // increase number of commands to be processed
    if (cmd->getCommands())
        m_pConnInfo->msgState.IncCommandsCount(cmd->getCommands()->size());

    SequencePtr ptrSequence((Funambol::Sequence*)cmd->clone());
    if(ptrSequence.get() == NULL)
    {
        GDLWARN("ptrSequence is NULL");
    }
    ActionCommand *pSequenceCmd = new(std::nothrow) MOTreeSequenceCommand(m_pPCH, ptrSequence,
        m_pConnInfo->LastServerMessageID(), m_cServerID);
    if(pSequenceCmd == (ActionCommand*)NULL)
    {
        GDLWARN("new MOTreeSequenceCommand");
    }
    enqueueExCommand(*pSequenceCmd);

GDLDEBUG("LEAVE");
}


void ResponseProcessor::processStatus(Funambol::Status *cmd)
{
GDLDEBUG("ENTER");

    if (!cmd) return;

    if (!strcmp(cmd->getCmdRef(), "0") && !strcmp(cmd->getCmd(), "SyncHdr"))
    {
        // we got a status about authentication on server
        //bool authenticated = m_pSession->IsAuthenticationPassed(*cmd);
        const char *data = "";
        if (cmd->getData())
            data = cmd->getData()->getData();
        int code = atoi(data);

        GDLDEBUG("status on SyncHdr: %d", code);
        if (AUTHENTICATION_ACCEPTED == code || OK == code)
        {
//          m_pPCH->GetNotificationCenter()->SessionStarted(true);
//          m_pPCH->GetServerExchangeManager()->NotifySessionStarted();
//          m_serverExchange.NotifySessionStarted();
            m_pSession->SetClientAuthenticated(true);
            m_pConnInfo->SetAuthenticated(true); // nice
            m_pConnInfo->state.hasToResendLastCommands = false;
            m_pConnInfo->state.authenticationFailed = false;

            if (cmd->getChal())
            {
                m_pSession->ReadChal(*(cmd->getChal()));
            }

            // get resp uri from SyncBody
            const char * responseURI = m_pSyncML->getSyncHdr()->getRespURI();
            if (responseURI)
            {
                GDLDEBUG("response url: %s", responseURI);
                if (strlen(responseURI))
                    m_pConnInfo->SetSessionURL(responseURI); // TODO move to processHeader

                GDLDEBUG("server auth status processed");
            }
            else
            {
                GDLDEBUG("server response has no RespURI set");
            }
            m_pConnInfo->msgState.DecCommandsCount();
        }
        else if (INVALID_CREDENTIALS == code || MISSING_CREDENTIALS == code)
        {
            m_pConnInfo->msgState.DecCommandsCount();
            m_pSession->SetClientAuthenticated(false);

            if (m_pSession->CredentialsSent() && !m_changeAuthType)
            {
                m_pConnInfo->state.authenticationFailed = true;
                m_pConnInfo->state.hasToResendLastCommands = false;
                m_pConnInfo->state.connectionFinished = true;
                m_sessionFinished = true;
            }
            else if (cmd->getChal())
            {
                m_pSession->ReadChal(*(cmd->getChal()));
                m_pConnInfo->state.hasToResendLastCommands = true;
                m_pConnInfo->state.repeatAuthentication = true;
                m_pConnInfo->state.connectionFinished = m_changeAuthType;
                m_sessionFinished = false;
            }
        }
        else
        {
            m_pConnInfo->SetAuthenticated(false);
            m_pConnInfo->msgState.DecCommandsCount();
            GDLDEBUG("\n\nServer refused authentication data\n\n");
        }
    }
    else
    {
        // parse responses from server on commands from client
        m_pConnInfo->msgState.DecCommandsCount();
        GDLDEBUG("for pending: %s, msg ref %s, cmd ref %s", cmd->getCmd(), cmd->getMsgRef(), cmd->getCmdRef());
        if (cmd->getData())
        {
            const char *data = cmd->getData()->getData();
            int value = atoi(data);
            if (e_ChunkedItemAcceptedAndBuffered == value) // server response on command is 213 - OK
                m_pConnInfo->state.hasToSendNextChunk = true;
        }
    }

GDLDEBUG("LEAVE");
}


// returned value:
// > 0  - error code is returned, on error happened during LO chunk processing
// = 0  - LO chunk successfully processed
// =-1  - command does not contain chunk, and should be processed with other routines
int ResponseProcessor::processLOChunk(Funambol::ItemizedCommand &cmd)
{
GDLDEBUG("ENTER");

    int res = -1;
    if (m_pLOCollector && cmd.getItems() && cmd.getItems()->size() == 1)
    {
        GDLDEBUG("process next chunk, cmd - %s", cmd.getName());
        Funambol::Item *item = (Funambol::Item *)cmd.getItems()->get(0);
        if (item)
        {
            res = m_pLOCollector->AddChunk(cmd);
            GDLDEBUG("  status of chunk processing: %d, cmdsink: %d", res, m_pCommandsSink);

            if (res > 0)
            {
                if (e_ChunkedItemAcceptedAndBuffered == res)
                {
                    if (m_pLOCollector->IsCompleted())
                    {
                        ItemizedCommandPtr ptrCmd = m_pLOCollector->GetResultCmd();
                        if(ptrCmd.get() == NULL)
                        {
                            GDLWARN("ptrCmd is NULL");
                        }
                        GDLDEBUG("  process command with completed LO inside");
                        // collector must be deleted before processing collected command
                        SAFE_DELETE(m_pLOCollector);
                        m_pConnInfo->SetWaitingForNextChunk(false);
                        m_pConnInfo->SetLOMode(false);
                        processCommand(ptrCmd.get());
                    }
                    else
                    {
                        SCommandPtr ptrStatus = SCommandFactory::CreateStatus((StatusCode)res, cmd);
                        if(ptrStatus.get() == NULL)
                        {
                            GDLWARN("ptrStatus is NULL");
                        }
                        GDLDEBUG("  LO chunk appended");
                        if (m_pCommandsSink)
                            m_pCommandsSink->AddCommand(ptrStatus, NULL);
                        // generate Alert to server to get next chunk
                        SAlertCommand *pAlert = new(std::nothrow) SAlertCommand(AC_LO_REQUEST_NEXT_CHUNK);
                        if(pAlert == (SAlertCommand*)NULL)
                        {
                            GDLWARN("new SAlertCommand");
                        }
                        if (m_pCommandsSink)
                            m_pCommandsSink->AddCommand(SCommandPtr(pAlert), NULL);
                        m_pConnInfo->SetWaitingForNextChunk(true);
                    }
                }
                else
                {
                    // on any error in collector - stop collecting LO
                    GDLDEBUG("  appending chunk ended with result %d", res);
                    SAFE_DELETE(m_pLOCollector);
                    m_pConnInfo->SetLOMode(false);
                    m_pConnInfo->SetWaitingForNextChunk(false);
                    if (m_pCommandsSink)
                        m_pCommandsSink->AddCommand(SCommandFactory::CreateStatus((StatusCode)res, cmd), NULL);
                }
            }

            if (e_ChunkedItemAcceptedAndBuffered == res)
                return 0;
        }
    }

GDLDEBUG("LEAVE");

    return res;
}


void ResponseProcessor::initProcessing(bool sumode, int commandsCount)
{
GDLDEBUG("ENTER");

    SAFE_DELETE_ARR(m_cServerID);
    // if su mode, leave server id = NULL
    if (!sumode)
    {
        m_pConnInfo->msgState.SetCommandsCount(commandsCount);
        m_cServerID = Funambol::stringdup(m_pConnInfo->GetServerID());
    }
    m_responseCommandsCount = commandsCount;

GDLDEBUG("LEAVE");
}

