1 /*
2  * PROJECT:     ReactOS Shell
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     CLanStatus: Lan connection status dialog
5  * COPYRIGHT:   Copyright 2008 Johannes Anderwald (johannes.anderwald@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 #include <winsock.h>
11 
12 CLanStatus::CLanStatus() :
13     m_lpNetMan(NULL),
14     m_pHead(NULL)
15 {
16 }
17 
18 VOID
19 UpdateLanStatusUiDlg(
20     HWND hwndDlg,
21     MIB_IFROW *IfEntry,
22     LANSTATUSUI_CONTEXT *pContext)
23 {
24     WCHAR szFormat[MAX_PATH] = {0};
25     WCHAR szBuffer[MAX_PATH] = {0};
26     SYSTEMTIME TimeConnected;
27     DWORD DurationSeconds;
28     WCHAR Buffer[100];
29     WCHAR DayBuffer[30];
30     WCHAR LocBuffer[50];
31 
32 #if 0
33     ULONGLONG Ticks;
34 #else
35     DWORD Ticks;
36 #endif
37 
38     if (IfEntry->dwSpeed < 1000)
39     {
40         if (LoadStringW(netshell_hInstance, IDS_FORMAT_BIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
41         {
42             swprintf(szBuffer, szFormat, IfEntry->dwSpeed);
43             SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
44         }
45     }
46     else if (IfEntry->dwSpeed < 1000000)
47     {
48         if (LoadStringW(netshell_hInstance, IDS_FORMAT_KBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
49         {
50             swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000);
51             SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
52         }
53     }
54     else if (IfEntry->dwSpeed < 1000000000)
55     {
56         if (LoadStringW(netshell_hInstance, IDS_FORMAT_MBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
57         {
58             swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000000);
59             SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
60         }
61     }
62     else
63     {
64         if (LoadStringW(netshell_hInstance, IDS_FORMAT_GBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
65         {
66             swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000000000);
67             SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
68         }
69     }
70 
71     if (StrFormatByteSizeW(IfEntry->dwInOctets, szBuffer, sizeof(szFormat)/sizeof(WCHAR)))
72     {
73         SendDlgItemMessageW(hwndDlg, IDC_RECEIVED, WM_SETTEXT, 0, (LPARAM)szBuffer);
74     }
75 
76     if (StrFormatByteSizeW(IfEntry->dwOutOctets, szBuffer, sizeof(szFormat)/sizeof(WCHAR)))
77     {
78         SendDlgItemMessageW(hwndDlg, IDC_SEND, WM_SETTEXT, 0, (LPARAM)szBuffer);
79     }
80 
81 #if 0
82     Ticks = GetTickCount64();
83 #else
84     Ticks = GetTickCount();
85 #endif
86 
87     DurationSeconds = Ticks / 1000;
88     TimeConnected.wSecond = (DurationSeconds % 60);
89     TimeConnected.wMinute = (DurationSeconds / 60) % 60;
90     TimeConnected.wHour = (DurationSeconds / (60 * 60)) % 24;
91     TimeConnected.wDay = DurationSeconds / (60 * 60 * 24);
92 
93     if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &TimeConnected, L"HH':'mm':'ss", LocBuffer, sizeof(LocBuffer) / sizeof(LocBuffer[0])))
94         return;
95 
96     if (!TimeConnected.wDay)
97     {
98         SendDlgItemMessageW(hwndDlg, IDC_DURATION, WM_SETTEXT, 0, (LPARAM)LocBuffer);
99     }
100     else
101     {
102         if (TimeConnected.wDay == 1)
103         {
104             if (!LoadStringW(netshell_hInstance, IDS_DURATION_DAY, DayBuffer, sizeof(DayBuffer) / sizeof(DayBuffer[0])))
105                 DayBuffer[0] = L'\0';
106         }
107         else
108         {
109             if (!LoadStringW(netshell_hInstance, IDS_DURATION_DAYS, DayBuffer, sizeof(DayBuffer) / sizeof(DayBuffer[0])))
110                 DayBuffer[0] = L'\0';
111         }
112         swprintf(Buffer, DayBuffer, TimeConnected.wDay, LocBuffer);
113         SendDlgItemMessageW(hwndDlg, IDC_DURATION, WM_SETTEXT, 0, (LPARAM)Buffer);
114     }
115 
116 }
117 
118 VOID
119 UpdateLanStatus(HWND hwndDlg,  LANSTATUSUI_CONTEXT * pContext)
120 {
121     MIB_IFROW IfEntry;
122     HICON hIcon, hOldIcon = NULL;
123     NOTIFYICONDATAW nid;
124     NETCON_PROPERTIES * pProperties = NULL;
125 
126     ZeroMemory(&IfEntry, sizeof(IfEntry));
127     IfEntry.dwIndex = pContext->dwAdapterIndex;
128     if (GetIfEntry(&IfEntry) != NO_ERROR)
129     {
130         return;
131     }
132 
133     hIcon = NULL;
134     if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
135     {
136         if (pContext->dwInOctets == IfEntry.dwInOctets && pContext->dwOutOctets == IfEntry.dwOutOctets && pContext->Status  != 0)
137         {
138             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE), IMAGE_ICON, 32, 32, LR_SHARED);
139             pContext->Status = 0;
140         }
141         else if (pContext->dwInOctets != IfEntry.dwInOctets && pContext->dwOutOctets != IfEntry.dwOutOctets && pContext->Status  != 1)
142         {
143             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_TRANSREC), IMAGE_ICON, 32, 32, LR_SHARED);
144             pContext->Status = 1;
145         }
146         else if (pContext->dwInOctets != IfEntry.dwInOctets && pContext->Status  != 2)
147         {
148             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_REC), IMAGE_ICON, 32, 32, LR_SHARED);
149             pContext->Status = 2;
150         }
151         else if (pContext->dwOutOctets != IfEntry.dwOutOctets && pContext->Status  != 3)
152         {
153             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_TRANS), IMAGE_ICON, 32, 32, LR_SHARED);
154             pContext->Status = 3;
155         }
156     }
157     else if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_UNREACHABLE || IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_DISCONNECTED)
158     {
159         if (pContext->Status != 4)
160         {
161             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF), IMAGE_ICON, 32, 32, LR_SHARED);
162             pContext->Status = 4;
163         }
164     }
165     else if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_NON_OPERATIONAL)
166     {
167         if (pContext->Status != 5)
168         {
169             hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF), IMAGE_ICON, 32, 32, LR_SHARED);
170             pContext->Status = 5;
171         }
172     }
173 
174     if (hwndDlg && hIcon)
175     {
176         hOldIcon = (HICON)SendDlgItemMessageW(hwndDlg, IDC_NETSTAT, STM_SETICON, (WPARAM)hIcon, 0);
177         if (hOldIcon)
178             DestroyIcon(hOldIcon);
179     }
180 
181     ZeroMemory(&nid, sizeof(nid));
182     nid.cbSize = sizeof(nid);
183     nid.uID = pContext->uID;
184     nid.hWnd = pContext->hwndStatusDlg;
185     nid.uVersion = NOTIFYICON_VERSION;
186 
187     if (pContext->pNet->GetProperties(&pProperties) == S_OK)
188     {
189         if (pProperties->dwCharacter & NCCF_SHOW_ICON)
190         {
191             if (hwndDlg)
192                 nid.hIcon = (HICON)CopyImage(hIcon, IMAGE_ICON, 16, 16, LR_COPYFROMRESOURCE);
193             else
194                 nid.hIcon = hIcon;
195 
196             if (nid.hIcon)
197                 nid.uFlags |= NIF_ICON;
198 
199             nid.uFlags |= NIF_STATE;
200             nid.dwState = 0;
201             nid.dwStateMask = NIS_HIDDEN;
202 
203             if (pProperties->pszwName)
204             {
205                 if (wcslen(pProperties->pszwName) * sizeof(WCHAR) < sizeof(nid.szTip))
206                 {
207                     nid.uFlags |= NIF_TIP;
208                     wcscpy(nid.szTip, pProperties->pszwName);
209                 }
210                 else
211                 {
212                     CopyMemory(nid.szTip, pProperties->pszwName, sizeof(nid.szTip) - sizeof(WCHAR));
213                     nid.szTip[(sizeof(nid.szTip)/sizeof(WCHAR))-1] = L'\0';
214                     nid.uFlags |= NIF_TIP;
215                 }
216             }
217         }
218         else
219         {
220             nid.uFlags |= NIF_STATE;
221             nid.dwState = NIS_HIDDEN;
222             nid.dwStateMask = NIS_HIDDEN;
223 
224         }
225         NcFreeNetconProperties(pProperties);
226     }
227 
228     Shell_NotifyIconW(NIM_MODIFY, &nid);
229 
230     if (nid.uFlags & NIF_ICON)
231         DestroyIcon(nid.hIcon);
232 
233     pContext->dwInOctets = IfEntry.dwInOctets;
234     pContext->dwOutOctets = IfEntry.dwOutOctets;
235 
236     if (hwndDlg)
237         UpdateLanStatusUiDlg(hwndDlg, &IfEntry, pContext);
238 }
239 
240 
241 VOID
242 InitializeLANStatusUiDlg(HWND hwndDlg, LANSTATUSUI_CONTEXT * pContext)
243 {
244     WCHAR szBuffer[MAX_PATH] = {0};
245     NETCON_PROPERTIES * pProperties;
246 
247     if (pContext->pNet->GetProperties(&pProperties) != S_OK)
248         return;
249 
250     if (pProperties->Status == NCS_DISCONNECTED)
251         LoadStringW(netshell_hInstance, IDS_STATUS_UNREACHABLE, szBuffer, MAX_PATH);
252     else if (pProperties->Status == NCS_MEDIA_DISCONNECTED)
253         LoadStringW(netshell_hInstance, IDS_STATUS_DISCONNECTED, szBuffer, MAX_PATH);
254     else if (pProperties->Status == NCS_CONNECTING)
255         LoadStringW(netshell_hInstance, IDS_STATUS_CONNECTING, szBuffer, MAX_PATH);
256     else if (pProperties->Status == NCS_CONNECTED)
257          LoadStringW(netshell_hInstance, IDS_STATUS_CONNECTED, szBuffer, MAX_PATH);
258 
259     SendDlgItemMessageW(hwndDlg, IDC_STATUS, WM_SETTEXT, 0, (LPARAM)szBuffer);
260 
261     pContext->dwInOctets = 0;
262     pContext->dwOutOctets = 0;
263 
264     /* update adapter info */
265     pContext->Status = -1;
266     UpdateLanStatus(hwndDlg, pContext);
267     NcFreeNetconProperties(pProperties);
268 }
269 
270 static
271 VOID
272 InsertColumnToListView(
273     HWND hDlgCtrl,
274     UINT ResId,
275     UINT SubItem,
276     UINT Size)
277 {
278     WCHAR szBuffer[200];
279     LVCOLUMNW lc;
280 
281     if (!LoadStringW(netshell_hInstance, ResId, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
282         return;
283 
284     memset(&lc, 0, sizeof(LV_COLUMN) );
285     lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
286     lc.iSubItem   = SubItem;
287     lc.fmt = LVCFMT_FIXED_WIDTH;
288     lc.cx         = Size;
289     lc.cchTextMax = wcslen(szBuffer);
290     lc.pszText    = szBuffer;
291 
292     (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, SubItem, (LPARAM)&lc);
293 }
294 
295 static
296 VOID
297 AddIPAddressToListView(
298     HWND hDlgCtrl,
299     PIP_ADDR_STRING pAddr,
300     INT Index)
301 {
302     LVITEMW li;
303     PIP_ADDR_STRING pCur;
304     WCHAR szBuffer[100];
305     UINT SubIndex;
306 
307     ZeroMemory(&li, sizeof(LVITEMW));
308     li.mask = LVIF_TEXT;
309     li.iItem = Index;
310     pCur = pAddr;
311     SubIndex = 0;
312 
313     do
314     {
315         if (SubIndex)
316         {
317             ZeroMemory(&li, sizeof(LVITEMW));
318             li.mask = LVIF_TEXT;
319             li.iItem = Index;
320             li.iSubItem = 0;
321             li.pszText = (LPWSTR)L"";
322             li.iItem = SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
323         }
324 
325         if (MultiByteToWideChar(CP_ACP, 0, pCur->IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
326         {
327             li.pszText = szBuffer;
328             li.iSubItem = 1;
329             li.iItem = Index++;
330             SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
331         }
332         SubIndex++;
333         pCur = pCur->Next;
334     } while (pCur && pCur->IpAddress.String[0]);
335 }
336 
337 static
338 INT
339 InsertItemToListView(
340     HWND hDlgCtrl,
341     UINT ResId)
342 {
343     LVITEMW li;
344     WCHAR szBuffer[100];
345 
346     ZeroMemory(&li, sizeof(LVITEMW));
347     li.mask = LVIF_TEXT;
348     li.iItem = ListView_GetItemCount(hDlgCtrl);
349     if (LoadStringW(netshell_hInstance, ResId, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
350     {
351         li.pszText = szBuffer;
352         return (INT)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
353     }
354     return -1;
355 }
356 
357 static
358 BOOL
359 tmToStr(
360     IN struct tm *pTM,
361     OUT LPWSTR szBuffer,
362     IN UINT nBufferSize)
363 {
364     SYSTEMTIME st;
365     CString strBufferDate;
366     CString strBufferTime;
367     UINT nCharDate, nCharTime;
368     BOOL bResult = FALSE;
369 
370     st.wYear = pTM->tm_year + 1900;
371     st.wMonth = pTM->tm_mon + 1;
372     st.wDay = pTM->tm_mday;
373     st.wHour = pTM->tm_hour;
374     st.wMinute = pTM->tm_min;
375     st.wSecond = pTM->tm_sec;
376 
377     /* Check required size before cpy/cat */
378     nCharDate = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, NULL, 0) + 1;
379     nCharTime = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, NULL, 0) + 1;
380 
381     if (GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, strBufferDate.GetBuffer(nCharDate), nCharDate) &&
382         GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, strBufferTime.GetBuffer(nCharTime), nCharTime))
383     {
384         StringCbCopy(szBuffer, nBufferSize, strBufferDate);
385         StringCbCat(szBuffer, nBufferSize, L" ");
386         StringCbCat(szBuffer, nBufferSize, strBufferTime);
387         bResult = TRUE;
388     }
389     strBufferDate.ReleaseBuffer();
390     strBufferTime.ReleaseBuffer();
391 
392     return bResult;
393 }
394 
395 INT_PTR
396 CALLBACK
397 LANStatusUiDetailsDlg(
398     HWND hwndDlg,
399     UINT uMsg,
400     WPARAM wParam,
401     LPARAM lParam
402 )
403 {
404     LANSTATUSUI_CONTEXT * pContext;
405     LVITEMW li;
406     WCHAR szBuffer[100];
407     PIP_ADAPTER_INFO pAdapterInfo, pCurAdapter;
408     PIP_PER_ADAPTER_INFO pPerAdapter;
409     DWORD dwSize;
410     HWND hDlgCtrl;
411     RECT rect;
412 
413     switch (uMsg)
414     {
415         case WM_INITDIALOG:
416             pContext = (LANSTATUSUI_CONTEXT*)lParam;
417 
418             hDlgCtrl = GetDlgItem(hwndDlg, IDC_DETAILS);
419 
420             /* get client rect */
421             GetClientRect(hDlgCtrl, &rect);
422 
423             /* calculate column width */
424             dwSize = rect.right / 2;
425 
426             InsertColumnToListView(hDlgCtrl, IDS_PROPERTY, 0, dwSize);
427             InsertColumnToListView(hDlgCtrl, IDS_VALUE, 1, dwSize);
428 
429             dwSize = 0;
430             pCurAdapter = NULL;
431             pAdapterInfo = NULL;
432             if (GetAdaptersInfo(NULL, &dwSize) == ERROR_BUFFER_OVERFLOW)
433             {
434                 pAdapterInfo = static_cast<PIP_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
435                 if (pAdapterInfo)
436                 {
437                     if (GetAdaptersInfo(pAdapterInfo, &dwSize) == NO_ERROR)
438                     {
439                         pCurAdapter = pAdapterInfo;
440                         while (pCurAdapter && pCurAdapter->Index != pContext->dwAdapterIndex)
441                             pCurAdapter = pCurAdapter->Next;
442 
443                         if (pCurAdapter->Index != pContext->dwAdapterIndex)
444                             pCurAdapter = NULL;
445                     }
446                 }
447             }
448 
449             ZeroMemory(&li, sizeof(LVITEMW));
450             li.mask = LVIF_TEXT;
451             li.iSubItem = 1;
452             li.pszText = szBuffer;
453 
454             if (pCurAdapter)
455             {
456                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_PHYSICAL_ADDRESS);
457                 if (li.iItem >= 0)
458                 {
459                     swprintf(szBuffer, L"%02x-%02x-%02x-%02x-%02x-%02x",pCurAdapter->Address[0], pCurAdapter->Address[1],
460                              pCurAdapter->Address[2], pCurAdapter->Address[3], pCurAdapter->Address[4], pCurAdapter->Address[5]);
461                     SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
462                 }
463                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_IP_ADDRESS);
464                 if (li.iItem >= 0)
465                     if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->IpAddressList.IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
466                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
467 
468                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_SUBNET_MASK);
469                 if (li.iItem >= 0)
470                     if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->IpAddressList.IpMask.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
471                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
472 
473                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_DEF_GATEWAY);
474                 if (li.iItem >= 0 && pCurAdapter->GatewayList.IpAddress.String[0] != '0')
475                 {
476                     if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->GatewayList.IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
477                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
478                 }
479 
480                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_DHCP_SERVER);
481                 if (li.iItem >= 0 && pCurAdapter->DhcpServer.IpAddress.String[0] != '0')
482                 {
483                     if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->DhcpServer.IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
484                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
485                 }
486 
487                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_LEASE_OBTAINED);
488                 if (li.iItem >= 0 && pCurAdapter->LeaseObtained != NULL)
489                 {
490                     struct tm *leaseOptained;
491 
492                     leaseOptained = localtime(&pCurAdapter->LeaseObtained);
493 
494                     if (tmToStr(leaseOptained, szBuffer, _countof(szBuffer)))
495                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
496                 }
497 
498                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_LEASE_EXPIRES);
499                 if (li.iItem >= 0 && pCurAdapter->LeaseExpires != NULL)
500                 {
501                     struct tm *leaseExpire;
502 
503                     leaseExpire = localtime(&pCurAdapter->LeaseExpires);
504 
505                     if (tmToStr(leaseExpire, szBuffer, _countof(szBuffer)))
506                         SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
507                 }
508             }
509 
510             dwSize = 0;
511             li.iItem = InsertItemToListView(hDlgCtrl, IDS_DNS_SERVERS);
512             if (GetPerAdapterInfo(pContext->dwAdapterIndex, NULL, &dwSize) == ERROR_BUFFER_OVERFLOW)
513             {
514                 pPerAdapter = static_cast<PIP_PER_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
515                 if (pPerAdapter)
516                 {
517                     if (GetPerAdapterInfo(pContext->dwAdapterIndex, pPerAdapter, &dwSize) == ERROR_SUCCESS)
518                     {
519                         if (li.iItem >= 0)
520                             AddIPAddressToListView(hDlgCtrl, &pPerAdapter->DnsServerList, li.iItem);
521                     }
522                     CoTaskMemFree(pPerAdapter);
523                 }
524             }
525 
526             if (pCurAdapter)
527             {
528                 li.iItem = InsertItemToListView(hDlgCtrl, IDS_WINS_SERVERS);
529                 if (pCurAdapter->HaveWins)
530                 {
531                     AddIPAddressToListView(hDlgCtrl, &pCurAdapter->PrimaryWinsServer, li.iItem);
532                     AddIPAddressToListView(hDlgCtrl, &pCurAdapter->SecondaryWinsServer, li.iItem+1);
533                 }
534             }
535 
536             CoTaskMemFree(pAdapterInfo);
537             break;
538 
539         case WM_COMMAND:
540             if (LOWORD(wParam) == IDC_CLOSE)
541             {
542                 EndDialog(hwndDlg, FALSE);
543                 break;
544             }
545     }
546 
547     return FALSE;
548 }
549 
550 INT_PTR
551 CALLBACK
552 LANStatusUiAdvancedDlg(
553     HWND hwndDlg,
554     UINT uMsg,
555     WPARAM wParam,
556     LPARAM lParam)
557 {
558     WCHAR szBuffer[100] = {0};
559     PROPSHEETPAGE *page;
560     LANSTATUSUI_CONTEXT * pContext;
561     DWORD dwIpAddr;
562 
563 
564     switch (uMsg)
565     {
566         case WM_INITDIALOG:
567             page = (PROPSHEETPAGE*)lParam;
568             pContext = (LANSTATUSUI_CONTEXT*)page->lParam;
569             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
570             if (pContext->DHCPEnabled)
571                 LoadStringW(netshell_hInstance, IDS_ASSIGNED_DHCP, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
572             else
573                 LoadStringW(netshell_hInstance, IDS_ASSIGNED_MANUAL, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
574 
575             szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
576             SendDlgItemMessageW(hwndDlg, IDC_DETAILSTYPE, WM_SETTEXT, 0, (LPARAM)szBuffer);
577 
578 
579             dwIpAddr = ntohl(pContext->IpAddress);
580             swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
581                      THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
582             SendDlgItemMessageW(hwndDlg, IDC_DETAILSIP, WM_SETTEXT, 0, (LPARAM)szBuffer);
583 
584             dwIpAddr = ntohl(pContext->SubnetMask);
585             swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
586                      THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
587             SendDlgItemMessageW(hwndDlg, IDC_DETAILSSUBNET, WM_SETTEXT, 0, (LPARAM)szBuffer);
588 
589             dwIpAddr = ntohl(pContext->Gateway);
590             if (dwIpAddr)
591             {
592                 swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
593                          THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
594                 SendDlgItemMessageW(hwndDlg, IDC_DETAILSGATEWAY, WM_SETTEXT, 0, (LPARAM)szBuffer);
595             }
596             return TRUE;
597         case WM_COMMAND:
598             if (LOWORD(wParam) == IDC_DETAILS)
599             {
600                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
601                 if (pContext)
602                 {
603                     DialogBoxParamW(netshell_hInstance, MAKEINTRESOURCEW(IDD_LAN_NETSTATUSDETAILS), GetParent(hwndDlg),
604                                     LANStatusUiDetailsDlg, (LPARAM)pContext);
605                 }
606             }
607             break;
608         default:
609             break;
610     }
611     return FALSE;
612 }
613 
614 VOID
615 DisableNetworkAdapter(INetConnection * pNet, LANSTATUSUI_CONTEXT * pContext, HWND hwndDlg)
616 {
617     HRESULT hr = pNet->Disconnect();
618     if (FAILED_UNEXPECTEDLY(hr))
619         return;
620 
621     NOTIFYICONDATAW nid;
622 
623     PropSheet_PressButton(GetParent(hwndDlg), PSBTN_CANCEL);
624     ZeroMemory(&nid, sizeof(nid));
625     nid.cbSize = sizeof(nid);
626     nid.uID = pContext->uID;
627     nid.hWnd = pContext->hwndDlg;
628     nid.uFlags = NIF_STATE;
629     nid.dwState = NIS_HIDDEN;
630     nid.dwStateMask = NIS_HIDDEN;
631 
632     Shell_NotifyIconW(NIM_MODIFY, &nid);
633 }
634 
635 
636 INT_PTR
637 CALLBACK
638 LANStatusUiDlg(
639     HWND hwndDlg,
640     UINT uMsg,
641     WPARAM wParam,
642     LPARAM lParam)
643 {
644     PROPSHEETPAGE *page;
645     LANSTATUSUI_CONTEXT * pContext;
646     LPPSHNOTIFY lppsn;
647 
648     switch (uMsg)
649     {
650         case WM_INITDIALOG:
651             page = (PROPSHEETPAGE*)lParam;
652             pContext = (LANSTATUSUI_CONTEXT*)page->lParam;
653             pContext->hwndDlg = hwndDlg;
654             InitializeLANStatusUiDlg(hwndDlg, pContext);
655             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
656             return TRUE;
657         case WM_COMMAND:
658             pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
659             if (LOWORD(wParam) == IDC_STATUS_PROPERTIES)
660             {
661                 if (pContext)
662                 {
663                     ShowNetConnectionProperties(pContext->pNet, GetParent(pContext->hwndDlg));
664                     BringWindowToTop(GetParent(pContext->hwndDlg));
665                 }
666                 break;
667             }
668             else if (LOWORD(wParam) == IDC_ENDISABLE)
669             {
670                 DisableNetworkAdapter(pContext->pNet, pContext, hwndDlg);
671                 break;
672             }
673         case WM_NOTIFY:
674             lppsn = (LPPSHNOTIFY) lParam;
675             if (lppsn->hdr.code == PSN_APPLY || lppsn->hdr.code == PSN_RESET)
676             {
677                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
678                 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
679                 pContext->hwndDlg = NULL;
680                 return TRUE;
681             }
682             break;
683     }
684     return FALSE;
685 }
686 
687 VOID
688 InitializePropertyDialog(
689     LANSTATUSUI_CONTEXT * pContext,
690     NETCON_PROPERTIES * pProperties)
691 {
692     DWORD dwSize, dwAdapterIndex, dwResult;
693     LPOLESTR pStr;
694     IP_ADAPTER_INFO *pAdapterInfo, *pCurAdapter;
695 
696     if (FAILED(StringFromCLSID((CLSID)pProperties->guidId, &pStr)))
697     {
698         return;
699     }
700 
701     /* get the IfTable */
702     dwSize = 0;
703     dwResult = GetAdaptersInfo(NULL, &dwSize);
704     if (dwResult!= ERROR_BUFFER_OVERFLOW)
705     {
706         CoTaskMemFree(pStr);
707         return;
708     }
709 
710     pAdapterInfo = static_cast<PIP_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
711     if (!pAdapterInfo)
712     {
713         CoTaskMemFree(pAdapterInfo);
714         CoTaskMemFree(pStr);
715         return;
716     }
717 
718     if (GetAdaptersInfo(pAdapterInfo, &dwSize) != NO_ERROR)
719     {
720         CoTaskMemFree(pAdapterInfo);
721         CoTaskMemFree(pStr);
722         return;
723     }
724 
725     if (!GetAdapterIndexFromNetCfgInstanceId(pAdapterInfo, pStr, &dwAdapterIndex))
726     {
727         CoTaskMemFree(pAdapterInfo);
728         CoTaskMemFree(pStr);
729         return;
730     }
731 
732     pCurAdapter = pAdapterInfo;
733     while (pCurAdapter->Index != dwAdapterIndex)
734         pCurAdapter = pCurAdapter->Next;
735 
736 
737     pContext->IpAddress = inet_addr(pCurAdapter->IpAddressList.IpAddress.String);
738     pContext->SubnetMask = inet_addr(pCurAdapter->IpAddressList.IpMask.String);
739     pContext->Gateway = inet_addr(pCurAdapter->GatewayList.IpAddress.String);
740     pContext->DHCPEnabled = pCurAdapter->DhcpEnabled;
741     CoTaskMemFree(pStr);
742     CoTaskMemFree(pAdapterInfo);
743     pContext->dwAdapterIndex = dwAdapterIndex;
744 }
745 
746 static int CALLBACK
747 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
748 {
749     // NOTE: This callback is needed to set large icon correctly.
750     HICON hIcon;
751     switch (uMsg)
752     {
753         case PSCB_INITIALIZED:
754         {
755             hIcon = LoadIconW(netshell_hInstance, MAKEINTRESOURCEW(IDI_NET_IDLE));
756             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
757             break;
758         }
759     }
760     return 0;
761 }
762 
763 VOID
764 ShowStatusPropertyDialog(
765     LANSTATUSUI_CONTEXT *pContext,
766     HWND hwndDlg)
767 {
768     HPROPSHEETPAGE hppages[2];
769     PROPSHEETHEADERW pinfo;
770     NETCON_PROPERTIES * pProperties = NULL;
771 
772     ZeroMemory(&pinfo, sizeof(PROPSHEETHEADERW));
773     ZeroMemory(hppages, sizeof(hppages));
774     pinfo.dwSize = sizeof(PROPSHEETHEADERW);
775     pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE | PSH_NOAPPLYNOW |
776                     PSH_USEICONID | PSH_USECALLBACK;
777     pinfo.phpage = hppages;
778     pinfo.hwndParent = hwndDlg;
779     pinfo.hInstance = netshell_hInstance;
780     pinfo.pszIcon = MAKEINTRESOURCEW(IDI_NET_IDLE);
781     pinfo.pfnCallback = PropSheetProc;
782 
783     if (pContext->pNet->GetProperties(&pProperties) == S_OK)
784     {
785         if (pProperties->pszwName)
786         {
787             pinfo.pszCaption = pProperties->pszwName;
788             pinfo.dwFlags |= PSH_PROPTITLE;
789         }
790         InitializePropertyDialog(pContext, pProperties);
791         if (pProperties->MediaType == NCM_LAN && pProperties->Status == NCS_CONNECTED)
792         {
793             hppages[0] = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_LAN_NETSTATUS), LANStatusUiDlg, (LPARAM)pContext, NULL);
794             if (hppages[0])
795                pinfo.nPages++;
796 
797             hppages[pinfo.nPages] = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_LAN_NETSTATUSADVANCED), LANStatusUiAdvancedDlg, (LPARAM)pContext, NULL);
798             if (hppages[pinfo.nPages])
799                pinfo.nPages++;
800 
801             if (pinfo.nPages)
802             {
803                 PropertySheetW(&pinfo);
804             }
805         }
806         else if (pProperties->Status == NCS_MEDIA_DISCONNECTED || pProperties->Status == NCS_DISCONNECTED ||
807                  pProperties->Status == NCS_HARDWARE_DISABLED)
808         {
809             ShowNetConnectionProperties(pContext->pNet, pContext->hwndDlg);
810         }
811 
812         NcFreeNetconProperties(pProperties);
813     }
814 }
815 
816 INT_PTR
817 CALLBACK
818 LANStatusDlg(
819     HWND hwndDlg,
820     UINT uMsg,
821     WPARAM wParam,
822     LPARAM lParam)
823 {
824     LANSTATUSUI_CONTEXT * pContext;
825 
826     switch (uMsg)
827     {
828         case WM_INITDIALOG:
829             pContext = (LANSTATUSUI_CONTEXT *)lParam;
830             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
831             pContext->nIDEvent = SetTimer(hwndDlg, 0xFABC, 1000, NULL);
832             return TRUE;
833         case WM_TIMER:
834             pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
835             if (wParam == (WPARAM)pContext->nIDEvent)
836             {
837                 UpdateLanStatus(pContext->hwndDlg, pContext);
838             }
839             break;
840         case WM_SHOWSTATUSDLG:
841             if (LOWORD(lParam) == WM_LBUTTONDOWN)
842             {
843                 pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
844                 if (!pContext)
845                     break;
846 
847                 if (pContext->hwndDlg)
848                 {
849                     ShowWindow(GetParent(pContext->hwndDlg), SW_SHOW);
850                     BringWindowToTop(GetParent(pContext->hwndDlg));
851                 }
852                 else
853                 {
854                     ShowStatusPropertyDialog(pContext, hwndDlg);
855                 }
856                 break;
857             }
858             break;
859     }
860     return FALSE;
861 }
862 
863 HRESULT
864 CLanStatus::InitializeNetTaskbarNotifications()
865 {
866     NOTIFYICONDATAW nid;
867     HWND hwndDlg;
868     CComPtr<INetConnectionManager> pNetConMan;
869     CComPtr<IEnumNetConnection> pEnumCon;
870     CComPtr<INetConnection> pNetCon;
871     NETCON_PROPERTIES* pProps;
872     HRESULT hr;
873     ULONG Count;
874     ULONG Index;
875     NOTIFICATION_ITEM * pItem, *pLast = NULL;
876     LANSTATUSUI_CONTEXT * pContext;
877 
878     TRACE("InitializeNetTaskbarNotifications\n");
879 
880     if (m_pHead)
881     {
882        pItem = m_pHead;
883        while (pItem)
884        {
885            hr = pItem->pNet->GetProperties(&pProps);
886            if (SUCCEEDED(hr))
887            {
888                 ZeroMemory(&nid, sizeof(nid));
889                 nid.cbSize = sizeof(nid);
890                 nid.uID = pItem->uID;
891                 nid.hWnd = pItem->hwndDlg;
892                 nid.uFlags = NIF_STATE;
893                 if (pProps->dwCharacter & NCCF_SHOW_ICON)
894                     nid.dwState = 0;
895                 else
896                     nid.dwState = NIS_HIDDEN;
897 
898                 nid.dwStateMask = NIS_HIDDEN;
899                 Shell_NotifyIconW(NIM_MODIFY, &nid);
900                 NcFreeNetconProperties(pProps);
901            }
902            pItem = pItem->pNext;
903        }
904        return S_OK;
905     }
906     /* get an instance to of IConnectionManager */
907     hr = CNetConnectionManager_CreateInstance(IID_PPV_ARG(INetConnectionManager, &pNetConMan));
908     if (FAILED_UNEXPECTEDLY(hr))
909         return hr;
910 
911     hr = pNetConMan->EnumConnections(NCME_DEFAULT, &pEnumCon);
912     if (FAILED_UNEXPECTEDLY(hr))
913         return hr;
914 
915     Index = 1;
916     while (TRUE)
917     {
918         hr = pEnumCon->Next(1, &pNetCon, &Count);
919         if (hr != S_OK)
920             break;
921 
922         TRACE("new connection\n");
923         pItem = static_cast<NOTIFICATION_ITEM*>(CoTaskMemAlloc(sizeof(NOTIFICATION_ITEM)));
924         if (!pItem)
925             break;
926 
927         pContext = static_cast<LANSTATUSUI_CONTEXT*>(CoTaskMemAlloc(sizeof(LANSTATUSUI_CONTEXT)));
928         if (!pContext)
929         {
930             CoTaskMemFree(pItem);
931             break;
932         }
933 
934         ZeroMemory(pContext, sizeof(LANSTATUSUI_CONTEXT));
935         pContext->uID = Index;
936         pContext->pNet = pNetCon;
937         pItem->uID = Index;
938         pItem->pNext = NULL;
939         pItem->pNet = pNetCon;
940         pNetCon->AddRef();
941         hwndDlg = CreateDialogParamW(netshell_hInstance, MAKEINTRESOURCEW(IDD_STATUS), NULL, LANStatusDlg, (LPARAM)pContext);
942         if (!hwndDlg)
943         {
944             ERR("CreateDialogParamW failed\n");
945             continue;
946         }
947 
948         ZeroMemory(&nid, sizeof(nid));
949         nid.cbSize = sizeof(nid);
950         nid.uID = Index++;
951         nid.uFlags = NIF_MESSAGE;
952         nid.uVersion = NOTIFYICON_VERSION;
953         nid.uCallbackMessage = WM_SHOWSTATUSDLG;
954         nid.hWnd = hwndDlg;
955 
956         hr = pNetCon->GetProperties(&pProps);
957         if (SUCCEEDED(hr))
958         {
959             CopyMemory(&pItem->guidItem, &pProps->guidId, sizeof(GUID));
960             if (!(pProps->dwCharacter & NCCF_SHOW_ICON))
961             {
962                 nid.dwState = NIS_HIDDEN;
963                 nid.dwStateMask = NIS_HIDDEN;
964                 nid.uFlags |= NIF_STATE;
965             }
966             if (pProps->Status == NCS_MEDIA_DISCONNECTED || pProps->Status == NCS_DISCONNECTED || pProps->Status == NCS_HARDWARE_DISABLED)
967                 nid.hIcon = LoadIcon(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF));
968             else if (pProps->Status == NCS_CONNECTED)
969                 nid.hIcon = LoadIcon(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE));
970 
971             if (nid.hIcon)
972                 nid.uFlags |= NIF_ICON;
973 
974             wcscpy(nid.szTip, pProps->pszwName);
975             nid.uFlags |= NIF_TIP;
976         }
977         pContext->hwndStatusDlg = hwndDlg;
978         pItem->hwndDlg = hwndDlg;
979 
980         if (Shell_NotifyIconW(NIM_ADD, &nid))
981         {
982             if (pLast)
983                 pLast->pNext = pItem;
984             else
985                 m_pHead = pItem;
986 
987             pLast = pItem;
988             Index++;
989         }
990         else
991         {
992             ERR("Shell_NotifyIconW failed\n");
993             CoTaskMemFree(pItem);
994         }
995 
996         if (nid.uFlags & NIF_ICON)
997             DestroyIcon(nid.hIcon);
998     }
999 
1000     m_lpNetMan = pNetConMan;
1001     return S_OK;
1002 }
1003 
1004 HRESULT
1005 CLanStatus::ShowStatusDialogByCLSID(const GUID *pguidCmdGroup)
1006 {
1007     NOTIFICATION_ITEM *pItem;
1008 
1009     pItem = m_pHead;
1010     while (pItem)
1011     {
1012         if (IsEqualGUID(pItem->guidItem, *pguidCmdGroup))
1013         {
1014             SendMessageW(pItem->hwndDlg, WM_SHOWSTATUSDLG, 0, WM_LBUTTONDOWN);
1015             return S_OK;
1016         }
1017         pItem = pItem->pNext;
1018     }
1019 
1020     ERR("not found\n");
1021     return E_FAIL;
1022 }
1023 
1024 HRESULT
1025 WINAPI
1026 CLanStatus::QueryStatus(
1027     const GUID *pguidCmdGroup,
1028     ULONG cCmds,
1029     OLECMD *prgCmds,
1030     OLECMDTEXT *pCmdText)
1031 {
1032     MessageBoxW(NULL, pCmdText->rgwz, L"IOleCommandTarget_fnQueryStatus", MB_OK);
1033     return E_NOTIMPL;
1034 }
1035 
1036 HRESULT
1037 WINAPI
1038 CLanStatus::Exec(
1039     const GUID *pguidCmdGroup,
1040     DWORD nCmdID,
1041     DWORD nCmdexecopt,
1042     VARIANT *pvaIn,
1043     VARIANT *pvaOut)
1044 {
1045     if (pguidCmdGroup)
1046     {
1047         if (IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
1048         {
1049             return InitializeNetTaskbarNotifications();
1050         }
1051         else
1052         {
1053             /* invoke status dialog */
1054             return ShowStatusDialogByCLSID(pguidCmdGroup);
1055         }
1056     }
1057     return S_OK;
1058 }
1059