--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/wget/wget.cpp Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,892 @@
+// wget.cpp
+//
+// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "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:
+// Accenture - Initial contribution
+//
+
+// TODO: byte-range support
+
+#include <commdbconnpref.h>
+#include <httpstringconstants.h>
+#include <httperr.h>
+#include <mhttpdatasupplier.h>
+#include <rhttpheaders.h>
+#include <thttphdrfielditer.h>
+#include <bautils.h>
+#include "wget.h"
+
+using namespace IoUtils;
+
+_LIT8(KHttpProtocol, "HTTP/TCP");
+_LIT(KDateFormat, "%D%M%Y%/0%1%/1%2%/2%3%/3 %:0%H%:1%T%:2%S.%C%:3");
+const TInt KMaxHeaderNameLen = 32;
+const TInt KMaxHeaderValueLen = 128;
+
+CCommandBase* CCmdWget::NewLC()
+ {
+ CCmdWget* self = new(ELeave) CCmdWget();
+ CleanupStack::PushL(self);
+ self->BaseConstructL();
+ return self;
+ }
+
+CCmdWget::~CCmdWget()
+ {
+ delete iUrl;
+ delete iUsername;
+ delete iPassword;
+ if (iSessionIsOpen)
+ {
+ iSession.Close(); // closes iTransaction also
+ }
+ if (iConnection.SubSessionHandle() > 0)
+ {
+ iConnection.Close();
+ }
+ if (iSocketServ.Handle() > 0)
+ {
+ iSocketServ.Close();
+ }
+ if (iLocalFile.SubSessionHandle() > 0)
+ {
+ iLocalFile.Flush();
+ iLocalFile.Close();
+ }
+ }
+
+CCmdWget::CCmdWget() : CCommandBase(CCommandBase::EManualComplete)
+ {
+ }
+
+const TDesC& CCmdWget::Name() const
+ {
+ _LIT(KName, "wget");
+ return KName;
+ }
+
+void CCmdWget::DoRunL()
+ {
+ // sanity check parameters
+ if (!iUrl || iUrl->Des().Length() > KMaxName)
+ {
+ if (iVerbose)
+ {
+ PrintError(KErrArgument, _L("Url not specified or is too large."));
+ }
+ User::Leave(KErrArgument);
+ }
+ if ((iUsername && iUsername->Des().Length() > KMaxName) || (iPassword && iPassword->Des().Length() > KMaxName))
+ {
+ if (iVerbose)
+ {
+ PrintError(KErrArgument, _L("Username or Password is too large."));
+ }
+ User::Leave(KErrArgument);
+ }
+
+ if (iUploadFilename.Length())
+ {
+ iPostData = ETrue; // Keep this member variable because lots of code assumes it
+ }
+
+ LaunchConnectionL(); // start a connection - KErrNone returned if successfully started or a compatible connection already exists
+
+ if (iPostData)
+ {
+ // http post
+ PrepareUploadFileL();
+ }
+ else
+ {
+ // http get
+ PrepareDownloadFileL(); // prep. the local file to receive the downloaded data
+ }
+ User::LeaveIfError(iLocalFile.Size(iLocalFileSize));
+ ConfigureHTTPL(); // setup http session & configure with connection parameters
+ LaunchHTTPTransactionL(); // launch a http transaction
+ }
+
+void CCmdWget::ArgumentsL(RCommandArgumentList& aArguments)
+ {
+ _LIT(KArg1, "url");
+ aArguments.AppendStringL(iUrl, KArg1);
+ }
+
+void CCmdWget::OptionsL(RCommandOptionList& aOptions)
+ {
+ _LIT(KOptContinue, "continue");
+ aOptions.AppendBoolL(iContinue, KOptContinue);
+
+ _LIT(KOptDestinationFilename, "downloadfile");
+ aOptions.AppendFileNameL(iDestinationFilename, KOptDestinationFilename);
+
+ _LIT(KOptSourceFilename, "uploadfile");
+ aOptions.AppendFileNameL(iUploadFilename, KOptSourceFilename);
+
+ _LIT(KOptIapId, "iap");
+ aOptions.AppendIntL(iIapId, KOptIapId);
+
+ _LIT(KOptUsername, "username");
+ aOptions.AppendStringL(iUsername, KOptUsername);
+
+ _LIT(KOptPassword, "password");
+ aOptions.AppendStringL(iPassword, KOptPassword);
+
+ _LIT(KOptVerbose, "verbose");
+ aOptions.AppendBoolL(iVerbose, KOptVerbose);
+ }
+
+//
+// CCmdWget::PrepareDownloadFileL
+// determine the destination file & path and open a handle to a local file
+//
+void CCmdWget::PrepareDownloadFileL()
+ {
+ ASSERT(iUrl);
+ ASSERT(!iPostData);
+ TFileName fname;
+ RFs& fs = FsL();
+ fname.Zero();
+ if (iDestinationFilename.Length() <= 0)
+ {
+ // use current path
+ fname.Append(Env().Pwd());
+
+ // use the same name as the file we're intending to download
+ TChar dirMarker('/');
+ TInt mark = iUrl->Des().LocateReverse(dirMarker);
+ if (mark <= 0)
+ {
+ User::Leave(KErrNotFound);
+ }
+ fname.Append(iUrl->Des().Mid(++mark)); // increment mark to step over the '/'
+ }
+ else
+ {
+ fname.Copy(iDestinationFilename); // user has specified a local file name
+ }
+ if (BaflUtils::FileExists(fs, fname))
+ {
+ if (iContinue)
+ {
+ // open the file & append any new data to what's already in there
+ User::LeaveIfError(iLocalFile.Open(fs, fname, EFileShareExclusive));
+ }
+ else
+ {
+ // open the file & replace old data with new data
+ User::LeaveIfError(iLocalFile.Replace(fs, fname, EFileShareExclusive));
+ }
+ }
+ else
+ {
+ // create the file for the first time
+ User::LeaveIfError(iLocalFile.Create(fs, fname, EFileShareExclusive));
+ }
+ }
+
+//
+// CCmdWget::PrepareUploadFileL
+// prep. the local file containing data for upload to the web server
+//
+void CCmdWget::PrepareUploadFileL()
+ {
+ ASSERT(iUrl);
+ ASSERT(iPostData);
+
+ User::LeaveIfError(iLocalFile.Open(FsL(), iUploadFilename, EFileRead | EFileShareReadersOnly));
+
+
+ }
+
+//
+// CCmdWget::LaunchConnectionL
+// establish a connection to the network
+//
+void CCmdWget::LaunchConnectionL()
+ {
+ User::LeaveIfError(iSocketServ.Connect());
+ User::LeaveIfError(iConnection.Open(iSocketServ));
+
+ TInt connError = KErrNone;
+ TCommDbConnPref prefs;
+ if (iIapId > 0)
+ {
+ prefs.SetIapId(iIapId);
+ prefs.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
+ connError = iConnection.Start(prefs);
+ }
+ else
+ {
+ connError = iConnection.Start();
+ }
+ if (iVerbose && (connError != KErrNone))
+ {
+ PrintError(connError, _L("Unable to establish network connection"));
+ User::Leave(connError);
+ }
+ }
+
+//
+// CCmdWget::ConfigureHTTPL
+//
+void CCmdWget::ConfigureHTTPL()
+ {
+ iSession.OpenL(KHttpProtocol);
+ iSessionIsOpen = ETrue;
+ iSession.SetSessionEventCallback(this);
+ RStringPool pool = iSession.StringPool();
+ RHTTPConnectionInfo conInf = iSession.ConnectionInfo();
+ conInf.SetPropertyL(pool.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable()), THTTPHdrVal(iSocketServ.Handle()));
+ conInf.SetPropertyL(pool.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable()), THTTPHdrVal(reinterpret_cast<TInt> (&iConnection)));
+ InstallAuthenticationL(iSession);
+ }
+
+//
+// CCmdWget::LaunchHTTPTransactionL
+// launches a new http transaction
+//
+void CCmdWget::LaunchHTTPTransactionL()
+ {
+ // create the transaction
+ TBuf8<KMaxName> url8;
+ url8.Copy(iUrl->Des());
+ TUriParser8 uri;
+ User::LeaveIfError(uri.Parse(url8));
+ RStringPool pool = iSession.StringPool();
+ RStringF method = pool.StringF(HTTP::EGET,RHTTPSession::GetTable());
+ if (iPostData)
+ {
+ method = pool.StringF(HTTP::EPOST,RHTTPSession::GetTable());
+ }
+ iTransaction = iSession.OpenTransactionL(uri, *this, method);
+
+ // some transaction configuration is required for posting data
+ if (iPostData)
+ {
+ RHTTPRequest req = iTransaction.Request();
+ req.SetBody(*this); // ccmdwget to supply the data for posting
+ THTTPHdrVal length(OverallDataSize());
+ THTTPHdrVal type(pool.StringF(HTTP::ETextAny, RHTTPSession::GetTable()));
+ RHTTPHeaders hdr = req.GetHeaderCollection();
+ hdr.SetFieldL(pool.StringF(HTTP::EContentLength, RHTTPSession::GetTable()), length);
+ hdr.SetFieldL(pool.StringF(HTTP::EContentType, RHTTPSession::GetTable()), type);
+ }
+
+ // launch it
+ iTransaction.SubmitL();
+ }
+
+//
+// CCmdWget::GetCredentialsL
+// request from the underlying HTTP session to provide it with some authentication credentials (if present)
+//
+TBool CCmdWget::GetCredentialsL(const TUriC8& /*aURI*/, RString aRealm, RStringF /*aAuthenticationType*/, RString& aUsername, RString& aPassword)
+ {
+ TBool present = EFalse;
+ RStringPool pl = aRealm.Pool();
+ if (iUsername)
+ {
+ present = ETrue;
+ TBuf8<KMaxName> user;
+ user.Copy(iUsername->Des());
+ aUsername = pl.OpenStringL(user);
+ }
+ if (iPassword)
+ {
+ present = ETrue;
+ TBuf8<KMaxName> pwd;
+ pwd.Copy(iPassword->Des());
+ aPassword = pl.OpenStringL(pwd);
+ }
+ return present;
+ }
+
+//
+// CCmdWget::MHFSessionRunL
+// handles any up-calls from the http session
+//
+void CCmdWget::MHFSessionRunL(const THTTPSessionEvent& aEvent)
+ {
+ switch (aEvent.iStatus)
+ {
+ case THTTPSessionEvent::EConnect:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Connect\r\n"));
+ }
+ }
+ break;
+
+ case THTTPSessionEvent::EConnectedOK:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Connected OK\r\n"));
+ }
+ }
+ break;
+
+ case THTTPSessionEvent::EDisconnect:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Disconnect\r\n"));
+ }
+ }
+ break;
+
+ case THTTPSessionEvent::EConnectedWithReducedCapabilities:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Connected with reduced capabilities\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EDisconnected:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Disconnected\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EAuthenticatedOK:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Authenticated OK\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EAuthenticationFailure:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Authentication failure\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EConnectionTimedOut:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Connection timed out\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::ENotConnected:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Not connected\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EExceptionInfo:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Exception info\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::ERedirected:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Redirected\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EAlreadyConnecting:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Already connecting\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EAlreadyConnected:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Already connected\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EAlreadyDisconnecting:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Already disconnecting\r\n"));
+ }
+
+ }
+ break;
+
+ case THTTPSessionEvent::EAlreadyDisconnected:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Already disconnected\r\n"));
+ }
+
+ }
+ break;
+
+ default:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Session Event unrecgonised\r\n"));
+ }
+ }
+ break;
+ };
+ }
+
+//
+// CCmdWget::MHFSessionRunError
+// handles an error related up-calls
+TInt CCmdWget::MHFSessionRunError(TInt aError, const THTTPSessionEvent& /*aEvent*/)
+ {
+ if (iVerbose)
+ {
+ PrintError(aError, _L("HTTP Session Error"));
+ }
+ return KErrNone;
+ }
+
+//
+// CCmdWget::MHFRunL
+// handles any up-calls regarding a current transaction
+//
+void CCmdWget::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
+ {
+ if (aTransaction.Id() != iTransaction.Id())
+ {
+ if (iVerbose)
+ {
+ PrintError(KErrUnknown, _L("HTTP Transaction Id is invalid"));
+ }
+ User::Leave(KErrUnknown);
+ }
+ switch (aEvent.iStatus)
+ {
+ case THTTPEvent::EGotResponseHeaders:
+ {
+ if (iVerbose)
+ {
+ DumpRespHeadersL(aTransaction);
+ }
+ }
+ break;
+
+ case THTTPEvent::EGotResponseBodyData:
+ {
+ RHTTPResponse response = aTransaction.Response();
+ if (iVerbose)
+ {
+ Printf(_L("HTTP <%d> received\r\n"), response.StatusCode());
+ }
+ switch (response.StatusCode())
+ {
+ // informational codes (1xx)
+ case HTTPStatus::EContinue:
+ case HTTPStatus::ESwitchingProtocols:
+ break;
+
+ // successful codes (2xx)
+ case HTTPStatus::EOk:
+ {
+ MHTTPDataSupplier* body = aTransaction.Response().Body();
+ TPtrC8 data;
+ TBool last = body->GetNextDataPart(data);
+ if (!iPostData)
+ {
+ User::LeaveIfError(iLocalFile.Write(data));
+ if (last)
+ {
+ iLocalFile.Flush();
+ }
+ if (iVerbose)
+ {
+ Printf(_L("bytes: %d\r\n"), data.Length());
+ }
+ }
+ else
+ {
+ TBuf<512> woop;
+ woop.Copy(data);
+ Stdout().Write(woop);
+ }
+ body->ReleaseData();
+ }
+ break;
+
+ case HTTPStatus::ECreated:
+ case HTTPStatus::EAccepted:
+ case HTTPStatus::ENonAuthoritativeInfo:
+ case HTTPStatus::ENoContent:
+ case HTTPStatus::EResetContent:
+ break;
+
+ case HTTPStatus::EPartialContent:
+ {
+ // TODO - byte range support
+ }
+ break;
+
+ // Redirection codes (3xx)
+ case HTTPStatus::EMultipleChoices:
+ case HTTPStatus::EMovedPermanently:
+ case HTTPStatus::EFound:
+ case HTTPStatus::ESeeOther:
+ case HTTPStatus::ENotModified:
+ case HTTPStatus::EUseProxy:
+ case HTTPStatus::EUnused:
+ case HTTPStatus::ETemporaryRedirect:
+ if (iVerbose)
+ {
+ Printf(_L("Redirecting\r\n"));
+ }
+
+ break;
+
+ // Client error codes (4xx)
+ case HTTPStatus::EBadRequest:
+ case HTTPStatus::EUnauthorized:
+ case HTTPStatus::EPaymentRequired:
+ case HTTPStatus::EForbidden:
+ case HTTPStatus::ENotFound:
+ case HTTPStatus::EMethodNotAllowed:
+ case HTTPStatus::ENotAcceptable:
+ case HTTPStatus::EProxyAuthenticationRequired:
+ case HTTPStatus::ERequestTimeout:
+ case HTTPStatus::EConflict:
+ case HTTPStatus::EGone:
+ case HTTPStatus::ELengthRequired:
+ case HTTPStatus::EPreconditionFailed:
+ case HTTPStatus::ERequestEntityTooLarge:
+ case HTTPStatus::ERequestURITooLong:
+ case HTTPStatus::EUnsupportedMediaType:
+ case HTTPStatus::ERequestedRangeNotSatisfiable:
+ case HTTPStatus::EExpectationFailed:
+ {
+ if (iVerbose)
+ {
+ PrintError(KErrGeneral, _L("HTTP client error"));
+ }
+ Complete(KErrGeneral);
+ }
+ break;
+
+ // Server error codes (5xx)
+ case HTTPStatus::EInternalServerError:
+ case HTTPStatus::ENotImplemented:
+ case HTTPStatus::EBadGateway:
+ case HTTPStatus::EServiceUnavailable:
+ case HTTPStatus::EGatewayTimeout:
+ case HTTPStatus::EHTTPVersionNotSupported:
+ {
+ if (iVerbose)
+ {
+ PrintError(KErrGeneral, _L("HTTP Remote Server Error"));
+ }
+ Complete(KErrGeneral);
+ }
+ break;
+
+ default:
+ Complete(KErrGeneral);
+ break;
+ };
+ }
+ break;
+
+ case THTTPEvent::EResponseComplete:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("HTTP Response complete.\r\n"));
+ }
+ }
+ break;
+
+ case THTTPEvent::ESucceeded:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("Download transaction complete.\r\n"));
+ }
+ Complete(KErrNone);
+ }
+ break;
+
+ case THTTPEvent::EFailed:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("Download transaction failed. Aborting\r\n"));
+ }
+ Complete(KErrGeneral);
+ }
+ break;
+
+ case THTTPEvent::ERedirectedPermanently:
+ case THTTPEvent::ERedirectedTemporarily:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("Redirecting\r\n"));
+ }
+ }
+ break;
+
+ case THTTPEvent::ERedirectRequiresConfirmation:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("Redirect requires confirmation. Aborting\r\n"));
+ }
+ Complete(KErrAbort);
+ }
+ break;
+
+ default:
+ {
+ if (iVerbose)
+ {
+ Printf(_L("Transaction result: <%d>\r\n"), aEvent.iStatus);
+ }
+ if (aEvent.iStatus < 0)
+ {
+ Complete(aEvent.iStatus);
+ }
+ }
+ break;
+ };
+ }
+
+//
+// CCmdWget::MHFRunError
+// handles any error related up-calls from an underlying transaction in progress
+//
+TInt CCmdWget::MHFRunError(TInt aError, RHTTPTransaction /* aTransaction */, const THTTPEvent& /* aEvent */)
+ {
+ if (iVerbose)
+ {
+ PrintError(aError, _L("HTTP Transaction error"));
+ }
+ return KErrNone;
+ }
+
+//
+// CCmdWget::DumpRespHeadersL
+// dump the transaction response headers
+//
+void CCmdWget::DumpRespHeadersL(RHTTPTransaction& aTransaction)
+ {
+ RHTTPResponse resp = aTransaction.Response();
+ RStringPool strP = aTransaction.Session().StringPool();
+ RHTTPHeaders hdr = resp.GetHeaderCollection();
+ THTTPHdrFieldIter it = hdr.Fields();
+
+ TBuf<KMaxHeaderNameLen> fieldName16;
+ TBuf<KMaxHeaderValueLen> fieldVal16;
+
+ while (it.AtEnd() == EFalse)
+ {
+ RStringTokenF fieldName = it();
+ RStringF fieldNameStr = strP.StringF(fieldName);
+ THTTPHdrVal fieldVal;
+ if (hdr.GetField(fieldNameStr,0,fieldVal) == KErrNone)
+ {
+ const TDesC8& fieldNameDesC = fieldNameStr.DesC();
+ fieldName16.Copy(fieldNameDesC.Left(KMaxHeaderNameLen));
+ switch (fieldVal.Type())
+ {
+ case THTTPHdrVal::KTIntVal:
+ Printf(_L("%S: %d\r\n"), &fieldName16, fieldVal.Int());
+ break;
+ case THTTPHdrVal::KStrFVal:
+ {
+ RStringF fieldValStr = strP.StringF(fieldVal.StrF());
+ const TDesC8& fieldValDesC = fieldValStr.DesC();
+ fieldVal16.Copy(fieldValDesC.Left(KMaxHeaderValueLen));
+ Printf(_L("%S: %S\r\n"), &fieldName16, &fieldVal16);
+ }
+ break;
+ case THTTPHdrVal::KStrVal:
+ {
+ RString fieldValStr = strP.String(fieldVal.Str());
+ const TDesC8& fieldValDesC = fieldValStr.DesC();
+ fieldVal16.Copy(fieldValDesC.Left(KMaxHeaderValueLen));
+ Printf(_L("%S: %S\r\n"), &fieldName16, &fieldVal16);
+ }
+ break;
+ case THTTPHdrVal::KDateVal:
+ {
+ TDateTime date = fieldVal.DateTime();
+ TBuf<40> dateTimeString;
+ TTime t(date);
+ t.FormatL(dateTimeString,KDateFormat);
+ Printf(_L("%S: %S\r\n"), &fieldName16, &dateTimeString);
+ }
+ break;
+ default:
+ Printf(_L("%S: <unrecognised value type>\r\n"), &fieldName16);
+ break;
+ };
+
+ // Display realm for WWW-Authenticate header
+ RStringF wwwAuth = strP.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable());
+ if (fieldNameStr == wwwAuth)
+ {
+ // check the auth scheme is 'basic'
+ RStringF basic = strP.StringF(HTTP::EBasic,RHTTPSession::GetTable());
+ RStringF realm = strP.StringF(HTTP::ERealm,RHTTPSession::GetTable());
+ THTTPHdrVal realmVal;
+ if ((fieldVal.StrF() == basic) &&
+ (!hdr.GetParam(wwwAuth, realm, realmVal)))
+ {
+ RStringF realmValStr = strP.StringF(realmVal.StrF());
+ fieldVal16.Copy(realmValStr.DesC());
+ Printf(_L("Realm is: %S\r\n"), &fieldVal16);
+ }
+ }
+ }
+ ++it;
+ }
+ }
+
+//
+// MHTTPDataSupplier methods
+//
+
+//
+// CCmdWget::GetNextDataPart
+// reads a chunk of data from the source file
+//
+TBool CCmdWget::GetNextDataPart(TPtrC8& aDataPart)
+ {
+ ASSERT(iPostData);
+ ASSERT(iLocalFile.SubSessionHandle() > 0);
+
+ TBool result = EFalse;
+
+ // calc read length
+ TInt readlength = KDefaultChunkSize;
+ if ((iLocalFileSize - iLocalBytesRead) < readlength)
+ {
+ readlength = iLocalFileSize - iLocalBytesRead;
+ }
+
+ // if necessary, return previous chunk (per the SDK's MHTTPDataSupplier documentation)
+ if (!iReleaseDataCalled && (iPrevData.Length() > 0))
+ {
+ iReleaseDataCalled = EFalse;
+ aDataPart.Set(iPrevData);
+ return result;
+ }
+
+ // read another chunk of the data & pass it back
+ TInt error = iLocalFile.Read(iPrevData, readlength);
+ if (error != KErrNone)
+ {
+ if (iVerbose)
+ {
+ PrintError(error, _L("Unable to read data from local file."));
+ }
+ Complete(error);
+ return result;
+ }
+ aDataPart.Set(iPrevData);
+ iReleaseDataCalled = EFalse;
+ iLocalBytesRead += readlength;
+ if (iLocalBytesRead >= iLocalFileSize)
+ {
+ ASSERT((iLocalBytesRead == iLocalFileSize)); // else our math has gone wrong somewhere
+ result = ETrue;
+ }
+ return result;
+ }
+
+//
+// CCmdWget::ReleaseData
+// tell the http transaction we have more data available
+//
+void CCmdWget::ReleaseData()
+ {
+ ASSERT(iPostData);
+ iReleaseDataCalled = ETrue;
+ if ((iLocalFileSize - iLocalBytesRead) > 0)
+ {
+ // more data to come
+ TRAPD(error, iTransaction.NotifyNewRequestBodyPartL());
+ if (error != KErrNone)
+ {
+ if (iVerbose)
+ {
+ PrintError(error, _L("Unable to release data."));
+ }
+ Complete(error);
+ }
+ }
+ }
+
+//
+// CCmdWget::OverallDataSize
+// return the total size of the data we're to upload to the server
+//
+TInt CCmdWget::OverallDataSize()
+ {
+ ASSERT(iPostData);
+ ASSERT(iLocalFile.SubSessionHandle() > 0);
+ return iLocalFileSize;
+ }
+
+//
+// CCmdWget::Reset
+// Reset the data supply to the beginning of the local file
+//
+TInt CCmdWget::Reset()
+ {
+ ASSERT(iPostData);
+ ASSERT(iLocalFile.SubSessionHandle() > 0);
+ TInt pos = 0;
+ TInt error = iLocalFile.Seek(ESeekStart, pos); // not interested in pos
+ return error;
+ }
+
+
+EXE_BOILER_PLATE(CCmdWget)