//*********************************************************************
//*                  Microsoft Windows                               **
//*            Copyright(c) Microsoft Corp., 1993                    **
//*********************************************************************

#include "admincfg.h"

INT_PTR CALLBACK ConnectDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam,
    LPARAM lParam);
BOOL InitConnectDlg(HWND hDlg);
BOOL ProcessConnectDlg(HWND hDlg);

TCHAR szRemoteName[COMPUTERNAMELEN+1];

#define MAX_KEY_NAME 200

typedef struct _KEYNODE {
    LPTSTR  lpUserName;
    struct _KEYNODE *pNext;
} KEYNODE, * LPKEYNODE;


BOOL AddKeyNode (LPKEYNODE *lpList, LPTSTR lpUserName);
BOOL FreeKeyList (LPKEYNODE lpList);

typedef struct _USERINFO {
    LPTSTR    lpComputerName;
    LPKEYNODE lpList;
    LPKEYNODE lpSelectedItem;
    HKEY      hkeyRemoteHLM;
} USERINFO, * LPUSERINFO;


// HKEYs to remote registry
HKEY hkeyRemoteHLM = NULL;	// remote HKEY_LOCAL_MACHINE
HKEY hkeyRemoteHCU = NULL;	// remote HKEY_CURRENT_USER

HKEY hkeyVirtHLM = HKEY_LOCAL_MACHINE;	// virtual HKEY_LOCAL_MACHINE
HKEY hkeyVirtHCU = HKEY_CURRENT_USER;	// virtual HKEY_CURRENT_USER

BOOL OnConnect(HWND hwndApp,HWND hwndList)
{
	if (dwAppState & AS_FILEDIRTY) {
		if (!QueryForSave(hwndApp,hwndList)) return TRUE;	// user cancelled
	}

	if (DialogBox(ghInst,MAKEINTRESOURCE(DLG_CONNECT),hwndApp,
		ConnectDlgProc)) {

		if (dwAppState & AS_FILELOADED) {
			// Free dirty file and free users
			RemoveAllUsers(hwndList);
		}

		if (!LoadFromRegistry(hwndApp,hwndList,TRUE)) {
			OnDisconnect(hwndApp);
			return FALSE;
		}

		lstrcpy(szDatFilename,szNull);

		dwAppState |= AS_FILELOADED | AS_FILEHASNAME | AS_REMOTEREGISTRY;
	 	dwAppState &= (~AS_CANOPENTEMPLATE & ~AS_LOCALREGISTRY & ~AS_POLICYFILE);
		EnableMenuItems(hwndApp,dwAppState);
		SetTitleBar(hwndApp,szRemoteName);
		EnableWindow(hwndList,TRUE);
	}
	return TRUE;
}

INT_PTR CALLBACK ConnectDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

	switch (uMsg) {

		case WM_INITDIALOG:

		    if (!InitConnectDlg(hDlg)) {
		        EndDialog(hDlg,0);
		        return FALSE;
                    }
		    return TRUE;

		case WM_COMMAND:

		    switch (LOWORD(wParam)) {

                        case IDOK:

			if (ProcessConnectDlg(hDlg))
			    EndDialog(hDlg,TRUE);
			    return TRUE;
			break;

			case IDCANCEL:
        	
                            EndDialog(hDlg,FALSE);
                            return TRUE;
                        break;
		    }

	    break;

	}

    return FALSE;
}

BOOL ProcessConnectDlg(HWND hDlg)
{
	TCHAR szComputerName[COMPUTERNAMELEN+1];

	hkeyRemoteHLM=NULL;

	// get computer name from dialog
	if (!GetDlgItemText(hDlg,IDD_COMPUTERNAME,szComputerName,
		ARRAYSIZE(szComputerName))) {
		SetFocus(GetDlgItem(hDlg,IDD_COMPUTERNAME));
		MsgBox(hDlg,IDS_NEEDCOMPUTERNAME,MB_OK,MB_ICONINFORMATION);
		return FALSE;
	}

	// make the connection
	if (RemoteConnect(hDlg,szComputerName,TRUE)) {
		HKEY hkeyState;

		// save this name to fill in UI as default in future connect dlgs
 		if (RegCreateKey(HKEY_CURRENT_USER,szAPPREGKEY,&hkeyState) ==
			ERROR_SUCCESS) {
			RegSetValueEx(hkeyState,szLASTCONNECTION,0,REG_SZ,szComputerName,(lstrlen(szComputerName)+1) * sizeof(TCHAR));
			RegCloseKey(hkeyState);
		}
		return TRUE;

	} else return FALSE;
}


void GetRealUserName (HKEY hRemoteHLM, LPTSTR lpRemoteMachine,
                      LPTSTR lpInput, LPTSTR lpOutput)
{
    TCHAR szName [MAX_PATH];
    TCHAR szDomainName [MAX_PATH];
    LONG lResult;
    HKEY hKey;
    DWORD dwSize, dwType, dwDomainSize;
    PSID pSid;
    SID_NAME_USE SidNameUse;


    //
    // Initialize the output with the default name
    //

    lstrcpy (lpOutput, lpInput);


    //
    // If the remote machine is NT, then this registry call will
    // succeed and we can get the real sid to look up with.
    // If the remote machine is Windows, then this call will fail
    // and we'll go with the default input name (which is ok because
    // Windows uses the user name in HKEY_USERS rather than a SID.
    //

    wsprintf (szName, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s"),
              lpInput);

    lResult = RegOpenKeyEx (hRemoteHLM,
                            szName,
                            0,
                            KEY_READ,
                            &hKey);


    if (lResult != ERROR_SUCCESS) {
        return;
    }


    //
    // Query the size of the SID (binary)
    //

    lResult = RegQueryValueEx (hKey,
                               TEXT("Sid"),
                               NULL,
                               &dwType,
                               NULL,
                               &dwSize);

    if (lResult != ERROR_SUCCESS) {
        RegCloseKey (hKey);
        return;
    }


    //
    // Allocate space for the SID
    //

    pSid = GlobalAlloc (GPTR, dwSize);

    if (!pSid) {
        RegCloseKey (hKey);
        return;
    }


    lResult = RegQueryValueEx (hKey,
                               TEXT("Sid"),
                               NULL,
                               &dwType,
                               pSid,
                               &dwSize);

    if (lResult != ERROR_SUCCESS) {
        GlobalFree (pSid);
        RegCloseKey (hKey);
        return;
    }


    //
    // Lookup the account name
    //

    dwSize = MAX_PATH;
    dwDomainSize = MAX_PATH;

    if (LookupAccountSid (lpRemoteMachine,
                          pSid,
                          szName,
                          &dwSize,
                          szDomainName,
                          &dwDomainSize,
                          &SidNameUse) ) {

       lstrcpy (lpOutput, szDomainName);
       lstrcat (lpOutput, TEXT("\\"));
       lstrcat (lpOutput, szName);

    } else {

       LoadSz(IDS_ACCOUNTUNKNOWN, lpOutput, MAX_KEY_NAME);
    }



    //
    // Clean up
    //

    GlobalFree (pSid);

    RegCloseKey (hKey);

}


LRESULT CALLBACK ChooseUserDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{

    switch (message) {

       case WM_INITDIALOG:
          {
          LPUSERINFO lpInfo = (LPUSERINFO) lParam;
          LPKEYNODE lpItem;
          TCHAR szMsg[60+COMPUTERNAMELEN],szFmt[60];
          TCHAR szUserName[MAX_KEY_NAME];
          INT iResult;

          //
          // Store the LPUSERINFO pointer in the extra words
          //

          SetWindowLongPtr (hDlg, GWLP_USERDATA, (LONG_PTR) lpInfo);


          //
          // Fill in the title
          //

          LoadSz(IDS_CHOOSEUSER_TITLE, szFmt, ARRAYSIZE(szFmt));
          wsprintf(szMsg,szFmt,lpInfo->lpComputerName);

          SendDlgItemMessage (hDlg, IDD_USER, WM_SETTEXT, 0, (LPARAM) szMsg);


          lpItem = lpInfo->lpList;

          while (lpItem) {

                //
                // If the user name is not .Default, add it to
                // the list.
                //

                if (lstrcmpi(lpItem->lpUserName, TEXT(".Default")) != 0) {

                    //
                    // Get the user name to display
                    //

                    GetRealUserName (lpInfo->hkeyRemoteHLM, lpInfo->lpComputerName,
                                     lpItem->lpUserName, szUserName);



                    iResult = (INT)SendDlgItemMessage (hDlg, IDD_LIST, LB_INSERTSTRING,
                                                  (WPARAM) -1, (LPARAM) szUserName);

                    if (iResult != LB_ERR) {

                        SendDlgItemMessage (hDlg, IDD_LIST, LB_SETITEMDATA,
                                            iResult, (LPARAM) lpItem);
                    }
                }

                lpItem = lpItem->pNext;
          }


          //
          // Select the first item, or disable the Ok button if no
          // one is logged on.
          //

          iResult = (INT)SendDlgItemMessage (hDlg, IDD_LIST, LB_GETCOUNT, 0, 0);

          if (iResult == 0) {
             EnableWindow (GetDlgItem (hDlg, IDOK), FALSE);

          } else {

             SendDlgItemMessage (hDlg, IDD_LIST, LB_SETCURSEL, 0,  0);
          }

          }
          break;


       case WM_COMMAND:

          if ((LOWORD(wParam) == IDOK) ||
             ((LOWORD(wParam) == IDD_LIST) && (HIWORD(wParam) == LBN_DBLCLK))){
             LPUSERINFO lpInfo = (LPUSERINFO) GetWindowLongPtr(hDlg, GWLP_USERDATA);
             INT iResult;


             if (!lpInfo) {
                return TRUE;
             }

             //
             // Find the selected item
             //

             iResult = (INT)SendDlgItemMessage (hDlg, IDD_LIST, LB_GETCURSEL, 0, 0);

             if (iResult != LB_ERR) {

                 //
                 // Save the item pointer
                 //

                 iResult = (INT)SendDlgItemMessage (hDlg, IDD_LIST, LB_GETITEMDATA,
                                              (WPARAM) iResult, 0);

                 if (iResult != LB_ERR) {
                    lpInfo->lpSelectedItem = (LPKEYNODE) IntToPtr(iResult);
                 } else {
                    lpInfo->lpSelectedItem = NULL;
                 }

                 EndDialog(hDlg, TRUE);
             }
             return TRUE;
          }

          if (LOWORD(wParam) == IDCANCEL) {
             EndDialog(hDlg, FALSE);
             return TRUE;
          }

          break;
    }


    return FALSE;
}


BOOL RemoteConnectHCU (HWND hwndOwner, TCHAR * pszComputerName,
                       HKEY hkeyRemoteHLM, HKEY * hkeyRemoteHCU,
                       BOOL fDisplayError)
{
    USERINFO UserInfo;
    HKEY hkeyRemoteHU;
    LONG lResult;
    DWORD dwSubKeys;
    TCHAR szUserName[MAX_KEY_NAME];
    LPKEYNODE lpList = NULL, lpItem;
    DWORD dwSize;
    UINT Index = 0;
    FILETIME ftWrite;
    BOOL bRetVal = FALSE;


    //
    // Connect to HKEY_USERS on the remote machine to see
    // how many people are logged on.
    //

    lResult = RegConnectRegistry(pszComputerName,HKEY_USERS,
                                 &hkeyRemoteHU);

    if (lResult != ERROR_SUCCESS) {
        return FALSE;
    }


    //
    // Enumerate the subkeys
    //

    dwSize = MAX_KEY_NAME;
    lResult = RegEnumKeyEx(hkeyRemoteHU, Index, szUserName, &dwSize, NULL,
                           NULL, NULL, &ftWrite);

    if (lResult == ERROR_SUCCESS) {

        do {

            //
            // Add the node
            //

            if (!AddKeyNode (&lpList, szUserName)) {
                break;
            }

            Index++;
            dwSize = MAX_KEY_NAME;

            lResult = RegEnumKeyEx(hkeyRemoteHU, Index, szUserName, &dwSize, NULL,
                                   NULL, NULL, &ftWrite);


        } while (lResult == ERROR_SUCCESS);

    } else {

        RegCloseKey(hkeyRemoteHU);
        return FALSE;
    }


    UserInfo.lpComputerName = pszComputerName;
    UserInfo.lpList = lpList;
    UserInfo.hkeyRemoteHLM = hkeyRemoteHLM;

    if (DialogBoxParam (ghInst, MAKEINTRESOURCE(DLG_CHOOSEUSER), hwndOwner,
                        ChooseUserDlgProc, (LPARAM)&UserInfo)) {

        if (UserInfo.lpSelectedItem) {

            lResult = RegOpenKeyEx (hkeyRemoteHU,
                                    UserInfo.lpSelectedItem->lpUserName,
                                    0,
                                    KEY_ALL_ACCESS,
                                    hkeyRemoteHCU);

            if (lResult == ERROR_SUCCESS) {
                bRetVal = TRUE;

            } else {

                SetFocus(GetDlgItem(hwndOwner,IDD_COMPUTERNAME));
                SendDlgItemMessage(hwndOwner,IDD_COMPUTERNAME,EM_SETSEL,0,-1);

                if (fDisplayError) {
                    TCHAR szMsg[MEDIUMBUF+COMPUTERNAMELEN+COMPUTERNAMELEN];
                    TCHAR szFmt[MEDIUMBUF];

                    LoadSz(IDS_CANTCONNECT,szFmt,ARRAYSIZE(szFmt));
                    wsprintf(szMsg,szFmt,pszComputerName,pszComputerName);
                    MsgBoxSz(hwndOwner,szMsg,MB_OK,MB_ICONINFORMATION);
                }
            }
        }
    }


    //
    // Free the link list
    //

    FreeKeyList (lpList);


    //
    // Close HKEY_USERS on the remote machine
    //

    RegCloseKey (hkeyRemoteHU);

    return bRetVal;
}



BOOL RemoteConnect(HWND hwndOwner,TCHAR * pszComputerName,BOOL fDisplayError)
{
	UINT uRet;
        HCURSOR hOldCursor;

#ifdef DEBUG
	wsprintf(szDebugOut,TEXT("ADMINCFG: connecting to %s\r\n"),pszComputerName);
	OutputDebugString(szDebugOut);
#endif

	hkeyRemoteHLM = hkeyRemoteHCU = NULL;

        hOldCursor=SetCursor(LoadCursor(NULL,IDC_WAIT));

        //
        // try to connect to remote registry HKEY_LOCAL_MACHINE
        //

	uRet = RegConnectRegistry(pszComputerName,HKEY_LOCAL_MACHINE,
		&hkeyRemoteHLM);

        SetCursor(hOldCursor);

        if (uRet != ERROR_SUCCESS) {

            SetFocus(GetDlgItem(hwndOwner,IDD_COMPUTERNAME));
            SendDlgItemMessage(hwndOwner,IDD_COMPUTERNAME,EM_SETSEL,0,-1);

            if (fDisplayError) {
                    TCHAR szMsg[MEDIUMBUF+COMPUTERNAMELEN+COMPUTERNAMELEN];
                    TCHAR szFmt[MEDIUMBUF];

                    LoadSz(IDS_CANTCONNECT,szFmt,ARRAYSIZE(szFmt));
                    wsprintf(szMsg,szFmt,pszComputerName,pszComputerName);
                    MsgBoxSz(hwndOwner,szMsg,MB_OK,MB_ICONINFORMATION);
            }
            return FALSE;
        }

        //
	// try to connect to remote registry HKEY_CURRENT_USER
        //

	uRet = RemoteConnectHCU (hwndOwner, pszComputerName, hkeyRemoteHLM,
	                         &hkeyRemoteHCU, fDisplayError);

	if (!uRet) {
            RegCloseKey(hkeyRemoteHLM);
            hkeyRemoteHLM = NULL;

            return FALSE;
	}


	hkeyVirtHLM = hkeyRemoteHLM;
	hkeyVirtHCU = hkeyRemoteHCU;

	// change "connect..." menu item to "disconnect"
	ReplaceMenuItem(hwndMain,IDM_CONNECT,IDM_DISCONNECT,IDS_DISCONNECT);
	
	lstrcpy(szRemoteName,pszComputerName);

	return TRUE;
}

BOOL OnDisconnect(HWND hwndOwner)
{
#ifdef DEBUG
        OutputDebugString(TEXT("ADMINCFG: Disconnecting.\r\n"));
#endif

	if (hkeyRemoteHLM) {
		RegCloseKey(hkeyRemoteHLM);
		hkeyRemoteHLM = NULL;
	}
	if (hkeyRemoteHCU) {
		RegCloseKey(hkeyRemoteHCU);
	 	hkeyRemoteHCU = NULL;
	}
	
	// point virtual HLM, HCU keys at local machine
	hkeyVirtHLM = HKEY_LOCAL_MACHINE;
	hkeyVirtHCU = HKEY_CURRENT_USER;

	// change "disconnect" menu item to "connect..."
	ReplaceMenuItem(hwndMain,IDM_DISCONNECT,IDM_CONNECT,IDS_CONNECT);
	SetTitleBar(hwndMain,NULL);
	
	return TRUE;
}

BOOL InitConnectDlg(HWND hDlg)
{				
 	HKEY hkeyState;
	TCHAR szComputerName[COMPUTERNAMELEN+1];
	DWORD dwSize = ARRAYSIZE(szComputerName);

	SetFocus(GetDlgItem(hDlg,IDD_COMPUTERNAME));
	SendDlgItemMessage(hDlg,IDD_COMPUTERNAME,EM_SETLIMITTEXT,
		COMPUTERNAMELEN,0L);

	if (RegOpenKey(HKEY_CURRENT_USER,szAPPREGKEY,&hkeyState) ==
		ERROR_SUCCESS) {
		if (RegQueryValueEx(hkeyState,szLASTCONNECTION,NULL,NULL,szComputerName,&dwSize)
			==ERROR_SUCCESS) {

			SetDlgItemText(hDlg,IDD_COMPUTERNAME,szComputerName);
			SendDlgItemMessage(hDlg,IDD_COMPUTERNAME,EM_SETSEL,0,-1);
		}
		RegCloseKey(hkeyState);
	}

	return TRUE;
}

//*************************************************************
//
//  AddKEYNODE()
//
//  Purpose:    Adds a key node to the link listed
//
//  Parameters: lpList         -   Link list of nodes
//              lpUserName     -   User Name
//
//
//  Return:     TRUE if successful
//              FALSE if an error occurs
//
//  Comments:
//
//  History:    Date        Author     Comment
//              1/16/96     ericflo    Created
//
//*************************************************************

BOOL AddKeyNode (LPKEYNODE *lpList, LPTSTR lpUserName)
{
    LPKEYNODE lpNewItem;


    if (!lpUserName || !*lpUserName) {
        return TRUE;
    }


    //
    // Setup the new node
    //

    lpNewItem = (LPKEYNODE) LocalAlloc(LPTR, sizeof(KEYNODE) +
                 ((lstrlen(lpUserName) + 1) * sizeof(TCHAR)));

    if (!lpNewItem) {
        return FALSE;
    }

    lpNewItem->lpUserName = (LPTSTR)((LPBYTE)lpNewItem + sizeof(KEYNODE));
    lstrcpy (lpNewItem->lpUserName, lpUserName);
    lpNewItem->pNext = *lpList;

    *lpList = lpNewItem;

    return TRUE;
}


//*************************************************************
//
//  FreeKeyList()
//
//  Purpose:    Free's a KEYNODE link list
//
//  Parameters: lpList  -   List to be freed
//
//  Return:     TRUE if successful
//              FALSE if an error occurs
//
//  Comments:
//
//  History:    Date        Author     Comment
//              1/16/96     ericflo    Created
//
//*************************************************************

BOOL FreeKeyList (LPKEYNODE lpList)
{
    LPKEYNODE lpNext;


    if (!lpList) {
        return TRUE;
    }


    lpNext = lpList->pNext;

    while (lpList) {
        LocalFree (lpList);
        lpList = lpNext;

        if (lpList) {
            lpNext = lpList->pNext;
        }
    }

    return TRUE;
}