--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/browserutilities/feedsengine/FeedsServer/Server/src/FeedsServerSession.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,2102 @@
+/*
+* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Represent a session on server side.
+*
+*/
+
+
+#include <S32Mem.h>
+#include <Uri16.h>
+
+#include "FeedsDatabase.h"
+#include "FeedsServer.h"
+#include "FeedsServerMsg.h"
+#include "FeedsServerSession.h"
+#include "SessionHttpConnection.h"
+#include "Logger.h"
+#include "PackedFeed.h"
+#include "PackedFolder.h"
+#include <SysUtil.h>
+
+_LIT(KTempDirName, "c:\\system\\temp\\");
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::NewL
+//
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CFeedsServerSession* CFeedsServerSession::NewL(CFeedsServer& aFeedsServer)
+ {
+ CFeedsServerSession* self;
+
+ self = new (ELeave) CFeedsServerSession(aFeedsServer);
+
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+
+ return self;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::NewL
+//
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ConstructL()
+ {
+ // Create the shared http connection in this sesssion
+ iHttpConnection = CSessionHttpConnection::NewL( *this );
+ iLazyCaller = CIdle::NewL(CActive::EPriorityIdle);
+ iOPMLImportTask = NULL;
+ iExportOPMLFileName = NULL;
+ iCurrOp = iPrevOp = 0;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::CFeedsServerSession
+//
+// C++ default constructor can NOT contain any code that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CFeedsServerSession::CFeedsServerSession(CFeedsServer& aFeedsServer):
+ iLeakTracker(CLeakTracker::EFeedsServerSession), iFeedsServer(aFeedsServer),
+ iStoreFeeds(ETrue), iWatchFolderListId(KNoFolderListId),iGetFeedCalled(EFalse)
+ {
+ iFeedsServer.SessionOpened();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::~CFeedsServerSession
+//
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CFeedsServerSession::~CFeedsServerSession()
+ {
+ delete iUpdateAllFeedsTask;
+ delete iUpdateFeedTask;
+ delete iPackedFeed;
+ delete iPackedFolder;
+ delete iOPMLImportTask;
+ delete iExportOPMLFileName;
+ delete iLazyCaller;
+ if (iHttpConnection != NULL)
+ {
+ iHttpConnection->CancelAnyConnectionAttempt();
+ iHttpConnection->AutoDelete();
+ }
+
+ iFeedsServer.SessionClosed();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::StartWait
+//
+// Notifies the observer that the task is about to start a lengthy
+// operation. In response the observer could display somekind of
+// status indicator.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::StartWait()
+ {
+ // Ignore.
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::SetConnection
+//
+// Set client's connection to use by the session http connection.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::SetConnectionL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt nameLength;
+ HBufC* nameBuf;
+ TPtr name( NULL, 0 );
+ TInt bearerType;
+ TInt setConn = EFalse;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ nameLength = stream.ReadUint16L();
+ nameBuf = HBufC::NewLC( nameLength );
+ name.Set( (TUint16*) nameBuf->Ptr(), nameLength, nameLength );
+ stream.ReadL( name, nameLength );
+
+ bearerType = stream.ReadUint16L();
+
+ // Update the http connection.
+ setConn = iHttpConnection->SetConnection( name, bearerType );
+
+ CleanupStack::PopAndDestroy( nameBuf );
+ CleanupStack::PopAndDestroy( /*stream*/ );
+ CleanupStack::PopAndDestroy( requestBuff );
+
+ if( setConn )
+ {
+ // make sure there's update task needing connection
+ __ASSERT_DEBUG( (iUpdateAllFeedsTask != NULL) || (iUpdateFeedTask != NULL), User::Panic(_L("FeedsSvrSes SetConn"), KErrGeneral) );
+ SetClientPendingMessage( aMessage );
+ }
+ else
+ {
+ // make sure no update task needing connection when CancelAll occurs bf SetConnection
+ __ASSERT_DEBUG( (iUpdateAllFeedsTask == NULL) && (iUpdateFeedTask == NULL), User::Panic(_L("FeedsSvrSes SetConn"), KErrGeneral) );
+ aMessage.Complete( KErrCancel );
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::NetworkConnectionNeededL
+//
+// Called upon connection request.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::NetworkConnectionNeededL()
+ {
+ // Tell the client that the connection is needed from client app.
+ TPckgBuf<TFeedsServerResponseType> responseType( EFeedsServerConnectionNeeded );
+
+ User::LeaveIfError( iPendingMessage.Write(KFeedsServerPackedResponseTypeArg,
+ responseType, 0) );
+
+ // Notify the client of result.
+ CompleteClientPendingMessage();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::Completed
+//
+// Called upon completion of the update feed task.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::Completed(CPackedFeed* aPackedFeed, const TDesC& aFeedUrl,TInt aFeedId,
+ TInt aStatusCode)
+ {
+
+ // Do the real work...
+ TRAPD(err, CompletedHelperL(aPackedFeed, aFeedUrl,aFeedId));
+ if (err != KErrNone)
+ {
+ delete aPackedFeed;
+
+ FEED_LOG1(_L("Feeds"), _L("Feeds_Errors.log"),
+ EFileLoggingModeAppend, _L("CFeedsServerSession::Completed: %d."), err);
+
+ aStatusCode = err;
+ }
+ if(aStatusCode != KErrCancel && aStatusCode != KErrNoMemory)
+ {
+ // Update the database.
+ TRAP_IGNORE(iFeedsServer.Database().UpdateFeedStatusL(aFeedId,aStatusCode));
+ }
+
+ // Solution of bug EMWG-7AC9HK,using CIdle class to send tocken instead sending it directly
+ iLazyCaller->Start(TCallBack(LazyCallBack,this));
+ // Compact the database.
+ iFeedsServer.Database().Compact();
+ iPendingStatus = aStatusCode;
+ iPendingMessageHandle = iPendingMessage.Handle();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::CompletedHelperL
+//
+// Called upon completion of the task -- helper method for Completed.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::CompletedHelperL(CPackedFeed*& aPackedFeed,
+ const TDesC& aFeedUrl,TInt aFeedId)
+ {
+ // A new packed feed is ready, send the first part to the client.
+ if (aPackedFeed != NULL)
+ {
+ // If need be update the database.
+ if (iStoreFeeds)
+ {
+ //TInt feedId;
+
+ // Update the database to reflect the feed.
+ iFeedsServer.iFeedsDatabase->UpdateFeedL(*aPackedFeed, aFeedUrl,aFeedId, iFolderListId);
+
+ // Extract the feed from the database rather than passing along the
+ // oringal feed as the database contains other feed information.
+ delete aPackedFeed;
+ aPackedFeed = NULL;
+
+ //(void) iFeedsServer.iFeedsDatabase->FeedIdFromUrlL(aFeedUrl, iFolderListId, feedId);
+
+ // Extract the updated feed.
+ iPackedFeed = CPackedFeed::NewL();
+ iFeedsServer.iFeedsDatabase->ExtractFeedL(aFeedId, *iPackedFeed);
+ }
+
+ // If the feed isn't being stored in the database then just use the feed.
+ else
+ {
+ iPackedFeed = aPackedFeed;
+ aPackedFeed = NULL;
+ }
+
+ }
+
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::UpdateAllFeedsProgress
+//
+// Called to notify the obsever how many feeds remain to be updated.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::UpdateAllFeedsProgress(TInt /*aMaxCount*/, TInt /*aRemaining*/)
+ {
+ // TODO:
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::UpdateAllFeedsCompleted
+//
+// Called upon completion of the task.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::UpdateAllFeedsCompleted(TInt aStatusCode)
+ {
+ TRAP_IGNORE(UpdateAllFeedsCompletedL(aStatusCode));
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::UpdateAllFeedsCompletedL
+//
+// Called upon completion of the task.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::UpdateAllFeedsCompletedL(TInt aStatusCode)
+ {
+ // Delete the task.
+ iUpdateAllFeedsTask->AutoDelete();
+ iUpdateAllFeedsTask = NULL;
+
+ // Compact the database.
+ iFeedsServer.Database().Compact();
+
+ // Tell the client that the manual update is done.
+ TPckgBuf<TFeedsServerResponseType> responseType( EFeedsServerManualUpdateDone );
+
+ User::LeaveIfError( iPendingMessage.Write(KFeedsServerPackedResponseTypeArg,
+ responseType, 0) );
+
+ // Notify the client.
+ CompleteClientPendingMessage( aStatusCode );
+
+ // Notify all open sessions that the folder list just changed -- the
+ // last-update timestamp.
+ if (aStatusCode == KErrNone)
+ {
+ iFeedsServer.NotifyFolderListChanged( iUpdateAllFolderListId );
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::ServiceL
+//
+// Client-server framework calls this function to handle messages from client.
+// This calls DispatchMessageL under the trap harness in order to propagate
+// any errors back to the client (via RMessage2::Complete) rather than leaving.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ServiceL(const RMessage2& aMessage)
+ {
+ // Ignore these messages...
+ switch (aMessage.Function())
+ {
+ case EFeedsServerOpenFeedSession:
+ case EFeedsServerOpenFolderSession:
+ aMessage.Complete(KErrNone);
+ return;
+
+ case EFeedsServerCloseFeedSession:
+ CancelFeedRequestsL();
+ aMessage.Complete(KErrNone);
+ return;
+
+ case EFeedsServerCompleteWatchFolderList:
+ if (iWatchFolderListId != KNoFolderListId)
+ {
+ iWatchFolderListMessage.Complete(KErrCancel);
+ }
+ aMessage.Complete(KErrNone);
+ return;
+
+ case EFeedsServerCloseFolderSession:
+ CancelFolderRequestsL();
+ aMessage.Complete(KErrNone);
+ return;
+
+ case EFeedsServerCompleteWatchSettings:
+ if ( iWatchSettingsMessage.IsNull() == EFalse )
+ {
+ iWatchSettingsMessage.Complete(KErrCancel);
+ }
+
+ aMessage.Complete(KErrNone);
+ return;
+ }
+
+ // allow following functions while update or updateAll is occuring
+ if ( (aMessage.Function() != EFeedsServerCancelAll) &&
+ (aMessage.Function() != EFeedsServerSetConnection) &&
+ ( (iUpdateAllFeedsTask != NULL) || (iUpdateFeedTask != NULL) ) )
+ {
+ User::Leave(KErrServerBusy);
+ }
+
+
+ // Handle the message.
+ // TODO: Does this need to be TRAPed? I think it "Complete" the message
+ // with the leave err if it does. If so the trap can be removed.
+ TRAPD(err, DispatchMessageL(aMessage));
+
+ // Propagate any errors back to the client.
+ if (err != KErrNone)
+ {
+ aMessage.Complete(err);
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::DispatchMessageL
+//
+// Handle messages from the client.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::DispatchMessageL(const RMessage2 &aMessage)
+ {
+ // Ensure the server is ready.
+ iFeedsServer.WakeupServerL();
+ iCurrOp = aMessage.Function();
+
+ switch (iCurrOp)
+ {
+ case EFeedsServerGetRootFolder:
+ GetRootFolderL(aMessage);
+ break;
+
+ case EFeedsServerAddFolderItem:
+ AddFolderItemL(aMessage);
+ break;
+
+ case EFeedsServerChangeFolderItem:
+ ChangeFolderItemL(aMessage);
+ break;
+
+ case EFeedsServerDeleteFolderItems:
+ DeleteFolderItemsL(aMessage);
+ break;
+
+ case EFeedsServerMoveFolderItems:
+ MoveFolderItemsL(aMessage);
+ break;
+
+ case EFeedsServerMoveFolderItemsTo:
+ MoveFolderItemsToL(aMessage);
+ break;
+
+ case EFeedsServerUpdateFolderItems:
+ UpdateFolderItemsL(aMessage);
+ break;
+
+ case EFeedsServerWatchFolderList:
+ WatchFolderListL(aMessage);
+ break;
+
+ case EFeedsServerImportOPML:
+ ImportOPMLAsyncL( aMessage );
+ break;
+
+ case EFeedsServerExportOPML:
+ ExportOPMLL( aMessage );
+ break;
+
+ case EFeedsServerGetSettings:
+ GetSettingsL(aMessage);
+ break;
+
+ case EFeedsServerChangeSettings:
+ ChangeSettingsL(aMessage);
+ break;
+
+ case EFeedsServerWatchSettings:
+ WatchSettingsL(aMessage);
+ break;
+
+ case EFeedsServerSetConnection:
+ SetConnectionL(aMessage);
+ break;
+
+ case EFeedsServerDisconnectManualUpdateConnection:
+ DisconnectManualUpdateConnection(aMessage);
+ break;
+
+ case EFeedsServerCancelAll:
+ CancelAllRequestsL(aMessage);
+ break;
+
+ case EFeedsServerGetFeed:
+ GetFeedL(aMessage);
+ break;
+
+ case EFeedsServerChangeFeedItemStatus:
+ ChangeFeedItemStatusL(aMessage);
+ break;
+
+ case EFeedsServerPrintDBTables:
+ #if defined(_DEBUG)
+ // iFeedsServer.iFeedsDatabase->DebugPrintTablesL();
+ #endif
+
+ aMessage.Complete(KErrNone);
+ break;
+
+ default:
+ {
+ // TODO:CR RMessage.Panic...
+ iFeedsServer.PanicClient(aMessage, EFeedsServerBadRequest);
+ break;
+ }
+ }
+ iPrevOp = iCurrOp;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::GetRootFolderL
+//
+// Returns the root folder item -- fetching it if need be.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::GetRootFolderL(const RMessage2& aMessage)
+ {
+ TFeedsServerResponseType type = EFeedsServerPayloadDone;
+ TPckg<TFeedsServerResponseType> typePkg(type);
+ iGetFeedCalled = EFalse;
+ iCurrentRequest = 0;
+ // Note: The a packed folder is made up of two buffers, a buffer of tokens
+ // and a string table buffer. The tokens define the structure of the
+ // folder-list where the string table contains the folder's data. This
+ // method sends the two buffers serially. To fetch the entire packed
+ // folder the client makes multiple requests.
+
+ // Get the response type
+ User::LeaveIfError(aMessage.Read(KFeedsServerPackedResponseTypeArg, typePkg, 0));
+
+ // When the response type equals init-payload that indicates that the folder
+ // buffer needs to be fetched and serialized.
+ if (type == EFeedsServerInitPayload)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt folderListId;
+ TInt len;
+ TBool itemTitleNeed;
+
+ // Reset the GetRootFolder state.
+ delete iPackedFolder;
+ iPackedFolder = NULL;
+
+ iResponseOffset[iCurrentRequest] = 0;
+ iResponseTokensSent[iCurrentRequest] = EFalse;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ // Read the feed-url flag
+ folderListId = stream.ReadInt32L();
+ itemTitleNeed = stream.ReadUint8L();
+
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Extract the root folder.
+ iPackedFolder = CPackedFolder::NewL();
+ iFeedsServer.iFeedsDatabase->ExtractRootFolderL( folderListId, *iPackedFolder, itemTitleNeed );
+
+ // Send the first chunk.
+ SendTokenChunkL(*iPackedFolder, aMessage);
+ aMessage.Complete(KErrNone);
+ }
+
+ // Otherwise just return the next chunk.
+ else
+ {
+ // Fixed for Bug id - JJUN-78VES7 (FeedsServer crashes under IPC attack)
+ if (iPackedFolder)
+ {
+ // Continue sending the token array.
+ if (!iResponseTokensSent[iCurrentRequest])
+ {
+ SendTokenChunkL(*iPackedFolder, aMessage);
+ }
+
+ // Otherwise write the next string table chunk.
+ else
+ {
+ SendStringTableChunkL(*iPackedFolder, aMessage);
+ }
+ }
+ else
+ {
+ User::Leave(KErrGeneral);
+ }
+
+
+ aMessage.Complete(KErrNone);
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::GetFeedL
+//
+// Returns the requested feed -- fetching it if need be.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::GetFeedL(const RMessage2& aMessage)
+ {
+ TFeedsServerResponseType type = EFeedsServerPayloadDone;
+ TPckg<TFeedsServerResponseType> typePkg(type);
+ TInt folderListId = KNoFolderListId;
+ const TInt KAutoUpdatingOff = 0;
+ iCurrentRequest = 1;
+ // Note: The a packed feed is made up of two buffers, a buffer of tokens
+ // and a string table buffer. The tokens define the structure of the
+ // feed where the string table contains the feed's data. This
+ // method sends the two buffers serially. To fetch the entire packed
+ // feed the client makes multiple requests.
+
+ // Get the response type
+ User::LeaveIfError(aMessage.Read(KFeedsServerPackedResponseTypeArg, typePkg, 0));
+
+ // When the response type equals init-payload that indicates that the feed
+ // buffer needs to be fetched and serialized.
+ if (type == EFeedsServerInitPayload)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ HBufC* feedUrlBuf = NULL;
+ TPtr feedUrl(NULL, 0);
+ TInt len;
+ TInt feedId;
+ TBool updateNeeded = EFalse;
+ TBool hasFeedUrl;
+
+ // Reset the GetFeed state.
+ delete iPackedFeed;
+ iPackedFeed = NULL;
+ iResponseOffset[iCurrentRequest] = 0;
+ iResponseTokensSent[iCurrentRequest] = EFalse;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ // Read the feed-url flag
+ hasFeedUrl = stream.ReadUint8L();
+
+ // Read the feed's url or id.
+ if (hasFeedUrl)
+ {
+ len = stream.ReadUint16L();
+ feedUrlBuf = HBufC::NewLC(len);
+ feedUrl.Set((TUint16*) feedUrlBuf->Ptr(), len, len);
+ stream.ReadL(feedUrl, len);
+ folderListId = stream.ReadInt32L();
+
+ // Get the corresponding feed id. If it isn't found then force
+ // an update.
+ //Gyanendra TODO // should create entry into database
+ if (!iFeedsServer.iFeedsDatabase->FeedIdFromUrlL(feedUrl, folderListId, feedId))
+ {
+ feedId = iFeedsServer.iFeedsDatabase->CommitFeedL(folderListId,KNullDesC,feedUrl, KAutoUpdatingOff);
+ updateNeeded = ETrue;
+ }
+ }
+ else
+ {
+ feedId = stream.ReadUint16L();
+
+ // Get the corresponding url.
+ if (!iFeedsServer.iFeedsDatabase->UrlFromFeedIdL(feedId, feedUrlBuf))
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ feedUrl.Set((TUint16*) feedUrlBuf->Ptr(), feedUrlBuf->Length(),
+ feedUrlBuf->Length());
+ CleanupStack::PushL(feedUrlBuf);
+ }
+
+ // Read the load flags.
+ updateNeeded |= stream.ReadUint8L();
+ iStoreFeeds = !(stream.ReadUint8L());
+
+ // If the feed is newly created, then set updateNeeded.
+ if (!updateNeeded && iFeedsServer.iFeedsDatabase->IsNewlyCreatedL(feedId))
+ {
+ updateNeeded = ETrue;
+ }
+
+ // If the feed is in database and its fresh extract it and send it.
+ if (!updateNeeded)
+ {
+ // Get the feed.
+ iPackedFeed = CPackedFeed::NewL();
+ iFeedsServer.iFeedsDatabase->ExtractFeedL(feedId, *iPackedFeed);
+
+ // Send the first chunk.
+ SendTokenChunkL(*iPackedFeed, aMessage);
+ aMessage.Complete(KErrNone);
+ }
+
+ // Otherwise create a task to update the feed.
+ else
+ {
+
+ TInt drive( EDriveC );
+ TBool isSpace( EFalse );
+ RFs rfs;
+
+ User::LeaveIfError(rfs.Connect());
+ CleanupClosePushL(rfs);
+
+ TRAP_IGNORE( isSpace = !SysUtil::DiskSpaceBelowCriticalLevelL(
+ &rfs,
+ KMinFreebytes,
+ drive ));
+
+ CleanupStack::PopAndDestroy(); //rfs
+
+ // Abort the updation of feeds under low memory.
+ if(isSpace)
+ {
+
+ // If need be clean up the previous task.
+ delete iUpdateFeedTask;
+ iUpdateFeedTask = NULL;
+
+ // Start a new task to update the feed.
+ iUpdateFeedTask = CUpdateFeedTask::NewL(iFeedsServer, feedUrl,feedId, *this);
+ SetClientPendingMessage( aMessage );
+ // When FetchFeedL called with FeedId, we don't know its folder list Id
+ if( folderListId == KNoFolderListId )
+ {
+ iFeedsServer.iFeedsDatabase->FolderListIdFromFeedIdL( feedId, folderListId );
+ }
+ iFolderListId = folderListId;
+
+ TRAPD(err, iUpdateFeedTask->StartTaskL());
+ if (err != KErrNone)
+ {
+ delete iUpdateFeedTask;
+ iUpdateFeedTask = NULL;
+ if(err != KErrCancel && err != KErrNoMemory)
+ {
+ iFeedsServer.Database().UpdateFeedStatusL(feedId,err);
+ NotifyFolderListChanged(folderListId);
+ }
+ CompleteClientPendingMessage(err);
+ }
+ }
+ else
+ {
+ aMessage.Complete(KErrNoMemory);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(feedUrlBuf);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+ }
+
+ // Otherwise just return the next chunk.
+ else
+ {
+ if(iPackedFeed)
+ {
+ // Continue sending the token array.
+ if (!iResponseTokensSent[iCurrentRequest])
+ {
+ SendTokenChunkL(*iPackedFeed, aMessage);
+ }
+
+ // Otherwise write the next string table chunk.
+ else
+ {
+ SendStringTableChunkL(*iPackedFeed, aMessage);
+ }
+
+ aMessage.Complete(KErrNone);
+ }
+ else
+ {
+ aMessage.Complete(KErrArgument);
+ }
+
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::CancelAllRequestsL
+//
+// Cancel all activities that can be cancelled.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::CancelAllRequestsL(const RMessage2& aMessage)
+ {
+ CancelFeedRequestsL();
+ CancelFolderRequestsL();
+
+ iHttpConnection->CancelAnyConnectionAttempt();
+
+ aMessage.Complete(KErrNone);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::CancelFeedRequestsL
+//
+// Cancel all feed related activities that can be cancelled.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::CancelFeedRequestsL()
+ {
+ // Cancel the update task.
+ if (iUpdateFeedTask != NULL)
+ {
+ delete iUpdateFeedTask;
+ iUpdateFeedTask = NULL;
+
+ CompleteClientPendingMessage( KErrCancel );
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::CancelFolderRequestsL
+//
+// Cancel all folder related activities that can be cancelled.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::CancelFolderRequestsL()
+ {
+ // Cancel the update all task.
+ if (iUpdateAllFeedsTask != NULL)
+ {
+ delete iUpdateAllFeedsTask;
+ iUpdateAllFeedsTask = NULL;
+
+ CompleteClientPendingMessage( KErrCancel );
+ }
+ else if(iOPMLImportTask != NULL)
+ {
+ delete iOPMLImportTask;
+ iOPMLImportTask = NULL;
+
+ CompleteClientPendingMessage( KErrCancel );
+ }
+
+ if(iPrevOp == EFeedsServerExportOPML)
+ {
+ // Delete the exported file
+ TBuf<KMaxFileName> path(KTempDirName);
+ path.Append(iExportOPMLFileName->Des());
+ RFs rfs;
+
+ User::LeaveIfError(rfs.Connect());
+ CleanupClosePushL(rfs);
+
+ rfs.Delete(path);
+
+ CleanupStack::PopAndDestroy(/*rfs*/);
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::ChangeFeedItemStatusL
+//
+// Updates the given feed's item status.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ChangeFeedItemStatusL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt feedId;
+ TInt itemCount;
+ RArray<TInt> itemStatus;
+ RArray<TInt> itemIds;
+ TInt unreadCount;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ feedId = stream.ReadUint16L();
+ itemCount = stream.ReadUint16L();
+
+ // Extract the updated item status.
+ CleanupClosePushL(itemIds);
+ CleanupClosePushL(itemStatus);
+ for (TInt i = 0; i < itemCount; i++)
+ {
+ User::LeaveIfError(itemIds.Append(stream.ReadUint16L()));
+ User::LeaveIfError(itemStatus.Append(stream.ReadUint16L()));
+ }
+
+ unreadCount = stream.ReadUint16L();
+
+ // Update the items status.
+ iFeedsServer.Database().FeedUpdateItemStatusL(feedId, itemIds, itemStatus, unreadCount);
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(/*itemStatus*/);
+ CleanupStack::PopAndDestroy(/*itemIds*/);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::AddFolderItemL
+//
+// Updates the database to reflect the addition of the folder item.
+// A update root folder item is sent out to all active
+// folder item sessions.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::AddFolderItemL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt titleLength;
+ HBufC* titleBuf;
+ TInt urlLength;
+ HBufC* urlBuf;
+ TBool isFolder;
+ TInt parentEntryId;
+ TInt folderListId;
+ TInt entryId = 0;
+ TPtr title(NULL, 0);
+ TPtr url(NULL, 0);
+ TInt freq;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+ parentEntryId = stream.ReadUint16L();
+ isFolder = stream.ReadUint16L();
+
+ titleLength = stream.ReadUint16L();
+ titleBuf = HBufC::NewLC(titleLength);
+ title.Set((TUint16*) titleBuf->Ptr(), titleLength, titleLength);
+ stream.ReadL(title, titleLength);
+
+ // Fixed for Bug id - JJUN-78VES7 (FeedsServer crashes under IPC attack)
+ if ( titleLength > KMaxTitleLength )
+ {
+ User::Leave(KErrOverflow);
+ }
+ urlLength = stream.ReadUint16L();
+ urlBuf = HBufC::NewLC(urlLength);
+ url.Set((TUint16*) urlBuf->Ptr(), urlLength, urlLength);
+ stream.ReadL(url, urlLength);
+
+ // If the title isn't set then use the url's host name.
+ if (title.Length() == 0)
+ {
+ TUriParser uriParser;
+ TInt err;
+
+ // Parse the url. If the url isn't valid then just leave the title blank.
+ err = uriParser.Parse(url);
+
+ if (err == KErrNone)
+ {
+ // Get the host name
+ const TDesC& host = uriParser.Extract(EUriHost);
+ const TDesC& path = uriParser.Extract(EUriPath);
+
+ if (host.Length() > 0)
+ {
+ TInt len = host.Length();
+ if (path.Length() > 0)
+ {
+ len += path.Length();
+ }
+
+ // Free the old title.
+ CleanupStack::Pop(urlBuf);
+ CleanupStack::PopAndDestroy(titleBuf);
+ CleanupStack::PushL(urlBuf);
+
+ titleBuf = HBufC::NewL(len);
+ titleBuf->Des().Append( host );
+ if (path.Length() > 0)
+ {
+ titleBuf->Des().Append( path );
+ }
+ title.Set((TUint16*) titleBuf->Ptr(), len, len);
+
+ CleanupStack::Pop(urlBuf);
+ CleanupStack::PushL(titleBuf);
+ CleanupStack::PushL(urlBuf);
+ }
+ }
+ }
+ freq = stream.ReadUint32L();
+ // Insert the new entry.
+ entryId = iFeedsServer.Database().FolderItemAddL(folderListId, title, url,
+ isFolder, parentEntryId, freq);
+
+ // Write the entry's id. This returns the new entry's id to the client.
+ TPckgBuf<TInt> entryIdPckg(entryId);
+
+ User::LeaveIfError(aMessage.Write(1, entryIdPckg, 0));
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(urlBuf);
+ CleanupStack::PopAndDestroy(titleBuf);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+
+ // Notify all open sessions that the folder list just changed.
+ iFeedsServer.NotifyFolderListChanged(folderListId);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::ChangeFolderItemL
+//
+// Updates the database to reflect the edited folder item.
+// A update root folder item is sent out to all active
+// folder item sessions.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ChangeFolderItemL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt folderListId;
+ TInt entryId;
+ TInt titleLength;
+ HBufC* titleBuf;
+ TInt urlLength;
+ HBufC* urlBuf;
+ TPtr title(NULL, 0);
+ TPtr url(NULL, 0);
+ TInt freq;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+ entryId = stream.ReadUint16L();
+
+ titleLength = stream.ReadUint16L();
+ titleBuf = HBufC::NewLC(titleLength);
+ title.Set((TUint16*) titleBuf->Ptr(), titleLength, titleLength);
+ stream.ReadL(title, titleLength);
+
+ urlLength = stream.ReadUint16L();
+ urlBuf = HBufC::NewLC(urlLength);
+ url.Set((TUint16*) urlBuf->Ptr(), urlLength, urlLength);
+ stream.ReadL(url, urlLength);
+
+ freq = stream.ReadUint32L();
+ // Insert the new entry.
+ iFeedsServer.Database().FolderItemUpdateL(entryId, title, url, freq);
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(urlBuf);
+ CleanupStack::PopAndDestroy(titleBuf);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+
+ // Notify all open sessions that the folder list just changed.
+ iFeedsServer.NotifyFolderListChanged(folderListId);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::DeleteFolderItemsL
+//
+// Updates the database to reflect the deletion of the folder item.
+// A update root folder item is sent out to all active
+// folder item sessions.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::DeleteFolderItemsL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ TInt folderListId;
+ TInt entryCount;
+ CBufFlat* requestBuff;
+ RArray<TInt> entries;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+ entryCount = stream.ReadUint16L();
+
+ // Extract the ids of the entries to delete.
+ CleanupClosePushL(entries);
+ for (TInt i = 0; i < entryCount; i++)
+ {
+ User::LeaveIfError(entries.Append(stream.ReadUint16L()));
+ }
+
+ // Delete the items.
+ iFeedsServer.Database().FolderItemDeleteL(entries,ETrue);
+ iFeedsServer.Database().Compact();
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(/*entries*/);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+
+ // Notify all open sessions that the folder list just changed.
+ iFeedsServer.NotifyFolderListChanged(folderListId);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::MoveFolderItemsL
+//
+// Updates the database to reflect the moved folder items.
+// A update root folder item is sent out to all active
+// folder item sessions.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::MoveFolderItemsL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt folderListId;
+ TInt targetIndex;
+ TInt entryCount;
+ RArray<TInt> entries;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+ targetIndex = stream.ReadUint16L();
+ entryCount = stream.ReadUint16L();
+
+ // Extract the ids of the entries to move.
+ CleanupClosePushL(entries);
+ for (TInt i = 0; i < entryCount; i++)
+ {
+ User::LeaveIfError(entries.Append(stream.ReadUint16L()));
+ }
+
+ // Move the entries.
+ iFeedsServer.Database().FolderItemMoveL(entries, targetIndex);
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(/*entries*/);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+
+ // Notify all open sessions that the folder list just changed.
+ iFeedsServer.NotifyFolderListChanged(folderListId);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::MoveFolderItemsToL
+//
+// Updates the database to reflect the new parentage of the
+// folder items. A update root folder item is sent out to
+// all active folder item sessions.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::MoveFolderItemsToL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt folderListId;
+ TInt parentId;
+ TInt entryCount;
+ RArray<TInt> entries;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+ parentId = stream.ReadUint16L();
+ entryCount = stream.ReadUint16L();
+
+ // Extract the ids of the entries to move.
+ CleanupClosePushL(entries);
+ for (TInt i = 0; i < entryCount; i++)
+ {
+ User::LeaveIfError(entries.Append(stream.ReadUint16L()));
+ }
+
+ // Move each of the entries to the new parent.
+ iFeedsServer.Database().FolderItemMoveToL(entries, parentId);
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(/*entries*/);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+
+ // Notify all open sessions that the folder list just changed.
+ iFeedsServer.NotifyFolderListChanged(folderListId);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::UpdateFolderItemsL
+//
+// Update the given folder items or all feeds associated with the folder list id.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::UpdateFolderItemsL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt folderListId;
+ TBool isFolderListId;
+ TInt err;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+
+ // If need be clean up the previous task.
+ delete iUpdateAllFeedsTask;
+ iUpdateAllFeedsTask = NULL;
+
+ // The update request is associated with a folder-list.
+ isFolderListId = stream.ReadUint8L();
+ if (isFolderListId)
+ {
+ // Create a task to update all of the feeds.
+ iUpdateAllFeedsTask = CUpdateAllFeedsTask::NewL(iFeedsServer, folderListId, *this);
+ iUpdateAllFolderListId = folderListId;
+ SetClientPendingMessage( aMessage );
+
+ TRAP(err, iUpdateAllFeedsTask->StartTaskL());
+ if (err != KErrNone)
+ {
+ delete iUpdateAllFeedsTask;
+ iUpdateAllFeedsTask = NULL;
+
+ aMessage.Complete(err);
+ }
+ }
+
+ // Otherwise update the given folder items.
+ else
+ {
+ TInt itemCount;
+ RArray<TInt> entries;
+
+ CleanupClosePushL(entries);
+
+ // Extract the updated item status.
+ itemCount = stream.ReadUint16L();
+
+ for (TInt i = 0; i < itemCount; i++)
+ {
+ User::LeaveIfError(entries.Append(stream.ReadUint16L()));
+ }
+
+ // Create a task to update the feeds.
+ iUpdateAllFeedsTask = CUpdateAllFeedsTask::NewL(iFeedsServer, folderListId, entries, *this);
+ iUpdateAllFolderListId = folderListId;
+ SetClientPendingMessage( aMessage );
+
+ TRAP(err, iUpdateAllFeedsTask->StartTaskL());
+ if (err != KErrNone)
+ {
+ delete iUpdateAllFeedsTask;
+ iUpdateAllFeedsTask = NULL;
+
+ aMessage.Complete(err);
+ }
+
+ CleanupStack::PopAndDestroy(/*entries*/);
+ }
+
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::GetSettingsL
+//
+// Returns the settings.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::GetSettingsL(const RMessage2& aMessage)
+ {
+ CBufFlat* buff;
+ RBufWriteStream stream;
+ TBool autoUpdate;
+ TBool autoUpdateWhileRoaming;
+ TInt autoUpdateFreq;
+ TUint32 autoUpdateAP;
+ CBufFlat* requestBuff;
+ RBufReadStream readStream;
+ TInt folderListId;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ readStream.Open(*requestBuff, 0);
+ CleanupClosePushL(readStream);
+
+ folderListId = readStream.ReadInt32L();
+ iFolderListId = folderListId;
+
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Extract the settings.
+ iFeedsServer.Database().ExtractAutoUpdateSettingsL( folderListId, autoUpdate, autoUpdateFreq,
+ autoUpdateAP, autoUpdateWhileRoaming );
+
+ // Package the settings.
+ buff = CBufFlat::NewL(128);
+ CleanupStack::PushL(buff);
+
+ stream.Open(*buff);
+ CleanupClosePushL(stream);
+
+ // Write out the settings.
+ stream.WriteUint8L(autoUpdate);
+ stream.WriteUint16L(autoUpdateFreq);
+ stream.WriteUint32L(autoUpdateAP);
+ stream.WriteUint8L(autoUpdateWhileRoaming);
+
+ buff->Compress();
+ CleanupStack::PopAndDestroy(/*stream*/);
+
+ // Send the response.
+ TPtrC8 ptr(buff->Ptr(0).Ptr(), buff->Size());
+
+ User::LeaveIfError(aMessage.Write(1, ptr, 0));
+ aMessage.Complete(KErrNone);
+
+ CleanupStack::PopAndDestroy(buff);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::ChangeSettingsL
+//
+// Updates the database to reflect the new settings.
+// A update settings is sent out to all active
+// server sessions.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ChangeSettingsL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TBool autoUpdate;
+ TBool autoUpdateWhileRoaming;
+ TInt autoUpdateFreq;
+ TUint32 autoUpdateAP;
+ TInt folderListId;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+ autoUpdate = stream.ReadUint8L();
+ autoUpdateFreq = stream.ReadUint16L();
+ autoUpdateAP = stream.ReadUint32L();
+ autoUpdateWhileRoaming = stream.ReadUint8L();
+
+ // Update the server.
+ iFeedsServer.SetAutoUpdateSettingsL( folderListId, autoUpdate, autoUpdateFreq, autoUpdateAP, autoUpdateWhileRoaming );
+
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::WatchSettingsL
+//
+// Sets up a notifier to execute when settings changes.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::WatchSettingsL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ TInt folderListId = stream.ReadInt32L();
+
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // We should never have more than a single outstanding asynchronous request
+ __ASSERT_DEBUG( iWatchSettingsMessage.IsNull(), User::Panic(_L("Feeds Server Session"), KErrGeneral) );
+ // Store the watch info.
+ iWatchSettingsMessage = aMessage;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::NotifySettingsChanged
+//
+// Notify the session that the settings associated with the folder list changed.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::NotifySettingsChanged(TInt aFolderListId)
+ {
+ if ((aFolderListId == iFolderListId) || (aFolderListId == KAllFolderListId))
+ {
+ if ( iWatchSettingsMessage.IsNull() == EFalse )
+ {
+ iWatchSettingsMessage.Complete(KErrNone);
+ }
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::DisconnectManualUpdateConnection
+//
+// Disconnect the session http connection provided by client app.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::DisconnectManualUpdateConnection(const RMessage2& aMessage)
+ {
+ iHttpConnection->Disconnect();
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::WatchFolderListL
+//
+// Sets up a notifier to execute when the folder list changes.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::WatchFolderListL(const RMessage2& aMessage)
+ {
+ RBufReadStream stream;
+ CBufFlat* requestBuff;
+ TInt folderListId;
+
+ // Extract the request.
+ requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(requestBuff);
+
+ // Store the watch info.
+ iWatchFolderListId = folderListId;
+ iWatchFolderListMessage = aMessage;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::NotifyFolderListChanged
+//
+// Notify the session that the given folder-list changed.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::NotifyFolderListChanged(TInt aFolderListId)
+ {
+ // TODO: Improve this so multiple folder-lists can be watched from
+ // a single session i.e. store this info in an array. The client
+ // is allowed to open multiple RFolderItems on the same RFeedsServer
+ // instance.
+
+ if ((aFolderListId == iWatchFolderListId) || (aFolderListId == KAllFolderListId))
+ {
+ if (iWatchFolderListId != KNoFolderListId)
+ {
+ iWatchFolderListId = KNoFolderListId;
+ iWatchFolderListMessage.Complete(KErrNone);
+ }
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::SendTokenChunkL
+//
+// Send the next chunk of the token-array to the client.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::SendTokenChunkL(CPacked& aPacked, const RMessagePtr2& aMessage)
+ {
+ // Determine how much to write. This is done by comparing the size of the client's
+ // receptor buffer to the amount left to write.
+ TInt size = KMaxFeedsServerMessage;
+ TInt clientSize;
+
+ clientSize = aMessage.GetDesMaxLengthL(KFeedsServerPackedResponseArg);
+ if (clientSize < KMaxFeedsServerMessage)
+ {
+ size = clientSize;
+ }
+
+ if ((aPacked.iTokenArrayAsDes.Length() - iResponseOffset[iCurrentRequest]) < size)
+ {
+ size = aPacked.iTokenArrayAsDes.Length() - iResponseOffset[iCurrentRequest];
+ }
+
+ // Tell the client that the payload contains token info.
+ TPckgBuf<TFeedsServerResponseType> responseType(EFeedsServerTokensPayload);
+
+ User::LeaveIfError(aMessage.Write(KFeedsServerPackedResponseTypeArg,
+ responseType, 0));
+
+ // TODO: Panic the client if the buffer isn't an increment of sizeof(TUint).
+
+ // Write the next chunk of token info.
+ TPtrC8 buff(aPacked.iTokenArrayAsDes.Ptr() + iResponseOffset[iCurrentRequest], size);
+
+ User::LeaveIfError(aMessage.Write(KFeedsServerPackedResponseArg, buff, 0));
+ iResponseOffset[iCurrentRequest] += size;
+
+ // If the entire token buffer is written then get ready to write the string table.
+ if (iResponseOffset[iCurrentRequest] >= aPacked.iTokenArrayAsDes.Length())
+ {
+ iResponseTokensSent[iCurrentRequest] = ETrue;
+ iResponseOffset[iCurrentRequest] = 0;
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::SendStringTableChunkL
+//
+// Send the next chunk of the string-table to the client.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::SendStringTableChunkL(CPacked& aPacked, const RMessage2& aMessage)
+ {
+ TPtrC8 stringTable8Bit((const TUint8*) aPacked.iStringTable->Ptr(),
+ aPacked.iStringTable->Size());
+
+ // Determine how much to write. This is done by comparing the size of the client's
+ // receptor buffer to the amount left to write.
+ TInt size = KMaxFeedsServerMessage;
+ TInt clientSize;
+
+ clientSize = aMessage.GetDesMaxLengthL(KFeedsServerPackedResponseArg);
+ if (clientSize < KMaxFeedsServerMessage)
+ {
+ size = clientSize;
+ }
+
+ if ((stringTable8Bit.Length() - iResponseOffset[iCurrentRequest]) < size)
+ {
+ size = stringTable8Bit.Length() - iResponseOffset[iCurrentRequest];
+ }
+
+ // TODO: Panic the client if the buffer isn't an increment of sizeof(TUint16).
+
+ // Write the next chunk of the string table.
+ TPtrC8 buff(stringTable8Bit.Ptr() + iResponseOffset[iCurrentRequest], size);
+
+ User::LeaveIfError(aMessage.Write(KFeedsServerPackedResponseArg, buff, 0));
+ iResponseOffset[iCurrentRequest] += size;
+
+ // Tell the client that the payload contains a chunk of the string table.
+ if (iResponseOffset[iCurrentRequest] < stringTable8Bit.Length())
+ {
+ TPckgBuf<TFeedsServerResponseType> responseType(EFeedsServerStringTablePayload);
+
+ User::LeaveIfError(aMessage.Write(KFeedsServerPackedResponseTypeArg,
+ responseType, 0));
+ }
+
+ // Otherwise tell the client that the payload contains a chunk of the
+ // string table and this is the last payload.
+ else
+ {
+ TPckgBuf<TFeedsServerResponseType> responseType(EFeedsServerPayloadDone);
+
+ User::LeaveIfError(aMessage.Write(KFeedsServerPackedResponseTypeArg,
+ responseType, 0));
+
+ if(iGetFeedCalled)
+ {
+ // Notify all open sessions that the folder list just changed.
+ iFeedsServer.NotifyFolderListChanged(iWatchFolderListId);
+ iGetFeedCalled = EFalse;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::ImportOPMLL
+//
+// Import OPML file passed from the client asyncronously.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ImportOPMLAsyncL( const RMessage2& aMessage )
+ {
+ SetClientPendingMessage( aMessage );
+ iOPMLImportTask = CImportFeedsTask::NewL(iFeedsServer, *this, aMessage);
+ ExtractClientImportMessageL();
+ iOPMLImportTask->StartTaskL();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CImportFeedsTask::ExtractClientImportMessageL.
+//
+// Extract the client passes message
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ExtractClientImportMessageL()
+ {
+ RBufReadStream stream;
+ TInt messageLen(0);
+
+ if( iPendingMessage.IsNull())
+ {
+ User::Leave(KErrArgument);
+ }
+
+ CBufFlat *requestBuff = CBufFlat::NewL(512);
+ CleanupStack::PushL(requestBuff);
+
+ messageLen = iPendingMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+
+ requestBuff->ExpandL(0, messageLen);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), messageLen);
+
+ iPendingMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ iOPMLImportTask->iFolderListId = stream.ReadInt32L();
+ iOPMLImportTask->iClearFolderList = stream.ReadUint8L();
+
+ TInt pathLen = stream.ReadUint16L();
+
+ iOPMLImportTask->iFullImportFileName = HBufC::NewL(pathLen);
+ TPtr str = iOPMLImportTask->iFullImportFileName->Des();
+ stream.ReadL(str, pathLen);
+
+ //Chop-off the path, to get the display name
+ TInt Pos = str.LocateReverse('\\');
+ if(Pos != KErrNotFound)
+ {
+ iOPMLImportTask->iDispImportFileName = str.Mid(Pos+1, Min(KMaxFileName, (str.Length() - (Pos + 1))));
+ }
+ else
+ {
+ iOPMLImportTask->iDispImportFileName = str.Mid(0, Min(KMaxFileName, str.Length()));
+ }
+
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(/*requestBuff*/);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::ImportOPMLL
+//
+// Import OPML file passed from the client.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ImportOPMLL( const RMessage2& aMessage )
+ {
+ RBufReadStream stream;
+ TInt len;
+ TInt folderListId;
+ TBool clearFolderList = EFalse;
+ TInt err = KErrNone;
+ TPtr fileName(NULL, 0);
+
+ // Extract the request.
+ CBufFlat *requestBuff = CBufFlat::NewL(512);
+ CleanupStack::PushL(requestBuff);
+
+ len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ stream.Open(*requestBuff, 0);
+ CleanupClosePushL(stream);
+
+ folderListId = stream.ReadInt32L();
+ clearFolderList = stream.ReadUint8L();
+
+ TInt pathLen = stream.ReadUint16L();
+ HBufC *fileNameBuf = HBufC::NewLC(pathLen);
+ fileName.Set((TUint16*) fileNameBuf->Ptr(), pathLen, pathLen);
+ stream.ReadL(fileName, pathLen);
+
+ RFs rfs;
+ RFile file;
+
+ // Get the path to the default folder.
+ User::LeaveIfError(rfs.Connect());
+ CleanupClosePushL(rfs);
+
+ err = file.Open(rfs, fileName, EFileRead | EFileShareReadersOnly);
+ User::LeaveIfError(err);
+
+ CleanupClosePushL(file);
+
+ // Import the default folder file synchronously.
+ CPackedFolder *packedFolder = NULL;
+
+ //Chop-off the path
+ TInt Pos = fileName.LocateReverse('\\');
+ if(Pos)
+ {
+ fileName = fileName.Mid(Pos+1);
+ }
+
+ TRAP(err, packedFolder = iFeedsServer.ImportFolderL(file, fileName));
+
+ CleanupStack::PopAndDestroy(/*file*/);
+ CleanupStack::PopAndDestroy(/*rfs*/);
+ CleanupStack::PopAndDestroy(/*fileNameBuf*/);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(/*requestBuff*/);
+
+ if(err != KErrNone)
+ {
+ delete packedFolder;
+ aMessage.Complete(err);
+ return;
+ }
+
+ CleanupStack::PushL(packedFolder);
+
+ // For news ticker, this is true
+ if(clearFolderList)
+ {
+ TRAP(err, iFeedsServer.Database().FolderListDeleteL(folderListId));
+ }
+
+ if(err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(/*packedFolder*/);
+
+ aMessage.Complete(err);
+ return;
+ }
+
+ // Load it into the database.
+
+ TRAP(err, iFeedsServer.Database().ImportFolderL(folderListId, *packedFolder));
+ if(err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(/*packedFolder*/);
+
+ aMessage.Complete(err);
+ return;
+ }
+
+ CleanupStack::PopAndDestroy(/*packedFolder*/);
+
+ // Compact the database.
+ iFeedsServer.Database().Compact();
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+ // Notify new folder, feeds added
+ iFeedsServer.NotifyFolderListChanged( folderListId );
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::ExportOPMLL
+//
+// Export feeds as an OPML file passed from the client.
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ExportOPMLL( const RMessage2& aMessage )
+ {
+ // Extract the request.
+ CBufFlat* requestBuff = CBufFlat::NewL(128);
+ CleanupStack::PushL(requestBuff);
+
+ TInt len = aMessage.GetDesLengthL(KFeedsServerPackedRequestArg);
+ requestBuff->ExpandL(0, len);
+ TPtr8 reqPtr((TUint8*) requestBuff->Ptr(0).Ptr(), len);
+
+ aMessage.ReadL(KFeedsServerPackedRequestArg, reqPtr, 0);
+
+ // Unpack the request.
+ RBufReadStream stream;
+ stream.Open(*requestBuff, 0);
+
+ CleanupClosePushL(stream);
+
+ TInt fileNameLength = stream.ReadUint16L();
+ if(iExportOPMLFileName)
+ {
+ delete iExportOPMLFileName;
+ iExportOPMLFileName = NULL;
+ }
+
+ iExportOPMLFileName = HBufC::NewL(fileNameLength);
+ TPtr fileName = iExportOPMLFileName->Des();
+ stream.ReadL(fileName, fileNameLength);
+
+ TInt folderListId = stream.ReadInt32L();
+ TInt entryCount = stream.ReadUint16L();
+
+ // Extract the ids of the entries to delete.
+ RArray<TInt> entries;
+ CleanupClosePushL(entries);
+ for (TInt i = 0; i < entryCount; i++)
+ {
+ User::LeaveIfError(entries.Append(stream.ReadUint16L()));
+ }
+
+ // Export the entries.
+ iFeedsServer.ExportFolderL(entries, fileName);
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(/*entries*/);
+ CleanupStack::PopAndDestroy(/*stream*/);
+ CleanupStack::PopAndDestroy(/*requestBuff*/);
+
+ // Send the response.
+ aMessage.Complete(KErrNone);
+ }
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::CompleteClientPendingMessage
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::CompleteClientPendingMessage( TInt aCompletionCode )
+ {
+ if ( iPendingMessage.IsNull() == EFalse )
+ {
+ iPendingMessage.Complete( aCompletionCode );
+ }
+ else
+ {
+ FEED_LOG(_L("Feeds"), _L("Feeds_Errors.log"),
+ EFileLoggingModeAppend, _L("CFeedsServerSession::CompleteClientPendingMessage - pending msg: Null."));
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::SetClientPendingMessage
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::SetClientPendingMessage( RMessagePtr2 aMessage )
+ {
+ // We should never have more than a single outstanding asynchronous request
+ __ASSERT_DEBUG( iPendingMessage.IsNull(), User::Panic(_L("Feeds Server Session"), KErrGeneral) );
+ iPendingMessage = aMessage;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::StartImportWait
+//
+// Called to notify the obsever to indicate the start of OPML import
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::StartImportWait()
+ {
+ // Ignore.
+ }
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::ImportCompleted
+//
+// Called to notify the obsever to indicate the completion OPML import
+// -----------------------------------------------------------------------------
+//
+void CFeedsServerSession::ImportCompleted(TInt aStatusCode)
+{
+ // Delete the import task.
+ delete iOPMLImportTask;
+ iOPMLImportTask = NULL;
+
+ // Compact the database.
+ iFeedsServer.Database().Compact();
+
+ CompleteClientPendingMessage( aStatusCode );
+}
+
+// -----------------------------------------------------------------------------
+// CFeedsServerSession::LazyCallBack
+//
+// This function calls SendTokenChunkL instead of calling it from CompletedHelperL function
+// To ensure it doesn't called if user has cancelled the request
+// -----------------------------------------------------------------------------
+//
+TInt CFeedsServerSession::LazyCallBack(TAny* aPtr)
+{
+ CFeedsServerSession* sessionPtr = (CFeedsServerSession*)aPtr;
+ sessionPtr->iCurrentRequest = 1; //This is GetFeed Call
+
+ if(sessionPtr->iPendingMessage.IsNull() == EFalse && sessionPtr->iPendingMessageHandle == sessionPtr->iPendingMessage.Handle())
+ {
+ if(sessionPtr->iPendingStatus == KErrNone)
+ {
+ sessionPtr->iGetFeedCalled = ETrue;
+ TRAP_IGNORE(sessionPtr->SendTokenChunkL(*(sessionPtr->iPackedFeed), sessionPtr->iPendingMessage));
+ }
+ else
+ {
+ // Notify all open sessions that the folder list just changed.
+ sessionPtr->iFeedsServer.NotifyFolderListChanged(sessionPtr->iWatchFolderListId);
+ sessionPtr->iGetFeedCalled = EFalse;
+ }
+ // Delete the task.
+ if(sessionPtr->iUpdateFeedTask != NULL)
+ {
+ sessionPtr->iUpdateFeedTask->AutoDelete();
+ sessionPtr->iUpdateFeedTask = NULL;
+ }
+ // Notify the client of result.
+ sessionPtr->CompleteClientPendingMessage( sessionPtr->iPendingStatus );
+ }
+ else if(sessionPtr->iPackedFeed != NULL)
+ {
+ delete sessionPtr->iPackedFeed;
+ sessionPtr->iPackedFeed = NULL;
+ }
+ return EFalse;
+}