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 595 by douglas, 2005-11-27T17:57:41-08:00 vs.
Revision 640 by douglas, 2006-01-04T20:54:20-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 + #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 + inline std::wstring Utf8(const std::string &string)
74 + {
75 +        std::wstring wstring(::MultiByteToWideChar(CP_UTF8, 0, string.data(), int(string.size()), NULL, 0), '\0');
76 +
77 +        ::MultiByteToWideChar(CP_UTF8, 0, string.data(), int(string.size()), const_cast<LPWSTR>(wstring.data()), int(wstring.size()));
78 +
79 +        return wstring;
80 + }
81 +
82 + class Finger
83 + {
84 +        class Login
85 +        {
86 +                std::wstring login;
87 +                mutable USER_INFO_11 *info;
88 +
89 +                inline void GetInfo() const
90 +                {
91 +                        if (!info)
92 +                                ::NetUserGetInfo(NULL, login.c_str(), 11, reinterpret_cast<LPBYTE *>(&info));
93 +                }
94 +        public:
95 +                std::string session;
96 +                DWORD id;
97 +                WTS_CONNECTSTATE_CLASS status;
98 +
99 +                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)
100 +                {
101 +                }
102 +
103 +                ~Login()
104 +                {
105 +                        if (!info)
106 +                                ::NetApiBufferFree(info);
107 +                }
108 +
109 +                std::string GetShortName() const
110 +                {
111 +                        GetInfo();
112 +
113 +                        return Utf8(std::wstring(info->usri11_full_name).substr(0, 20));
114 +                }
115 +
116 +                std::string GetName() const
117 +                {
118 +                        GetInfo();
119 +
120 +                        return Utf8(info->usri11_full_name);
121 +                }
122 +
123 +                std::string GetDirectory() const
124 +                {
125 +                        HANDLE token;
126 +
127 +                        if (::WTSQueryUserToken(id, &token))
128 +                        {
129 +                                TCHAR directory[MAX_PATH];
130 +
131 +                                ::SHGetFolderPath(NULL, CSIDL_PROFILE, token, SHGFP_TYPE_CURRENT, directory);
132 +                                ::CloseHandle(token);
133 +
134 +                                return Utf8(directory);
135 +                        }
136 +                        else
137 +                        {
138 +                                TCHAR directory_[MAX_PATH];
139 +
140 +                                ::SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, directory_);
141 +
142 +                                std::wstring directory(directory_);
143 +
144 +                                directory.replace(directory.rfind('\\') + 1, std::wstring::npos, login);
145 +
146 +                                return Utf8(directory);
147 +                        }
148 +                }
149 +        };
150 +
151 +        std::ostringstream stream;
152 +        std::multimap<std::string, Login> logins;
153 +
154 +        void Full()
155 +        {
156 +                for (std::multimap<std::string, Login>::const_iterator login(logins.begin()); login != logins.end(); login = logins.upper_bound(login->first))
157 +                {
158 +                        if (login != logins.begin())
159 +                                stream << "\r\n";
160 +
161 +                        std::string directory(login->second.GetDirectory());
162 +
163 +                        stream << "Login: " << login->first << std::string(33 - login->first.size(), ' ') << "Name: " << login->second.GetName() << "\r\nDirectory: " << directory << "\r\n";
164 +
165 +                        for (std::multimap<std::string, Login>::const_iterator login_(logins.lower_bound(login->first)); login_ != logins.upper_bound(login->first); ++login_)
166 +                                stream << login_->second.status << ' ' << login_->second.session << ' ' << login_->second.id << "\r\n";
167 +
168 +                        std::string files[] = { "\\.project", "\\.plan" };
169 +
170 +                        for (std::string *file(files); file != files + sizeof (files) / sizeof (*file); ++file)
171 +                        {
172 +                                file->insert(0, directory);
173 +
174 +                                std::ifstream in(file->c_str());
175 +
176 +                                if (!in.is_open())
177 +                                        continue;
178 +
179 +                                switch (file - files)
180 +                                {
181 +                                case 0:
182 +                                        stream << "Project:\r\n";
183 +
184 +                                        break;
185 +                                case 1:
186 +                                        stream << "Plan:\r\n";
187 +                                }
188 +
189 +                                std::string buffer;
190 +
191 +                                while (std::getline(in, buffer))
192 +                                        stream << buffer << std::endl;
193 +                        }
194 +                }
195 +        }
196 +
197 + public:
198 +        Finger(bool full)
199 +        {
200 +                PWTS_SESSION_INFO sessions;
201 +                DWORD count;
202 +
203 +                ::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &count);
204 +
205 +                for (PWTS_SESSION_INFO session(sessions); session != sessions + count; ++session)
206 +                {
207 +                        LPTSTR name;
208 +                        DWORD size;
209 +
210 +                        ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSUserName, &name, &size);
211 +
212 +                        std::wstring name_(name);
213 +
214 +                        ::WTSFreeMemory(name);
215 +
216 +                        if (!name_.empty())
217 +                        {
218 +                                std::transform(name_.begin(), name_.end(), name_.begin(), std::towlower);
219 +
220 +                                LPTSTR session_;
221 +
222 +                                ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSWinStationName, &session_, &size);
223 +
224 +                                Login login(name_, session->SessionId, session_, session->State);
225 +
226 +                                ::WTSFreeMemory(session_);
227 +
228 +                                logins.insert(std::make_pair(Utf8(name_), login));
229 +                        }
230 +                }
231 +
232 +                ::WTSFreeMemory(sessions);
233 +
234 +                if (!full)
235 +                {
236 +                        stream << "Login" << std::string(11, ' ') << "Name" << std::string(17, ' ') << "Id     Session       Status\r\n";
237 +
238 +                        for (std::multimap<std::string, Login>::const_iterator login(logins.begin()); login != logins.end(); ++login)
239 +                                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";
240 +                }
241 +                else
242 +                        Full();
243 +        }
244 +
245 +        Finger(const std::string &name_)
246 +        {
247 +                std::wstring name(Utf8(name_));
248 +
249 +                std::transform(name.begin(), name.end(), name.begin(), std::towlower);
250 +
251 +                DWORD size;
252 +                PNET_DISPLAY_USER users;
253 +
254 +                ::NetQueryDisplayInformation(NULL, 1, 0, 100, MAX_PREFERRED_LENGTH, &size, reinterpret_cast<PVOID *>(&users));
255 +
256 +                 for (PNET_DISPLAY_USER user = users; user != users + size; ++user)
257 +                 {
258 +                         std::wstring name_(user->usri1_name);
259 +
260 +                         std::transform(name_.begin(), name_.end(), name_.begin(), std::towlower);
261 +
262 +                         if (name_.find(name) != std::wstring::npos)
263 +                                 ;//logins.insert(std::make_pair(Utf8(name_),
264 +                         else
265 +                         {
266 +                                 std::wstring full(user->usri1_full_name);
267 +
268 +                                 std::transform(full.begin(), full.end(), full.begin(), std::towlower);
269 +
270 +                                 if (full.find(name) != std::wstring::npos)
271 +                                         ;//logins.insert(std::make_pair(Utf8(name_),
272 +                         }
273 +                 }
274 +
275 +                 ::NetApiBufferFree(users);
276 +                
277 +                 if (!logins.empty())
278 +                        Full();
279 +                 else
280 +                         stream << "finger: " << name_ << ": no such user\r\n";
281 +        }
282 +
283 +        inline operator std::string()
284 +        {
285 +                return stream.str();
286 +        }
287 + };
288  
289   LPTSTR name;
290   SERVICE_STATUS status;
291   SERVICE_STATUS_HANDLE handle;
292   HANDLE stop;
293   WSADATA data;
294 + std::vector<HANDLE> threads;
295  
296 + void FingerDaemon();
297 + DWORD WINAPI FingerListen(LPVOID server_);
298 + DWORD WINAPI FingerDo(LPVOID client_);
299 + void FingerStop(int);
300   void WINAPI FingerMain(DWORD argc, LPTSTR *argv);
301   void WINAPI FingerControl(DWORD control);
302  
303   int _tmain(int argc, TCHAR *argv[])
304   {
305 <        SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCS Finger Daemon"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
305 >        SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCSFinger"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
306  
307 <        if (!StartServiceCtrlDispatcher(entry))
307 >        if (!::StartServiceCtrlDispatcher(entry))
308          {
309 <                DWORD error(GetLastError());
309 >                DWORD error(::GetLastError());
310  
311                  switch (error)
312                  {
# Line 51 | Line 333 | int _tmain(int argc, TCHAR *argv[])
333          return 0;
334  
335   go:
336 <        std::cout << "Here!" << std::endl;
336 >        for (int index(1); index != argc; ++index)
337 >        {
338 >                std::wstring arg(argv[index]);
339 >
340 >                if (arg == TEXT("create"))
341 >                {
342 >                        TCHAR file[MAX_PATH];
343 >
344 >                        ::GetModuleFileName(NULL, file, MAX_PATH);
345 >
346 >                        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("")));
347 >
348 >                        if (!service)
349 >                                std::cerr << ::GetLastError() << std::endl;
350 >                        else
351 >                                ::CloseServiceHandle(service);
352 >
353 >                        ::CloseServiceHandle(manager);
354 >
355 >                        return 0;
356 >                }
357 >                else if (arg == TEXT("delete"))
358 >                {
359 >                        SC_HANDLE manager(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, DELETE)), service(::OpenService(manager, TEXT("CCSFinger"), DELETE));
360 >
361 >                        if (!::DeleteService(service))
362 >                                std::cerr << ::GetLastError() << std::endl;
363 >
364 >                        ::CloseServiceHandle(service);
365 >                        ::CloseServiceHandle(manager);
366 >
367 >                        return 0;
368 >                }
369 >        }
370 >
371 >        stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
372 >
373 >        ::signal(SIGINT, FingerStop);
374 >
375 >        try
376 >        {
377 >                FingerDaemon();
378 >        }
379 >        catch (...) {}
380  
381          return 0;
382   }
383  
384 < void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
384 > void FingerDaemon()
385   {
386 <        name = argv[0];
387 <        handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
388 <        stop = CreateEvent(NULL, TRUE, FALSE, NULL);
386 >        ::WSAStartup(MAKEWORD(2, 0), &data);
387 >
388 >        //
389 >
390 >        SOCKET server(::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
391 >        SOCKADDR_IN service;
392 >        
393 >        service.sin_family = AF_INET;
394 >        service.sin_addr.s_addr = inet_addr("0.0.0.0");
395 >        service.sin_port = htons(79);
396 >
397 >        ::bind(server, (SOCKADDR *)(&service), sizeof (service));
398 >        ::listen(server, SOMAXCONN);
399 >
400 >        threads.push_back(::CreateThread(NULL, 0, FingerListen, &server, 0, NULL));
401 >
402 >        while(::WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0);
403  
404          //
405  
406 <        WSAStartup(MAKEWORD(2, 0), &data);
406 >        ::closesocket(server);
407 >
408 >        ::WSACleanup();
409 > }
410 >
411 > DWORD WINAPI FingerListen(LPVOID server_)
412 > {
413 >        SOCKET &server(*reinterpret_cast<SOCKET *>(server_));
414 >
415 >        while (true)
416 >        {
417 >                SOCKET client(accept(server, NULL, NULL));
418 >
419 >                threads.push_back(::CreateThread(NULL, 0, FingerDo, &client, 0, NULL));
420 >        }
421 >
422 >        return 0;
423 > }
424 >
425 > DWORD WINAPI FingerDo(LPVOID client_)
426 > {
427 >        SOCKET &client(*reinterpret_cast<SOCKET *>(client_));
428 >        char buffer[1024];
429 >        std::istringstream stream(std::string(buffer, ::recv(client, buffer, sizeof buffer, 0)));
430 >        std::string line;
431 >
432 >        std::getline(stream, line);
433 >
434 >        stream.str(line);
435 >
436 >        std::getline(stream, line, '\r');
437 >
438 >        stream.str(line);
439 >
440 >        std::string name;
441 >        bool full(false);
442 >
443 >        while (stream >> line)
444 >                if (line == "/W")
445 >                        full = true;
446 >                else
447 >                        name = line;
448 >
449 >        std::string finger(name.empty() ? Finger(full) : Finger(name));
450 >
451 >        ::send(client, finger.data(), int(finger.size()), 0);
452 >        ::closesocket(client);
453 >
454 >        return 0;
455 > }
456 >
457 > void FingerStop(int)
458 > {
459 >        ::SetEvent(stop);
460 > }
461 >
462 > void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
463 > {
464 >        name = argv[0];
465 >        handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
466 >        stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
467  
468          //
469  
# Line 76 | Line 475 | void WINAPI FingerMain(DWORD argc, LPTST
475          status.dwCheckPoint = 0;
476          status.dwWaitHint = 0;
477  
478 <        SetServiceStatus(handle, &status);
478 >        ::SetServiceStatus(handle, &status);
479  
480 <        SOCKET sock(socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
82 <        SOCKADDR_IN service;
83 <        
84 <        service.sin_family = AF_INET;
85 <        service.sin_addr.s_addr = inet_addr("0.0.0.0");
86 <        service.sin_port = htons(79);
87 <
88 <        bind(sock, (SOCKADDR *)(&service), sizeof (service));
89 <        listen(sock, SOMAXCONN);
90 <
91 <        while(WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0 /*&&*/)
480 >        try
481          {
482 <                //
482 >                FingerDaemon();
483          }
484 <
96 <        //
97 <
98 <        WSACleanup();
484 >        catch (...) {}
485  
486          status.dwCurrentState = SERVICE_STOPPED;
487          status.dwWin32ExitCode = NO_ERROR;
488          status.dwCheckPoint = 0;
489          status.dwWaitHint = 0;
490  
491 <        SetServiceStatus(handle, &status);
491 >        ::SetServiceStatus(handle, &status);
492   }
493  
494   void WINAPI FingerControl(DWORD control)
# Line 113 | Line 499 | void WINAPI FingerControl(DWORD control)
499          case SERVICE_CONTROL_SHUTDOWN:
500                  status.dwCurrentState = SERVICE_STOP_PENDING;
501  
502 <                SetEvent(stop);
502 >                ::SetEvent(stop);
503  
504                  break;
505  
# Line 121 | Line 507 | void WINAPI FingerControl(DWORD control)
507                  break;
508          }
509  
510 <        SetServiceStatus(handle, &status);
510 >        ::SetServiceStatus(handle, &status);
511   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines