#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <commctrl.h>
#include <string.h>
#include <Lm.h>

#define ID_TIMER	5000

HINSTANCE	m_hInstance				= NULL;
HWND		m_hWnd					= NULL;
HWND		m_hWnd_ListComputers	= NULL;
HWND		m_hWnd_ListProperies	= NULL;

static BOOL InitApplication();
static BOOL InitInstance(int nCmdShow) ;
static LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); 
static void Refresh_Computers ();


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow )
{
	MSG		msg; 
	BOOL	fGotMessage;

	m_hInstance = hInstance;

	if (!InitApplication()) 
		return FALSE; 

	if (!InitInstance(nCmdShow)) 
		return FALSE; 

	
	while ((fGotMessage = GetMessage(&msg, (HWND) m_hWnd, 0, 0)) != 0 && fGotMessage != -1) 
	{ 
		TranslateMessage(&msg); 
		DispatchMessage(&msg); 
	} 
	
	return msg.wParam; 
	
	UNREFERENCED_PARAMETER(lpCmdLine); 
	return 0;
}


 
static BOOL InitApplication() 
{ 
    WNDCLASSEX wcx; 

	InitCommonControls ();

 
    // Fill in the window class structure with parameters 
    // that describe the main window. 
 
    wcx.cbSize = sizeof(wcx);          // size of structure 
    wcx.style = CS_HREDRAW |         CS_VREDRAW;                    // redraw if size changes 
    wcx.lpfnWndProc = MainWndProc;     // points to window procedure 
    wcx.cbClsExtra = 0;                // no extra class memory 
    wcx.cbWndExtra = 0;                // no extra window memory 
    wcx.hInstance = m_hInstance;         // to instance 
    wcx.hIcon = LoadIcon(NULL,         IDI_APPLICATION);              // predefined app. icon 
    wcx.hCursor = LoadCursor(NULL, IDC_ARROW);                    // predefined arrow 
    wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);                  // white background brush 
    wcx.lpszMenuName =  NULL;
    wcx.lpszClassName = "WNDCLASSW32NetEnum";  // name of window class 
    wcx.hIconSm = (HICON)LoadImage(m_hInstance, // small class icon 
        MAKEINTRESOURCE(5),
        IMAGE_ICON, 
        GetSystemMetrics(SM_CXSMICON), 
        GetSystemMetrics(SM_CYSMICON), 
        LR_DEFAULTCOLOR); 
 
    // Register the window class. 
 
    return RegisterClassEx(&wcx); 
} 
 
static BOOL InitInstance(int nCmdShow) 
{ 
    HWND hwnd; 
 
    // Create the main window. 
 
    hwnd = CreateWindow( 
        "WNDCLASSW32NetEnum",        // name of window class 
        "W32NetEnum",            // title-bar string 
        WS_OVERLAPPEDWINDOW, // top-level window 
        CW_USEDEFAULT,       // default horizontal position 
        CW_USEDEFAULT,       // default vertical position 
        CW_USEDEFAULT,       // default width 
        CW_USEDEFAULT,       // default height 
        (HWND) NULL,         // no owner window 
        (HMENU) NULL,        // use class menu 
        m_hInstance,           // handle to application instance 
        (LPVOID) NULL);      // no window-creation data 
 
    if (!hwnd) 
        return FALSE; 

	m_hWnd = hwnd;

    // Show the window and send a WM_PAINT message to the window 
    // procedure. 
 
    ShowWindow(hwnd, nCmdShow); 
    UpdateWindow(hwnd); 


    return TRUE; 
 
}

static void InitControls (HWND hWnd)
{
	LVCOLUMN	Column;

	/* m_hWnd_ListComputers */

	m_hWnd_ListComputers = CreateWindowEx (
		WS_EX_CLIENTEDGE,
		WC_LISTVIEW, "", 
		WS_CHILD | LVS_REPORT | LVS_EDITLABELS | WS_VISIBLE  , 
		0, 0, 100, 100,
		hWnd , 0, m_hInstance, NULL);

	ListView_SetExtendedListViewStyleEx (m_hWnd_ListComputers, 0, LVS_EX_FULLROWSELECT);

	memset (&Column, 0, sizeof(Column));

	Column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	Column.cx = 250;

	Column.pszText = "Name";
	ListView_InsertColumn(m_hWnd_ListComputers, 1, &Column);


	Column.pszText = "Comment";
	ListView_InsertColumn(m_hWnd_ListComputers, 2, &Column);

	/* m_hWnd_ListProperies */

	m_hWnd_ListProperies = CreateWindowEx (
		WS_EX_CLIENTEDGE,
		WC_LISTVIEW, "", 
		WS_CHILD | LVS_REPORT | LVS_EDITLABELS | WS_VISIBLE  , 
		0, 0, 100, 100,
		hWnd , 0, m_hInstance, NULL);

	ListView_SetExtendedListViewStyleEx (m_hWnd_ListProperies, 0, LVS_EX_FULLROWSELECT);

	memset (&Column, 0, sizeof(Column));

	Column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	Column.cx = 250;

	Column.pszText = "Property";
	ListView_InsertColumn(m_hWnd_ListProperies, 1, &Column);

	Column.pszText = "Value";
	ListView_InsertColumn(m_hWnd_ListProperies, 2, &Column);


	/* initial refresh */


	Refresh_Computers();

	SetTimer (hWnd, ID_TIMER, 5000, NULL);
}


static void Refresh_Computers ()
{
	NET_API_STATUS	status;
	SERVER_INFO_101	*info;
	unsigned char	*buffer;
	DWORD			entriesread;
	DWORD			totalentries;
	LVITEM			Item;

	if (NULL == m_hWnd_ListComputers) {
		return;
	}

	status = NetServerEnum (
					NULL,
					101,
					&buffer,
					MAX_PREFERRED_LENGTH,
					&entriesread,
					&totalentries,
					SV_TYPE_ALL,
					NULL,
					0);

	ListView_DeleteAllItems(m_hWnd_ListComputers);

	memset (&Item, 0, sizeof(Item));

	Item.mask = LVIF_TEXT;

	for (info = (SERVER_INFO_101*)buffer; entriesread; --entriesread, ++info,++Item.iItem) {
		char			sTemp[128];

		/* name */
		sprintf_s (sTemp, sizeof(sTemp)-1, "%ws", info->sv101_name);

		Item.pszText = sTemp;

		ListView_InsertItem (m_hWnd_ListComputers, &Item);

		/* comment */
		sprintf_s (sTemp, sizeof(sTemp)-1, "%ws",info->sv101_comment);

		Item.pszText = sTemp;

		ListView_SetItemText (m_hWnd_ListComputers, Item.iItem, 1, sTemp);
	}

	if (buffer) {
		NetApiBufferFree (buffer);
	}
}

inline static void list_add (LVITEM *pItem, LPSTR Property, LPSTR Value)
{
	pItem->pszText = Property;
	ListView_InsertItem (m_hWnd_ListProperies, pItem);
	ListView_SetItemText (m_hWnd_ListProperies, pItem->iItem, 1, Value);
	++pItem->iItem;
}

inline static void Refresh_Properties (DWORD iItem)
{
	HWND			hWnd		= m_hWnd_ListProperies;
	LVITEM			Item;
	char			sName[128];
	char			sBuffer[4096];
	LPBYTE			ptr;
	DWORD			entriesread, totalentries ;
	wchar_t			UncName[256];
	DWORD			i;
	

	memset (sName, 0, sizeof(sName));
	memset (sBuffer, 0, sizeof(sBuffer));
	memset (UncName, 0, sizeof(UncName));
	memset (&Item, 0, sizeof(Item));

	sName[0] = '\\';
	sName[1] = '\\';

	Item.iItem = iItem;
	Item.mask = LVIF_TEXT;
	Item.pszText = sName + 2;
	Item.cchTextMax = sizeof(sName)-3;

	if (FALSE == ListView_GetItem(m_hWnd_ListComputers, &Item)) {
		return;
	}

	for (i=0; sName[i]; ++i) {
		UncName[i] = WCHAR(sName[i]);
	}
	UncName[i] = WCHAR(0);

	ListView_DeleteAllItems(hWnd);

	memset (&Item, 0, sizeof(Item));

	Item.mask = LVIF_TEXT;
	Item.iItem = 0;

	/* unc-name */
	list_add (&Item, "Name", sName);

	/* TimeOfDay */
	if (NERR_Success == NetRemoteTOD (UncName, &ptr)) {
		TIME_OF_DAY_INFO	*pTod = (TIME_OF_DAY_INFO*)ptr;

		sprintf_s(
			sBuffer, sizeof(sBuffer)-1,
			"%02d.%02d.%04d %02d:%02d:%02d tz(%d)",
			pTod->tod_day,
			pTod->tod_month,
			pTod->tod_year,
			pTod->tod_hours,
			pTod->tod_mins,
			pTod->tod_secs,
			pTod->tod_timezone
			);
		list_add (&Item, "Time Of Day", sBuffer);
		
		NetApiBufferFree (ptr);
		ptr = NULL;
	}

	/* NetServerGetInfo(): geht nicht "nicht abgefangene ausnahme in kernel32.dl" */
	if (NERR_Success == NetServerGetInfo( (LPSTR)UncName, 102, &ptr)) {
		SERVER_INFO_102	*info_102 = (SERVER_INFO_102*)ptr;

		sprintf_s (sBuffer, sizeof(sBuffer)-1, "%d", info_102->sv102_users);
		switch (info_102->sv102_platform_id) {
		case PLATFORM_ID_DOS:	list_add (&Item, "platform", "DOS");	break;
		case PLATFORM_ID_OS2:	list_add (&Item, "platform", "OS2");	break;
		case PLATFORM_ID_NT:	list_add (&Item, "platform", "NT");		break;
		case PLATFORM_ID_OSF:	list_add (&Item, "platform", "OSF");	break;
		case PLATFORM_ID_VMS:	list_add (&Item, "platform", "VMS");	break;
		default:				list_add (&Item, "platform", "unknown");	break;
		}

		sprintf_s (sBuffer, sizeof(sBuffer)-1, "%d", info_102->sv102_users);
		list_add (&Item, "Max. Users (via licence)", sBuffer);

		sprintf_s (sBuffer, sizeof(sBuffer)-1, "%d", info_102->sv102_licenses);
		list_add (&Item, "number of users per license", sBuffer);

		sprintf_s (sBuffer, sizeof(sBuffer)-1, "%d", info_102->sv102_disc );
		list_add (&Item, "auto-disconnect time, in minutes", sBuffer);

		sprintf_s (sBuffer, sizeof(sBuffer)-1, "%d", info_102->sv102_announce);
		list_add (&Item, "network announce rate, in seconds", sBuffer);

		switch (info_102->sv102_hidden) {
		case SV_VISIBLE:
			list_add (&Item, "visible to other computers", "visible");
			break;
		case SV_HIDDEN:
			list_add (&Item, "visible to other computers", "hidden");
			break;
		default:
			list_add (&Item, "visible to other computers", "unknown");
			break;
		}

		/* type */
		if (info_102->sv102_type & SV_TYPE_WORKSTATION) list_add(&Item, "type", "A LAN Manager workstation");
		if (info_102->sv102_type & SV_TYPE_SERVER) list_add(&Item, "type",  "A LAN Manager server");
		if (info_102->sv102_type & SV_TYPE_SQLSERVER) list_add(&Item, "type",  "Any server running with Microsoft SQL Server");
		if (info_102->sv102_type & SV_TYPE_DOMAIN_CTRL) list_add(&Item, "type",  "Primary domain controller");
		if (info_102->sv102_type & SV_TYPE_DOMAIN_BAKCTRL) list_add(&Item, "type",  "Backup domain controller");
		if (info_102->sv102_type & SV_TYPE_TIME_SOURCE) list_add(&Item, "type",  "Server running the Timesource service");
		if (info_102->sv102_type & SV_TYPE_AFP) list_add(&Item, "type",  "Apple File Protocol server");
		if (info_102->sv102_type & SV_TYPE_NOVELL) list_add(&Item, "type",  "Novell server");
		if (info_102->sv102_type & SV_TYPE_DOMAIN_MEMBER) list_add(&Item, "type","LAN Manager 2.x domain member");
		if (info_102->sv102_type & SV_TYPE_LOCAL_LIST_ONLY) list_add(&Item, "type",  "Servers maintained by the browser");
		if (info_102->sv102_type & SV_TYPE_PRINTQ_SERVER) list_add(&Item, "type",  "Server sharing print queue");
		if (info_102->sv102_type & SV_TYPE_DIALIN_SERVER) list_add(&Item, "type",  "Server running dial-in service");
		if (info_102->sv102_type & SV_TYPE_XENIX_SERVER) list_add(&Item, "type",  "Xenix server");
		if (info_102->sv102_type & SV_TYPE_SERVER_MFPN) list_add(&Item, "type",  "Microsoft File and Print for NetWare");
		if (info_102->sv102_type & SV_TYPE_NT) list_add(&Item, "type",  "Windows Server 2003, Windows XP, Windows 2000, or Windows NT");
		if (info_102->sv102_type & SV_TYPE_WFW) list_add(&Item, "type" ,"Server running Windows for Workgroups");
		if (info_102->sv102_type & SV_TYPE_SERVER_NT) list_add(&Item, "type",  "Windows server that is not a domain controller");
		if (info_102->sv102_type & SV_TYPE_POTENTIAL_BROWSER) list_add(&Item, "type"  ,"Server that can run the browser service");
		if (info_102->sv102_type & SV_TYPE_BACKUP_BROWSER) list_add(&Item, "type"  ,"Server running a browser service as backup");
		if (info_102->sv102_type & SV_TYPE_MASTER_BROWSER) list_add(&Item, "type" ,"Server running the master browser service");
		if (info_102->sv102_type & SV_TYPE_DOMAIN_MASTER) list_add(&Item, "type"  ,"Server running the domain master browser");
		if (info_102->sv102_type & SV_TYPE_DOMAIN_ENUM) list_add(&Item, "type"  ,"Primary domain");
		if (info_102->sv102_type & SV_TYPE_WINDOWS) list_add(&Item, "type"  ,"Windows 95/98/Me");
		if (info_102->sv102_type & SV_TYPE_TERMINALSERVER) list_add(&Item, "type"  ,"Terminal Server");
		if (info_102->sv102_type & SV_TYPE_CLUSTER_NT) list_add(&Item, "type"  ,"Server clusters available in the domain");
		if (info_102->sv102_type & SV_TYPE_CLUSTER_VS_NT) list_add(&Item, "type",  "Cluster virtual servers available in the domain");

		sprintf_s (sBuffer, sizeof(sBuffer)-1, "%ws", info_102->sv102_userpath );
		list_add (&Item, "path to user directories", sBuffer);

		NetApiBufferFree (ptr);
		ptr = NULL;
	}

	/* NetServerDiskEnum */
	if (NERR_Success == NetServerDiskEnum((LPSTR)UncName,0, &ptr, MAX_PREFERRED_LENGTH, &entriesread , &totalentries , NULL)) {
		DWORD	i;
		const char	*Drive = (const char*)ptr;
		
		sBuffer[0] = 0;
		for (i=0;entriesread;i+=2,--entriesread,Drive+=6) {
			sBuffer[i] = *Drive;
			sBuffer[i+1] = ',';
		}
		if (i) {
			sBuffer[i-1] = 0;
			list_add (&Item, "drive list", sBuffer);
		}

		NetApiBufferFree (ptr);
		ptr = NULL;
	}

#if 1
	/* NetServerTransportEnum  */
	if (NERR_Success == NetServerTransportEnum ((LPSTR)UncName, 1, &ptr, MAX_PREFERRED_LENGTH, &entriesread , &totalentries , NULL)) {
		SERVER_TRANSPORT_INFO_1  *data = (SERVER_TRANSPORT_INFO_1*)ptr;

		for (;entriesread;--entriesread,++data) {

			sprintf_s (sBuffer, sizeof(sBuffer)-1,
				"domain(%ws) address(%ws) name(%ws)",
				data->svti1_domain,
				data->svti1_networkaddress,
				data->svti1_transportname
				);

			list_add (&Item, "transport", sBuffer);
		}
		NetApiBufferFree (ptr);
	}
#endif

	if (NERR_Success == NetShareEnum((LPSTR)UncName, 502, &ptr, MAX_PREFERRED_LENGTH, &entriesread , &totalentries , NULL)) {
		SHARE_INFO_502	*data = (SHARE_INFO_502 *)ptr;

		for (;entriesread;--entriesread,++data) {
			const char	*sType;

			switch (data->shi502_type) {
			case STYPE_DISKTREE:
				sType = "Disk";
				break;
			case STYPE_PRINTQ:
				sType = "Printer";
				break;
			case STYPE_DEVICE:
				sType = "Communication ";
				break;
			case STYPE_IPC:
				sType = "IPC";
				break;
			case STYPE_SPECIAL:
				sType = "Special share";
				break;
			case STYPE_TEMPORARY:
				sType = "A temporary share";
				break;
			default:
				sType = "unknown";
			}

			sprintf_s (sBuffer, sizeof(sBuffer)-1,
				"name(%ws) local(%ws) type(%s) users(%d/%d)",
				data->shi502_netname,
				data->shi502_path,
				sType,
				data->shi502_current_uses,
				data->shi502_max_uses);

			list_add(&Item, "Share", sBuffer);
		}


		NetApiBufferFree (ptr);
		ptr = NULL;
	}

	if (NERR_Success == NetStatisticsGet((LPSTR)UncName, (LPSTR)(L"SERVICE_WORKSTATION"), 0, 0, &ptr)) {
		MessageBox (NULL,"!","!",MB_OK);
		NetApiBufferFree (ptr);
		ptr = NULL;
	}
	


#if 0
	if (NERR_Success == NetGetDCName((LPSTR)UncName, "HCSDOM", &ptr)) {
		Item.pszText = "primary domain controller ";
		ListView_InsertItem (hWnd, &Item);

		wprintf_s (sBuffer, sizeof(sBuffer)-1, "%s", ptr);

		ListView_SetItemText (hWnd, Item.iItem, 1, sBuffer);

		++Item.iItem;

		NetApiBufferFree (ptr);
		ptr = NULL;
	}
#endif

}



static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	LPNMITEMACTIVATE	lpnmitem;
	
    
	switch (uMsg) {
	case WM_CREATE:
		InitControls(hWnd);
		return 0;

	case WM_SIZE:
		if (m_hWnd_ListComputers) {
			SetWindowPos(m_hWnd_ListComputers, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam) / 2, SWP_NOMOVE | SWP_NOZORDER);
		}

		if (m_hWnd_ListProperies) {
			SetWindowPos(m_hWnd_ListProperies, NULL, 0, HIWORD(lParam) / 2, LOWORD(lParam), HIWORD(lParam) / 2, SWP_NOZORDER);
		}

		return 0;

	case WM_NOTIFY:
		lpnmitem = (LPNMITEMACTIVATE) lParam;

		if (lpnmitem->iItem > -1) {
			if (lpnmitem->hdr.hwndFrom == m_hWnd_ListComputers) {
				switch (lpnmitem->hdr.code) {
				case NM_CLICK: 
					Refresh_Properties (lpnmitem->iItem);
					return 0;
				}
			}
		}
		return 0;
		

	case WM_TIMER:
		Refresh_Computers();
		return 0;
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam); 
}
