diff -Nur Filezilla3/src/engine/ControlSocket.h Filezilla3.patch/src/engine/ControlSocket.h
--- Filezilla3/src/engine/ControlSocket.h	Wed Aug 15 21:15:50 2007
+++ Filezilla3.patch/src/engine/ControlSocket.h	Wed Aug 15 21:34:19 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	Wed Aug 15 21:15:52 2007
+++ Filezilla3.patch/src/engine/FileZillaEngine.cpp	Wed Aug 15 21:34:45 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/engineprivate.cpp Filezilla3.patch/src/engine/engineprivate.cpp
--- Filezilla3/src/engine/engineprivate.cpp	Wed Aug 15 21:15:52 2007
+++ Filezilla3.patch/src/engine/engineprivate.cpp	Wed Aug 15 21:35:14 2007
@@ -525,6 +525,18 @@
 	return m_pControlSocket->Chmod(command);
 }
 
+int CFileZillaEnginePrivate::KeepAlive(const CKeepAliveCommand& command)
+{
+	if (!IsConnected())
+		return FZ_REPLY_NOTCONNECTED;
+
+	if (IsBusy())
+		return FZ_REPLY_BUSY;
+
+	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	Wed Aug 15 21:15:52 2007
+++ Filezilla3.patch/src/engine/ftpcontrolsocket.cpp	Wed Aug 15 21:38:08 2007
@@ -147,6 +147,8 @@
 {
 	LogMessage(Debug_Verbose, _T("CFtpControlSocket::OnReceive()"));
 
+	m_stopWatch.Start();
+
 	m_pBackend->Read(m_receiveBuffer + m_bufferLen, RECVBUFFERSIZE - m_bufferLen);
 	
 	if (m_pBackend->Error())
@@ -386,6 +388,9 @@
 	case cmd_rawtransfer:
 		TransferParseResponse();
 		break;
+	case cmd_keepalive:
+		KeepAliveParseResponse();
+		break;
 	case cmd_none:
 		LogMessage(Debug_Verbose, _T("Out-of-order reply, ignoring."));
 		break;
@@ -798,6 +803,7 @@
 		LogMessage(::Error, _T("Failed to convert command to 8 bit charset"));
 		return false;
 	}
+	m_stopWatch.Start();
 	unsigned int len = (unsigned int)strlen(buffer);
 	bool res = CRealControlSocket::Send(buffer, len);
 	if (res)
@@ -1254,6 +1260,8 @@
 		return DeleteSend(prevResult);
 	case cmd_removedir:
 		return RemoveDirSend(prevResult);
+	case cmd_keepalive:
+		return KeepAliveSend();
 	default:
 		LogMessage(__TFILE__, __LINE__, this, ::Debug_Warning, _T("Unknown opID (%d) in SendNextCommand"), m_pCurOpData->opId);
 		ResetOperation(FZ_REPLY_INTERNALERROR);
@@ -3007,6 +3015,74 @@
 
 	return FZ_REPLY_WOULDBLOCK;
 }
+
+class CKeepAliveOpData : public COpData
+{
+public:
+	CKeepAliveOpData(const wxString& command)
+		: COpData(cmd_keepalive)
+	{
+		m_command = command;
+	}
+
+	wxString m_command;
+};
+
+int CFtpControlSocket::KeepAlive(const CKeepAliveCommand& command)
+{
+	LogMessage(Debug_Verbose, _("CFtpControlSocket::KeepAlive"));
+
+	// ignore keepalive for last I/O for socket less than 15 seconds
+	if (m_stopWatch.Time() < 15000)
+		return FZ_REPLY_OK;
+	// choose any command
+	wxString commands[4] = {_T("PWD"),_T("REST 0"), _T("TYPE A"), _T("TYPE I") };
+	int choice=(rand()*4)/(RAND_MAX+1);
+	m_pCurOpData = new CKeepAliveOpData(commands[choice]);
+
+	return SendNextCommand();
+}
+
+int CFtpControlSocket::KeepAliveSend()
+{
+	LogMessage(Debug_Verbose, _T("CFtpControlSocket::KeepAliveSend"));
+
+	if (!m_pCurOpData)
+	{
+		LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Empty m_pCurOpData"));
+		ResetOperation(FZ_REPLY_INTERNALERROR);
+		return FZ_REPLY_ERROR;
+	}
+
+	CDirectoryCache cache;
+	cache.InvalidateServer(*m_pCurrentServer);
+	m_CurrentPath = CServerPath();
+
+	CKeepAliveOpData *pData = static_cast<CKeepAliveOpData *>(m_pCurOpData);
+
+	if (!Send(pData->m_command))
+		return FZ_REPLY_ERROR;
+
+	return FZ_REPLY_WOULDBLOCK;
+}
+
+int CFtpControlSocket::KeepAliveParseResponse()
+{
+	LogMessage(Debug_Verbose, _T("CFtpControlSocket::KeepAliveParseResponse"));
+
+	int code = GetReplyCode();
+	if (code == 2 || code == 3)
+	{
+		ResetOperation(FZ_REPLY_OK);
+		return FZ_REPLY_OK;
+	}
+	else
+	{
+		ResetOperation(FZ_REPLY_ERROR);
+		return FZ_REPLY_ERROR;
+	}
+}
+
 
 bool CFtpControlSocket::IsMisleadingListResponse() const
 {
diff -Nur Filezilla3/src/engine/ftpcontrolsocket.h Filezilla3.patch/src/engine/ftpcontrolsocket.h
--- Filezilla3/src/engine/ftpcontrolsocket.h	Wed Aug 15 21:15:50 2007
+++ Filezilla3.patch/src/engine/ftpcontrolsocket.h	Wed Aug 15 21:30:14 2007
@@ -24,6 +24,11 @@
 
 protected:
 	
+	wxStopWatch m_stopWatch;
+	virtual int KeepAlive(const CKeepAliveCommand& command);
+	int KeepAliveParseResponse();
+	int KeepAliveSend();
+
 	virtual int ResetOperation(int nErrorCode);
 
 	virtual int Connect(const CServer &server);
diff -Nur Filezilla3/src/include/commands.h Filezilla3.patch/src/include/commands.h
--- Filezilla3/src/include/commands.h	Wed Aug 15 21:15:37 2007
+++ Filezilla3.patch/src/include/commands.h	Wed Aug 15 21:15:07 2007
@@ -19,6 +19,7 @@
 	cmd_rename,
 	cmd_chmod,
 	cmd_raw,
+	cmd_keepalive,
 
 	// Only used internally
 	cmd_cwd,
@@ -76,6 +77,8 @@
 	CServer m_Server;
 };
 
+DECLARE_COMMAND(CKeepAliveCommand, cmd_keepalive)
+};
 DECLARE_COMMAND(CDisconnectCommand, cmd_disconnect)
 };
 
diff -Nur Filezilla3/src/include/engineprivate.h Filezilla3.patch/src/include/engineprivate.h
--- Filezilla3/src/include/engineprivate.h	Wed Aug 15 21:15:37 2007
+++ Filezilla3.patch/src/include/engineprivate.h	Wed Aug 15 21:15:07 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	Wed Aug 15 21:15:58 2007
+++ Filezilla3.patch/src/interface/Mainfrm.cpp	Wed Aug 15 21:33:21 2007
@@ -43,6 +43,7 @@
 #endif
 
 #define TRANSFERSTATUS_TIMER_ID wxID_HIGHEST + 3
+#define KEEPALIVE_TIMER_ID TRANSFERSTATUS_TIMER_ID + 1
 
 static const int statbarWidths[6] = {
 #ifdef __WXMSW__
@@ -159,6 +160,7 @@
 	}
 
 	m_transferStatusTimer.SetOwner(this, TRANSFERSTATUS_TIMER_ID);
+	m_keepAliveTimer.SetOwner(this, KEEPALIVE_TIMER_ID);
 
 	CreateMenus();
 	CreateToolBar();
@@ -696,6 +698,7 @@
 	if (!m_pState->m_pCommandQueue->Idle())
 		return;
 
+	m_keepAliveTimer.Stop();
 	m_pState->m_pCommandQueue->ProcessCommand(new CDisconnectCommand());
 }
 
@@ -769,6 +772,8 @@
 	m_pSendLed = 0;
 	m_pRecvLed = 0;
 
+	m_keepAliveTimer.Stop();
+
 	m_transferStatusTimer.Stop();
 
 	bool res = true;
@@ -826,6 +831,9 @@
 	CServerPath path;
 	path.SetSafePath(COptions::Get()->GetOption(OPTION_LASTSERVERPATH));
 	m_pState->Connect(server, false, path);
+	// FIXME:
+	// need to read from options, do this only for KeepAlive enabled
+	m_keepAliveTimer.Start(1000);
 }
 
 void CMainFrame::OnRefresh(wxCommandEvent &event)
@@ -898,6 +906,39 @@
 		else
 			m_transferStatusTimer.Stop();
 	}
+	else if (event.GetId() == KEEPALIVE_TIMER_ID && m_keepAliveTimer.IsRunning())
+	{
+		// make sure engine and commandqueue exist
+		if (!m_pState && !m_pState->m_pEngine && !m_pState->m_pCommandQueue)
+		{
+			m_keepAliveTimer.Stop();
+			return;
+		}
+		// just do this for idle, wait for next timer
+		if (!m_pState->m_pCommandQueue->Idle())
+			return;
+		// if not connected, stop keepalive timer
+		if (!m_pState->m_pEngine->IsConnected())
+		{
+			m_keepAliveTimer.Stop();
+			return;
+		}
+		// FIXME:
+		// need to read the values from options...
+		int min_wait = 30;
+		int max_wait = 60;
+
+		// if just connected, the interval will be 1000
+		bool first_time = (m_keepAliveTimer.GetInterval() == 1000);
+
+		int waitsecond = min_wait + (int)(rand()*(max_wait - min_wait)/(RAND_MAX+1));
+		m_keepAliveTimer.Stop();
+		m_keepAliveTimer.Start(waitsecond * 1000);
+		// skip keepalive for just connected
+		if (first_time)
+			return;
+		m_pState->m_pCommandQueue->ProcessCommand(new CKeepAliveCommand());
+	}
 }
 
 void CMainFrame::SetProgress(const CTransferStatus *pStatus)
@@ -1342,6 +1383,9 @@
 	}
 
 	m_pState->Connect(pData->m_server, true, pData->m_remoteDir);
+	// FIXME:
+	// need to read from options, do this only for KeepAlive enabled
+	m_keepAliveTimer.Start(1000);
 
 	if (pData->m_localDir != _T(""))
 		m_pState->SetLocalDir(pData->m_localDir);
diff -Nur Filezilla3/src/interface/Mainfrm.h Filezilla3.patch/src/interface/Mainfrm.h
--- Filezilla3/src/interface/Mainfrm.h	Wed Aug 15 21:15:56 2007
+++ Filezilla3.patch/src/interface/Mainfrm.h	Wed Aug 15 21:15:21 2007
@@ -84,6 +84,9 @@
 	CLed* m_pRecvLed;
 	CLed* m_pSendLed;
 	wxTimer m_transferStatusTimer;
+
+	wxTimer m_keepAliveTimer;
+
 	CThemeProvider* m_pThemeProvider;
 #if FZ_MANUALUPDATECHECK && FZ_AUTOUPDATECHECK
 	CUpdateWizard* m_pUpdateWizard;
