/*
* net.c
*
* Purpose:
* net functions
*
* Owner:
* MikeSart
*/
#define UNICODE 1
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <string.h>
#include <time.h>
#include <lm.h>
#include "netwatch.h"
#include "rcids.h"
ASSERTDATA
// From lmcons.h:
// NNLEN: max share name
// UNLEN: max user name
// MAXCOMMENTSZ: max comment length
// PATHLEN: max path
// From datetime.c
TCHAR*PutTime(time_t tm_t, TCHAR *szStr, UINT cch);
TCHAR*PutDate(time_t tm_t, TCHAR *szStr, UINT cch);
TCHAR*PutCounterTime(DWORD dw, TCHAR *szStr, UINT cch);
/*
*Useful macros
*/
// Should we consider szShare hidden?
#define FIsShareHidden(_szShare) \
((_szShare)[lstrlen(_szShare) - 1] == TEXT('$'))
// Is the lParam in the TV_ITEM a pointer to TVDATA or just a type?
#define FIsLParamTVData(_lp) \
(((_lp) + 1) > 1)
/*
*Globules
*/
SCONST TCHARszFmtNum[] = TEXT("%lu");
/*
*Typedefs
*/
typedef struct tagTVDATA
{
DWORDdwType;
} TVDATA;
typedef struct tagTVDATASHARE
{
DWORDdwType;// TYPE_SHARE, TYPE_USER, or TYPE_FILE
DWORDdwShareType;// STYPE_IPC, etc.
TCHARszShareName[NNLEN + 1];// e$, etc.
TCHARszServerName[UNCLEN + 1];
} TVDATASHARE;
typedef struct tagTVDATAUSER
{
DWORDdwType;// TYPE_SHARE, TYPE_USER, or TYPE_FILE
TCHARszUserName[UNLEN + 1];// BillG, etc.
TCHARszNetName[UNCLEN + 1];// \\BILLG1, etc.
TVDATASHARE*pTVDataShare;// Parent data
} TVDATAUSER;
typedef struct tagTVDATAFILE
{
DWORDdwType;// TYPE_SHARE, TYPE_USER, or TYPE_FILE
DWORDdwFileId;// fi3_id
TVDATAUSER*pTVDataUser;// Parent data
} TVDATAFILE;
/*
*Treeview nonsense
*/
/*
*TreeView_FindExactString
*
*Purpose:
*Find a szText starting from hItemStart
*
*Arguments:
*hParent, hItemStart, szText
*
*Returns:
*hItem or NULL
*/
HTREEITEM
TreeView_FindExactString(HWND hwndTV, HTREEITEM hParent, HTREEITEM hItemStart,
TCHAR *szText)
{
TCHARszT[cchTVSzMax];
// Start looking one node after us
hItemStart = hItemStart ? TreeView_GetNextSibling(hwndTV, hItemStart) :
TreeView_GetChild(hwndTV, hParent);
// Loop through looking for that baby
while(hItemStart)
{
// Get the text
if(FTreeView_GetString(hwndTV, hItemStart, szT, cchTVSzMax))
{
UINT nRet = lstrcmp(szText, szT);
// Strings should be in the treeview control like:
// aaaa$
// bbbb$
// zzzz$
// bbbb
// ffff
// So, if the strings match, return em
// Else szText is larger than szT and we're past the hidden shares
// so the item shouldn't be here
if(!nRet)
return hItemStart;
else if((nRet < 0) && !FIsShareHidden(szT))
return NULL;
}
hItemStart = TreeView_GetNextSibling(hwndTV, hItemStart);
}
return hItemStart;
}
/*
*FTreeView_DeleteRange
*
*Purpose: Delete hItemStart+1 to hItemEnd-1
*hItemStart
*hItemStart+1
*...
*HItemEnd-1
*HItemEnd
*
*Arguments:
*hwndTV, hItemStart, hItemEnd
*
*Returns:
*TRUE - success, FALSE - failure
*/
BOOL
FTreeView_DeleteRange(HWND hwndTV, HTREEITEM hParent, HTREEITEM hItemStart,
HTREEITEM hItemEnd)
{
// If NULL, we want the first item, else we want hItemStart + 1
hItemStart = hItemStart ? TreeView_GetNextSibling(hwndTV, hItemStart) :
TreeView_GetChild(hwndTV, hParent);
while(hItemStart && (hItemStart != hItemEnd))
{
HTREEITEMhItemT;
hItemT = TreeView_GetNextSibling(hwndTV, hItemStart);
TreeView_DeleteItem(hwndTV, hItemStart);
hItemStart = hItemT;
}
return TRUE;
}
/*
*TreeView_TVReplacelParam
*
*Purpose:
*Replace an lparam and free any associated memory
*
*Arguments:
*hItem to replace and lParamNew
*
*Returns:
*TRUE - success, FALSE - failed
*/
BOOL
TreeView_TVReplacelParam(HWND hwndTV, HTREEITEM hItem, LPARAM lParamNew)
{
TV_ITEMtvItem;
LPARAMlParamOld;
tvItem.mask = TVIF_PARAM;
tvItem.hItem = hItem;
TreeView_GetItem(hwndTV, &tvItem);
lParamOld = tvItem.lParam;
tvItem.lParam = lParamNew;
TreeView_SetItem(hwndTV, &tvItem);
if(FIsLParamTVData(lParamOld))
GlobalFreePtr((TVDATA *)lParamOld);
return TRUE;
}
/*
*TreeView_TVDataInsert
*
*Purpose:
*Try to be smart when inserting TV items
*
*Arguments:
*ptvis to insert
*
*Returns:
*hItem of newly inserted item
*/
HTREEITEM
TreeView_TVDataInsert(HWND hwndTV, TV_INSERTSTRUCT *ptvis)
{
HTREEITEMhItem;
// See if this item exists anywhere already
hItem = TreeView_FindExactString(hwndTV, ptvis->hParent,
ptvis->hInsertAfter, ptvis->item.pszText);
// It does: del everything from the last inserted node to right before us
if(hItem)
{
OutputDbgStr("TreeView_TVDataInsert found '%ls'", ptvis->item.pszText);
FTreeView_DeleteRange(hwndTV, ptvis->hParent, ptvis->hInsertAfter,
hItem);
TreeView_TVReplacelParam(hwndTV, hItem, ptvis->item.lParam);
ptvis->hInsertAfter = hItem;
return hItem;
}
// ok, it's a new string, insert it
// If this is the first one, make sure it's the first one
OutputDbgStr("TreeView_TVDataInsert inserting '%ls'", ptvis->item.pszText);
if(!ptvis->hInsertAfter)
ptvis->hInsertAfter = TVI_FIRST;
hItem = TreeView_InsertItem(hwndTV, ptvis);
// Store away the last item we've inserted
ptvis->hInsertAfter = hItem;
return hItem;
}
/*
*TreeView_FreeItemData
*
*Purpose:
*Free our alloc'd lParam (called via DELETEITEM)
*
*Arguments:
*ptvItem of item being deleted
*
*Returns:
*nada
*/
VOID
TreeView_FreeItemData(TV_ITEM *ptvItem)
{
if(FIsLParamTVData(ptvItem->lParam))
{
OutputDbgStr("TreeView_FreeItemData '%d'",
((TVDATA *)ptvItem->lParam)->dwType);
GlobalFreePtr((TVDATA *)ptvItem->lParam);
ptvItem->lParam = 0;
}
}
/*
*TreeView_GetSelectedItemData
*
*Purpose:
*Get type and lParam of selected item
*
*Arguments:
*pdwType
*
*Returns:
*lParam of selected item
*/
LPARAM
TreeView_GetSelectedItemData(HWND hwndTV, DWORD *pdwType)
{
HTREEITEMhItem;
TV_ITEMtvItem;
*pdwType = TYPE_ERROR;
if(!(hItem = TreeView_GetSelection(hwndTV)))
return 0;
tvItem.mask = TVIF_PARAM;
tvItem.hItem = hItem;
tvItem.lParam = TYPE_ERROR;
TreeView_GetItem(hwndTV, &tvItem);
*pdwType = FIsLParamTVData(tvItem.lParam) ?
((TVDATA *)tvItem.lParam)->dwType : tvItem.lParam;
return tvItem.lParam;
}
/*
*Sorting routines
*/
/*
*CompareShareNames
*
*Purpose:
*compare two share names being 'smart' about hidden shares
*
*Arguments:
*share1, share2
*
*Returns:
*-1, 0, 1
*/
int
CompareShareNames(TCHAR *szShareName1, TCHAR *szShareName2)
{
BOOLfShare1Hidden;
BOOLfShare2Hidden;
fShare1Hidden = FIsShareHidden(szShareName1);
fShare2Hidden = FIsShareHidden(szShareName2);
// If they're the same type, just string compare them
if(fShare1Hidden == fShare2Hidden)
return lstrcmpi(szShareName1, szShareName2);
// Otherwise we want hidden shares to go first
return fShare1Hidden ? -1 : 1;
}
/*
*QSortCallbacks
*
*Purpose:
*called from qsort to figure what goes where
*
*Arguments:
*elements to compare
*
*Returns:
*< 0: elem1 less than elem2
*= 0: elem1 equivalent to elem2
*> 0: elem1 greater than elem2
*/
int __cdecl
CompareShareNamesQSortCallback(const void *elem1, const void *elem2)
{
return CompareShareNames(((SHARE_INFO_2 *)elem1)->shi2_netname,
((SHARE_INFO_2 *)elem2)->shi2_netname);
}
int __cdecl
CompareUserNamesQSortCallback(const void *elem1, const void *elem2)
{
return lstrcmp(((CONNECTION_INFO_1 *)elem1)->coni1_username,
((CONNECTION_INFO_1 *)elem2)->coni1_username);
}
int __cdecl
CompareFileNamesQSortCallback(const void *elem1, const void *elem2)
{
return lstrcmp(((FILE_INFO_3 *)elem1)->fi3_pathname,
((FILE_INFO_3 *)elem2)->fi3_pathname);
}
/*
*Enumeration routines
*/
/*
*FilesEnum
*
*Purpose:
*Enumerate the open files on a sharepath, username, and server
*
*Arguments:
*all kinds of stuff
*
*Returns:
*nas
*/
NET_API_STATUS
FilesEnum(HWND hwndTV, HTREEITEM hParent, LPTSTR szServerName, TCHAR *username,
TCHAR *sharepath, TVDATAUSER *pTVDataUser)
{
NET_API_STATUSnas;
TV_INSERTSTRUCTtvis;
FILE_INFO_3*pfi3;
FILE_INFO_3*fi3 = NULL;
DWORDdwentriesread;
DWORDdwtotalentries;
TCHAR*psharepathend;
// Some stuff doesn't change
tvis.hInsertAfter = NULL;
tvis.hParent = hParent;
tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
// Reasoning: if you are passed c:\ as a sharepath, sometimes c: is opened
// as execute. But since we would be qualifying paths on c:\, it won't show
// c: as being open. So - remove the last \ if it's there.
if(sharepath && sharepath[0])
{
psharepathend = sharepath + lstrlen(sharepath) - 1;
if(*psharepathend == TEXT('\\'))
*psharepathend = '\0';
}
nas = NetFileEnum(szServerName, sharepath, username, 3,
(LPBYTE *)&fi3, MAX_PREFERRED_LENGTH,
&dwentriesread, &dwtotalentries, NULL);
if(nas || !dwentriesread)
goto err;
qsort(fi3, dwentriesread, sizeof(fi3[0]), CompareFileNamesQSortCallback);
for(pfi3 = fi3; dwentriesread; pfi3++, dwentriesread--)
{
TVDATAFILE*pTVDataFile;
UINTnBitmap = BMP_READ;
// And our bmp is...
if((pfi3->fi3_permissions & PERM_FILE_WRITE) ||
(pfi3->fi3_permissions & PERM_FILE_CREATE))
nBitmap = BMP_WRITE;
// Things to remember for properties, delete, etc.
if(pTVDataFile = (TVDATAFILE *)GlobalAllocPtr(GHND, sizeof(TVDATAFILE)))
{
pTVDataFile->dwType = TYPE_FILE;
pTVDataFile->dwFileId = pfi3->fi3_id;
pTVDataFile->pTVDataUser = pTVDataUser;
}
// Insert that baby
tvis.item.lParam = (LPARAM)pTVDataFile;
tvis.item.pszText = pfi3->fi3_pathname;
tvis.item.iImage = tvis.item.iSelectedImage = nBitmap;
TreeView_TVDataInsert(hwndTV, &tvis);
}
err:
// Whack any stragglers hanging at the end
FTreeView_DeleteRange(hwndTV, hParent, tvis.hInsertAfter, NULL);
NetApiBufferFree(fi3);
if(nas)
AddErrorStringToTV(hwndTV, hParent, IDS_ERRENUMFILES, nas);
return nas;
}
/*
*UsersEnum
*
*Purpose:
*Enumerate the users on a sharepath and server
*
*Arguments:
*lots o garbage
*
*Returns:
*nas
*/
NET_API_STATUS
UsersEnum(HWND hwndTV, HTREEITEM hParent, LPTSTR szServerName, TCHAR *sharename,
TCHAR *sharepath, TVDATASHARE *pTVDataShare)
{
NET_API_STATUSnas;
TV_INSERTSTRUCTtvis;
HTREEITEMhItem;
CONNECTION_INFO_1*pci1;
CONNECTION_INFO_1*ci1 = NULL;
DWORDdwentriesread;
DWORDdwtotalentries;
static TCHARszFmtUser[cchSzMax + 1];
TCHARszUserT[NNLEN + UNLEN + cchSzMax + 1];
// Some stuff doesn't change
tvis.hInsertAfter = NULL;
tvis.hParent = hParent;
tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
if(!szFmtUser[0])
lstrcpy(szFmtUser, szFromIDS1(IDS_FMTUSER));
nas = NetConnectionEnum(szServerName, sharename, 1, (LPBYTE *)&ci1,
MAX_PREFERRED_LENGTH, &dwentriesread, &dwtotalentries, NULL);
if(nas || !dwentriesread)
goto err;
qsort(ci1, dwentriesread, sizeof(ci1[0]), CompareUserNamesQSortCallback);
for(pci1 = ci1; dwentriesread; pci1++, dwentriesread--)
{
TCHAR*netname;
TCHAR*username;
TVDATAUSER*pTVDataUser;
username = pci1->coni1_username;
netname = pci1->coni1_netname;
if(!username || !username[0])
username = szNil;
else
CharLower(username);
if(!netname || !netname[0])
netname = szNil;
else
CharUpper(netname);
if(lstrlen(netname) > CNLEN)
netname[CNLEN] = 0;
if(lstrlen(username) > UNLEN)
username[UNLEN] = 0;
wsprintf(szUserT, szFmtUser, username, netname);
// Things to remember for properties, delete, etc.
if(pTVDataUser = (TVDATAUSER *)GlobalAllocPtr(GHND, sizeof(TVDATAUSER)))
{
pTVDataUser->dwType = TYPE_USER;
lstrcpy(pTVDataUser->szUserName, username);
pTVDataUser->szNetName[0] = pTVDataUser->szNetName[1] = '\\';
lstrcpy(&pTVDataUser->szNetName[2], netname);
pTVDataUser->pTVDataShare = pTVDataShare;
}
tvis.item.lParam = (LPARAM)pTVDataUser;
tvis.item.pszText = szUserT;
tvis.item.iImage = tvis.item.iSelectedImage = BMP_USER;
hItem = TreeView_TVDataInsert(hwndTV, &tvis);
// If we haven't run into any errors and the user wants to see files
if(pci1->coni1_num_opens &&
unMenuFlags[IDM_SHOWFILES & 0xff] == MF_CHECKED && !nas)
{
// Enum the files
nas = FilesEnum(hwndTV, hItem, szServerName, username,
sharepath, pTVDataUser);
// make sure we're expanded
TreeView_Expand(hwndTV, hItem, TVE_EXPAND);
}
else
{
// Delete all our children
FTreeView_DeleteRange(hwndTV, hItem, NULL, NULL);
}
}
// reset any filesenum errors we may have encountered
nas = 0;
err:
// Whack any stragglers hanging at the end
FTreeView_DeleteRange(hwndTV, hParent, tvis.hInsertAfter, NULL);
NetApiBufferFree(ci1);
if(nas)
AddErrorStringToTV(hwndTV, hParent, IDS_ERRENUMUSERS, nas);
return nas;
}
/*
*SharesEnum
*
*Purpose:
*Enumerate the shares on a server
*
*Arguments:
*server to enum
*
*Returns:
*nas
*/
#define offsetof(s, m) (size_t)&(((s *)0)->m)
#define shoffset(l, m) (offsetof(SHARE_INFO_##l, m))
NET_API_STATUS
SharesEnum(HWND hwndTV, HTREEITEM hParent, LPTSTR szServerName, UINT *pcUsers,
INT nLevel)
{
NET_API_STATUSnas;
TV_INSERTSTRUCTtvis;
HTREEITEMhItem;
SHARE_INFO_2*pshi2;
UINTcbStruct;
SHARE_INFO_2*shi2 = NULL;
DWORDdwentriesread;
DWORDdwtotalentries;
SCONST TCHARszEndSep[] = TEXT(")");
SCONST TCHARszBegSep[] = TEXT(" (");
// +3 for the begsep and endsep
TCHARszShareT[NNLEN + MAXCOMMENTSZ + 3 + 1];
Assert(nLevel == 1 || nLevel == 2);
// We assume the first three parts of these structs are the same. Make sure.
// Using cbStruct here cause the compiler loses the entire line if I don't?
Assert((cbStruct = shoffset(1, shi1_netname)) == shoffset(2, shi2_netname));
Assert((cbStruct = shoffset(1, shi1_type)) == shoffset(2, shi2_type));
Assert((cbStruct = shoffset(1, shi1_remark)) == shoffset(2, shi2_remark));
cbStruct = nLevel == 2 ? sizeof(SHARE_INFO_2) : sizeof(SHARE_INFO_1);
// WARNING: don't use the following members of shi2 without checking nLevel!
//shi2_permissions;
//shi2_max_uses;
//shi2_current_uses
//shi2_path;
//shi2_passwd;
// Some stuff doesn't change
tvis.hInsertAfter = NULL;
tvis.hParent = hParent;
tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
nas = NetShareEnum(szServerName, nLevel, (LPBYTE *)&shi2,
MAX_PREFERRED_LENGTH, &dwentriesread, &dwtotalentries, NULL);
if(nas || !dwentriesread)
goto err;
// Sort the shares and then cruise through adding em all to the TV
qsort(shi2, dwentriesread, cbStruct, CompareShareNamesQSortCallback);
for(pshi2 = shi2; dwentriesread; ((LPBYTE)pshi2) += cbStruct, dwentriesread--)
{
TCHAR*sharename;
TCHAR*shareremark;
UINTnCurrentUses;
TVDATASHARE*pTVDataShare;
sharename = pshi2->shi2_netname;
shareremark = pshi2->shi2_remark;
nCurrentUses = (nLevel == 2) ? pshi2->shi2_current_uses : 0;
if(!sharename)
continue;
if(!shareremark)
shareremark = szNil;
if(lstrlen(sharename) > NNLEN)
sharename[NNLEN] = 0;
if(lstrlen(shareremark) > MAXCOMMENTSZ)
shareremark[MAXCOMMENTSZ] = 0;
// skip hidden shares
if((unMenuFlags[IDM_SHOWHIDDEN & 0xff] == MF_UNCHECKED) &&
FIsShareHidden(sharename))
continue;
// Keep a running total
*pcUsers += nCurrentUses;
// If we have any users connected or the onlyshowinuse isn't checked
if(nCurrentUses || (unMenuFlags[IDM_SHOWINUSE & 0xff] != MF_CHECKED))
{
int nBitmap = ((pshi2->shi2_type & 0xf) == STYPE_IPC) ?
BMP_IPC : BMP_SHARE;
// Copy over the share name and comment
lstrcpy(szShareT, sharename);
if(shareremark[0])
{
lstrcat(szShareT, szBegSep);
lstrcat(szShareT, shareremark);
lstrcat(szShareT, szEndSep);
}
// Things to remember for properties, delete, etc.
if(pTVDataShare = (TVDATASHARE *)GlobalAllocPtr(GHND,
sizeof(TVDATASHARE)))
{
pTVDataShare->dwType = TYPE_SHARE;
pTVDataShare->dwShareType = pshi2->shi2_type;
lstrcpy(pTVDataShare->szShareName, sharename);
lstrcpy(pTVDataShare->szServerName, szServerName);
}
tvis.item.lParam = (LPARAM)pTVDataShare;
tvis.item.pszText = szShareT;
tvis.item.iImage = tvis.item.iSelectedImage = nBitmap;
hItem = TreeView_TVDataInsert(hwndTV, &tvis);
// If we previously got an error enuming users, don't waste our time
// trying again.
if(!nas && nCurrentUses)
{
Assert(nLevel == 2);
nas = UsersEnum(hwndTV, hItem, szServerName,
sharename, pshi2->shi2_path, pTVDataShare);
// Make sure we're showing it all
TreeView_Expand(hwndTV, hItem, TVE_EXPAND);
}
else
{
// Delete all our children
FTreeView_DeleteRange(hwndTV, hItem, NULL, NULL);
}
}
}
// reset any errors UsersEnum may have trickled up
nas = 0;
err:
// Whack any stragglers hanging at the end
FTreeView_DeleteRange(hwndTV, hParent, tvis.hInsertAfter, NULL);
if(nas)
AddErrorStringToTV(hwndTV, hParent, IDS_ERRENUMSHARES, nas);
NetApiBufferFree(shi2);
return nas;
}
/*
*RefreshDisplay
*
*Purpose:
*Update the treeview with piping hot info
*
*Arguments:
*main hwnd
*
*Returns:
*Count of uses connected to shares
*/
UINT
RefreshDisplay(HWND hwnd, HWND hwndTV)
{
HTREEITEMhItem;
HCURSORhCursor;
UINTcUsers = 0;
static UINTcRefreshes = 0;
// Turn off the timer
PunchTimer(hwnd, FALSE);
OutputDbgStr("RefreshDisplay (%d): 0x%08lx", cRefreshes, GetTickCount());
// This may take a while
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
// Enumerate all the shares
hItem = TreeView_GetRoot(hwndTV);
while(hItem)
{
TV_ITEMtvItem;
HTREEITEMhItemChild;
TCHARszT[UNCLEN + 1];
// Check to see if the first child is an error
if((cRefreshes % 4) && (hItemChild = TreeView_GetChild(hwndTV, hItem)))
{
// If it is, only update it 1 out of 4 times
tvItem.mask = TVIF_PARAM;
tvItem.hItem = hItemChild;
if(TreeView_GetItem(hwndTV, &tvItem) && tvItem.lParam == TYPE_ERROR)
{
OutputDbgStr("Skipping errored out server");
goto nextserver;
}
}
// Get the server name and server image
tvItem.mask = TVIF_TEXT | TVIF_IMAGE;
tvItem.hItem = hItem;
tvItem.pszText = szT;
tvItem.cchTextMax = UNCLEN + 1;
if(TreeView_GetItem(hwndTV, &tvItem) && (szT[0] == '\\'))
{
// Enumerate all the shares under here
SharesEnum(hwndTV, hItem, szT, &cUsers,
tvItem.iImage == BMP_COMPUTER ? 2 : 1);
// Make sure we're showing it all
TreeView_Expand(hwndTV, hItem, TVE_EXPAND);
}
// Next server
nextserver:
hItem = TreeView_GetNextSibling(hwndTV, hItem);
}
// Bring back our arrow
SetCursor(hCursor);
// Swing the selection back into view
if(hItem = TreeView_GetSelection(hwndTV))
TreeView_EnsureVisible(hwndTV, hItem);
// Resume the timer again
PunchTimer(hwnd, TRUE);
// Update our number of refreshes and return the count of users
cRefreshes++;
return cUsers;
}
/*
*Properties
*/
/*
*DisplayComputerDetails
*
*Purpose:
*Delete/Show property page for computer
*
*Arguments:
*hwnd, wAction
*
*Returns:
*nas
*/
NET_API_STATUS
DisplayComputerDetails(HWND hwnd, TVDATA *pTVData, WORD wAction)
{
HTREEITEMhItem;
HWNDhwndTV;
NET_API_STATUSnas = 0;
SERVER_INFO_102*si102 = NULL;
if(!(hwndTV = GetDlgItem(hwnd, IDD_tvwSHARES)))
return 0;
if(!(hItem = TreeView_GetSelection(hwndTV)))
return 0;
if(wAction == VK_DELETE)
{
TreeView_DeleteItem(hwndTV, hItem);
}
else
{
TV_ITEMtvItem;
HCURSORhCursor;
TCHARszT[UNCLEN + 1];
TCHARszVer[cchSzMax + 1];
szT[0] = 0;
tvItem.mask = TVIF_TEXT;
tvItem.hItem = hItem;
tvItem.pszText = szT;
tvItem.cchTextMax = UNCLEN + 1;
TreeView_GetItem(hwndTV, &tvItem);
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
nas = NetServerGetInfo(szT, 102, (LPBYTE *)&si102);
SetCursor(hCursor);
if(nas || !si102)
goto err;
wsprintf(szVer, TEXT("%d.%d"),
si102->sv102_version_major & MAJOR_VERSION_MASK,
si102->sv102_version_minor);
PropertyDlg(hwnd,
IDS_SERVERPROPS,
0xfffffff1,
si102->sv102_name,
si102->sv102_comment,
si102->sv102_userpath,
szVer,
szFromIDS1(IDS_HIDDEN + !!si102->sv102_hidden),
NULL);
}
err:
NetApiBufferFree(si102);
return nas;
}
/*
*DisplayShareDetails
*
*Purpose:
*Delete/Show property page for shares
*
*Arguments:
*hwnd, pTVDataShare, wAction
*
*Returns:
*nas
*/
NET_API_STATUS
DisplayShareDetails(HWND hwnd, TVDATA *pTVData, WORD wAction)
{
NET_API_STATUSnas;
HCURSORhCursor;
SHARE_INFO_2*shi2 = NULL;
TVDATASHARE*pTVDataShare = (TVDATASHARE *)pTVData;
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
nas = NetShareGetInfo(pTVDataShare->szServerName, pTVDataShare->szShareName,
2, (LPBYTE *)&shi2);
SetCursor(hCursor);
if(!nas && shi2)
{
if(wAction == VK_DELETE)
{
// if no one is connected, nuke it, else confirm with user
if(!(shi2->shi2_current_uses) ||
(MessageBox(hwnd, szFromIDS1(IDS_AREYOUSURE + TYPE_SHARE),
szAppName, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2) ==
IDYES))
{
nas = NetShareDel(pTVDataShare->szServerName,
pTVDataShare->szShareName, 0);
}
}
else
{
TCHARszMaxUses[11];
TCHARszMaxCurrent[11];
wsprintf(szMaxUses, szFmtNum, shi2->shi2_max_uses);
wsprintf(szMaxCurrent, szFmtNum, shi2->shi2_current_uses);
PropertyDlg(hwnd,
IDS_SHAREPROPS,
((shi2->shi2_type & 0xf) == STYPE_IPC) ? 0xfffffff8 : 0xfffffff0,
shi2->shi2_netname,
shi2->shi2_path,
shi2->shi2_remark,
(shi2->shi2_max_uses == SHI_USES_UNLIMITED) ?
szFromIDS1(IDS_NOLIMIT) : szMaxUses,
szMaxCurrent,
NULL);
}
}
NetApiBufferFree(shi2);
return nas;
}
/*
*DisplayFileDetails
*
*Purpose:
*Delete/Show property page for files
*
*Arguments:
*hwnd, pTVDataFile, wAction
*
*Returns:
*nas
*/
NET_API_STATUS
DisplayFileDetails(HWND hwnd, TVDATA *pTVData, WORD wAction)
{
NET_API_STATUSnas;
HCURSORhCursor;
FILE_INFO_3*fi3 = NULL;
TCHAR*szServerName;
TVDATAFILE*pTVDataFile = (TVDATAFILE *)pTVData;
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
szServerName = pTVDataFile->pTVDataUser->pTVDataShare->szServerName;
nas = NetFileGetInfo(szServerName, pTVDataFile->dwFileId, 3, (LPBYTE *)&fi3);
SetCursor(hCursor);
if(!nas && fi3)
{
if(wAction == VK_DELETE)
{
TCHARszMsg[cchMsgMax];
wsprintf(szMsg, szFromIDS1(IDS_AREYOUSURE + TYPE_FILE),
pTVDataFile->pTVDataUser->szUserName, fi3->fi3_pathname);
if(MessageBox(hwnd, szMsg, szAppName,
MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2) == IDYES)
{
nas = NetFileClose(szServerName, pTVDataFile->dwFileId);
}
}
else
{
TCHARszNumLocks[11];
UINTnBitmap = BMP_READ;
if((fi3->fi3_permissions & PERM_FILE_WRITE) ||
(fi3->fi3_permissions & PERM_FILE_CREATE))
nBitmap = BMP_WRITE;
wsprintf(szNumLocks, szFmtNum, fi3->fi3_num_locks);
PropertyDlg(hwnd,
IDS_FILEPROPS,
0xfffff072 | (nBitmap << 8),
fi3->fi3_pathname,
fi3->fi3_username,
szFromIDS1(IDS_FILEPROPS + 10 + nBitmap),
szNumLocks,
NULL,
NULL);
}
}
NetApiBufferFree(fi3);
return nas;
}
/*
*DisplayUserDetails
*
*Purpose:
*Delete/Show property page for users
*
*Arguments:
*hwnd, pTVDataUser, wAction
*
*Returns:
*nas
*/
NET_API_STATUS
DisplayUserDetails(HWND hwnd, TVDATA *pTVData, WORD wAction)
{
NET_API_STATUSnas;
time_ttm_t;
TCHAR*szServerName;
SESSION_INFO_2*sesi2 = NULL;
TCHARszUserName[UNLEN + cchSzMax + 1];
TVDATAUSER*pTVDataUser = (TVDATAUSER *)pTVData;
szServerName = pTVDataUser->pTVDataShare->szServerName;
nas = NetSessionGetInfo(szServerName, pTVDataUser->szNetName,
pTVDataUser->szUserName, 2, (LPBYTE *)&sesi2);
if(!nas && sesi2)
{
if(wAction == VK_DELETE)
{
UINTids;
TCHARszMsg[cchMsgMax];
// if user has open files, tell the del happy person this
// otherwise just reaffirm that they wanna hack em.
ids = sesi2->sesi2_num_opens ?
IDS_AREYOUSURE + TYPE_USER : IDS_AREYOUSUREDISUSER;
wsprintf(szMsg, szFromIDS1(ids), pTVDataUser->szUserName);
if(MessageBox(hwnd, szMsg, szAppName,
MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2) == IDYES)
{
nas = NetSessionDel(szServerName, pTVDataUser->szNetName,
pTVDataUser->szUserName);
}
}
else
{
TCHARszNumOpens[11];
TCHARszIdleTime[cchSzMax];
TCHARszConnectTime[cchSzMax];
SCONST TCHAR szSpace[] = TEXT(" ");
lstrcpy(szUserName, pTVDataUser->szUserName);
if(sesi2->sesi2_user_flags & SESS_GUEST)
lstrcat(szUserName, szFromIDS1(IDS_GUEST));
time(&tm_t);
PutTime(tm_t - sesi2->sesi2_time, szIdleTime, cchSzMax);
PutDate(tm_t - sesi2->sesi2_time, szConnectTime, cchSzMax);
lstrcat(szConnectTime, szSpace);
lstrcat(szConnectTime, szIdleTime);
wsprintf(szNumOpens, szFmtNum, sesi2->sesi2_num_opens);
PropertyDlg(hwnd,
IDS_USERPROPS,
pTVDataUser->pTVDataShare->dwShareType == STYPE_IPC ?
0xfffff817 : 0xfffff017,
szUserName,
pTVDataUser->szNetName,
pTVDataUser->pTVDataShare->szShareName,
szConnectTime,
PutCounterTime(sesi2->sesi2_idle_time, szIdleTime, cchSzMax),
szNumOpens);
}
}
if(!nas && !sesi2)
nas = ERROR_NOT_CONNECTED;
NetApiBufferFree(sesi2);
return nas;
}
/*
*Nifty little array of property functions
*/
typedef NET_API_STATUS (*PFNDISPLAYDETAILS)(HWND hwnd, TVDATA *pTVData, WORD wAction);
SCONST PFNDISPLAYDETAILS pfnDisplayDetails[TYPE_MAX] =
{
DisplayComputerDetails,
DisplayShareDetails,
DisplayUserDetails,
DisplayFileDetails
};
/*
*HandleWM_VKEY
*
*Purpose:
*handle WM_VKEYS: VK_DELETE and VK_RETURN
*
*Arguments:
*main hwnd and wAction
*
*Returns:
*TRUE - success, FALSE - error
*/
BOOL
HandleWM_VKEY(HWND hwnd, HWND hwndTV, WORD wAction)
{
NET_API_STATUSnas = 0;
TVDATA*pTVData;
DWORDdwType = TYPE_COMPUTER;
OutputDbgStr("HandleWM_VKEY");
// Only handle return and delete keys
if((wAction != VK_RETURN) && (wAction != VK_DELETE))
return FALSE;
// Get the Selected item data
pTVData = (TVDATA *)TreeView_GetSelectedItemData(hwndTV, &dwType);
// Ok, do the order
PunchTimer(hwnd, FALSE);
// jump to the display page
if(dwType < TYPE_MAX)
nas = (pfnDisplayDetails[dwType])(hwnd, pTVData, wAction);
// Report any errors
if(nas)
{
TCHARszMsg[cchErrMax];
TCHAR*szErrMessage = NULL;
lstrcpy(szMsg, szFromIDS1(IDS_ERRACTION));
if(szErrMessage = GetSystemErrMessage(nas))
lstrcat(szMsg, szErrMessage);
MessageBox(hwnd, szMsg, szAppName, MB_ICONEXCLAMATION);
GlobalFreeNullPtr(szErrMessage);
}
// If we hit an error or they whacked something, update now
if(nas || (wAction == VK_DELETE))
PostMessage(hwnd, WM_TIMER, 0, 0L);
else
PunchTimer(hwnd, TRUE);
return TRUE;
}
/*
*AddErrorStringToTV
*
*Purpose:
*Slap an error string in the TV
*
*Arguments:
*hParent, ids of error, nas of error
*
*Returns:
*nada
*/
VOID
AddErrorStringToTV(HWND hwndTV, HTREEITEM hParent, UINT ids, NET_API_STATUS nas)
{
TV_INSERTSTRUCTtvis;
TCHAR*szErrMessage;
SCONST TCHARszSep[] = TEXT(": ");
TCHARszErrBuf[cchErrMax];
// Get the text
lstrcpy(szErrBuf, szFromIDS1(ids));
if(szErrMessage = GetSystemErrMessage(nas))
{
lstrcat(szErrBuf, szSep);
lstrcat(szErrBuf, szErrMessage);
LocalFree((HLOCAL)szErrMessage);
}
// Add the error string
tvis.hParent = hParent;
tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvis.hInsertAfter = NULL;
tvis.item.pszText = szErrBuf;
tvis.item.iImage = tvis.item.iSelectedImage = BMP_DENIED;
tvis.item.lParam = (LPARAM)TYPE_ERROR;
TreeView_TVDataInsert(hwndTV, &tvis);
// Delete all other children
FTreeView_DeleteRange(hwndTV, hParent, tvis.hInsertAfter, NULL);
}
/*
*FAnyRemoteDrives
*
*Purpose:
*Checks if there are any remote drives connected
*
*Arguments:
*zip
*
*Returns:
*Returns TRUE if there are
*/
BOOL
FAnyRemoteDrives()
{
INTch;
UINTerrmode;
TCHARszRoot[4];
BOOLfRet = FALSE;
errmode = SetErrorMode(SEM_FAILCRITICALERRORS);
szRoot[1] = ':';
szRoot[2] = '\\';
szRoot[3] = 0;
for (ch = 'C'; ch <= 'Z'; ch++)
{
szRoot[0] = ch;
if(GetDriveType(szRoot) == DRIVE_REMOTE)
{
fRet = TRUE;
break;
}
}
SetErrorMode(errmode);
return fRet;
}
/*
*HandleMenu
*
*Purpose:
*Disable\Enable\Change menu according to what is selected
*
*Arguments:
*hwnd
*
*Returns:
*zip
*/
VOID
HandleMenu(HWND hwnd, HWND hwndTV, HMENU hMenu)
{
DWORDdwType = TYPE_COMPUTER;
TreeView_GetSelectedItemData(hwndTV, &dwType);
OutputDbgStr("Item type %d selected", dwType);
// Enable/disable the disconnect network drive menu item
if(hMenu == ghMenu)
{
EnableMenuItem(hMenu, IDM_DISCONNECTDRIVE, FAnyRemoteDrives() ?
MF_BYCOMMAND | MF_ENABLED : MF_BYCOMMAND | MF_GRAYED);
}
if(dwType == TYPE_ERROR)
{
EnableMenuItem(hMenu, IDM_DELETERESOURCE, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(hMenu, IDM_PROPERTIES, MF_BYCOMMAND | MF_GRAYED);
}
else
{
EnableMenuItem(hMenu, IDM_PROPERTIES, MF_BYCOMMAND | MF_ENABLED);
ModifyMenu(hMenu, IDM_DELETERESOURCE, MF_BYCOMMAND | MF_STRING,
IDM_DELETERESOURCE, szFromIDS1(IDS_DELETERESOURCE + dwType));
}
}