RemoteInterface.cpp
上传用户:surprise9
上传日期:2007-01-04
资源大小:426k
文件大小:19k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. // This is part of the WAR SOFTWARE SERIES initiated by Jarle Aase
  2. // Copyright 1996 by Jarle Aase. All rights reserved.
  3. // See the "War Software Series Licende Agreement" for details concerning 
  4. // use and distribution.
  5. // ---
  6. // This source code, executables and programs containing source code or
  7. // binaries or proprietetary technology from the War Software Series are
  8. // NOT alloed used, viewed or tested by any governmental agencies in
  9. // any countries. This includes the government, departments, police, 
  10. // military etc.
  11. // ---
  12. // This file is intended for use with Tab space = 2
  13. // Created and maintained in MSVC Developer Studio
  14. // ---
  15. // NAME : RemoteInterface.cpp
  16. // PURPOSE : Basic socket handeling
  17. // PROGRAM : 
  18. // DATE : Nov. 14 1996
  19. // AUTHOR : Jarle Aase
  20. // ---
  21. // REVISION HISTORY
  22. // 
  23. #include "stdafx.h"
  24. #include "telnet.h"
  25. #include "ftp.h"
  26. #include "WarSoftware.h"
  27. #ifdef _DEBUG
  28. #define new DEBUG_NEW
  29. #undef THIS_FILE
  30. static char THIS_FILE[] = __FILE__;
  31. #endif
  32. ///////////////////////////////////////////////////////////////////////////////
  33. // Generic Remote connection interface
  34. // Handles standard Internet server reply codes for the supported protocols
  35. // The replies include the server reply code.
  36. CRemoteInterface::CRemoteInterface()
  37. {
  38. m_CurrentRequest.Empty();
  39. m_CurrentReply.Empty();
  40. CurrentQueueIndex = 0;
  41. CurrentRequestQueue = NULL;
  42. CurrentReplyQueue = NULL;
  43. m_InBuf.Empty();
  44. m_OutBuf.Empty();
  45. m_SuspendOnClose = TRUE;
  46. m_Type = LT_REMOTE;
  47. m_FileHandle = INVALID_HANDLE_VALUE;
  48. m_BytesLeftToDownload = 0;
  49. }
  50. CRemoteInterface::~CRemoteInterface()
  51. {
  52. if (CurrentRequestQueue)
  53. delete CurrentRequestQueue;
  54. if (CurrentReplyQueue)
  55. delete CurrentReplyQueue;
  56. m_RequestQueue.KillAll();
  57. }
  58. // Open a connection to a War daemon
  59. BOOL CRemoteInterface::OpenRemote(LPCSTR Address, UINT Port, int Service, LPCSTR UserName, 
  60. LPCSTR UserPwd)
  61. {
  62. CString cBuf;
  63. m_ConnectionTimer.Reset();
  64. char buf[MAX_PATH];
  65. m_UserName = UserName;
  66. m_UserPwd = UserPwd;
  67. switch(Service)
  68. {
  69. case LT_REMOTE:
  70. m_Type = LT_REMOTE;
  71. break;
  72. case LT_FTP:
  73. m_Type = LT_FTP;
  74. // Handle firewalls
  75. // Classic proxy
  76. if (COptions::GetOption(COPTION_CFTPCLIENTFIREWALL, CFTPCLIENTOPTIONS_FIREWALLTYPE) == '1')
  77. {
  78. m_UserName.Format("%s@%s", UserName, Address);
  79. strcpy(buf,COptions::GetOption(COPTION_CFTPCLIENTFIREWALL, CFTPCLIENTOPTIONS_FIREWALLHOST));
  80. cBuf = COptions::GetOption(COPTION_CFTPCLIENTFIREWALL, CFTPCLIENTOPTIONS_FIREWALLPORT);
  81. if (cBuf == "FTP")
  82. cBuf = "21";
  83. if ((Port = atoi(cBuf)) == 0)
  84. {
  85. LogMsg(LOGF_ERROR,"Port not defined for proxy/firewall");
  86. return FALSE;
  87. }
  88. LogMsg(LOGF_INOUT,"Using classic proxy logon at %s:%d (USER %s).", 
  89. buf, Port,m_UserName);
  90. Address = buf;
  91. }
  92. break;
  93. default:
  94. LogMsg(LOGF_ERROR,"OpenRemote() - Create() failed. Unknown daemon type (%d).", Service);
  95. return FALSE;
  96. }
  97. if (!Create())
  98. {
  99. LogMsg(LOGF_ERROR,"OpenRemote() - Create() failed. %s.", GetLastErrorText());
  100. return FALSE;
  101. }
  102. LogMsg(LOGF_DEBUG, "Connecting to remote host (%s) %s on port %u", 
  103. SafeStringIndex(CSock::DaemonTypes, m_Type, LT_INVALID), Address, Port);
  104. AsyncSelect(FD_CONNECT|FD_CLOSE);
  105. if (!Connect(Address,Port))
  106. {
  107. if (GetLastError() != WSAEWOULDBLOCK)
  108. {
  109. LogMsg(LOGF_ERROR,"OpenRemote() - Connect() failed. %s.", GetLastErrorText());
  110. return FALSE;
  111. }
  112. return TRUE;
  113. }
  114. // Connected without delay.... Don't know if this can happen...
  115. try
  116. {
  117. OnConnect(0);
  118. }
  119. catch(CSocketException *pExc)
  120. {
  121. LogMsg(LOGF_DEBUG,"CRemoteInterface::OpenRemote() - Caught exception '%s' from module %s",
  122. pExc->m_ErrorText, pExc->m_ErrorText);
  123. if (pExc->m_ErrorNum)
  124. throw pExc;
  125. delete pExc;
  126. }
  127. catch(...)
  128. {
  129. LogMsg(LOGF_ERROR,"CRemoteInterface::OpenRemote() - Caught unknown exception");
  130. return FALSE;
  131. }
  132. return TRUE;
  133. }
  134. void CRemoteInterface::OnConnect( int nErrorCode )
  135. {
  136. CSock::OnConnect(nErrorCode);
  137. AsyncSelect(m_AsyncSelectMask);
  138. BOOL bVal = TRUE; SetSockOpt(TCP_NODELAY,&bVal,sizeof(bVal),IPPROTO_TCP);
  139. }
  140. void CRemoteInterface::OnSend( int nErrorCode )
  141. {
  142. CString cBuf;
  143. CSock::OnSend(nErrorCode);
  144. if (nErrorCode)
  145. {
  146. LogMsg(LOGF_ERROR,"OnSend() - Connection to server lost. %s", GetLastErrorText());
  147. OnServerMessage( -1 );
  148. return;
  149. }
  150. DoSend();
  151. }
  152. void CRemoteInterface::OnClose( int nErrorCode )
  153. {
  154. CSock::OnClose(nErrorCode);
  155. }
  156. void CRemoteInterface::OnReceive( int nErrorCode )
  157. {
  158. CString cBuf;
  159. CSock::OnReceive(nErrorCode);
  160. char buf[1024];
  161. int nBytes;
  162. BOOL DoThrow = FALSE;
  163. if (nErrorCode)
  164. {
  165. LogMsg(LOGF_ERROR,"OnReceive() - Connection to server lost. %s", GetLastErrorText());
  166. OnServerMessage( -1 );
  167. return;
  168. }
  169. again:
  170. try
  171. {
  172. if (m_BytesLeftToDownload)
  173. {
  174. DWORD nBytesWritten;
  175. ASSERT(m_FileHandle != INVALID_HANDLE_VALUE);
  176. while(m_ClearToReceive && m_BytesLeftToDownload && ((nBytes =  Receive(buf, min(sizeof(buf), m_BytesLeftToDownload))) > 0))
  177. {
  178. WriteFile(
  179. m_FileHandle,
  180. buf,
  181. nBytes,
  182. &nBytesWritten,
  183. NULL);
  184. m_BytesLeftToDownload -= nBytes;
  185. }
  186. }
  187. else
  188. {
  189. nBytes = Receive(buf, sizeof(buf));
  190. {
  191. // Q&D patch to strip off Telnet echo off reply code...
  192. unsigned char *up = (unsigned char *)buf;
  193. if ((up[0] == IAC) && (up[1] == WONT) && (up[2] == TELOPT_ECHO))
  194. {
  195. nBytes -= 3;
  196. memmove(buf, buf + 3, nBytes);
  197. }
  198. buf[nBytes] = 0;
  199. m_InBuf += buf;
  200. }
  201. }
  202. }
  203. catch(CSocketException *pExc)
  204. {
  205. LogMsg(LOGF_DEBUG,"CRemoteInterface::OnReceive() - Caught exception '%s' from module %s",
  206. pExc->m_ErrorText, pExc->m_ErrorText);
  207. if (pExc->m_ErrorNum)
  208. throw pExc;
  209. delete pExc;
  210. DoThrow = TRUE;
  211. }
  212. if (m_BytesLeftToDownload || (m_FileHandle != INVALID_HANDLE_VALUE))
  213. {
  214. if (!m_BytesLeftToDownload)
  215. {
  216. // EOF
  217. CloseHandle(m_FileHandle);
  218. m_FileHandle = INVALID_HANDLE_VALUE;
  219. m_InBuf.Format("200 {local} received file "%s" "%s" (%d bytes) OKrn",
  220. m_FileName, m_TempFileName, m_BytesToDownload);
  221. goto have_something;
  222. }
  223. }
  224. else 
  225. {
  226. have_something:
  227. if (m_InBuf.GetLength())
  228. {
  229. // See if this is the whole message
  230. LPSTR p = m_InBuf.GetBuffer(1);
  231. LPSTR pp = p + m_InBuf.GetLength() - 1;
  232. BOOL GotEol = FALSE;
  233. if (pp > p)
  234. {
  235. if (m_Type == LT_REMOTE)
  236. GotEol = !strcmp(pp - 1, ": "); // Valid end of line for remote admin
  237. if (!GotEol)
  238. GotEol = !strcmp(pp - 1, "rn"); // Valid end of line for all admin's
  239. m_LastLineInBuf = pp;
  240. }
  241. if (GotEol)
  242. {
  243. // Parse the lines
  244. for(pp = strtok(p, "rn"); pp; pp = strtok(NULL,"rn"))
  245. {
  246. if (!memcmp(pp, OOB_HDR, 4))
  247. {
  248. CurrentServerNotifications.AddLast((LPVOID)strdup(pp + 4));
  249. }
  250. else if (isdigit(pp[0]) && isdigit(pp[1]) && isdigit(pp[2]))
  251. {
  252. CurrentServerReply.AddLast((LPVOID)strdup(pp));
  253. }
  254. else
  255. {
  256. if (m_Type == LT_FTP)
  257. OnClientLogNotify(pp); // Show raw test on the display...
  258. else
  259. LogMsg(LOGF_WARNINGS,"Received trash from server: '%s'", pp);
  260. }
  261. }
  262. m_InBuf.Empty();
  263. // Process the lines
  264. while(pp = (LPSTR)CurrentServerReply.GetAndDeleteFirst())
  265. {
  266. if (!m_InBuf.IsEmpty())
  267. m_InBuf += 'n';
  268. int Index = m_InBuf.GetLength();
  269. OnClientLogNotify(pp);
  270. m_InBuf += pp;
  271. m_LastLineInBuf = (LPCSTR)m_InBuf + Index;
  272. if (m_LastLineInBuf[3] == ' ')
  273. {
  274. // Last line of a server reply (nnn<SP>)
  275. OnServerMessage( 0 );
  276. m_InBuf.Empty();
  277. }
  278. delete pp;
  279. }
  280. if (!m_InBuf.IsEmpty())
  281. m_InBuf += "rn"; // Prepere for next pass
  282. while(pp = (LPSTR)CurrentServerNotifications.GetAndDeleteFirst())
  283. {
  284. OnNotification(0, pp);
  285. delete pp;
  286. }
  287. }
  288. }
  289. if (DoThrow)
  290. CSocketException::Throw(this, "CRemoteInterface::OnReceive",nErrorCode,"Connection is closed by remote host.");
  291. if (!m_IsConnected)
  292. {
  293. OnServerMessage( -1 );
  294. return;
  295. }
  296. if (m_ClearToReceive)
  297. goto again;
  298. return;
  299. }
  300. void CRemoteInterface::OnServerMessage( int nErrorCode )
  301. {
  302. if ( nErrorCode )
  303. {
  304. error:
  305. // Cancel all requests and mark the connection as disconnected
  306. m_IsConnected = FALSE;
  307. if (m_State < PROCESS)
  308. {
  309. LogMsg(LOGF_DEBUG,"OnServerMessage() - Remote Connection closed.");
  310. OnOpen(nErrorCode ? nErrorCode : -1);
  311. return;
  312. }
  313. while(m_RequestQueue.GetItemCount())
  314. NotifyRequest(nErrorCode ? nErrorCode : -1);
  315. return;
  316. }
  317. // Handle direct file download
  318. if (atoi(m_LastLineInBuf) == 280)
  319. {
  320. if (m_BytesLeftToDownload)
  321. CSocketException::Throw(this, "CRemoteInterface::OnServerMessage",0,"Can not download 2 files at the same time!");
  322. MySscanf(m_LastLineInBuf,""%C" (%d)",
  323. &m_FileName, &m_BytesLeftToDownload);
  324. LogMsg(LOGF_FILEACC,"CRemoteInterface::OnServerMessage() - Downloading file '%s', %d bytes",
  325. m_FileName, m_BytesLeftToDownload);
  326. if (m_BytesLeftToDownload)
  327. {
  328. char TempName[MAX_PATH];
  329. if (!GetTempPath(MAX_PATH,TempName))
  330. strcpy(TempName,".");
  331. GetTempFileName(TempName, "~tmp_file", 0, m_TempFileName.GetBuffer(MAX_PATH));
  332. m_TempFileName.ReleaseBuffer();
  333. if ((m_FileHandle = ::CreateFile(
  334. m_TempFileName,
  335. GENERIC_WRITE,
  336. 0,
  337. NULL,
  338. CREATE_ALWAYS,
  339. FILE_FLAG_SEQUENTIAL_SCAN,
  340. NULL)) == INVALID_HANDLE_VALUE)
  341. {
  342. LogMsg(LOGF_WARNINGS,"CRemoteInterface::OnServerMessage() - Failed to create tmp file '%s' %s",
  343. m_TempFileName, GetLastErrorText());
  344. m_BytesLeftToDownload = 0;
  345. m_LastLineInBuf = "550 (local) Failed to create temp file";
  346. }
  347. else
  348. {
  349. m_BytesToDownload = m_BytesLeftToDownload;
  350. return;
  351. }
  352. }
  353. // If null file, let the original message go trough..
  354. }
  355. switch(m_State)
  356. {
  357. case PRELOGIN: // Send user name.
  358. if (atoi(m_LastLineInBuf) != 220)
  359. {
  360. LogMsg(LOGF_ERROR,"Login refused. (%s)", m_LastLineInBuf);
  361. if (m_Type == LT_REMOTE)
  362. AfxMessageBox(m_InBuf);
  363. goto error;
  364. }
  365. switch(m_Type)
  366. {
  367. case LT_FTP:
  368. if (!SendCmd("USER %s", m_UserName))
  369. goto error;
  370. break;
  371. case LT_REMOTE:
  372. if (!SendCmd("%c%c%c%s", IAC, DONT, TELOPT_ECHO, m_UserName))
  373. goto error;
  374. break;
  375. default:
  376. ASSERT(FALSE);
  377. }
  378. m_State = GOTNAME;
  379. break;
  380. case GOTNAME:
  381. if (atoi(m_LastLineInBuf) == 230)
  382. {
  383. m_State = PROCESS;
  384. OnOpen( 0 );
  385. break;
  386. }
  387. if (atoi(m_LastLineInBuf) != 331)
  388. {
  389. LogMsg(LOGF_ERROR,"Login refused. (%s)", m_LastLineInBuf);
  390. if (m_Type == LT_REMOTE)
  391. AfxMessageBox(m_InBuf);
  392. goto error;
  393. }
  394. switch(m_Type)
  395. {
  396. case LT_FTP:
  397. if (!SendCmd("PASS %s", m_UserPwd))
  398. goto error;
  399. break;
  400. case LT_REMOTE:
  401. if (!SendCmd("%s", m_UserPwd))
  402. goto error;
  403. break;
  404. default:
  405. ASSERT(FALSE);
  406. }
  407. m_State = GOTNAME;
  408. break;
  409. case HOLD:
  410. if (NotifyRequest( 0 ))
  411. {
  412. m_State = PROCESS;
  413. ProcessRequest( 0 );
  414. }
  415. break;
  416. default:
  417. LogMsg(LOGF_ERROR,"Trash received from server. : %s", m_CurrentReply);
  418. }
  419. }
  420. // Process the next request
  421. BOOL CRemoteInterface::ProcessRequest(int nErrorCode)
  422. {
  423. if (m_State != PROCESS)
  424. {
  425. LogMsg(LOGF_DEBUG,"ProcessRequest() - Must delay processing until state is PROCESS...");
  426. return TRUE;
  427. }
  428. CRemoteRequest *Req;
  429. if ((Req = (CRemoteRequest *)m_RequestQueue.FirstPtr()) == NULL)
  430. return TRUE; // Nothing to process
  431. switch(Req->m_Type)
  432. {
  433. case RQ_SINGLE:
  434. m_CurrentRequest = Req->m_Request;
  435. break;
  436. case RQ_MULTIPLE:
  437. if (CurrentQueueIndex == 0)
  438. {
  439. // Start of new batch..
  440. CurrentRequestQueue = Req->m_RequestQueue;
  441. CurrentReplyQueue = new CCmdArgs;
  442. }
  443. m_CurrentRequest = Req->m_RequestQueue->Arg(CurrentQueueIndex++);
  444. break;
  445. default:
  446. ASSERT(FALSE);
  447. }
  448. if (!SendCmd("%s", m_CurrentRequest))
  449. {
  450. OnServerMessage( -1 );
  451. return FALSE;
  452. }
  453. m_State = HOLD;
  454. return TRUE;
  455. }
  456. BOOL CRemoteInterface::NotifyRequest(int nErrorCode)
  457. {
  458. CRemoteRequest *Req;
  459. BOOL DoSuspend = TRUE;
  460. Req = (CRemoteRequest *)m_RequestQueue.FirstPtr();
  461. ASSERT(Req != NULL);
  462. switch(Req->m_Type)
  463. {
  464. case RQ_SINGLE:
  465. m_CurrentReply = m_InBuf;
  466. *Req->m_ReplyBuf = m_CurrentReply;
  467. DoSuspend = OnRequest( nErrorCode, Req );
  468. break;
  469. case RQ_MULTIPLE:
  470. ASSERT(CurrentRequestQueue != NULL);
  471. ASSERT(CurrentReplyQueue != NULL);
  472. ASSERT(CurrentQueueIndex >= 0);
  473. CurrentReplyQueue->AddArg(m_InBuf);
  474. if (CurrentQueueIndex == CurrentRequestQueue->m_argc)
  475. {
  476. OnRequestMulti( nErrorCode, Req);
  477. CurrentRequestQueue = NULL;
  478. CurrentReplyQueue = NULL;
  479. CurrentQueueIndex = 0;
  480. }
  481. break;
  482. default:
  483. ASSERT(FALSE);
  484. }
  485. if (DoSuspend)
  486. {
  487. m_RequestQueue.GetAndDeleteFirst();
  488. delete Req;
  489. }
  490. else
  491. Req->m_ReplyBuf->Empty(); // Reuse
  492. return DoSuspend;
  493. }
  494. // Called when a connection to a war deamon is compleated, or has failed
  495. void CRemoteInterface::OnOpen(int nErrorCode)
  496. {
  497. if (!nErrorCode)
  498. {
  499. AsyncSelect(m_AsyncSelectMask = FD_READ | FD_WRITE | FD_CLOSE); // Receive all notifications, except OOB
  500. }
  501. }
  502. // Request some action from the daemon
  503. BOOL CRemoteInterface::Request(LPCSTR Request, CString &cReplyBuf, CWnd *cWnd, int nMsg, 
  504. BOOL (* Func)(int nErrorCode, LPVOID ReplyBuf, LPVOID Arg), LPVOID Arg, HANDLE *CancelHndl)
  505. {
  506. CRemoteRequest *Req = new CRemoteRequest;
  507. Req->m_Type = RQ_SINGLE;
  508. Req->m_Request = Request;
  509. Req->m_ReplyBuf = &cReplyBuf;
  510. Req->m_cWnd = cWnd;
  511. Req->m_Msg = nMsg;
  512. Req->m_Func = Func;
  513. Req->m_FuncArg = Arg;
  514. Req->m_IsReleased = FALSE;
  515. if (CancelHndl)
  516. *CancelHndl = (HANDLE)Req;
  517. if (!CNotificationWnd::IsSameThread())
  518. {
  519. // Since we use sockets, we have to route this to the correct thread.
  520. // This also simplifies multithread access to the resources.
  521. BOOL Rval = SendMessage(CNotificationWnd::GetHwnd(), WMU_RCTDREQ, (WPARAM)this, (LPARAM)Req);
  522. return Rval;
  523. }
  524. return CRemoteInterface::Request(Req);
  525. }
  526. BOOL CRemoteInterface::Request(CRemoteRequest *Req)
  527. {
  528. m_RequestQueue.AddLast((LPVOID)Req);
  529. return ProcessRequest( 0 );
  530. }
  531. // Blocking request. Can not be called from the main therad.
  532. BOOL CRemoteInterface::Req(HANDLE Remote, LPCSTR RequestText, CString& ReplyBuf, int timeout)
  533. {
  534. ASSERT(CNotificationWnd::IsSameThread() == FALSE);
  535. CRemoteInterface *pRI = (CRemoteInterface *)Remote;
  536. ASSERT(AfxIsValidAddress(pRI, sizeof(CRemoteInterface)));
  537. HANDLE h;
  538. CEvent MyEvent(FALSE, TRUE);
  539. MyEvent.ResetEvent();
  540. if (!pRI->Request(RequestText, ReplyBuf, NULL, 0, ReqCallback, (LPVOID)&MyEvent, &h))
  541. return FALSE;
  542. CSingleLock MyLock(&MyEvent);
  543. again:
  544. if (!MyLock.Lock(timeout))
  545. {
  546. try
  547. {
  548. if (!pRI->CancelRequest(h))
  549. goto again;
  550. return FALSE;
  551. }
  552. catch(...)
  553. {
  554. CLog::GetLog()->LogMsg(LOGF_ERROR,"CRemoteInterface::Req() - Caught exception. Terminating therad.");
  555. PostQuitMessage(1);
  556. }
  557. }
  558. return TRUE;
  559. }
  560. // Cancel a request. The request is not cancelled to the server, but the notifiications
  561. // on completion is turned off.
  562. BOOL CRemoteInterface::CancelRequest(HANDLE h)
  563. {
  564. CRemoteRequest *Req = (CRemoteRequest *)h;
  565. ASSERT(AfxIsValidAddress(Req, sizeof(h)));
  566. BOOL Rval = TRUE;
  567. Req->m_Lock.Lock();
  568. if (Req->m_IsReleased)
  569. Rval = FALSE;
  570. else
  571. {
  572. Req->m_Func = NULL;
  573. Req->m_cWnd = NULL;
  574. }
  575. Req->m_Lock.Unlock();
  576. return Rval;
  577. }
  578. BOOL CRemoteInterface::ReqCallback(int nErrorCode, LPVOID ReplyBuf, LPVOID Arg)
  579. {
  580. CEvent *pEvent = (CEvent *)Arg;
  581. ASSERT(AfxIsValidAddress(pEvent, sizeof(CEvent)));
  582. if (nErrorCode)
  583. AfxThrowUserException();
  584. pEvent->SetEvent();
  585. return TRUE;
  586. }
  587. // Called when a simple request is completed, or has failed
  588. BOOL CRemoteInterface::OnRequest(int nErrorCode, CRemoteRequest *Req)
  589. {
  590. BOOL Rval = TRUE;
  591. Req->m_Lock.Lock();
  592. if (Req->m_cWnd)
  593. Req->m_cWnd->SendMessage(Req->m_Msg, (WPARAM)nErrorCode, (LPARAM)Req->m_ReplyBuf);
  594. if (Req->m_Func)
  595. Rval = Req->m_IsReleased = Req->m_Func(nErrorCode, (LPVOID)Req->m_ReplyBuf, Req->m_FuncArg);
  596. Req->m_Lock.Unlock();
  597. return Rval;
  598. }
  599. // Process multiple reuests. The requests are stored as in the request list.
  600. BOOL CRemoteInterface::RequestMulti(CCmdArgs *RequestList, CWnd *cWnd, int nMsg, 
  601. BOOL (* Func)(int nErrorCode, LPVOID ReplyBuf, LPVOID Arg), LPVOID Arg)
  602. {
  603. CRemoteRequest *Req = new CRemoteRequest;
  604. Req->m_Type = RQ_MULTIPLE;
  605. Req->m_Request.Empty();
  606. Req->m_RequestQueue = RequestList;
  607. Req->m_cWnd = cWnd;
  608. Req->m_Msg = nMsg;
  609. Req->m_Func = Func;
  610. Req->m_FuncArg = Arg;
  611. m_RequestQueue.AddLast((LPVOID)Req);
  612. return ProcessRequest( 0 );
  613. }
  614. // Called when multiple requests has been processed, or failed.
  615. // The reply buffer is allocated by the framework and must be deleted manually.
  616. // (this is done if this base function is called).
  617. // The replies are stored in the same order as they was requested.
  618. void CRemoteInterface::OnRequestMulti(int nErrorCode, CRemoteRequest *Req)
  619. {
  620. if (Req->m_cWnd)
  621. Req->m_cWnd->SendMessage(Req->m_Msg, (WPARAM)nErrorCode, (LPARAM)CurrentReplyQueue);
  622. if (Req->m_Func)
  623. Req->m_Func(nErrorCode, (LPVOID)CurrentReplyQueue, Req->m_FuncArg);
  624. }
  625. // Notification messages from the server. These messages are sent as OutOfBand
  626. // data in the form: <sssss eee msg> where s=message size, e=event msg=message. The message
  627. // can contain any ascii or binary 8 bit data, including .
  628. BOOL CRemoteInterface::OnNotification(int nErrorCode, LPSTR cNotification)
  629. {
  630. return TRUE;
  631. }
  632. // Abort all pending requests to the server
  633. // This call will cause an appropriate cancel request to the server, and a NOOP
  634. // to get back in sync.
  635. BOOL CRemoteInterface::Abort()
  636. {
  637. // Set the state to PROCESS so that cancel request can be sent.
  638. if (m_State > PROCESS)
  639. m_State = PROCESS;
  640. return TRUE;
  641. }
  642. BOOL CRemoteInterface::SendCmd(LPCSTR Format, ...)
  643. {
  644. CWarString cBuf;
  645. ASSERT(AfxIsValidString(Format, FALSE));
  646. va_list argList;
  647. va_start(argList, Format);
  648. cBuf.FormatVaList(Format,argList);
  649. va_end(argList);
  650. return _SendCmd(cBuf);
  651. }
  652. BOOL CRemoteInterface::_SendCmd(LPCSTR Command)
  653. {
  654. m_OutBuf += Command;
  655. m_OutBuf += "rn";
  656. return DoSend();
  657. }
  658. BOOL CRemoteInterface::DoSend()
  659. {
  660. CString cBuf;
  661. int nBytes = 1;
  662. if (!m_IsConnected)
  663. return FALSE;
  664. while(nBytes && !m_OutBuf.IsEmpty())
  665. {
  666. nBytes = Send(m_OutBuf,m_OutBuf.GetLength());
  667. if (nBytes == m_OutBuf.GetLength())
  668. m_OutBuf.Empty();
  669. else
  670. {
  671. LPSTR p = m_OutBuf.GetBuffer(1);
  672. memmove(p, p + nBytes, m_OutBuf.GetLength() - nBytes);
  673. p[nBytes] = 0;
  674. m_OutBuf.ReleaseBuffer();
  675. }
  676. }
  677. return m_IsConnected;
  678. }
  679. void CRemoteInterface::OnClientLogNotify(LPCSTR Text)
  680. {
  681. }