ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/CCSFinger/CCSFinger.cpp
(Generate patch)

Comparing CCSFinger/CCSFinger.cpp (file contents):
Revision 594 by douglas, 2005-11-27T17:04:53-08:00 vs.
Revision 618 by douglas, 2005-12-13T02:23:55-08:00

# Line 5 | Line 5
5   // Windows Finger Daemon
6  
7   #include <windows.h>
8 + #include <lm.h>
9 + #include <signal.h>
10   #include <tchar.h>
11 + #include <shlobj.h>
12 + #include <wtsapi32.h>
13  
14 < /*LPTSTR name;
14 > #include <algorithm>
15 > #include <cctype>
16 > #include <cwctype>
17 > #include <fstream>
18 > #include <iomanip>
19 > #include <iostream>
20 > #include <map>
21 > #include <sstream>
22 > #include <string>
23 > #include <vector>
24 >
25 > std::ostream &operator<<(std::ostream &out, WTS_CONNECTSTATE_CLASS status)
26 > {
27 >        switch (status)
28 >        {
29 >        case WTSActive:
30 >                return out << "Active";
31 >
32 >        case WTSConnected:
33 >                return out << "Connected";
34 >
35 >        case WTSConnectQuery:
36 >                return out << "Connecting";
37 >
38 >        case WTSShadow:
39 >                return out << "Shadowing";
40 >
41 >        case WTSDisconnected:
42 >                return out << "Disconnected";
43 >
44 >        case WTSIdle:
45 >                return out << "Idle";
46 >
47 >        case WTSListen:
48 >                return out << "Listening";
49 >
50 >        case WTSReset:
51 >                return out << "Reseting";
52 >
53 >        case WTSDown:
54 >                return out << "Down";
55 >
56 >        case WTSInit:
57 >                return out << "Initializing";
58 >
59 >        default:
60 >                return out << "Unknown";
61 >        }
62 > }
63 >
64 > inline std::string Utf8(const std::wstring &wstring)
65 > {
66 >        std::string string(::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), NULL, 0, NULL, NULL), '\0');
67 >
68 >        ::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), const_cast<LPSTR>(string.data()), int(string.size()), NULL, NULL);
69 >
70 >        return string;
71 > }
72 >
73 > class Finger
74 > {
75 >        class Login
76 >        {
77 >                std::wstring login;
78 >                mutable USER_INFO_11 *info;
79 >
80 >                inline void GetInfo() const
81 >                {
82 >                        if (!info)
83 >                                ::NetUserGetInfo(NULL, login.c_str(), 11, reinterpret_cast<LPBYTE *>(&info));
84 >                }
85 >        public:
86 >                std::string session;
87 >                DWORD id;
88 >                WTS_CONNECTSTATE_CLASS status;
89 >
90 >                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)
91 >                {
92 >                }
93 >
94 >                ~Login()
95 >                {
96 >                        if (!info)
97 >                                ::NetApiBufferFree(info);
98 >                }
99 >
100 >                std::string GetShortName() const
101 >                {
102 >                        GetInfo();
103 >
104 >                        return Utf8(std::wstring(info->usri11_full_name).substr(0, 20));
105 >                }
106 >
107 >                std::string GetName() const
108 >                {
109 >                        GetInfo();
110 >
111 >                        return Utf8(info->usri11_full_name);
112 >                }
113 >
114 >                std::string GetDirectory() const
115 >                {
116 >                        HANDLE token;
117 >
118 >                        if (::WTSQueryUserToken(id, &token))
119 >                        {
120 >                                TCHAR directory[MAX_PATH];
121 >
122 >                                ::SHGetFolderPath(NULL, CSIDL_PROFILE, token, SHGFP_TYPE_CURRENT, directory);
123 >                                ::CloseHandle(token);
124 >
125 >                                return Utf8(directory);
126 >                        }
127 >                        else
128 >                        {
129 >                                TCHAR directory_[MAX_PATH];
130 >
131 >                                ::SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, directory_);
132 >
133 >                                std::wstring directory(directory_);
134 >
135 >                                directory.replace(directory.rfind('\\') + 1, std::wstring::npos, login);
136 >
137 >                                return Utf8(directory);
138 >                        }
139 >                }
140 >        };
141 >
142 >        std::ostringstream stream;
143 >        std::multimap<std::string, Login> logins;
144 >
145 >        void Full()
146 >        {
147 >                for (std::multimap<std::string, Login>::const_iterator login(logins.begin()); login != logins.end(); login = logins.upper_bound(login->first))
148 >                {
149 >                        std::string directory(login->second.GetDirectory());
150 >
151 >                        stream << "Login: " << login->first << std::string(33 - login->first.size(), ' ') << "Name: " << login->second.GetName() << "\r\nDirectory: " << directory << "\r\n";
152 >
153 >                        for (std::multimap<std::string, Login>::const_iterator login_(logins.lower_bound(login->first)); login_ != logins.upper_bound(login->first); ++login_)
154 >                                stream << login_->second.status << ' ' << login_->second.session << ' ' << login_->second.id << "\r\n";
155 >
156 >                        std::string files[] = { "\\.project", "\\.plan" };
157 >
158 >                        for (std::string *file(files); file != files + sizeof (files) / sizeof (*file); ++file)
159 >                        {
160 >                                file->insert(0, directory);
161 >
162 >                                std::ifstream in(file->c_str());
163 >
164 >                                if (!in.is_open())
165 >                                        continue;
166 >
167 >                                switch (file - files)
168 >                                {
169 >                                case 0:
170 >                                        stream << "Project:\r\n";
171 >
172 >                                        break;
173 >                                case 1:
174 >                                        stream << "Plan:\r\n";
175 >                                }
176 >
177 >                                std::string buffer;
178 >
179 >                                while (std::getline(in, buffer))
180 >                                        stream << buffer << std::endl;
181 >                        }
182 >                }
183 >        }
184 >
185 > public:
186 >        Finger(bool full)
187 >        {
188 >                PWTS_SESSION_INFO sessions;
189 >                DWORD count;
190 >
191 >                ::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &count);
192 >
193 >                for (PWTS_SESSION_INFO session(sessions); session != sessions + count; ++session)
194 >                {
195 >                        LPTSTR name;
196 >                        DWORD size;
197 >
198 >                        ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSUserName, &name, &size);
199 >
200 >                        std::wstring name_(name);
201 >
202 >                        ::WTSFreeMemory(name);
203 >
204 >                        if (!name_.empty())
205 >                        {
206 >                                std::transform(name_.begin(), name_.end(), name_.begin(), std::towlower);
207 >
208 >                                LPTSTR session_;
209 >
210 >                                ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSWinStationName, &session_, &size);
211 >
212 >                                Login login(name_, session->SessionId, session_, session->State);
213 >
214 >                                ::WTSFreeMemory(session_);
215 >
216 >                                logins.insert(std::make_pair(Utf8(name_), login));
217 >                        }
218 >                }
219 >
220 >                ::WTSFreeMemory(sessions);
221 >
222 >                if (!full)
223 >                {
224 >                        stream << "Login" << std::string(11, ' ') << "Name" << std::string(17, ' ') << "Id     Session       Status\r\n";
225 >
226 >                        for (std::multimap<std::string, Login>::const_iterator login(logins.begin()); login != logins.end(); ++login)
227 >                                stream << login->first << std::string(16 - login->first.size(), ' ') << login->second.GetShortName() << std::string(21 - login->second.GetShortName().size(), ' ') << std::setw(5) << std::left << login->second.id << "  " << login->second.session << std::string(14 - login->second.session.size(), ' ') << login->second.status << "\r\n";
228 >                }
229 >                else
230 >                        Full();
231 >        }
232 >
233 >        Finger(const std::string &name)
234 >        {
235 >                //NetQueryDisplayInformation
236 >                //NetUserGetInfo
237 >        }
238 >
239 >        inline operator std::string()
240 >        {
241 >                return stream.str();
242 >        }
243 > };
244 >
245 > LPTSTR name;
246   SERVICE_STATUS status;
247   SERVICE_STATUS_HANDLE handle;
248 < HANDLE stop;*/
248 > HANDLE stop;
249   WSADATA data;
250 + std::vector<HANDLE> threads;
251  
252 < /*void WINAPI FingerMain(DWORD argc, LPTSTR *argv);
253 < void WINAPI FingerControl(DWORD control);*/
252 > void FingerDaemon();
253 > DWORD WINAPI FingerListen(LPVOID server_);
254 > DWORD WINAPI FingerDo(LPVOID client_);
255 > void FingerStop(int);
256 > void WINAPI FingerMain(DWORD argc, LPTSTR *argv);
257 > void WINAPI FingerControl(DWORD control);
258  
259   int _tmain(int argc, TCHAR *argv[])
260   {
261 <        /*SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCS Finger Daemon"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
261 >        SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCSFinger"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
262  
263 <        if (!StartServiceCtrlDispatcher(entry))
263 >        if (!::StartServiceCtrlDispatcher(entry))
264          {
265 <                DWORD error(GetLastError());
265 >                DWORD error(::GetLastError());
266  
267                  switch (error)
268                  {
269                  case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
270 <                        std::cerr << "ERROR_FAILED_SERVICE_CONTROLLER_CONNECT" << std::endl;
31 <
32 <                        break;
270 >                        goto go;
271  
272                  case ERROR_INVALID_DATA:
273                          std::cerr << "ERROR_INVALID_DATA" << std::endl;
# Line 49 | Line 287 | int _tmain(int argc, TCHAR *argv[])
287          }
288  
289          return 0;
52 }
290  
291 < void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
292 < {
293 <        name = argv[0];
294 <        handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
58 <        stop = CreateEvent(NULL, TRUE, FALSE, NULL);
291 > go:
292 >        for (int index(1); index != argc; ++index)
293 >        {
294 >                std::wstring arg(argv[index]);
295  
296 <        //*/
296 >                if (arg == TEXT("create"))
297 >                {
298 >                        TCHAR file[MAX_PATH];
299  
300 <        WSAStartup(MAKEWORD(2, 0), &data);
300 >                        ::GetModuleFileName(NULL, file, MAX_PATH);
301  
302 <        //
302 >                        SC_HANDLE manager(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE)), service(::CreateService(manager, TEXT("CCSFinger"), TEXT("CCS Finger Daemon"), 0, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, file, NULL, NULL, TEXT("TermService\0"), NULL, TEXT("")));
303  
304 <        /*status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
305 <        status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
306 <        status.dwServiceSpecificExitCode = 0;
307 <        status.dwCurrentState = SERVICE_RUNNING;
70 <        status.dwWin32ExitCode = NO_ERROR;
71 <        status.dwCheckPoint = 0;
72 <        status.dwWaitHint = 0;
304 >                        if (!service)
305 >                                std::cerr << ::GetLastError() << std::endl;
306 >                        else
307 >                                ::CloseServiceHandle(service);
308  
309 <        SetServiceStatus(handle, &status);*/
309 >                        ::CloseServiceHandle(manager);
310  
311 <        SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
311 >                        return 0;
312 >                }
313 >                else if (arg == TEXT("delete"))
314 >                {
315 >                        SC_HANDLE manager(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, DELETE)), service(::OpenService(manager, TEXT("CCSFinger"), DELETE));
316 >
317 >                        if (!::DeleteService(service))
318 >                                std::cerr << ::GetLastError() << std::endl;
319 >
320 >                        ::CloseServiceHandle(service);
321 >                        ::CloseServiceHandle(manager);
322 >
323 >                        return 0;
324 >                }
325 >        }
326 >
327 >        stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
328 >
329 >        ::signal(SIGINT, FingerStop);
330 >
331 >        try
332 >        {
333 >                FingerDaemon();
334 >        }
335 >        catch (...) {}
336 >
337 >        return 0;
338 > }
339 >
340 > void FingerDaemon()
341 > {
342 >        ::WSAStartup(MAKEWORD(2, 0), &data);
343 >
344 >        //
345 >
346 >        SOCKET server(::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
347          SOCKADDR_IN service;
348          
349          service.sin_family = AF_INET;
350          service.sin_addr.s_addr = inet_addr("0.0.0.0");
351          service.sin_port = htons(79);
352  
353 <        bind(sock, (SOCKADDR *)(&service), sizeof (service));
354 <        listen(sock, SOMAXCONN);
353 >        ::bind(server, (SOCKADDR *)(&service), sizeof (service));
354 >        ::listen(server, SOMAXCONN);
355 >
356 >        threads.push_back(::CreateThread(NULL, 0, FingerListen, &server, 0, NULL));
357 >
358 >        while(::WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0);
359  
360 <        //while(/*WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0*/ /*&&*/)
360 >        //
361 >
362 >        ::closesocket(server);
363 >
364 >        ::WSACleanup();
365 > }
366 >
367 > DWORD WINAPI FingerListen(LPVOID server_)
368 > {
369 >        SOCKET &server(*reinterpret_cast<SOCKET *>(server_));
370 >
371 >        while (true)
372          {
373 <                //
373 >                SOCKET client(accept(server, NULL, NULL));
374 >
375 >                threads.push_back(::CreateThread(NULL, 0, FingerDo, &client, 0, NULL));
376          }
377  
378 +        return 0;
379 + }
380 +
381 + DWORD WINAPI FingerDo(LPVOID client_)
382 + {
383 +        SOCKET &client(*reinterpret_cast<SOCKET *>(client_));
384 +        char buffer[1024];
385 +        std::istringstream stream(std::string(buffer, ::recv(client, buffer, sizeof buffer, 0)));
386 +        std::string line;
387 +
388 +        std::getline(stream, line);
389 +
390 +        stream.str(line);
391 +
392 +        std::getline(stream, line, '\r');
393 +
394 +        stream.str(line);
395 +
396 +        std::string name;
397 +        bool full(false);
398 +
399 +        while (stream >> line)
400 +                if (line == "/W")
401 +                        full = true;
402 +                else
403 +                        name = line;
404 +
405 +        std::string finger(name.empty() ? Finger(full) : Finger(name));
406 +
407 +        ::send(client, finger.data(), int(finger.size()), 0);
408 +        ::closesocket(client);
409 +
410 +        return 0;
411 + }
412 +
413 + void FingerStop(int)
414 + {
415 +        ::SetEvent(stop);
416 + }
417 +
418 + void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
419 + {
420 +        name = argv[0];
421 +        handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
422 +        stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
423 +
424          //
425  
426 <        WSACleanup();
426 >        status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
427 >        status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
428 >        status.dwServiceSpecificExitCode = 0;
429 >        status.dwCurrentState = SERVICE_RUNNING;
430 >        status.dwWin32ExitCode = NO_ERROR;
431 >        status.dwCheckPoint = 0;
432 >        status.dwWaitHint = 0;
433 >
434 >        ::SetServiceStatus(handle, &status);
435  
436 <        /*status.dwCurrentState = SERVICE_STOPPED;
436 >        try
437 >        {
438 >                FingerDaemon();
439 >        }
440 >        catch (...) {}
441 >
442 >        status.dwCurrentState = SERVICE_STOPPED;
443          status.dwWin32ExitCode = NO_ERROR;
444          status.dwCheckPoint = 0;
445          status.dwWaitHint = 0;
446  
447 <        SetServiceStatus(handle, &status);
447 >        ::SetServiceStatus(handle, &status);
448   }
449  
450   void WINAPI FingerControl(DWORD control)
# Line 108 | Line 455 | void WINAPI FingerControl(DWORD control)
455          case SERVICE_CONTROL_SHUTDOWN:
456                  status.dwCurrentState = SERVICE_STOP_PENDING;
457  
458 <                SetEvent(stop);
458 >                ::SetEvent(stop);
459  
460                  break;
461  
# Line 116 | Line 463 | void WINAPI FingerControl(DWORD control)
463                  break;
464          }
465  
466 <        SetServiceStatus(handle, &status);*/
120 <
121 <        return 0;
466 >        ::SetServiceStatus(handle, &status);
467   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines