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 |
|
{ |
69 |
|
|
70 |
|
class Finger |
71 |
|
{ |
72 |
< |
private: |
71 |
< |
struct Login |
72 |
> |
class Login |
73 |
|
{ |
74 |
< |
std::string login, name, session; |
75 |
< |
DWORD id; |
75 |
< |
WTS_CONNECTSTATE_CLASS status; |
76 |
< |
Login(const std::wstring &login, DWORD id, const std::wstring &session, WTS_CONNECTSTATE_CLASS status) : login(Utf8(login)), id(id), session(Utf8(session)), status(status) |
77 |
< |
{ |
78 |
< |
USER_INFO_11 *info; |
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 |
< |
name = Utf8(std::wstring(info->usri11_full_name).substr(0, 20)); |
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 |
|
|
90 |
< |
::NetApiBufferFree(info); |
90 |
> |
~Login() |
91 |
> |
{ |
92 |
> |
if (!info) |
93 |
> |
::NetApiBufferFree(info); |
94 |
|
} |
95 |
|
|
96 |
< |
bool operator<(const Login &login) const |
96 |
> |
std::string GetName() const |
97 |
|
{ |
98 |
< |
if (this->login == login.login) |
99 |
< |
return id < login.id; |
100 |
< |
else |
101 |
< |
return this->login < login.login; |
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(name, session->SessionId, session_, session->State); |
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 |
|
} |
125 |
– |
|
126 |
– |
::WTSFreeMemory(name); |
149 |
|
} |
150 |
|
|
151 |
|
::WTSFreeMemory(sessions); |
152 |
|
|
153 |
|
if (!full) |
154 |
|
{ |
155 |
< |
stream << "Login\t\tName" << std::string(17, ' ') << "Id Session Status\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(), ' ') << std::setw(5) << std::left << login->id << " " << login->session << std::string(14 - login->session.size(), ' ') << login->status << "\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) |