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.

312 lines
11 KiB

  1. /*****************************************************************************\
  2. FILE: newmenu.cpp
  3. DESCRIPTION:
  4. The file supports the "New" menu to create new items on the FTP server.
  5. This currently only supports Folders but hopefully it will support other
  6. items later.
  7. \*****************************************************************************/
  8. #include "priv.h"
  9. #include "util.h"
  10. #include "newmenu.h"
  11. // This is used to surf the hwnds to find the one we need to
  12. // hack because IShellView2::SelectAndPositionItem() isn't implemented
  13. // on Browser Only.
  14. #define DEFVIEW_CLASS_BROWSERONLYA "SHELLDLL_DefView"
  15. /////////////////////////////////////////////////////////////////////////
  16. /////// Private helpers /////////////////////////////////////////////
  17. /////////////////////////////////////////////////////////////////////////
  18. LPITEMIDLIST DV_GetPIDL(HWND hwndLV, int i)
  19. {
  20. LV_ITEM item;
  21. item.mask = LVIF_PARAM;
  22. item.iItem = i;
  23. item.iSubItem = 0;
  24. item.lParam = 0;
  25. if (i != -1)
  26. {
  27. ListView_GetItem(hwndLV, &item);
  28. }
  29. return (LPITEMIDLIST) item.lParam;
  30. }
  31. int DefView_FindItemHack(CFtpFolder * pff, HWND hwndListView, LPCITEMIDLIST pidl)
  32. {
  33. int nIndex;
  34. int nItemsTotal;
  35. nItemsTotal = ListView_GetItemCount(hwndListView);
  36. for (nIndex = 0; nItemsTotal > nIndex; nIndex++)
  37. {
  38. HRESULT hres = ResultFromShort(-1);
  39. LPITEMIDLIST pidlT = DV_GetPIDL(hwndListView, nIndex);
  40. if (!pidlT)
  41. return -1;
  42. hres = pff->CompareIDs(COL_NAME, pidl, pidlT);
  43. ASSERT(SUCCEEDED(hres));
  44. if (FAILED(hres))
  45. return -1;
  46. if (ShortFromResult(hres) == 0)
  47. {
  48. return nIndex;
  49. }
  50. }
  51. return -1; // not found
  52. }
  53. typedef struct tagFOLDERNAMECOMP
  54. {
  55. BOOL * pfFound;
  56. LPCWSTR pszFolderName;
  57. } FOLDERNAMECOMP;
  58. /*****************************************************************************\
  59. FUNCTION: _ComparePidlAndFolderStr
  60. DESCRIPTION:
  61. Compare the pidl and folder name str.
  62. \*****************************************************************************/
  63. int _ComparePidlAndFolderStr(LPVOID pvPidl, LPVOID pvFolderNameComp)
  64. {
  65. FOLDERNAMECOMP * pFolderNameComp = (FOLDERNAMECOMP *) pvFolderNameComp;
  66. LPCITEMIDLIST pidl = (LPCITEMIDLIST) pvPidl;
  67. WCHAR wzDisplayName[MAX_PATH];
  68. BOOL fContinue = TRUE;
  69. if (EVAL(SUCCEEDED(FtpPidl_GetDisplayName(pidl, wzDisplayName, ARRAYSIZE(wzDisplayName)))))
  70. {
  71. if (!StrCmpW(wzDisplayName, pFolderNameComp->pszFolderName))
  72. {
  73. *pFolderNameComp->pfFound = TRUE;
  74. fContinue = FALSE;
  75. }
  76. }
  77. return fContinue; // Continue looking?
  78. }
  79. /*****************************************************************************\
  80. FUNCTION: _DoesFolderExist
  81. DESCRIPTION:
  82. Look thru all the items (files and folders) in this folder and see if
  83. any have the same name as pszFolderName.
  84. \*****************************************************************************/
  85. BOOL _DoesFolderExist(LPCWSTR pszFolderName, CFtpDir * pfd)
  86. {
  87. BOOL fExist = FALSE;
  88. if (EVAL(pfd))
  89. {
  90. CFtpPidlList * pPidlList = pfd->GetHfpl();
  91. // This may fail, but the worst that will happen is that the new folder won't appear.
  92. // This happens when the cache is flushed.
  93. if (pPidlList)
  94. {
  95. FOLDERNAMECOMP folderNameComp = {&fExist, pszFolderName};
  96. pPidlList->Enum(_ComparePidlAndFolderStr, (LPVOID) &folderNameComp);
  97. pPidlList->Release();
  98. }
  99. }
  100. return fExist;
  101. }
  102. /*****************************************************************************\
  103. FUNCTION: _CreateNewFolderName
  104. DESCRIPTION:
  105. Create the name of a new folder.
  106. \*****************************************************************************/
  107. HRESULT _CreateNewFolderName(LPWSTR pszNewFolder, DWORD cchSize, CFtpDir * pfd)
  108. {
  109. HRESULT hr = S_OK;
  110. int nTry = 1;
  111. WCHAR wzTemplate[MAX_PATH];
  112. wzTemplate[0] = 0;
  113. LoadStringW(HINST_THISDLL, IDS_NEW_FOLDER_FIRST, pszNewFolder, cchSize);
  114. while (_DoesFolderExist(pszNewFolder, pfd))
  115. {
  116. if (0 == wzTemplate[0])
  117. LoadStringW(HINST_THISDLL, IDS_NEW_FOLDER_TEMPLATE, wzTemplate, ARRAYSIZE(wzTemplate));
  118. nTry++; // Try the next number.
  119. wnsprintf(pszNewFolder, cchSize, wzTemplate, nTry);
  120. }
  121. return hr;
  122. }
  123. /*****************************************************************************\
  124. FUNCTION: _CreateNewFolder
  125. DESCRIPTION:
  126. Create the actual directory.
  127. \*****************************************************************************/
  128. HRESULT CreateNewFolderCB(HINTERNET hint, HINTPROCINFO * phpi, LPVOID pvFCFS, BOOL * pfReleaseHint)
  129. {
  130. HRESULT hr = S_OK;
  131. FTPCREATEFOLDERSTRUCT * pfcfs = (FTPCREATEFOLDERSTRUCT *) pvFCFS;
  132. WIRECHAR wFilePath[MAX_PATH];
  133. CWireEncoding * pWireEncoding = phpi->pfd->GetFtpSite()->GetCWireEncoding();
  134. hr = pWireEncoding->UnicodeToWireBytes(NULL, pfcfs->pszNewFolderName, (phpi->pfd->IsUTF8Supported() ? WIREENC_USE_UTF8 : WIREENC_NONE), wFilePath, ARRAYSIZE(wFilePath));
  135. if (EVAL(SUCCEEDED(hr)))
  136. {
  137. hr = FtpCreateDirectoryWrap(hint, TRUE, wFilePath);
  138. if (SUCCEEDED(hr))
  139. {
  140. LPITEMIDLIST pidlNew;
  141. HINTERNET hIntFind;
  142. // For some reason, FtpFindFirstFile needs an '*' behind the name.
  143. StrCatBuffA(wFilePath, SZ_ASTRICSA, ARRAYSIZE(wFilePath));
  144. hr = FtpFindFirstFilePidlWrap(hint, TRUE, NULL, pWireEncoding, wFilePath, &pidlNew, (INTERNET_NO_CALLBACK | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RESYNCHRONIZE | INTERNET_FLAG_RELOAD), 0, &hIntFind);
  145. if (EVAL(SUCCEEDED(hr)))
  146. {
  147. // Notify the folder of the new item so the Shell Folder updates.
  148. // PERF: I worry about doing a FtpFindFirstFile() being too expensive onto to get the date correct
  149. // for SHChangeNotify().
  150. FtpChangeNotify(phpi->hwnd, SHCNE_MKDIR, pfcfs->pff, phpi->pfd, pidlNew, NULL, TRUE);
  151. ILFree(pidlNew);
  152. InternetCloseHandle(hIntFind);
  153. }
  154. }
  155. }
  156. return hr;
  157. }
  158. /////////////////////////////////////////////////////////////////////////
  159. /////// DLL Wide Functions /////////////////////////////////////////////
  160. /////////////////////////////////////////////////////////////////////////
  161. HRESULT CreateNewFolder(HWND hwnd, CFtpFolder * pff, CFtpDir * pfd, IUnknown * punkSite, BOOL fPosition, POINT point)
  162. {
  163. HRESULT hr = E_FAIL;
  164. CFtpDir * pfdTemp = NULL;
  165. if (!pfd)
  166. pfd = pfdTemp = pff->GetFtpDir();
  167. if (EVAL(pfd))
  168. {
  169. WCHAR wzNewFolderName[MAX_PATH];
  170. // 1. Check if "New Folder" exists.
  171. // 2. Cycle thru names until a unique name is found.
  172. hr = _CreateNewFolderName(wzNewFolderName, ARRAYSIZE(wzNewFolderName), pfd);
  173. if (EVAL(SUCCEEDED(hr) && pfd))
  174. {
  175. FTPCREATEFOLDERSTRUCT fcfs = {wzNewFolderName, pff};
  176. // 3. Create a Directory with that name.
  177. hr = pfd->WithHint(NULL, hwnd, CreateNewFolderCB, (LPVOID) &fcfs, punkSite, pff);
  178. if (SUCCEEDED(hr))
  179. {
  180. WIRECHAR wNewFolderWireName[MAX_PATH];
  181. LPITEMIDLIST pidlFolder = NULL;
  182. CWireEncoding * pWireEncoding = pff->GetCWireEncoding();
  183. // Give me UTF-8 baby.
  184. EVAL(SUCCEEDED(pWireEncoding->UnicodeToWireBytes(NULL, wzNewFolderName, (pfd->IsUTF8Supported() ? WIREENC_USE_UTF8 : WIREENC_NONE), wNewFolderWireName, ARRAYSIZE(wNewFolderWireName))));
  185. if (EVAL(SUCCEEDED(FtpItemID_CreateFake(wzNewFolderName, wNewFolderWireName, TRUE, FALSE, FALSE, &pidlFolder))))
  186. {
  187. // Is this browser only?
  188. if (SHELL_VERSION_W95NT4 == GetShellVersion())
  189. {
  190. HWND hwndDefView = NULL;
  191. // Yes, so we need to do this the hard way.
  192. // 1.
  193. ShellFolderView_SetItemPos(hwnd, pidlFolder, point.x, point.y);
  194. hwndDefView = FindWindowExA(hwnd, NULL, DEFVIEW_CLASS_BROWSERONLYA, NULL);
  195. if (EVAL(hwndDefView))
  196. {
  197. HWND hwndListView = FindWindowExA(hwndDefView, NULL, WC_LISTVIEWA, NULL);
  198. if (EVAL(hwndListView))
  199. {
  200. int nIndex = DefView_FindItemHack(pff, hwndListView, pidlFolder);
  201. if (EVAL(-1 != nIndex))
  202. ListView_EditLabel(hwndListView, nIndex);
  203. }
  204. }
  205. }
  206. else
  207. {
  208. // No, so this won't be as hard.
  209. IShellView2 * pShellView2 = NULL;
  210. // ASSERT(punkSite); // Can happen when invoked from Captionbar.
  211. IUnknown_QueryService(punkSite, SID_DefView, IID_IShellView2, (void **)&pShellView2);
  212. if (!pShellView2)
  213. {
  214. IDefViewFrame * pdvf = NULL;
  215. IUnknown_QueryService(punkSite, SID_DefView, IID_IDefViewFrame, (void **)&pdvf);
  216. if (pdvf) // Can fail when invoked from caption bar.
  217. {
  218. EVAL(SUCCEEDED(pdvf->QueryInterface(IID_IShellView2, (void **) &pShellView2)));
  219. pdvf->Release();
  220. }
  221. }
  222. if (pShellView2) // Can fail when invoked from the caption bar. Oh well, cry me a river.
  223. {
  224. if (fPosition)
  225. pShellView2->SelectAndPositionItem(pidlFolder, (SVSI_SELECT | SVSI_TRANSLATEPT | SVSI_EDIT), &point);
  226. else
  227. pShellView2->SelectItem(pidlFolder, (SVSI_EDIT | SVSI_SELECT));
  228. pShellView2->Release();
  229. }
  230. }
  231. ILFree(pidlFolder);
  232. }
  233. }
  234. else
  235. {
  236. // An error occured, so display UI. Most often because access is denied.
  237. DisplayWininetError(hwnd, TRUE, HRESULT_CODE(hr), IDS_FTPERR_TITLE_ERROR, IDS_FTPERR_NEWFOLDER, IDS_FTPERR_WININET, MB_OK, NULL);
  238. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  239. }
  240. }
  241. if (pfdTemp)
  242. pfdTemp->Release();
  243. }
  244. return hr;
  245. }