Leaked source code of windows server 2003
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.

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