#include "pch.h"
#include "System/Diagnostics/TerminalSession.h"
#include "System/UnauthorizedAccessException.h"
#include "System/Utils/StringConvert.h"
#include <vector>

#if defined(_WIN32)
#include <winsock2.h>
#include <windows.h>
#include <wtsapi32.h>
#pragma comment(lib, "wtsapi32.lib")
#endif

namespace DotNetDupe {
    namespace System {
        namespace Diagnostics {

            TerminalSession::TerminalSession() {}
            TerminalSession::~TerminalSession() {}

#if defined(_WIN32)
            RdpSessionState TerminalSession::ConvertWtsState(int iState) {
                switch (iState) {
                case WTSActive: return RdpSessionState::Active;
                case WTSConnected: return RdpSessionState::Connected;
                case WTSConnectQuery: return RdpSessionState::ConnectQuery;
                case WTSShadow: return RdpSessionState::Shadow;
                case WTSDisconnected: return RdpSessionState::Disconnected;
                case WTSIdle: return RdpSessionState::Idle;
                case WTSListen: return RdpSessionState::Listen;
                case WTSReset: return RdpSessionState::Reset;
                case WTSDown: return RdpSessionState::Down;
                case WTSInit: return RdpSessionState::Init;
                default: return RdpSessionState::Unknown;
                }
            }

            String TerminalSession::QueryWtsString(unsigned long uSessionId, unsigned int eInfoClass) {
                LPWSTR pBuffer = NULL;
                DWORD dwBytesReturned = 0;
                String sResult;

                if (::WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, uSessionId, static_cast<WTS_INFO_CLASS>(eInfoClass), &pBuffer, &dwBytesReturned)) {
                    if (pBuffer != NULL && dwBytesReturned > 0) {
                        sResult = String(pBuffer);
                    }
                    ::WTSFreeMemory(pBuffer);
                } else if (::GetLastError() == ERROR_ACCESS_DENIED) {
                    throw UnauthorizedAccessException("Access denied querying terminal session information.");
                }

                return sResult;
            }

            void TerminalSession::QuerySessionDetails(unsigned long uSessionId, const String& sSessionName, RdpSessionState eState, RdpSessionInfo& info) {
                info.uSessionId = uSessionId;
                info.sSessionName = sSessionName;
                info.eState = eState;
                info.sUserName = QueryWtsString(uSessionId, WTSUserName);
                info.sDomainName = QueryWtsString(uSessionId, WTSDomainName);
                info.sClientName = QueryWtsString(uSessionId, WTSClientName);
                info.sClientIpAddress = QueryWtsString(uSessionId, WTSClientAddress);
                info.bIsRdpSession = !info.sClientName.IsEmpty() || info.sSessionName.Contains("RDP");
            }

            Collections::Generic::List<RdpSessionInfo> TerminalSession::GetSessions() {
                Collections::Generic::List<RdpSessionInfo> lstResult;
                WTS_SESSION_INFOW* pSessionInfo = NULL;
                DWORD dwCount = 0;
                if (::WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount)) {
                    for (DWORD i = 0; i < dwCount; ++i) {
                        RdpSessionInfo info;
                        String sName = (pSessionInfo[i].pWinStationName != NULL) ? String(pSessionInfo[i].pWinStationName) : String("");
                        RdpSessionState eState = ConvertWtsState(pSessionInfo[i].State);
                        QuerySessionDetails(pSessionInfo[i].SessionId, sName, eState, info);
                        lstResult.Add(info);
                    }
                    ::WTSFreeMemory(pSessionInfo);
                } else if (::GetLastError() == ERROR_ACCESS_DENIED) {
                    throw UnauthorizedAccessException("Access denied enumerating terminal sessions. Administrator privileges required.");
                }
                return lstResult;
            }
#else
            Collections::Generic::List<RdpSessionInfo> TerminalSession::GetSessions() {
                return Collections::Generic::List<RdpSessionInfo>();
            }
#endif

            Collections::Generic::List<RdpSessionInfo> TerminalSession::GetActiveSessions() {
                auto lstAll = GetSessions();
                Collections::Generic::List<RdpSessionInfo> lstActive;
                for (int i = 0; i < lstAll.GetCount(); ++i) {
                    if (lstAll[i].eState == RdpSessionState::Active) lstActive.Add(lstAll[i]);
                }
                return lstActive;
            }

            Collections::Generic::List<RdpSessionInfo> TerminalSession::GetDisconnectedSessions() {
                auto lstAll = GetSessions();
                Collections::Generic::List<RdpSessionInfo> lstDisconnected;
                for (int i = 0; i < lstAll.GetCount(); ++i) {
                    if (lstAll[i].eState == RdpSessionState::Disconnected) lstDisconnected.Add(lstAll[i]);
                }
                return lstDisconnected;
            }

        }
    }
}

Generated by OpenCppCoverage (Version: 0.9.9.0)