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