1 /*
2  * PROJECT:     ReactOS ipconfig utility
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        base/applications/network/ipconfig/ipconfig.c
5  * PURPOSE:     Display IP info for net adapters
6  * PROGRAMMERS: Copyright 2005 - 2006 Ged Murphy (gedmurphy@gmail.com)
7  */
8 /*
9  * TODO:
10  * fix renew / release
11  * implement flushdns, registerdns, displaydns, showclassid, setclassid
12  * allow globbing on adapter names
13  */
14 
15 #include <stdarg.h>
16 #include <windef.h>
17 #include <winbase.h>
18 #include <winuser.h>
19 #include <winreg.h>
20 #include <stdio.h>
21 #include <tchar.h>
22 #include <time.h>
23 #include <iphlpapi.h>
24 
25 #include "resource.h"
26 
27 #define GUID_LEN 40
28 
29 HINSTANCE hInstance;
30 HANDLE ProcessHeap;
31 
32 int LoadStringAndOem(HINSTANCE hInst,
33                      UINT uID,
34                      LPTSTR szNode,
35                      int byteSize)
36 {
37     TCHAR *szTmp;
38     int res;
39 
40     szTmp = (LPTSTR)HeapAlloc(ProcessHeap, 0, byteSize);
41     if (szTmp == NULL)
42     {
43         return 0;
44     }
45 
46     res = LoadString(hInst, uID, szTmp, byteSize);
47     CharToOem(szTmp, szNode);
48     HeapFree(ProcessHeap, 0, szTmp);
49     return res;
50 }
51 
52 LPTSTR GetNodeTypeName(UINT NodeType)
53 {
54     static TCHAR szNode[14];
55 
56     switch (NodeType)
57     {
58         case 1:
59             if (!LoadStringAndOem(hInstance, IDS_BCAST, szNode,  sizeof(szNode)))
60                 return NULL;
61             break;
62 
63         case 2:
64             if (!LoadStringAndOem(hInstance, IDS_P2P, szNode,  sizeof(szNode)))
65                 return NULL;
66             break;
67 
68         case 4:
69             if (!LoadStringAndOem(hInstance, IDS_MIXED, szNode,  sizeof(szNode)))
70                 return NULL;
71             break;
72 
73         case 8:
74             if (!LoadStringAndOem(hInstance, IDS_HYBRID, szNode,  sizeof(szNode)))
75                 return NULL;
76             break;
77 
78         default :
79             if (!LoadStringAndOem(hInstance, IDS_UNKNOWN, szNode,  sizeof(szNode)))
80                 return NULL;
81             break;
82     }
83 
84     return szNode;
85 }
86 
87 
88 LPTSTR GetInterfaceTypeName(UINT InterfaceType)
89 {
90     static TCHAR szIntType[25];
91 
92     switch (InterfaceType)
93     {
94         case MIB_IF_TYPE_OTHER:
95             if (!LoadStringAndOem(hInstance, IDS_OTHER, szIntType, sizeof(szIntType)))
96                 return NULL;
97             break;
98 
99         case MIB_IF_TYPE_ETHERNET:
100             if (!LoadStringAndOem(hInstance, IDS_ETH, szIntType, sizeof(szIntType)))
101                 return NULL;
102             break;
103 
104         case MIB_IF_TYPE_TOKENRING:
105             if (!LoadStringAndOem(hInstance, IDS_TOKEN, szIntType, sizeof(szIntType)))
106                 return NULL;
107             break;
108 
109         case MIB_IF_TYPE_FDDI:
110             if (!LoadStringAndOem(hInstance, IDS_FDDI, szIntType, sizeof(szIntType)))
111                 return NULL;
112             break;
113 
114         case MIB_IF_TYPE_PPP:
115             if (!LoadStringAndOem(hInstance, IDS_PPP, szIntType, sizeof(szIntType)))
116                 return NULL;
117             break;
118 
119         case MIB_IF_TYPE_LOOPBACK:
120             if (!LoadStringAndOem(hInstance, IDS_LOOP, szIntType, sizeof(szIntType)))
121                 return NULL;
122             break;
123 
124         case MIB_IF_TYPE_SLIP:
125             if (!LoadStringAndOem(hInstance, IDS_SLIP, szIntType, sizeof(szIntType)))
126                 return NULL;
127             break;
128 
129         default:
130             if (!LoadStringAndOem(hInstance, IDS_UNKNOWN, szIntType, sizeof(szIntType)))
131                 return NULL;
132             break;
133     }
134 
135     return szIntType;
136 }
137 
138 
139 /* print MAC address */
140 PTCHAR PrintMacAddr(PBYTE Mac)
141 {
142     static TCHAR MacAddr[20];
143 
144     _stprintf(MacAddr, _T("%02x-%02x-%02x-%02x-%02x-%02x"),
145         Mac[0], Mac[1], Mac[2], Mac[3], Mac[4],  Mac[5]);
146 
147     return MacAddr;
148 }
149 
150 
151 VOID DoFormatMessage(LONG ErrorCode)
152 {
153     LPVOID lpMsgBuf;
154     //DWORD ErrorCode;
155 
156     if (ErrorCode == 0)
157         ErrorCode = GetLastError();
158 
159     if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
160                         FORMAT_MESSAGE_FROM_SYSTEM |
161                         FORMAT_MESSAGE_IGNORE_INSERTS,
162                       NULL,
163                       ErrorCode,
164                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
165                       (LPTSTR) &lpMsgBuf,
166                       0,
167                       NULL))
168     {
169         _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
170         LocalFree(lpMsgBuf);
171     }
172 }
173 
174 
175 LPTSTR GetConnectionType(LPTSTR lpClass)
176 {
177     HKEY hKey = NULL;
178     LPTSTR ConType = NULL;
179     LPTSTR ConTypeTmp = NULL;
180     TCHAR Path[256];
181     LPTSTR PrePath  = _T("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\");
182     LPTSTR PostPath = _T("\\Connection");
183     DWORD PathSize;
184     DWORD dwType;
185     DWORD dwDataSize;
186 
187     /* don't overflow the buffer */
188     PathSize = lstrlen(PrePath) + lstrlen(lpClass) + lstrlen(PostPath) + 1;
189     if (PathSize >= 255)
190         return NULL;
191 
192     wsprintf(Path, _T("%s%s%s"), PrePath, lpClass, PostPath);
193 
194     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
195                      Path,
196                      0,
197                      KEY_READ,
198                      &hKey) == ERROR_SUCCESS)
199     {
200         if (RegQueryValueEx(hKey,
201                             _T("Name"),
202                             NULL,
203                             &dwType,
204                             NULL,
205                             &dwDataSize) == ERROR_SUCCESS)
206         {
207             ConTypeTmp = (LPTSTR)HeapAlloc(ProcessHeap,
208                                            0,
209                                            dwDataSize);
210 
211             if (ConTypeTmp == NULL)
212                 return NULL;
213 
214             ConType = (LPTSTR)HeapAlloc(ProcessHeap,
215                                         0,
216                                         dwDataSize);
217 
218             if (ConType == NULL)
219             {
220                 HeapFree(ProcessHeap, 0, ConTypeTmp);
221                 return NULL;
222             }
223 
224             if (RegQueryValueEx(hKey,
225                                 _T("Name"),
226                                 NULL,
227                                 &dwType,
228                                 (PBYTE)ConTypeTmp,
229                                 &dwDataSize) != ERROR_SUCCESS)
230             {
231                 HeapFree(ProcessHeap,
232                          0,
233                          ConType);
234 
235                 ConType = NULL;
236             }
237 
238             if (ConType)
239                 CharToOem(ConTypeTmp, ConType);
240             HeapFree(ProcessHeap, 0, ConTypeTmp);
241         }
242     }
243 
244     if (hKey != NULL)
245         RegCloseKey(hKey);
246 
247     return ConType;
248 }
249 
250 
251 LPTSTR GetConnectionDescription(LPTSTR lpClass)
252 {
253     HKEY hBaseKey = NULL;
254     HKEY hClassKey = NULL;
255     LPTSTR lpKeyClass = NULL;
256     LPTSTR lpConDesc = NULL;
257     LPTSTR lpPath = NULL;
258     TCHAR szPrePath[] = _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\");
259     DWORD dwType;
260     DWORD dwDataSize;
261     INT i;
262 
263     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
264                      szPrePath,
265                      0,
266                      KEY_READ,
267                      &hBaseKey) != ERROR_SUCCESS)
268     {
269         return NULL;
270     }
271 
272     for (i = 0; ; i++)
273     {
274         DWORD PathSize;
275         LONG Status;
276         TCHAR szName[10];
277         DWORD NameLen = 9;
278 
279         if ((Status = RegEnumKeyEx(hBaseKey,
280                                    i,
281                                    szName,
282                                    &NameLen,
283                                    NULL,
284                                    NULL,
285                                    NULL,
286                                    NULL)) != ERROR_SUCCESS)
287         {
288             if (Status == ERROR_NO_MORE_ITEMS)
289             {
290                 DoFormatMessage(Status);
291                 lpConDesc = NULL;
292                 goto CLEANUP;
293             }
294             else
295                 continue;
296         }
297 
298         PathSize = lstrlen(szPrePath) + lstrlen(szName) + 1;
299         lpPath = (LPTSTR)HeapAlloc(ProcessHeap,
300                                    0,
301                                    PathSize * sizeof(TCHAR));
302         if (lpPath == NULL)
303             goto CLEANUP;
304 
305         wsprintf(lpPath, _T("%s%s"), szPrePath, szName);
306 
307         //MessageBox(NULL, lpPath, NULL, 0);
308 
309         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
310                          lpPath,
311                          0,
312                          KEY_READ,
313                          &hClassKey) != ERROR_SUCCESS)
314         {
315             goto CLEANUP;
316         }
317 
318         HeapFree(ProcessHeap, 0, lpPath);
319         lpPath = NULL;
320 
321         if (RegQueryValueEx(hClassKey,
322                             _T("NetCfgInstanceId"),
323                             NULL,
324                             &dwType,
325                             NULL,
326                             &dwDataSize) == ERROR_SUCCESS)
327         {
328             lpKeyClass = (LPTSTR)HeapAlloc(ProcessHeap,
329                                            0,
330                                            dwDataSize);
331             if (lpKeyClass == NULL)
332                 goto CLEANUP;
333 
334             if (RegQueryValueEx(hClassKey,
335                                 _T("NetCfgInstanceId"),
336                                 NULL,
337                                 &dwType,
338                                 (PBYTE)lpKeyClass,
339                                 &dwDataSize) != ERROR_SUCCESS)
340             {
341                 HeapFree(ProcessHeap, 0, lpKeyClass);
342                 lpKeyClass = NULL;
343                 continue;
344             }
345         }
346         else
347             continue;
348 
349         if (!lstrcmp(lpClass, lpKeyClass))
350         {
351             HeapFree(ProcessHeap, 0, lpKeyClass);
352             lpKeyClass = NULL;
353 
354             if (RegQueryValueEx(hClassKey,
355                                 _T("DriverDesc"),
356                                 NULL,
357                                 &dwType,
358                                 NULL,
359                                 &dwDataSize) == ERROR_SUCCESS)
360             {
361                 lpConDesc = (LPTSTR)HeapAlloc(ProcessHeap,
362                                               0,
363                                               dwDataSize);
364                 if (lpConDesc == NULL)
365                     goto CLEANUP;
366 
367                 if (RegQueryValueEx(hClassKey,
368                                     _T("DriverDesc"),
369                                     NULL,
370                                     &dwType,
371                                     (PBYTE)lpConDesc,
372                                     &dwDataSize) != ERROR_SUCCESS)
373                 {
374                     HeapFree(ProcessHeap, 0, lpConDesc);
375                     lpConDesc = NULL;
376                     goto CLEANUP;
377                 }
378             }
379             else
380             {
381                 lpConDesc = NULL;
382             }
383 
384             break;
385         }
386     }
387 
388 CLEANUP:
389     if (hBaseKey != NULL)
390         RegCloseKey(hBaseKey);
391     if (hClassKey != NULL)
392         RegCloseKey(hClassKey);
393     if (lpPath != NULL)
394         HeapFree(ProcessHeap, 0, lpPath);
395     if (lpKeyClass != NULL)
396         HeapFree(ProcessHeap, 0, lpKeyClass);
397 
398     return lpConDesc;
399 }
400 
401 
402 VOID ShowInfo(BOOL bAll)
403 {
404     MIB_IFROW mibEntry;
405     PIP_ADAPTER_INFO pAdapterInfo = NULL;
406     PIP_ADAPTER_INFO pAdapter = NULL;
407     ULONG adaptOutBufLen = 0;
408     PFIXED_INFO pFixedInfo = NULL;
409     ULONG netOutBufLen = 0;
410     ULONG ret = 0;
411 
412     /* call GetAdaptersInfo to obtain the adapter info */
413     ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
414     if (ret == ERROR_BUFFER_OVERFLOW)
415     {
416         pAdapterInfo = (IP_ADAPTER_INFO *)HeapAlloc(ProcessHeap, 0, adaptOutBufLen);
417         if (pAdapterInfo == NULL)
418             return;
419 
420         ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
421         if (ret != NO_ERROR)
422         {
423             DoFormatMessage(0);
424             HeapFree(ProcessHeap, 0, pAdapterInfo);
425             return;
426         }
427     }
428     else
429     {
430         if (ret != ERROR_NO_DATA)
431         {
432             DoFormatMessage(0);
433             return;
434         }
435     }
436 
437     /* call GetNetworkParams to obtain the network info */
438     if (GetNetworkParams(pFixedInfo, &netOutBufLen) == ERROR_BUFFER_OVERFLOW)
439     {
440         pFixedInfo = (FIXED_INFO *)HeapAlloc(ProcessHeap, 0, netOutBufLen);
441         if (pFixedInfo == NULL)
442         {
443             if (pAdapterInfo)
444                 HeapFree(ProcessHeap, 0, pAdapterInfo);
445             return;
446         }
447         if (GetNetworkParams(pFixedInfo, &netOutBufLen) != NO_ERROR)
448         {
449             DoFormatMessage(0);
450             if (pAdapterInfo)
451                 HeapFree(ProcessHeap, 0, pAdapterInfo);
452             HeapFree(ProcessHeap, 0, pFixedInfo);
453             return;
454         }
455     }
456     else
457     {
458         if (pAdapterInfo)
459             HeapFree(ProcessHeap, 0, pAdapterInfo);
460         DoFormatMessage(0);
461         return;
462     }
463 
464     pAdapter = pAdapterInfo;
465 
466     _tprintf(_T("\nReactOS IP Configuration\n\n"));
467     if (bAll)
468     {
469         _tprintf(_T("\tHost Name . . . . . . . . . . . . : %s\n"), pFixedInfo->HostName);
470         _tprintf(_T("\tPrimary DNS Suffix. . . . . . . . : \n"));
471         _tprintf(_T("\tNode Type . . . . . . . . . . . . : %s\n"), GetNodeTypeName(pFixedInfo->NodeType));
472         if (pFixedInfo->EnableRouting)
473             _tprintf(_T("\tIP Routing Enabled. . . . . . . . : Yes\n"));
474         else
475             _tprintf(_T("\tIP Routing Enabled. . . . . . . . : No\n"));
476         if (pAdapter && pAdapter->HaveWins)
477             _tprintf(_T("\tWINS Proxy enabled. . . . . . . . : Yes\n"));
478         else
479             _tprintf(_T("\tWINS Proxy enabled. . . . . . . . : No\n"));
480         _tprintf(_T("\tDNS Suffix Search List. . . . . . : %s\n"), pFixedInfo->DomainName);
481     }
482 
483     while (pAdapter)
484     {
485         LPTSTR IntType, myConType;
486         BOOLEAN bConnected = TRUE;
487 
488         mibEntry.dwIndex = pAdapter->Index;
489         GetIfEntry(&mibEntry);
490 
491         IntType = GetInterfaceTypeName(pAdapter->Type);
492         myConType = GetConnectionType(pAdapter->AdapterName);
493 
494         _tprintf(_T("\n%s %s: \n\n"), IntType , myConType);
495 
496         if (myConType != NULL) HeapFree(ProcessHeap, 0, myConType);
497 
498         /* check if the adapter is connected to the media */
499         if (mibEntry.dwOperStatus != MIB_IF_OPER_STATUS_CONNECTED && mibEntry.dwOperStatus != MIB_IF_OPER_STATUS_OPERATIONAL)
500         {
501             bConnected = FALSE;
502             _tprintf(_T("\tMedia State . . . . . . . . . . . : Media disconnected\n"));
503         }
504         else
505         {
506             _tprintf(_T("\tConnection-specific DNS Suffix. . : %s\n"), pFixedInfo->DomainName);
507         }
508 
509         if (bAll)
510         {
511             LPTSTR lpDesc = GetConnectionDescription(pAdapter->AdapterName);
512             _tprintf(_T("\tDescription . . . . . . . . . . . : %s\n"), lpDesc);
513             HeapFree(ProcessHeap, 0, lpDesc);
514             _tprintf(_T("\tPhysical Address. . . . . . . . . : %s\n"), PrintMacAddr(pAdapter->Address));
515             if (bConnected)
516             {
517                 if (pAdapter->DhcpEnabled)
518                     _tprintf(_T("\tDHCP Enabled. . . . . . . . . . . : Yes\n"));
519                 else
520                     _tprintf(_T("\tDHCP Enabled. . . . . . . . . . . : No\n"));
521                 _tprintf(_T("\tAutoconfiguration Enabled . . . . : \n"));
522             }
523         }
524 
525         if (!bConnected)
526         {
527             pAdapter = pAdapter->Next;
528             continue;
529         }
530 
531         _tprintf(_T("\tIP Address. . . . . . . . . . . . : %s\n"), pAdapter->IpAddressList.IpAddress.String);
532         _tprintf(_T("\tSubnet Mask . . . . . . . . . . . : %s\n"), pAdapter->IpAddressList.IpMask.String);
533         if (pAdapter->GatewayList.IpAddress.String[0] != '0')
534             _tprintf(_T("\tDefault Gateway . . . . . . . . . : %s\n"), pAdapter->GatewayList.IpAddress.String);
535         else
536             _tprintf(_T("\tDefault Gateway . . . . . . . . . :\n"));
537 
538         if (bAll)
539         {
540             PIP_ADDR_STRING pIPAddr;
541 
542             if (pAdapter->DhcpEnabled)
543                _tprintf(_T("\tDHCP Server . . . . . . . . . . . : %s\n"), pAdapter->DhcpServer.IpAddress.String);
544 
545             _tprintf(_T("\tDNS Servers . . . . . . . . . . . : "));
546             _tprintf(_T("%s\n"), pFixedInfo->DnsServerList.IpAddress.String);
547             pIPAddr = pFixedInfo->DnsServerList.Next;
548             while (pIPAddr)
549             {
550                 _tprintf(_T("\t\t\t\t\t    %s\n"), pIPAddr ->IpAddress.String );
551                 pIPAddr = pIPAddr->Next;
552             }
553 
554             if (pAdapter->HaveWins)
555             {
556                 _tprintf(_T("\tPrimary WINS Server . . . . . . . : %s\n"), pAdapter->PrimaryWinsServer.IpAddress.String);
557                 _tprintf(_T("\tSecondary WINS Server . . . . . . : %s\n"), pAdapter->SecondaryWinsServer.IpAddress.String);
558             }
559 
560             if (pAdapter->DhcpEnabled && _tcscmp(pAdapter->DhcpServer.IpAddress.String, _T("255.255.255.255")))
561             {
562                 _tprintf(_T("\tLease Obtained. . . . . . . . . . : %s"), _tasctime(localtime(&pAdapter->LeaseObtained)));
563                 _tprintf(_T("\tLease Expires . . . . . . . . . . : %s"), _tasctime(localtime(&pAdapter->LeaseExpires)));
564             }
565         }
566         _tprintf(_T("\n"));
567 
568         pAdapter = pAdapter->Next;
569 
570     }
571 
572     HeapFree(ProcessHeap, 0, pFixedInfo);
573     if (pAdapterInfo)
574         HeapFree(ProcessHeap, 0, pAdapterInfo);
575 }
576 
577 VOID Release(LPTSTR Index)
578 {
579     IP_ADAPTER_INDEX_MAP AdapterInfo;
580     DWORD ret;
581     DWORD i;
582 
583     /* if interface is not given, query GetInterfaceInfo */
584     if (Index == NULL)
585     {
586         PIP_INTERFACE_INFO pInfo = NULL;
587         ULONG ulOutBufLen = 0;
588 
589         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
590         {
591             pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, ulOutBufLen);
592             if (pInfo == NULL)
593                 return;
594 
595             if (GetInterfaceInfo(pInfo, &ulOutBufLen) == NO_ERROR )
596             {
597                 for (i = 0; i < pInfo->NumAdapters; i++)
598                 {
599                     CopyMemory(&AdapterInfo, &pInfo->Adapter[i], sizeof(IP_ADAPTER_INDEX_MAP));
600                     _tprintf(_T("name - %ls\n"), pInfo->Adapter[i].Name);
601 
602                     /* Call IpReleaseAddress to release the IP address on the specified adapter. */
603                     if ((ret = IpReleaseAddress(&AdapterInfo)) != NO_ERROR)
604                     {
605                         _tprintf(_T("\nAn error occured while releasing interface %ls : \n"), AdapterInfo.Name);
606                         DoFormatMessage(ret);
607                     }
608                 }
609 
610                 HeapFree(ProcessHeap, 0, pInfo);
611             }
612             else
613             {
614                 DoFormatMessage(0);
615                 HeapFree(ProcessHeap, 0, pInfo);
616                 return;
617             }
618         }
619         else
620         {
621             DoFormatMessage(0);
622             return;
623         }
624     }
625     else
626     {
627         ;
628         /* FIXME:
629          * we need to be able to release connections by name with support for globbing
630          * i.e. ipconfig /release Eth* will release all cards starting with Eth...
631          *      ipconfig /release *con* will release all cards with 'con' in their name
632          */
633     }
634 }
635 
636 
637 
638 
639 VOID Renew(LPTSTR Index)
640 {
641     IP_ADAPTER_INDEX_MAP AdapterInfo;
642     DWORD i;
643 
644     /* if interface is not given, query GetInterfaceInfo */
645     if (Index == NULL)
646     {
647         PIP_INTERFACE_INFO pInfo;
648         ULONG ulOutBufLen = 0;
649 
650         pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, sizeof(IP_INTERFACE_INFO));
651         if (pInfo == NULL)
652         {
653             _tprintf(_T("memory allocation error"));
654             return;
655         }
656 
657         /* Make an initial call to GetInterfaceInfo to get
658          * the necessary size into the ulOutBufLen variable */
659         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
660         {
661             HeapFree(ProcessHeap, 0, pInfo);
662             pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, ulOutBufLen);
663             if (pInfo == NULL)
664             {
665                 _tprintf(_T("memory allocation error"));
666                 return;
667             }
668         }
669 
670         /* Make a second call to GetInterfaceInfo to get the actual data we want */
671         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == NO_ERROR)
672         {
673             for (i = 0; i < pInfo->NumAdapters; i++)
674             {
675                 CopyMemory(&AdapterInfo, &pInfo->Adapter[i], sizeof(IP_ADAPTER_INDEX_MAP));
676                 _tprintf(_T("name - %ls\n"), pInfo->Adapter[i].Name);
677 
678                 /* Call IpRenewAddress to renew the IP address on the specified adapter. */
679                 if (IpRenewAddress(&AdapterInfo) != NO_ERROR)
680                 {
681                     _tprintf(_T("\nAn error occured while renew interface %s : "), _T("*name*"));
682                     DoFormatMessage(0);
683                 }
684             }
685         }
686         else
687         {
688             _tprintf(_T("\nGetInterfaceInfo failed : "));
689             DoFormatMessage(0);
690         }
691 
692         HeapFree(ProcessHeap, 0, pInfo);
693     }
694     else
695     {
696         ;
697         /* FIXME:
698          * we need to be able to renew connections by name with support for globbing
699          * i.e. ipconfig /renew Eth* will renew all cards starting with Eth...
700          *      ipconfig /renew *con* will renew all cards with 'con' in their name
701          */
702     }
703 }
704 
705 
706 
707 VOID Usage(VOID)
708 {
709     HRSRC hRes;
710     LPTSTR lpUsage;
711     DWORD Size;
712 
713     LPTSTR lpName = (LPTSTR)MAKEINTRESOURCE((IDS_USAGE >> 4) + 1);
714 
715     hRes = FindResource(hInstance,
716                         lpName,
717                         RT_STRING);
718     if (hRes != NULL)
719     {
720         if ((Size = SizeofResource(hInstance,
721                                    hRes)))
722         {
723             lpUsage = (LPTSTR)HeapAlloc(ProcessHeap,
724                                         0,
725                                         Size);
726             if (lpUsage == NULL)
727                 return;
728 
729             if (LoadStringAndOem(hInstance,
730                            IDS_USAGE,
731                            lpUsage,
732                            Size))
733             {
734                 _tprintf(_T("%s"), lpUsage);
735             }
736 
737             HeapFree(ProcessHeap, 0, lpUsage);
738         }
739     }
740 
741 
742 }
743 
744 int main(int argc, char *argv[])
745 {
746     BOOL DoUsage=FALSE;
747     BOOL DoAll=FALSE;
748     BOOL DoRelease=FALSE;
749     BOOL DoRenew=FALSE;
750     BOOL DoFlushdns=FALSE;
751     BOOL DoRegisterdns=FALSE;
752     BOOL DoDisplaydns=FALSE;
753     BOOL DoShowclassid=FALSE;
754     BOOL DoSetclassid=FALSE;
755 
756     hInstance = GetModuleHandle(NULL);
757     ProcessHeap = GetProcessHeap();
758 
759     /* Parse command line for options we have been given. */
760     if ((argc > 1) && (argv[1][0]=='/' || argv[1][0]=='-'))
761     {
762         if (!_tcsicmp(&argv[1][1], _T("?")))
763         {
764             DoUsage = TRUE;
765         }
766         else if (!_tcsnicmp(&argv[1][1], _T("ALL"), _tcslen(&argv[1][1])))
767         {
768            DoAll = TRUE;
769         }
770         else if (!_tcsnicmp(&argv[1][1], _T("RELEASE"), _tcslen(&argv[1][1])))
771         {
772             DoRelease = TRUE;
773         }
774         else if (!_tcsnicmp(&argv[1][1], _T("RENEW"), _tcslen(&argv[1][1])))
775         {
776             DoRenew = TRUE;
777         }
778         else if (!_tcsnicmp(&argv[1][1], _T("FLUSHDNS"), _tcslen(&argv[1][1])))
779         {
780             DoFlushdns = TRUE;
781         }
782         else if (!_tcsnicmp(&argv[1][1], _T("FLUSHREGISTERDNS"), _tcslen(&argv[1][1])))
783         {
784             DoRegisterdns = TRUE;
785         }
786         else if (!_tcsnicmp(&argv[1][1], _T("DISPLAYDNS"), _tcslen(&argv[1][1])))
787         {
788             DoDisplaydns = TRUE;
789         }
790         else if (!_tcsnicmp(&argv[1][1], _T("SHOWCLASSID"), _tcslen(&argv[1][1])))
791         {
792             DoShowclassid = TRUE;
793         }
794         else if (!_tcsnicmp(&argv[1][1], _T("SETCLASSID"), _tcslen(&argv[1][1])))
795         {
796             DoSetclassid = TRUE;
797         }
798     }
799 
800     switch (argc)
801     {
802         case 1:  /* Default behaviour if no options are given*/
803             ShowInfo(FALSE);
804             break;
805         case 2:  /* Process all the options that take no parameters */
806             if (DoUsage)
807                 Usage();
808             else if (DoAll)
809                 ShowInfo(TRUE);
810             else if (DoRelease)
811                 Release(NULL);
812             else if (DoRenew)
813                 Renew(NULL);
814             else if (DoFlushdns)
815                 _tprintf(_T("\nSorry /flushdns is not implemented yet\n"));
816             else if (DoRegisterdns)
817                 _tprintf(_T("\nSorry /registerdns is not implemented yet\n"));
818             else if (DoDisplaydns)
819                 _tprintf(_T("\nSorry /displaydns is not implemented yet\n"));
820             else
821                 Usage();
822             break;
823         case 3: /* Process all the options that can have 1 parameter */
824             if (DoRelease)
825                 _tprintf(_T("\nSorry /release [adapter] is not implemented yet\n"));
826                 //Release(argv[2]);
827             else if (DoRenew)
828                 _tprintf(_T("\nSorry /renew [adapter] is not implemented yet\n"));
829             else if (DoShowclassid)
830                 _tprintf(_T("\nSorry /showclassid adapter is not implemented yet\n"));
831             else if (DoSetclassid)
832                 _tprintf(_T("\nSorry /setclassid adapter is not implemented yet\n"));
833             else
834                 Usage();
835             break;
836         case 4:  /* Process all the options that can have 2 parameters */
837             if (DoSetclassid)
838                 _tprintf(_T("\nSorry /setclassid adapter [classid]is not implemented yet\n"));
839             else
840                 Usage();
841             break;
842         default:
843             Usage();
844     }
845 
846     return 0;
847 }
848