diff -Nur Filezilla3/src/engine/ControlSocket.h Filezilla3.patch/src/engine/ControlSocket.h
--- Filezilla3/src/engine/ControlSocket.h	Mon Sep 24 22:05:20 2007
+++ Filezilla3.patch/src/engine/ControlSocket.h	Mon Sep 24 22:05:49 2007
@@ -115,6 +115,8 @@
 	virtual int Chmod(const CChmodCommand& command) { return FZ_REPLY_NOTSUPPORTED; }
 	virtual bool Connected() const = 0;
 
+	virtual int KeepAlive(const CKeepAliveCommand& command) { return FZ_REPLY_OK; }
+
 	// If m_pCurrentOpData is zero, this function returns the current command
 	// from the engine.
 	enum Command GetCurrentCommandId() const;
diff -Nur Filezilla3/src/engine/FileZillaEngine.cpp Filezilla3.patch/src/engine/FileZillaEngine.cpp
--- Filezilla3/src/engine/FileZillaEngine.cpp	Mon Sep 24 22:05:20 2007
+++ Filezilla3.patch/src/engine/FileZillaEngine.cpp	Mon Sep 24 22:05:49 2007
@@ -70,6 +70,9 @@
 	case cmd_chmod:
 		res = Chmod(reinterpret_cast<const CChmodCommand&>(command));
 		break;
+	case cmd_keepalive:
+		res = KeepAlive(reinterpret_cast<const CKeepAliveCommand &>(command));
+		break;
 	default:
 		return FZ_REPLY_SYNTAXERROR;
 	}
diff -Nur Filezilla3/src/engine/commands.cpp Filezilla3.patch/src/engine/commands.cpp
--- Filezilla3/src/engine/commands.cpp	Mon Sep 24 22:05:20 2007
+++ Filezilla3.patch/src/engine/commands.cpp	Mon Sep 24 22:05:49 2007
@@ -10,6 +10,16 @@
 	return m_Server;
 }
 
+CKeepAliveCommand::CKeepAliveCommand(bool keepAlive /*=true*/)
+    : m_keepAlive(keepAlive)
+{
+}
+
+bool CKeepAliveCommand::IsKeepAlive() const
+{
+	return m_keepAlive;
+}
+
 CListCommand::CListCommand(bool refresh /*=false*/)
 	: m_refresh(refresh)
 {
diff -Nur Filezilla3/src/engine/engineprivate.cpp Filezilla3.patch/src/engine/engineprivate.cpp
--- Filezilla3/src/engine/engineprivate.cpp	Mon Sep 24 22:05:20 2007
+++ Filezilla3.patch/src/engine/engineprivate.cpp	Mon Sep 24 22:05:49 2007
@@ -525,6 +525,12 @@
 	return m_pControlSocket->Chmod(command);
 }
 
+int CFileZillaEnginePrivate::KeepAlive(const CKeepAliveCommand& command)
+{
+	m_pCurrentCommand = command.Clone();
+	return m_pControlSocket->KeepAlive(command);
+}
+
 void CFileZillaEnginePrivate::SendDirectoryListingNotification(const CServerPath& path, bool onList, bool modified, bool failed)
 {
 	wxASSERT(m_pControlSocket);
diff -Nur Filezilla3/src/engine/ftpcontrolsocket.cpp Filezilla3.patch/src/engine/ftpcontrolsocket.cpp
--- Filezilla3/src/engine/ftpcontrolsocket.cpp	Mon Sep 24 22:05:20 2007
+++ Filezilla3.patch/src/engine/ftpcontrolsocket.cpp	Mon Sep 24 22:05:49 2007
@@ -24,8 +24,11 @@
 #define LOGON_CUSTOMCOMMANDS 10
 #define LOGON_DONE		11
 
+#define KEEPALIVE_TIMER_ID wxID_HIGHEST + 5
+
 BEGIN_EVENT_TABLE(CFtpControlSocket, CRealControlSocket)
 EVT_FZ_EXTERNALIPRESOLVE(wxID_ANY, CFtpControlSocket::OnExternalIPAddress)
+EVT_TIMER(wxID_ANY, CFtpControlSocket::OnTimer)
 END_EVENT_TABLE();
 
 CRawTransferOpData::CRawTransferOpData()
@@ -137,6 +140,8 @@
 	m_pTlsSocket = 0;
 	m_protectDataChannel = false;
 	m_lastTypeBinary = -1;
+	m_bEnableKeepAlive = false;
+	m_keepAliveTimer.SetOwner(this, KEEPALIVE_TIMER_ID);
 }
 
 CFtpControlSocket::~CFtpControlSocket()
@@ -147,12 +152,16 @@
 {
 	LogMessage(Debug_Verbose, _T("CFtpControlSocket::OnReceive()"));
 
+	m_keepAliveStopWatch.Start();
+
 	m_pBackend->Read(m_receiveBuffer + m_bufferLen, RECVBUFFERSIZE - m_bufferLen);
-	
+
 	if (m_pBackend->Error())
 	{
 		if (m_pBackend->LastError() != wxSOCKET_WOULDBLOCK)
 		{
+			m_bEnableKeepAlive = false;
+			m_keepAliveTimer.Stop();
 			LogMessage(::Error, _("Disconnected from server"));
 			DoClose();
 		}
@@ -344,6 +353,7 @@
 
 	if (m_repliesToSkip)
 	{
+		SetWait(false);
 		LogMessage(Debug_Info, _T("Skipping reply after cancelled operation."));
 		if (m_Response[0] != '1')
 			m_repliesToSkip--;
@@ -798,6 +808,7 @@
 		LogMessage(::Error, _T("Failed to convert command to 8 bit charset"));
 		return false;
 	}
+	m_keepAliveStopWatch.Start();
 	unsigned int len = (unsigned int)strlen(buffer);
 	bool res = CRealControlSocket::Send(buffer, len);
 	if (res)
@@ -3006,6 +3017,75 @@
 	}
 
 	return FZ_REPLY_WOULDBLOCK;
+}
+
+int CFtpControlSocket::KeepAlive(const CKeepAliveCommand& command)
+{
+	LogMessage(Debug_Verbose, _T("CFtpControlSocket::KeepAlive"));
+
+	if (command.IsKeepAlive())
+	{
+		if (!m_bEnableKeepAlive)
+		{
+			m_bEnableKeepAlive = true;
+			// FIXME:
+			// read keepalive option here
+			int min_wait = 30;
+			int max_wait = 60;
+			int waitsecond = min_wait + (int)(rand()*(max_wait - min_wait)/(RAND_MAX+1));
+			m_keepAliveTimer.Start(waitsecond * 1000);
+		}
+	}
+	else
+	{
+		if (m_bEnableKeepAlive)
+		{
+			m_bEnableKeepAlive = false;
+			m_keepAliveTimer.Stop();
+		}
+	}
+
+	m_bEnableKeepAlive = true;
+	return FZ_REPLY_OK;
+}
+
+void CFtpControlSocket::DoKeepAlive()
+{
+	LogMessage(Debug_Verbose, _T("CFtpControlSocket::DoKeepAlive"));
+
+	// ignore keepalive for last I/O for socket less than 15 seconds
+	if (m_keepAliveStopWatch.Time() < 15000)
+		return;
+	// choose any command
+	wxString commands[4] = {_T("PWD"),_T("REST 0"), _T("NOOP"), _T("STAT") };
+	int choice=(rand()*4)/(RAND_MAX+1);
+
+	m_repliesToSkip++;
+	Send(commands[choice]);
+	return;
+}
+
+void CFtpControlSocket::OnTimer(wxTimerEvent& event)
+{
+	if (event.GetId() == KEEPALIVE_TIMER_ID)
+	{
+		if (m_keepAliveTimer.IsRunning())
+		{
+			m_keepAliveTimer.Stop();
+			if (m_bEnableKeepAlive && IsConnected()) {
+				// FIXME:
+				// need to read the values from options...
+				int min_wait = 30;
+				int max_wait = 60;
+
+				int waitsecond = min_wait + (int)(rand()*(max_wait - min_wait)/(RAND_MAX+1));
+				m_keepAliveTimer.Start(waitsecond * 1000);
+				DoKeepAlive();
+			}
+		}
+	}
+	else
+		CControlSocket::OnTimer(event);
 }
 
 bool CFtpControlSocket::IsMisleadingListResponse() const
diff -Nur Filezilla3/src/engine/ftpcontrolsocket.h Filezilla3.patch/src/engine/ftpcontrolsocket.h
--- Filezilla3/src/engine/ftpcontrolsocket.h	Mon Sep 24 22:05:20 2007
+++ Filezilla3.patch/src/engine/ftpcontrolsocket.h	Mon Sep 24 22:05:49 2007
@@ -24,6 +24,12 @@
 
 protected:
 	
+	bool m_bEnableKeepAlive;
+	wxTimer m_keepAliveTimer;
+	wxStopWatch m_keepAliveStopWatch;
+	virtual int KeepAlive(const CKeepAliveCommand& command);
+	void DoKeepAlive();
+
 	virtual int ResetOperation(int nErrorCode);
 
 	virtual int Connect(const CServer &server);
@@ -128,6 +134,7 @@
 
 	DECLARE_EVENT_TABLE();
 	void OnExternalIPAddress(fzExternalIPResolveEvent& event);
+	void OnTimer(wxTimerEvent& event);
 };
 
 class CIOThread;
diff -Nur Filezilla3/src/include/commands.h Filezilla3.patch/src/include/commands.h
--- Filezilla3/src/include/commands.h	Mon Sep 24 22:05:12 2007
+++ Filezilla3.patch/src/include/commands.h	Mon Sep 24 22:05:49 2007
@@ -19,6 +19,7 @@
 	cmd_rename,
 	cmd_chmod,
 	cmd_raw,
+	cmd_keepalive,
 
 	// Only used internally
 	cmd_cwd,
@@ -74,6 +75,15 @@
 	const CServer GetServer() const;
 protected:
 	CServer m_Server;
+};
+
+DECLARE_COMMAND(CKeepAliveCommand, cmd_keepalive)
+	CKeepAliveCommand(bool keepAlive = true);
+
+	bool IsKeepAlive() const;
+
+protected:
+	bool m_keepAlive;
 };
 
 DECLARE_COMMAND(CDisconnectCommand, cmd_disconnect)
diff -Nur Filezilla3/src/include/engineprivate.h Filezilla3.patch/src/include/engineprivate.h
--- Filezilla3/src/include/engineprivate.h	Mon Sep 24 22:05:12 2007
+++ Filezilla3.patch/src/include/engineprivate.h	Mon Sep 24 22:05:49 2007
@@ -69,6 +69,7 @@
 	int Mkdir(const CMkdirCommand& command);
 	int Rename(const CRenameCommand& command);
 	int Chmod(const CChmodCommand& command);
+	int KeepAlive(const CKeepAliveCommand& command);
 
 	int ContinueConnect();
 
diff -Nur Filezilla3/src/interface/Mainfrm.cpp Filezilla3.patch/src/interface/Mainfrm.cpp
--- Filezilla3/src/interface/Mainfrm.cpp	Mon Sep 24 22:08:54 2007
+++ Filezilla3.patch/src/interface/Mainfrm.cpp	Mon Sep 24 22:09:18 2007
@@ -932,7 +932,10 @@
 
 	CServerPath path;
 	path.SetSafePath(COptions::Get()->GetOption(OPTION_LASTSERVERPATH));
-	m_pState->Connect(server, false, path);
+	// FIXME:
+	// read keepalive from option
+	bool keepAlive = true;
+	m_pState->Connect(server, false, keepAlive, path);
 }
 
 void CMainFrame::OnRefresh(wxCommandEvent &event)
@@ -1456,7 +1459,10 @@
 			return;
 	}
 
-	m_pState->Connect(pData->m_server, true, pData->m_remoteDir);
+	// FIXME:
+	// read keepalive from option
+	bool keepAlive = true;
+	m_pState->Connect(pData->m_server, true, keepAlive, pData->m_remoteDir);
 
 	if (pData->m_localDir != _T(""))
 		m_pState->SetLocalDir(pData->m_localDir);
diff -Nur Filezilla3/src/interface/quickconnectbar.cpp Filezilla3.patch/src/interface/quickconnectbar.cpp
--- Filezilla3/src/interface/quickconnectbar.cpp	Mon Sep 24 22:08:54 2007
+++ Filezilla3.patch/src/interface/quickconnectbar.cpp	Mon Sep 24 22:09:18 2007
@@ -108,7 +108,10 @@
 		return;
 	}
 
-	if (!m_pState->Connect(server, true))
+	// FIXME:
+	// read keepalive from option
+	bool keepAlive = true;
+	if (!m_pState->Connect(server, true, keepAlive))
 		return;
 
 	CRecentServerList::SetMostRecentServer(server);
diff -Nur Filezilla3/src/interface/state.cpp Filezilla3.patch/src/interface/state.cpp
--- Filezilla3/src/interface/state.cpp	Mon Sep 24 22:08:54 2007
+++ Filezilla3.patch/src/interface/state.cpp	Mon Sep 24 22:09:18 2007
@@ -259,7 +259,7 @@
 	NotifyHandlers(STATECHANGE_APPLYFILTER);
 }
 
-bool CState::Connect(const CServer& server, bool askBreak, const CServerPath& path /*=CServerPath()*/)
+bool CState::Connect(const CServer& server, bool askBreak, bool keepAlive /*=false*/, const CServerPath& path /*=CServerPath()*/)
 {
 	if (!m_pEngine)
 		return false;
@@ -273,6 +273,8 @@
 
 	m_pCommandQueue->ProcessCommand(new CConnectCommand(server));
 	m_pCommandQueue->ProcessCommand(new CListCommand(path));
+	if (keepAlive)
+		m_pCommandQueue->ProcessCommand(new CKeepAliveCommand(true));
 	
 	COptions::Get()->SetLastServer(server);
 	COptions::Get()->SetOption(OPTION_LASTSERVERPATH, path.GetSafePath());
diff -Nur Filezilla3/src/interface/state.h Filezilla3.patch/src/interface/state.h
--- Filezilla3/src/interface/state.h	Mon Sep 24 22:08:54 2007
+++ Filezilla3.patch/src/interface/state.h	Mon Sep 24 22:09:18 2007
@@ -40,7 +40,7 @@
 	static bool LocalDirHasParent(const wxString& dir);
 	static bool LocalDirIsWriteable(const wxString& dir);
 
-	bool Connect(const CServer& server, bool askBreak, const CServerPath& path = CServerPath());
+	bool Connect(const CServer& server, bool askBreak, bool keepAlive = false, const CServerPath& path = CServerPath());
 
 	bool SetRemoteDir(const CDirectoryListing *m_pDirectoryListing, bool modified = false);
 	const CDirectoryListing *GetRemoteDir() const;
