nt-makefile-clean-targets-20010917
[openafs.git] / src / WINNT / client_exp / shell_ext.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include "stdafx.h"
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include "afs_shl_ext.h"
19 #include "shell_ext.h"
20 #include "volume_info.h"
21 #include "set_afs_acl.h"
22 #include "gui2fs.h"
23 #include "make_mount_point_dlg.h"
24 #include "msgs.h"
25 #include "server_status_dlg.h"
26 #include "auth_dlg.h"
27 #include "submounts_dlg.h"
28
29
30 #ifdef _DEBUG
31 #define new DEBUG_NEW
32 #undef THIS_FILE
33 static char THIS_FILE[] = __FILE__;
34 #endif
35
36
37 ULONG nCMRefCount = 0;  // IContextMenu ref count
38 ULONG nSERefCount = 0;  // IShellExtInit ref count
39
40
41 static BOOL IsADir(const CString& strName)
42 {
43         struct _stat statbuf;
44
45         if (_stat(strName, &statbuf) < 0)
46                 return FALSE;
47
48         return statbuf.st_mode & _S_IFDIR;
49 }
50
51 /////////////////////////////////////////////////////////////////////////////
52 // CShellExt
53
54 IMPLEMENT_DYNCREATE(CShellExt, CCmdTarget)
55
56 CShellExt::CShellExt()
57 {
58         EnableAutomation();
59         nCMRefCount++;
60 }
61
62 CShellExt::~CShellExt()
63 {
64         nCMRefCount--;
65 }
66
67
68 void CShellExt::OnFinalRelease()
69 {
70         // When the last reference for an automation object is released
71         // OnFinalRelease is called.  The base class will automatically
72         // deletes the object.  Add additional cleanup required for your
73         // object before calling the base class.
74
75         CCmdTarget::OnFinalRelease();
76 }
77
78
79 BEGIN_MESSAGE_MAP(CShellExt, CCmdTarget)
80         //{{AFX_MSG_MAP(CShellExt)
81                 // NOTE - the ClassWizard will add and remove mapping macros here.
82         //}}AFX_MSG_MAP
83 END_MESSAGE_MAP()
84
85 BEGIN_DISPATCH_MAP(CShellExt, CCmdTarget)
86         //{{AFX_DISPATCH_MAP(CShellExt)
87                 // NOTE - the ClassWizard will add and remove mapping macros here.
88         //}}AFX_DISPATCH_MAP
89 END_DISPATCH_MAP()
90
91 // Note: we add support for IID_IShellExt to support typesafe binding
92 //  from VBA.  This IID must match the GUID that is attached to the 
93 //  dispinterface in the .ODL file.
94
95 // {DC515C27-6CAC-11D1-BAE7-00C04FD140D2}
96 static const IID IID_IShellExt =
97 { 0xdc515c27, 0x6cac, 0x11d1, { 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2 } };
98
99 BEGIN_INTERFACE_MAP(CShellExt, CCmdTarget)
100         INTERFACE_PART(CShellExt, IID_IShellExt, Dispatch)
101     INTERFACE_PART(CShellExt, IID_IContextMenu, MenuExt)
102     INTERFACE_PART(CShellExt, IID_IShellExtInit, ShellInit)
103 END_INTERFACE_MAP()
104
105 IMPLEMENT_OLECREATE(CShellExt, "AfsClientContextMenu", 0xdc515c27, 0x6cac, 0x11d1, 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2)
106
107
108 /////////////////////////////////////////////////////////////////////////////
109 // CShellExt message handlers
110 /////////////////////////////////////////////////////////////////////////////
111
112
113 /////////////////////////////////////////////////////////////////////////////
114 // IUnknown for IContextMenu
115 /////////////////////////////////////////////////////////////////////////////
116 STDMETHODIMP CShellExt::XMenuExt::QueryInterface(REFIID riid, void** ppv)
117 {
118     METHOD_PROLOGUE(CShellExt, MenuExt);
119
120     return pThis->ExternalQueryInterface(&riid, ppv);
121 }
122
123 STDMETHODIMP_(ULONG) CShellExt::XMenuExt::AddRef(void)
124 {
125         return ++nCMRefCount;
126 }
127
128 STDMETHODIMP_(ULONG) CShellExt::XMenuExt::Release(void)
129 {
130         if (nCMRefCount > 0)
131                 nCMRefCount--;
132
133         return nCMRefCount;
134 }
135
136 /////////////////////////////////////////////////////////////////////////////
137 // IConextMenu Functions
138 /////////////////////////////////////////////////////////////////////////////
139 STDMETHODIMP CShellExt::XMenuExt::QueryContextMenu(HMENU hMenu,UINT indexMenu,
140     UINT idCmdFirst, UINT idCmdLast,UINT uFlags)
141 {
142     METHOD_PROLOGUE(CShellExt, MenuExt);
143
144         // Don't add any menu items if we're being asked to deal with this file as a shortcut.
145         if (uFlags & CMF_VERBSONLY)
146                 return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)0));
147
148         // Check to see if there's already an AFS menu here; if so, remove it
149         int nItemsNow = GetMenuItemCount (hMenu);
150         CString strAfsItemText = GetMessageString(IDS_AFS_ITEM);
151         LPCTSTR pszAfsItemText = (LPCTSTR)strAfsItemText;
152         for (int iItem = 0; iItem < nItemsNow; iItem++) {
153                 TCHAR szItemText[256];
154                 if (!GetMenuString (hMenu, iItem, szItemText, 256, MF_BYPOSITION))
155                         continue;
156                 if (!lstrcmp (szItemText, pszAfsItemText)) {
157                         DeleteMenu (hMenu, iItem, MF_BYPOSITION);
158                         break;
159                 }
160         }
161
162         int indexShellMenu = 0;
163
164         // Create the AFS submenu using the allowed ID's.
165         HMENU hAfsMenu = CreatePopupMenu();
166         int indexAfsMenu = 0;
167
168         // The Authentication item has been removed from the AFS menu because
169         // there is now a tray icon to handle authentication.
170         //
171         //::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_AUTHENTICATION, GetMessageString(IDS_AUTHENTICATION_ITEM));
172         
173         // Only enable the ACL menu item if a single directory is selected
174         int nSingleDirOnly = MF_GRAYED;
175         if (pThis->m_bDirSelected && (pThis->m_astrFileNames.GetSize() == 1))
176                 nSingleDirOnly = MF_ENABLED;
177         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | nSingleDirOnly, idCmdFirst + IDM_ACL_SET, GetMessageString(IDS_ACLS_ITEM));
178         
179         // Volume/Partition submenu of the AFS submenu
180         HMENU hVolPartMenu = CreatePopupMenu();
181         int indexVolPartMenu = 0;
182         ::InsertMenu(hVolPartMenu, indexVolPartMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_VOLUME_PROPERTIES, GetMessageString(IDS_VOL_PART_PROPS_ITEM));
183         ::InsertMenu(hVolPartMenu, indexVolPartMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE, GetMessageString(IDS_VOL_PART_REFRESH_ITEM));
184         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hVolPartMenu, GetMessageString(IDS_VOL_PART_ITEM));
185
186         // Mount Point submenu of the AFS submenu
187         HMENU hMountPointMenu = CreatePopupMenu();
188         int indexMountPointMenu = 0;
189         ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_SHOW, GetMessageString(IDS_MP_SHOW_ITEM));
190         ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_REMOVE, GetMessageString(IDS_MP_REMOVE_ITEM));
191         ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_MAKE, GetMessageString(IDS_MP_MAKE_ITEM));
192         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hMountPointMenu, GetMessageString(IDS_MOUNT_POINT_ITEM));
193
194         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_FLUSH, GetMessageString(IDS_FLUSH_FILE_DIR_ITEM));   
195         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_FLUSH_VOLUME, GetMessageString(IDS_FLUSH_VOLUME_ITEM));
196         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHOW_SERVER, GetMessageString(IDS_SHOW_FILE_SERVERS_ITEM));
197         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHOWCELL, GetMessageString(IDS_SHOW_CELL_ITEM));
198         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SERVER_STATUS, GetMessageString(IDS_SHOW_SERVER_STATUS_ITEM));
199         
200         // The Submounts menu has been removed because the AFS tray icon
201         // and control panel now support mapping drives directly to an AFS
202         // path.
203         //
204         // HMENU hSubmountMenu = CreatePopupMenu();
205         // int indexSubmountMenu = 0;
206         // ::InsertMenu(hSubmountMenu, indexSubmountMenu++, MF_STRING | MF_BYPOSITION | nSingleDirOnly, idCmdFirst + IDM_SUBMOUNTS_CREATE, GetMessageString(IDS_SUBMOUNTS_CREATE_ITEM));
207         // ::InsertMenu(hSubmountMenu, indexSubmountMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SUBMOUNTS_EDIT, GetMessageString(IDS_SUBMOUNTS_EDIT_ITEM));
208         // ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hSubmountMenu, GetMessageString(IDS_SUBMOUNTS_ITEM));
209
210         // Add a separator
211         ::InsertMenu (hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
212
213         // Add the AFS submenu to the shell's menu
214         ::InsertMenu(hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hAfsMenu, GetMessageString(IDS_AFS_ITEM));
215
216         // Add a separator after us
217         ::InsertMenu (hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
218         
219     return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 
220                         (USHORT)indexAfsMenu + indexVolPartMenu + indexMountPointMenu + indexShellMenu));
221 }
222
223 STDMETHODIMP CShellExt::XMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
224 {
225     METHOD_PROLOGUE(CShellExt, MenuExt);
226
227     if (HIWORD(lpici->lpVerb ))
228         return E_FAIL;
229
230         AddRef();
231
232         CStringArray &files = pThis->m_astrFileNames;
233
234         switch (LOWORD(lpici->lpVerb))
235         {
236                 case IDM_AUTHENTICATION:        {
237                                                                                 CAuthDlg dlg;
238                                                                                 dlg.DoModal();
239                                                                                 break;
240                                                                         }
241                 
242                 case IDM_ACL_SET:                       { 
243                                                                                 CSetAfsAcl dlg;
244                                                                                 ASSERT(files.GetSize() == 1);
245                                                                                 dlg.SetDir(files[0]);
246                                                                                 dlg.DoModal();
247                                                                         }
248                                                                         break;
249                 
250                 case IDM_VOLUME_PROPERTIES:     {
251                                                                                 CVolumeInfo dlg;
252                                                                                 dlg.SetFiles(files);
253                                                                                 dlg.DoModal();
254                                                                         }
255                                                                         break;
256
257                 case IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE:     CheckVolumes();
258                                                                                                         break;
259
260                 case IDM_MOUNTPOINT_SHOW:       ListMount(files);
261                                                                         break;
262
263                 case IDM_MOUNTPOINT_REMOVE:     {
264                                                                                 int nChoice = ShowMessageBox(IDS_REALLY_DEL_MOUNT_POINTS, MB_ICONQUESTION | MB_YESNO, IDS_REALLY_DEL_MOUNT_POINTS);
265                                                                                 if (nChoice == IDYES)
266                                                                                         RemoveMount(files);
267                                                                         }
268                                                                         break;
269                 
270                 case IDM_MOUNTPOINT_MAKE:       {
271                                                                                 CMakeMountPointDlg dlg;
272                                                                                 ASSERT(files.GetSize() == 1);
273                                                                                 dlg.SetDir(files[0]);
274                                                                                 dlg.DoModal();
275                                                                         }
276                                                                         break;
277
278
279                 case IDM_FLUSH:                         Flush(files);
280                                                                         break;
281                 
282                 case IDM_FLUSH_VOLUME:          FlushVolume(files);
283                                                                         break;
284
285                 case IDM_SHOW_SERVER:           WhereIs(files);
286                                                                         break;
287                 
288                 case IDM_SHOWCELL:                      WhichCell(files);
289                                                                         break;
290
291                 case IDM_SERVER_STATUS:         {
292                                                                                 CServerStatusDlg dlg;
293                                                                                 dlg.DoModal();
294                                                                         }
295                                                                         break;
296                 
297                 case IDM_SUBMOUNTS_EDIT:        {
298                                                                                 CSubmountsDlg dlg;
299                                                                                 dlg.DoModal();
300                                                                         }
301                                                                         break;
302
303                 case IDM_SUBMOUNTS_CREATE:      {
304                                                                                 ASSERT(files.GetSize() == 1);
305                                                                                 CSubmountsDlg dlg;
306                                                                                 dlg.SetAddOnlyMode(files[0]);
307                                                                                 dlg.DoModal();
308                                                                         }
309                                                                         break;
310
311                 default:
312                         ASSERT(FALSE);
313                         Release();
314                     return E_INVALIDARG;
315         }
316
317         Release();
318
319     return NOERROR;
320 }
321
322 STDMETHODIMP CShellExt::XMenuExt::GetCommandString(UINT idCmd, UINT uType,
323     UINT* pwReserved, LPSTR pszName, UINT cchMax)
324 {
325         if (uType != GCS_HELPTEXT)
326                 return NOERROR;                 // ?????????????????????????????????????????????????
327
328         UINT nCmdStrID;
329
330     AfxSetResourceHandle(theApp.m_hInstance);
331
332     switch (idCmd)
333         {
334                 case IDM_AUTHENTICATION:        nCmdStrID = ID_AUTHENTICATE;
335                                                                         break;
336                 
337                 case IDM_ACL_SET:                       nCmdStrID = ID_ACL_SET;
338                                                                         break;
339                 
340                 case IDM_VOLUME_PROPERTIES:     nCmdStrID = ID_VOLUME_PROPERTIES;
341                                                                         break;
342
343                 case IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE:     nCmdStrID = ID_VOLUMEPARTITION_UPDATENAMEIDTABLE;
344                                                                                                         break;
345
346                 case IDM_MOUNTPOINT_SHOW:       nCmdStrID = ID_MOUNTPOINT_SHOW;
347                                                                         break;
348
349                 case IDM_MOUNTPOINT_REMOVE:     nCmdStrID = ID_MOUNTPOINT_REMOVE;
350                                                                         break;
351                 
352                 case IDM_MOUNTPOINT_MAKE:       nCmdStrID = ID_MOUNTPOINT_MAKE;
353                                                                         break;
354
355                 case IDM_FLUSH:                         nCmdStrID = ID_FLUSH;
356                                                                         break;
357                 
358                 case IDM_FLUSH_VOLUME:          nCmdStrID = ID_VOLUME_FLUSH;
359                                                                         break;
360
361                 case IDM_SHOW_SERVER:           nCmdStrID = ID_WHEREIS;
362                                                                         break;
363                 
364                 case IDM_SHOWCELL:                      nCmdStrID = ID_SHOWCELL;
365                                                                         break;
366
367                 case IDM_SERVER_STATUS:         nCmdStrID = ID_SERVER_STATUS;
368                                                                         break;
369
370                 case IDM_SUBMOUNTS_CREATE:      nCmdStrID = ID_SUBMOUNTS_CREATE;
371                                                                         break;
372                 
373                 case IDM_SUBMOUNTS_EDIT:        nCmdStrID = ID_SUBMOUNTS_EDIT;
374                                                                         break;
375                 
376                 default:
377                         ASSERT(FALSE);
378                         Release();
379                     return E_INVALIDARG;
380         }
381
382     CString strMsg;
383     LoadString (strMsg, nCmdStrID);
384
385     strncpy(pszName, strMsg, cchMax);
386
387     return NOERROR;
388 }
389
390 /////////////////////////////////////////////////////////////////////////////
391 // IUnknown for IShellExtInit
392 /////////////////////////////////////////////////////////////////////////////
393 STDMETHODIMP CShellExt::XShellInit::QueryInterface(REFIID riid, void** ppv)
394 {
395     METHOD_PROLOGUE(CShellExt, ShellInit);
396
397     return pThis->ExternalQueryInterface(&riid, ppv);
398 }
399
400 STDMETHODIMP_(ULONG) CShellExt::XShellInit::AddRef(void)
401 {
402         return ++nSERefCount;
403 }
404
405 STDMETHODIMP_(ULONG) CShellExt::XShellInit::Release(void)
406 {
407         if (nSERefCount > 0)
408                 nSERefCount--;
409         
410         return nSERefCount;
411 }
412
413 /////////////////////////////////////////////////////////////////////////////
414 // IShellInit Functions
415 /////////////////////////////////////////////////////////////////////////////
416 STDMETHODIMP CShellExt::XShellInit::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
417 {
418     METHOD_PROLOGUE(CShellExt, ShellInit);
419
420     HRESULT hres = E_FAIL;
421     FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
422     STGMEDIUM medium;
423
424         // We must have a data object
425     if (pdobj == NULL)
426             return E_FAIL;
427
428     //  Use the given IDataObject to get a list of filenames (CF_HDROP)
429     hres = pdobj->GetData(&fmte, &medium);
430     if (FAILED(hres))
431             return E_FAIL;
432
433     int nNumFiles = DragQueryFile((HDROP)medium.hGlobal, 0xFFFFFFFF, NULL, 0);
434         if (nNumFiles == 0)
435                 hres = E_FAIL;
436         else {
437                 pThis->m_bDirSelected = FALSE;
438
439                 for (int ii = 0; ii < nNumFiles; ii++) {
440                         CString strFileName;
441
442                         // Get the size of the file name string
443                         int nNameLen = DragQueryFile((HDROP)medium.hGlobal, ii, 0, 0);
444
445                         // Make room for it in our string object
446                         LPTSTR pszFileNameBuf = strFileName.GetBuffer(nNameLen + 1);    // +1 for the terminating NULL
447                         ASSERT(pszFileNameBuf);
448                         
449                         // Get the file name
450                         DragQueryFile((HDROP)medium.hGlobal, ii, pszFileNameBuf, nNameLen + 1);
451                         
452                         strFileName.ReleaseBuffer();
453
454                         if (!IsPathInAfs(strFileName)) {
455                                 pThis->m_astrFileNames.RemoveAll();
456                                 break;
457                         }
458
459                         if (IsADir(strFileName))
460                                 pThis->m_bDirSelected = TRUE;
461
462                         pThis->m_astrFileNames.Add(strFileName);
463                 }
464
465                 if (pThis->m_astrFileNames.GetSize() > 0)
466                         hres = S_OK;
467                 else
468                         hres = E_FAIL;
469     }
470  
471     //  Release the data
472     ReleaseStgMedium(&medium);
473
474     return hres;
475 }
476