--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/builtins/ymodem.cpp Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,283 @@
+// ymodem.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
+//
+
+#include <fshell/ioutils.h>
+#include "ymodem.h"
+
+using namespace IoUtils;
+
+CCommandBase* CCmdYmodem::NewLC()
+ {
+ CCmdYmodem* self = new(ELeave) CCmdYmodem();
+ CleanupStack::PushL(self);
+ self->BaseConstructL();
+ self->ConstructL();
+ return self;
+ }
+
+CCmdYmodem::~CCmdYmodem()
+ {
+ iFileNames.Close();
+ }
+
+CCmdYmodem::CCmdYmodem()
+ {
+ }
+
+const TDesC& CCmdYmodem::Name() const
+ {
+ _LIT(KName, "ymodem");
+ return KName;
+ }
+
+class TFailedFile
+ {
+public:
+ TFailedFile();
+public:
+ TInt iError;
+ TFileName2 iFileName;
+ };
+
+TFailedFile::TFailedFile()
+ : iError(KErrNone)
+ {
+ }
+
+void CCmdYmodem::DoRunL()
+ {
+ PrepareConsoleToTransferL();
+
+ if (iMode == EReceive)
+ {
+ TPtrC receiveDir;
+ if (iFileNames.Count() > 1)
+ {
+ PrintError(KErrArgument, _L("Too many arguments - only the receive directory may be specified in receive mode."));
+ User::Leave(KErrArgument);
+ }
+ else if (iFileNames.Count() == 1)
+ {
+ TFileName2 fileName(iFileNames[0]);
+ receiveDir.Set(iFileNames[0]);
+
+ if ((fileName.Exists(FsL()) && !fileName.IsDirL(FsL())) || (!fileName.Exists(FsL()) && !iOverwrite))
+ {
+ LeaveIfErr(KErrArgument, _L("\"%S\" is not a directory"), &fileName);
+ }
+ }
+ else
+ {
+ receiveDir.Set(Env().Pwd());
+ }
+
+ Progress(_L("YMODEM receive to \"%S\"\r\n"), &receiveDir);
+ RArray<TFileName2> receivedFiles;
+ CleanupClosePushL(receivedFiles);
+ TFailedFile failedFile;
+ TBool finished(EFalse);
+ while (!finished)
+ {
+ TSyncResult syncResult = SendSyncL();
+ if (syncResult == EEot)
+ {
+ finished = ETrue;
+ }
+ else
+ {
+ iPacketNumber = 0;
+ TBool isFinalBlock(EFalse);
+ TPtrC block(ReceiveBlockL(ETrue, isFinalBlock));
+ TPtrC fileName(block.Ptr()); // filename is the first null terminated string in the block.
+ if (fileName.Length() > 0)
+ {
+ TFileName2 fileName2(fileName);
+ fileName2.MakeAbsoluteL(receiveDir);
+ TLex lex(block.Mid(fileName.Length() + 1));
+ TInt size;
+ User::LeaveIfError(lex.Val(size));
+ TInt err = KErrNone;
+ if (!iOverwrite && fileName2.Exists(FsL()))
+ {
+ err = KErrAlreadyExists;
+ }
+ RFile file;
+ if (err == KErrNone)
+ {
+ if (size == 0)
+ {
+ if (iOverwrite)
+ {
+ err = file.Replace(FsL(), fileName2, EFileWrite);
+ }
+ else
+ {
+ err = file.Create(FsL(), fileName2, EFileWrite);
+ }
+ }
+ else
+ {
+ Progress(_L("Starting receive of \"%S\" (%d bytes)\r\n"), &fileName, size);
+ SendSyncL();
+ TRAP(err, ReceiveToFileL(fileName2));
+ if (err == KErrNone)
+ {
+ err = file.Open(FsL(), fileName2, EFileWrite);
+ if (err == KErrNone)
+ {
+ err = file.SetSize(size);
+ }
+ }
+ else
+ {
+ Fs().Delete(fileName2);
+ }
+ }
+ }
+ else
+ {
+ TRAP_IGNORE(ReceiveToNullL());
+ }
+ file.Close();
+ if (err)
+ {
+ failedFile.iError = err;
+ failedFile.iFileName = fileName2;
+ finished = ETrue;
+ }
+ else
+ {
+ receivedFiles.Append(fileName2); // Ignore error.
+ }
+ }
+ else
+ {
+ finished = ETrue;
+ }
+ }
+ }
+
+ CleanupClonsoleAfterTransferL();
+
+ const TInt numFilesReceived = receivedFiles.Count();
+ if (numFilesReceived == 0)
+ {
+ if (failedFile.iError == KErrNone)
+ {
+ Printf(_L("No files to receive.\r\n"));
+ }
+ }
+ else if (numFilesReceived == 1)
+ {
+ const TFileName2& fileName = receivedFiles[0];
+ Printf(_L("Successfully received \"%S\".\r\n"), &fileName);
+ }
+ else
+ {
+ Printf(_L("Successfully received:\r\n"));
+ for (TInt i = 0; i < numFilesReceived; ++i)
+ {
+ const TFileName2& fileName = receivedFiles[i];
+ Printf(_L("\t\"%S\"\r\n"), &fileName);
+ }
+ }
+
+ if (failedFile.iError)
+ {
+ PrintError(failedFile.iError, _L("Failed to receive \"%S\""), &failedFile.iFileName);
+ }
+ CleanupStack::PopAndDestroy(&receivedFiles);
+ }
+ else if (iMode == ESend)
+ {
+ const TInt numFiles = iFileNames.Count();
+ if (numFiles == 0)
+ {
+ PrintError(KErrArgument, _L("No files to send specified"));
+ User::Leave(KErrArgument);
+ }
+ for (TInt i = 0; i < numFiles; ++i)
+ {
+ const TFileName2& fileName = iFileNames[i];
+ if (fileName.Exists(FsL()))
+ {
+ if (fileName.IsDirL(FsL()))
+ {
+ LeaveIfErr(KErrArgument, _L("\"%S\" is not a file"), &fileName);
+ }
+ }
+ else
+ {
+ LeaveIfErr(KErrArgument, _L("\"%S\" does not exist"), &fileName);
+ }
+ }
+ WaitForSyncL();
+ HBufC* buf = HBufC::NewLC(iBlockSize);
+ TPtr bufPtr(buf->Des());
+ for (TInt i = 0; i < numFiles; ++i)
+ {
+ const TFileName2& fileName = iFileNames[i];
+ LeaveIfFileNotFound(fileName);
+ TEntry entry;
+ User::LeaveIfError(FsL().Entry(fileName, entry));
+ bufPtr.SetLength(bufPtr.MaxLength());
+ bufPtr.FillZ();
+ bufPtr.Copy(fileName.NameAndExt());
+ bufPtr.SetLength(buf->Length() + 1); // To leave a terminating null after the file name.
+ bufPtr.AppendNum(entry.iSize);
+ if (bufPtr.Length() < iBlockSize)
+ {
+ // There's not enough data to fill this block, so pad with NULL.
+ bufPtr.AppendFill(0, iBlockSize - bufPtr.Length());
+ }
+ iPacketNumber = 0;
+ SendBlockL(*buf);
+ WaitForSyncL();
+ SendFileL(fileName);
+ }
+ iPacketNumber = 0;
+ bufPtr.SetLength(bufPtr.MaxLength());
+ bufPtr.FillZ();
+ SendBlockL(*buf);
+ CleanupStack::PopAndDestroy(buf);
+ CleanupClonsoleAfterTransferL();
+
+ if (numFiles == 1)
+ {
+ Printf(_L("Successfully sent \"%S\".\r\n"), &iFileNames[0]);
+ }
+ else
+ {
+ Printf(_L("Successfully sent:\r\n"));
+ for (TInt i = 0; i < numFiles; ++i)
+ {
+ const TFileName2& fileName = iFileNames[i];
+ Printf(_L("\t\"%S\"\r\n"), &fileName);
+ }
+ }
+ }
+ User::LeaveIfError(Stdin().CancelCaptureAllKeys());
+ }
+
+void CCmdYmodem::ArgumentsL(RCommandArgumentList& aArguments)
+ {
+ _LIT(KArg1, "mode");
+ aArguments.AppendEnumL((TInt&)iMode, KArg1);
+ _LIT(KArg2, "file_name");
+ aArguments.AppendFileNameL(iFileNames, KArg2);
+ }
+
+void CCmdYmodem::OptionsL(RCommandOptionList& aOptions)
+ {
+ CCmdXmodem::OptionsL(aOptions);
+ }
+