Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

650 lines
13 KiB

  1. #include "precomp.h"
  2. #include "resource.h"
  3. #include "ConfUtil.h"
  4. #include "ConfPolicies.h"
  5. // SDK includes
  6. #include "NmEnum.h"
  7. #include "NmConference.h"
  8. #include "SDKInternal.h"
  9. #include "NmMember.h"
  10. #include "NmChannel.h"
  11. #include "NmChannelFt.h"
  12. #include "NmFt.h"
  13. #include "FtHook.h"
  14. CNmChannelFtObj::CNmChannelFtObj()
  15. : m_bSentSinkLocalMember(false)
  16. {
  17. DBGENTRY(CNmChannelFtObj::CNmChannelFtObj);
  18. DBGEXIT(CNmChannelFtObj::CNmChannelFtObj);
  19. }
  20. CNmChannelFtObj::~CNmChannelFtObj()
  21. {
  22. DBGENTRY(CNmChannelFtObj::~CNmChannelFtObj);
  23. CFt::UnAdvise(this);
  24. // Free our Ft objects
  25. for(int i = 0; i < m_SDKFtObjs.GetSize(); ++i)
  26. {
  27. m_SDKFtObjs[i]->Release();
  28. }
  29. DBGEXIT(CNmChannelFtObj::~CNmChannelFtObj);
  30. }
  31. //
  32. HRESULT CNmChannelFtObj::CreateInstance(CNmConferenceObj* pConfObj, INmChannel** ppChannel)
  33. {
  34. DBGENTRY(CNmChannelFtObj::CreateInstance);
  35. HRESULT hr = S_OK;
  36. typedef CNmChannel<CNmChannelFtObj, &IID_INmChannelFt, NMCH_FT> channel_type;
  37. channel_type* p = NULL;
  38. p = new CComObject<channel_type>(NULL);
  39. if (p != NULL)
  40. {
  41. if(ppChannel)
  42. {
  43. p->SetVoid(NULL);
  44. hr = p->QueryInterface(IID_INmChannel, reinterpret_cast<void**>(ppChannel));
  45. if(SUCCEEDED(hr))
  46. {
  47. // We don't have to RefCount this because our lifetime is
  48. // contained in the CConf's lifetime
  49. p->m_pConfObj = pConfObj;
  50. }
  51. if(FAILED(hr))
  52. {
  53. *ppChannel = NULL;
  54. delete p;
  55. }
  56. }
  57. else
  58. {
  59. hr = E_POINTER;
  60. }
  61. }
  62. else
  63. {
  64. hr = E_OUTOFMEMORY;
  65. }
  66. DBGEXIT_HR(CNmChannelFtObj::CreateInstance,hr);
  67. return hr;
  68. }
  69. /* V A L I D A T E F I L E */
  70. /*-------------------------------------------------------------------------
  71. %%Function: ValidateFile
  72. Verify that a file is a valid to send (it exists, not a folder, etc.)
  73. -------------------------------------------------------------------------*/
  74. HRESULT ValidateFile(LPCTSTR pszFile, DWORD *pdwSizeInBytes)
  75. {
  76. WIN32_FIND_DATA findData;
  77. *pdwSizeInBytes = 0;
  78. HRESULT hr = S_OK;
  79. if (FEmptySz(pszFile) || (MAX_PATH < lstrlen(pszFile)))
  80. {
  81. TRACE_OUT(("SendFile: invalid filename"));
  82. return E_INVALIDARG;
  83. }
  84. // get file information
  85. HANDLE hFind = FindFirstFile(pszFile, &findData);
  86. if (INVALID_HANDLE_VALUE == hFind)
  87. {
  88. TRACE_OUT(("SendFile: Bad Filename [%s]", pszFile));
  89. return E_INVALIDARG;
  90. }
  91. FindClose(hFind);
  92. if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  93. {
  94. WARNING_OUT(("SendFile: [%s] is a directory", pszFile));
  95. return E_INVALIDARG;
  96. }
  97. // Check whether we are allowed to send files of this size.
  98. DWORD dwMaxSendFileSize = ConfPolicies::GetMaxSendFileSize();
  99. if (dwMaxSendFileSize) {
  100. DWORD dwFileSizeInK = (findData.nFileSizeLow >> 10) |
  101. (findData.nFileSizeHigh << (sizeof(DWORD) * 8 - 10));
  102. if ((dwFileSizeInK >= dwMaxSendFileSize) ||
  103. ((findData.nFileSizeHigh >> 10) > 0)) {
  104. return NM_E_FILE_TOO_BIG;
  105. }
  106. }
  107. *pdwSizeInBytes = findData.nFileSizeLow;
  108. return S_OK;
  109. }
  110. ///////////////////////////////////////////////////////////////////////////////////
  111. // INmChannelFt methods
  112. ///////////////////////////////////////////////////////////////////////////////////
  113. STDMETHODIMP CNmChannelFtObj::SendFile(INmFt **ppFt, INmMember *pMember, BSTR bstrFile, ULONG uOptions)
  114. {
  115. DBGENTRY(CNmChannelFtObj::SendFile);
  116. HRESULT hr = S_OK;
  117. USES_CONVERSION;
  118. LPCTSTR szFileName = OLE2T(bstrFile);
  119. DWORD dwSizeInBytes = 0;
  120. hr = ValidateFile(szFileName,&dwSizeInBytes);
  121. ULONG gccID = 0;
  122. MBFTEVENTHANDLE hEvent;
  123. MBFTFILEHANDLE hFile;
  124. // We should never be passed NULL because of the marshalling code...
  125. ASSERT(ppFt);
  126. if(!GetbActive())
  127. {
  128. // We are not active yet!
  129. hr = E_FAIL;
  130. goto end;
  131. }
  132. if(SUCCEEDED(hr))
  133. {
  134. if(pMember)
  135. {
  136. // Make sure that this member is valid and in the channel
  137. if(!_MemberInChannel(pMember))
  138. {
  139. hr = E_INVALIDARG;
  140. goto end;
  141. }
  142. hr = pMember->GetID(&gccID);
  143. if(FAILED(hr)) goto end;
  144. }
  145. hr = CFt::SendFile(szFileName,
  146. static_cast<T120NodeID>(gccID),
  147. &hEvent,
  148. &hFile);
  149. if(SUCCEEDED(hr))
  150. {
  151. hr = CNmFtObj::CreateInstance(
  152. this,
  153. hEvent,
  154. hFile,
  155. false, // bIsIncoming
  156. szFileName, // FileName
  157. dwSizeInBytes, // Size in Bytes of the file
  158. pMember,
  159. ppFt
  160. );
  161. if(SUCCEEDED(hr))
  162. {
  163. (*ppFt)->AddRef();
  164. m_SDKFtObjs.Add(*ppFt);
  165. Fire_FtUpdate(CONFN_FT_STARTED, *ppFt);
  166. }
  167. }
  168. }
  169. end:
  170. DBGEXIT_HR(CNmChannelFtObj::SendFile,hr);
  171. return hr;
  172. }
  173. STDMETHODIMP CNmChannelFtObj::SetReceiveFileDir(BSTR bstrDir)
  174. {
  175. DBGENTRY(CNmChannelFtObj::SetReceiveFileDir);
  176. HRESULT hr = S_OK;
  177. USES_CONVERSION;
  178. LPTSTR szDir = OLE2T(bstrDir);
  179. if(bstrDir)
  180. {
  181. if(szDir)
  182. {
  183. if(FEnsureDirExists(szDir))
  184. {
  185. hr = _ChangeRecDir(szDir);
  186. }
  187. else
  188. {
  189. hr = E_INVALIDARG;
  190. }
  191. }
  192. else
  193. {
  194. hr = E_OUTOFMEMORY;
  195. }
  196. }
  197. else
  198. {
  199. hr = E_INVALIDARG;
  200. }
  201. DBGEXIT_HR(CNmChannelFtObj::SetReceiveFileDir,hr);
  202. return hr;
  203. }
  204. // static
  205. HRESULT CNmChannelFtObj::_ChangeRecDir(LPTSTR pszRecDir)
  206. {
  207. PSTR psz;
  208. TCHAR szPath[MAX_PATH];
  209. HRESULT hr = S_OK;
  210. RegEntry reFileXfer(FILEXFER_KEY, HKEY_CURRENT_USER);
  211. if (NULL == pszRecDir)
  212. {
  213. // NULL directory specified - get info from registry or use default
  214. psz = reFileXfer.GetString(REGVAL_FILEXFER_PATH);
  215. if (!FEmptySz(psz))
  216. {
  217. lstrcpyn(szPath, psz, CCHMAX(szPath));
  218. }
  219. else
  220. {
  221. TCHAR szInstallDir[MAX_PATH];
  222. GetInstallDirectory(szInstallDir);
  223. FLoadString1(IDS_FT_RECDIR_DEFAULT, szPath, szInstallDir);
  224. }
  225. pszRecDir = szPath;
  226. }
  227. psz = pszRecDir;
  228. // Remove trailing backslash, if any
  229. for (; *psz; psz = CharNext(psz))
  230. {
  231. if ((_T('\\') == *psz) && (_T('\0') == *CharNext(psz)) )
  232. {
  233. *psz = _T('\0');
  234. break;
  235. }
  236. }
  237. TRACE_OUT(("ChangeRecDir [%s]", pszRecDir));
  238. if (!FEnsureDirExists(pszRecDir))
  239. {
  240. WARNING_OUT(("ChangeRecDir: FT directory is invalid [%s]", pszRecDir));
  241. hr = E_FAIL;
  242. }
  243. else
  244. {
  245. // update the registry
  246. reFileXfer.SetValue(REGVAL_FILEXFER_PATH, pszRecDir);
  247. }
  248. return hr;
  249. }
  250. STDMETHODIMP CNmChannelFtObj::GetReceiveFileDir(BSTR *pbstrDir)
  251. {
  252. DBGENTRY(CNmChannelFtObj::GetReceiveFileDir);
  253. HRESULT hr = S_OK;
  254. if(pbstrDir)
  255. {
  256. RegEntry reFileXfer(FILEXFER_KEY, HKEY_CURRENT_USER);
  257. *pbstrDir = T2BSTR(reFileXfer.GetString(REGVAL_FILEXFER_PATH));
  258. if(!*pbstrDir)
  259. {
  260. hr = E_OUTOFMEMORY;
  261. }
  262. }
  263. else
  264. {
  265. hr = E_POINTER;
  266. }
  267. DBGEXIT_HR(CNmChannelFtObj::GetReceiveFileDir,hr);
  268. return hr;
  269. }
  270. ///////////////////////////////////////////////////////////////////////////////
  271. // IInternalChannelObj methods
  272. ///////////////////////////////////////////////////////////////////////////////
  273. STDMETHODIMP CNmChannelFtObj::GetInternalINmChannel(INmChannel** ppChannel)
  274. {
  275. DBGENTRY(CNmChannelFtObj::GetInternalINmChannel);
  276. HRESULT hr = S_OK;
  277. if(ppChannel)
  278. {
  279. *ppChannel = NULL;
  280. }
  281. else
  282. {
  283. hr = E_POINTER;
  284. }
  285. DBGEXIT_HR(CNmChannelFtObj::GetInternalINmChannel,hr);
  286. return hr;
  287. }
  288. HRESULT CNmChannelFtObj::ChannelRemoved()
  289. {
  290. HRESULT hr = S_OK;
  291. RemoveMembers();
  292. CNmConferenceObj* pConfObj = GetConfObj();
  293. if(pConfObj)
  294. {
  295. hr = pConfObj->Fire_ChannelChanged(NM_CHANNEL_REMOVED, com_cast<INmChannel>(GetUnknown()));
  296. }
  297. else
  298. {
  299. ERROR_OUT(("ChannelRemoved, but no ConfObject"));
  300. hr = E_UNEXPECTED;
  301. }
  302. m_bSentSinkLocalMember = false;
  303. return hr;
  304. }
  305. void CNmChannelFtObj::_OnActivate(bool bActive)
  306. {
  307. bActive ? CFt::Advise(this) : CFt::UnAdvise(this);
  308. }
  309. ///////////////////////////////////////////////////////////////////////////////
  310. // Helpers
  311. ///////////////////////////////////////////////////////////////////////////////
  312. HRESULT CNmChannelFtObj::Fire_MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pMember)
  313. {
  314. DBGENTRY(CNmChannelFtObj::Fire_MemberChanged);
  315. HRESULT hr = S_OK;
  316. /////////////////////////////////////////////////////
  317. // INmChannelNotify
  318. /////////////////////////////////////////////////////
  319. IConnectionPointImpl<CNmChannelFtObj, &IID_INmChannelNotify, CComDynamicUnkArray>* pCP = this;
  320. for(int i = 0; i < pCP->m_vec.GetSize(); ++i )
  321. {
  322. if(NM_MEMBER_ADDED == uNotify)
  323. {
  324. if(!m_bSentSinkLocalMember)
  325. {
  326. m_bSentSinkLocalMember = true;
  327. NotifySinksOfLocalMember();
  328. }
  329. }
  330. INmChannelNotify* pNotify = reinterpret_cast<INmChannelNotify*>(pCP->m_vec.GetAt(i));
  331. if(pNotify)
  332. {
  333. pNotify->MemberChanged(uNotify, pMember);
  334. }
  335. }
  336. /////////////////////////////////////////////////////
  337. // INmChannelFtNotify
  338. /////////////////////////////////////////////////////
  339. IConnectionPointImpl<CNmChannelFtObj, &IID_INmChannelFtNotify, CComDynamicUnkArray>* pCP2 = this;
  340. for(i = 0; i < pCP2->m_vec.GetSize(); ++i )
  341. {
  342. if(NM_MEMBER_ADDED == uNotify)
  343. {
  344. if(!m_bSentSinkLocalMember)
  345. {
  346. m_bSentSinkLocalMember = true;
  347. NotifySinksOfLocalMember();
  348. }
  349. }
  350. INmChannelFtNotify* pNotify2 = reinterpret_cast<INmChannelFtNotify*>(pCP2->m_vec.GetAt(i));
  351. if(pNotify2)
  352. {
  353. pNotify2->MemberChanged(uNotify, pMember);
  354. }
  355. }
  356. DBGEXIT_HR(CNmChannelFtObj::Fire_MemberChanged,hr);
  357. return hr;
  358. }
  359. HRESULT CNmChannelFtObj::Fire_FtUpdate(CONFN uNotify, INmFt* pNmFt)
  360. {
  361. DBGENTRY(CNmChannelFtObj::Fire_FtUpdate);
  362. HRESULT hr = S_OK;
  363. /////////////////////////////////////////////////////
  364. // INmChannelFtNotify
  365. /////////////////////////////////////////////////////
  366. IConnectionPointImpl<CNmChannelFtObj, &IID_INmChannelFtNotify, CComDynamicUnkArray>* pCP2 = this;
  367. for(int i = 0; i < pCP2->m_vec.GetSize(); ++i )
  368. {
  369. INmChannelFtNotify* pNotify2 = reinterpret_cast<INmChannelFtNotify*>(pCP2->m_vec.GetAt(i));
  370. if(pNotify2)
  371. {
  372. pNotify2->FtUpdate(uNotify, pNmFt);
  373. }
  374. }
  375. DBGEXIT_HR(CNmChannelFtObj::Fire_FtUpdate,hr);
  376. return hr;
  377. }
  378. void CNmChannelFtObj::_RemoveFt(INmFt* pFt)
  379. {
  380. INmFt* pRet = NULL;
  381. for( int i = 0; i < m_SDKFtObjs.GetSize(); ++i)
  382. {
  383. CComPtr<INmFt> spFt = m_SDKFtObjs[i];
  384. if(spFt.IsEqualObject(pFt))
  385. {
  386. m_SDKFtObjs.RemoveAt(i);
  387. spFt.p->Release();
  388. break;
  389. }
  390. }
  391. }
  392. INmMember* CNmChannelFtObj::GetSDKMemberFromInternalMember(INmMember* pInternalMember)
  393. {
  394. ASSERT(GetConfObj());
  395. return GetConfObj()->GetSDKMemberFromInternalMember(pInternalMember);
  396. }
  397. HRESULT CNmChannelFtObj::_IsActive()
  398. {
  399. return GetbActive() ? S_OK : S_FALSE;
  400. }
  401. HRESULT CNmChannelFtObj::_SetActive(BOOL bActive)
  402. {
  403. if (GetbActive() == bActive)
  404. return S_FALSE;
  405. return E_FAIL;
  406. }
  407. // IMbftEvent Interface
  408. STDMETHODIMP CNmChannelFtObj::OnInitializeComplete(void)
  409. {
  410. // This is handled by the conference object
  411. return S_OK;
  412. }
  413. STDMETHODIMP CNmChannelFtObj::OnPeerAdded(MBFT_PEER_INFO *pInfo)
  414. {
  415. // This is handled by the conference object
  416. return S_OK;
  417. }
  418. STDMETHODIMP CNmChannelFtObj::OnPeerRemoved(MBFT_PEER_INFO *pInfo)
  419. {
  420. // This is handled by the conference object
  421. return S_OK;
  422. }
  423. STDMETHODIMP CNmChannelFtObj::OnFileOffer(MBFT_FILE_OFFER *pOffer)
  424. {
  425. CNmConferenceObj* pConfObj = GetConfObj();
  426. if(pConfObj)
  427. {
  428. CComPtr<INmMember> spMember;
  429. HRESULT hr = S_OK;
  430. if(pOffer->NodeID)
  431. {
  432. hr = pConfObj->GetMemberFromNodeID(pOffer->NodeID, &spMember);
  433. }
  434. if(SUCCEEDED(hr))
  435. {
  436. RegEntry reFileXfer(FILEXFER_KEY, HKEY_CURRENT_USER);
  437. ASSERT(1 == pOffer->uNumFiles);
  438. CFt::AcceptFileOffer( pOffer,
  439. reFileXfer.GetString(REGVAL_FILEXFER_PATH),
  440. pOffer->lpFileInfoList[0].szFileName
  441. );
  442. CComPtr<INmFt> spFt;
  443. hr = CNmFtObj::CreateInstance(
  444. this,
  445. pOffer->hEvent, // hEvent
  446. 0, // hFile is 0 for now...
  447. true, // bIsIncoming
  448. pOffer->lpFileInfoList[0].szFileName, // FileName
  449. pOffer->lpFileInfoList[0].lFileSize, // Size in Bytes of the file
  450. spMember,
  451. &spFt
  452. );
  453. if(SUCCEEDED(hr))
  454. {
  455. spFt.p->AddRef();
  456. m_SDKFtObjs.Add(spFt.p);
  457. Fire_FtUpdate(CONFN_FT_STARTED, spFt);
  458. }
  459. }
  460. }
  461. return S_OK;
  462. }
  463. INmFt* CNmChannelFtObj::_GetFtFromHEvent(MBFTEVENTHANDLE hEvent)
  464. {
  465. for(int i = 0; i < m_SDKFtObjs.GetSize(); ++i)
  466. {
  467. UINT CurhEvent;
  468. if(SUCCEEDED(com_cast<IInternalFtObj>(m_SDKFtObjs[i])->GetHEvent(&CurhEvent)) && (hEvent == CurhEvent))
  469. {
  470. return m_SDKFtObjs[i];
  471. }
  472. }
  473. return NULL;
  474. }
  475. STDMETHODIMP CNmChannelFtObj::OnFileProgress(MBFT_FILE_PROGRESS *pProgress)
  476. {
  477. DBGENTRY(CNmChannelFtObj::OnFileProgress);
  478. HRESULT hr = S_OK;
  479. INmFt* pFt = _GetFtFromHEvent(pProgress->hEvent);
  480. if(pFt)
  481. {
  482. com_cast<IInternalFtObj>(pFt)->OnFileProgress(pProgress->hFile, pProgress->lFileSize, pProgress->lBytesTransmitted);
  483. Fire_FtUpdate(CONFN_FT_PROGRESS, pFt);
  484. }
  485. DBGEXIT_HR(CNmChannelFtObj::OnFileProgress,hr);
  486. return hr;
  487. }
  488. STDMETHODIMP CNmChannelFtObj::OnFileEnd(MBFTFILEHANDLE hFile)
  489. {
  490. // according to Lon, this is bogus
  491. return S_OK;
  492. }
  493. STDMETHODIMP CNmChannelFtObj::OnFileError(MBFT_EVENT_ERROR *pEvent)
  494. {
  495. DBGENTRY(CNmChannelFtObj::OnFileError);
  496. HRESULT hr = S_OK;
  497. INmFt* pFt = _GetFtFromHEvent(pEvent->hEvent);
  498. if(pFt)
  499. {
  500. com_cast<IInternalFtObj>(pFt)->OnError();
  501. }
  502. DBGEXIT_HR(CNmChannelFtObj::OnFileError,hr);
  503. return hr;
  504. }
  505. STDMETHODIMP CNmChannelFtObj::OnFileEventEnd(MBFTEVENTHANDLE hEvent)
  506. {
  507. INmFt* pFt = _GetFtFromHEvent(hEvent);
  508. if(pFt)
  509. {
  510. bool bHasSomeoneCanceled = (S_FALSE == com_cast<IInternalFtObj>(pFt)->FileTransferDone());
  511. Fire_FtUpdate(bHasSomeoneCanceled ? CONFN_FT_CANCELED : CONFN_FT_COMPLETE, pFt);
  512. _RemoveFt(pFt);
  513. }
  514. return S_OK;
  515. }
  516. STDMETHODIMP CNmChannelFtObj::OnSessionEnd(void)
  517. {
  518. CFt::UnAdvise(this);
  519. return S_OK;
  520. }