8 |
|
#include <tchar.h> |
9 |
|
#include <signal.h> |
10 |
|
#include <wtsapi32.h> |
11 |
+ |
#include <lm.h> |
12 |
|
|
13 |
+ |
#include <algorithm> |
14 |
|
#include <iostream> |
15 |
+ |
#include <iomanip> |
16 |
|
#include <string> |
17 |
|
#include <sstream> |
18 |
|
#include <vector> |
19 |
< |
#include <set> |
19 |
> |
#include <map> |
20 |
> |
#include <cwctype> |
21 |
> |
|
22 |
> |
std::ostream &operator<<(std::ostream &out, WTS_CONNECTSTATE_CLASS status) |
23 |
> |
{ |
24 |
> |
switch (status) |
25 |
> |
{ |
26 |
> |
case WTSActive: |
27 |
> |
return out << "Active"; |
28 |
> |
|
29 |
> |
case WTSConnected: |
30 |
> |
return out << "Connected"; |
31 |
> |
|
32 |
> |
case WTSConnectQuery: |
33 |
> |
return out << "Connecting"; |
34 |
> |
|
35 |
> |
case WTSShadow: |
36 |
> |
return out << "Shadowing"; |
37 |
> |
|
38 |
> |
case WTSDisconnected: |
39 |
> |
return out << "Disconnected"; |
40 |
> |
|
41 |
> |
case WTSIdle: |
42 |
> |
return out << "Idle"; |
43 |
> |
|
44 |
> |
case WTSListen: |
45 |
> |
return out << "Listening"; |
46 |
> |
|
47 |
> |
case WTSReset: |
48 |
> |
return out << "Reseting"; |
49 |
> |
|
50 |
> |
case WTSDown: |
51 |
> |
return out << "Down"; |
52 |
> |
|
53 |
> |
case WTSInit: |
54 |
> |
return out << "Initializing"; |
55 |
> |
|
56 |
> |
default: |
57 |
> |
return out << "Unknown"; |
58 |
> |
} |
59 |
> |
} |
60 |
|
|
61 |
|
inline std::string Utf8(const std::wstring &wstring) |
62 |
|
{ |
69 |
|
|
70 |
|
class Finger |
71 |
|
{ |
72 |
< |
private: |
30 |
< |
struct Login |
72 |
> |
class Login |
73 |
|
{ |
74 |
< |
std::string login, name, session; |
75 |
< |
Login(const std::string &login, const std::string &session) : login(login), session(session) |
74 |
> |
std::wstring login; |
75 |
> |
mutable USER_INFO_11 *info; |
76 |
> |
|
77 |
> |
inline void GetInfo() const |
78 |
> |
{ |
79 |
> |
::NetUserGetInfo(NULL, login.c_str(), 11, reinterpret_cast<LPBYTE *>(&info)); |
80 |
> |
} |
81 |
> |
public: |
82 |
> |
std::string session; |
83 |
> |
DWORD id; |
84 |
> |
WTS_CONNECTSTATE_CLASS status; |
85 |
> |
|
86 |
> |
Login(const std::wstring &login, DWORD id, const std::wstring &session, WTS_CONNECTSTATE_CLASS status) : login(login), info(NULL), id(id), session(Utf8(session)), status(status) |
87 |
|
{ |
88 |
|
} |
89 |
< |
bool operator<(const Login &login) const |
89 |
> |
|
90 |
> |
~Login() |
91 |
|
{ |
92 |
< |
if (this->login == login.login) |
93 |
< |
return session < login.session; |
94 |
< |
else |
95 |
< |
return this->login < login.login; |
92 |
> |
if (!info) |
93 |
> |
::NetApiBufferFree(info); |
94 |
> |
} |
95 |
> |
|
96 |
> |
std::string GetName() const |
97 |
> |
{ |
98 |
> |
if (!info) |
99 |
> |
GetInfo(); |
100 |
> |
|
101 |
> |
return Utf8(std::wstring(info->usri11_full_name).substr(0, 20)); |
102 |
|
} |
103 |
|
}; |
104 |
+ |
|
105 |
|
std::ostringstream stream; |
106 |
< |
std::set<Login> logins; |
106 |
> |
std::multimap<std::string, Login> logins; |
107 |
> |
|
108 |
> |
void Full() |
109 |
> |
{ |
110 |
> |
for (std::multimap<std::string, Login>::const_iterator login(logins.begin()); login != logins.end(); login = logins.upper_bound(login->first)) |
111 |
> |
{ |
112 |
> |
stream << "Login: " << login->first << std::string(33 - login->first.size(), ' ') << "Name: " << login->second.GetName() << "\r\n"; |
113 |
> |
} |
114 |
> |
} |
115 |
|
|
116 |
|
public: |
117 |
|
Finger(bool full) |
128 |
|
|
129 |
|
::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSUserName, &name, &size); |
130 |
|
|
131 |
< |
if (!std::wstring(name).empty()) |
131 |
> |
std::wstring name_(name); |
132 |
> |
|
133 |
> |
::WTSFreeMemory(name); |
134 |
> |
|
135 |
> |
if (!name_.empty()) |
136 |
|
{ |
137 |
+ |
std::transform(name_.begin(), name_.end(), name_.begin(), std::towlower); |
138 |
+ |
|
139 |
|
LPTSTR session_; |
140 |
|
|
141 |
|
::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSWinStationName, &session_, &size); |
142 |
|
|
143 |
< |
Login login(Utf8(name), Utf8(session_)); |
143 |
> |
Login login(name_, session->SessionId, session_, session->State); |
144 |
|
|
145 |
|
::WTSFreeMemory(session_); |
146 |
|
|
147 |
< |
logins.insert(login); |
147 |
> |
logins.insert(std::make_pair(Utf8(name_), login)); |
148 |
|
} |
74 |
– |
|
75 |
– |
::WTSFreeMemory(name); |
149 |
|
} |
150 |
|
|
151 |
|
::WTSFreeMemory(sessions); |
152 |
|
|
153 |
|
if (!full) |
154 |
|
{ |
155 |
< |
stream << "Login\t\tName" << std::string(17, ' ') << "Session\r\n"; |
155 |
> |
stream << "Login" << std::string(11, ' ') << "Name" << std::string(17, ' ') << "Id Session Status\r\n"; |
156 |
|
|
157 |
< |
for (std::set<Login>::const_iterator login(logins.begin()); login != logins.end(); ++login) |
158 |
< |
stream << login->login << std::string(16 - login->login.size(), ' ') << login->name << std::string(21 - login->name.size(), ' ') << login->session << "\r\n"; |
157 |
> |
for (std::multimap<std::string, Login>::const_iterator login(logins.begin()); login != logins.end(); ++login) |
158 |
> |
stream << login->first << std::string(16 - login->first.size(), ' ') << login->second.GetName() << std::string(21 - login->second.GetName().size(), ' ') << std::setw(5) << std::left << login->second.id << " " << login->second.session << std::string(14 - login->second.session.size(), ' ') << login->second.status << "\r\n"; |
159 |
|
} |
160 |
+ |
else |
161 |
+ |
Full(); |
162 |
|
} |
163 |
|
|
164 |
|
Finger(const std::string &name) |