core/builtins/ymodem.cpp
changeset 0 7f656887cf89
--- /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);
+	}
+