]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
mDNSResponder-87.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / DNSServiceBrowser / Windows / Sources / ChooserDialog.cpp
1 /*
2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: ChooserDialog.cpp,v $
26 Revision 1.2 2004/07/13 21:24:26 rpantos
27 Fix for <rdar://problem/3701120>.
28
29 Revision 1.1 2004/06/18 04:04:36 rpantos
30 Move up one level
31
32 Revision 1.10 2004/04/23 01:19:41 bradley
33 Changed TXT record new line delimiter from \n to \r\n so it works now that it is an edit text.
34
35 Revision 1.9 2004/03/07 05:51:04 bradley
36 Updated service type list table to include all service types from dns-sd.org as of 2004-03-06.
37 Added separate Service Type and Service Description columns so both are show in the window.
38
39 Revision 1.8 2004/01/30 02:56:32 bradley
40 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
41
42 Revision 1.7 2003/12/25 03:42:04 bradley
43 Added login dialog to get username/password when going to FTP sites. Added more services.
44
45 Revision 1.6 2003/10/31 12:18:30 bradley
46 Added display of the resolved host name. Show separate TXT record entries on separate lines.
47
48 Revision 1.5 2003/10/16 09:21:56 bradley
49 Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
50
51 Revision 1.4 2003/10/10 03:41:29 bradley
52 Changed HTTP double-click handling to work with or without the path= prefix in the TXT record.
53
54 Revision 1.3 2003/10/09 19:50:40 bradley
55 Sort service type list by description.
56
57 Revision 1.2 2003/10/09 19:41:29 bradley
58 Changed quit handling to go through normal close path so dialog is freed on quit. Integrated changes
59 from Andrew van der Stock for the addition of an _rfb._tcp service type for a VNC Remote Framebuffer
60 Server for KDE support. Widened service type list to handle larger service type descriptions.
61
62 Revision 1.1 2003/08/21 02:06:47 bradley
63 Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
64
65 Revision 1.7 2003/08/20 06:45:56 bradley
66 Updated for IP address changes in DNSServices. Added support for browsing for Xserve RAID.
67
68 Revision 1.6 2003/08/12 19:56:28 cheshire
69 Update to APSL 2.0
70
71 Revision 1.5 2003/07/13 01:03:55 cheshire
72 Diffs provided by Bob Bradley to provide provide proper display of Unicode names
73
74 Revision 1.4 2003/07/02 21:20:06 cheshire
75 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
76
77 Revision 1.3 2002/09/21 20:44:55 zarzycki
78 Added APSL info
79
80 Revision 1.2 2002/09/20 08:39:21 bradley
81 Make sure each resolved item matches the selected service type to handle resolved that may have
82 been queued up on the Windows Message Loop. Reduce column to fit when scrollbar is present.
83
84 Revision 1.1 2002/09/20 06:12:52 bradley
85 DNSServiceBrowser for Windows
86
87 */
88
89 #include <assert.h>
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <string.h>
93 #include <time.h>
94
95 #include <algorithm>
96 #include <memory>
97
98 #include "stdafx.h"
99
100 #include "DNSServices.h"
101
102 #include "Application.h"
103 #include "AboutDialog.h"
104 #include "LoginDialog.h"
105 #include "Resource.h"
106
107 #include "ChooserDialog.h"
108
109 #ifdef _DEBUG
110 #define new DEBUG_NEW
111 #undef THIS_FILE
112 static char THIS_FILE[] = __FILE__;
113 #endif
114
115 #if 0
116 #pragma mark == Constants ==
117 #endif
118
119 //===========================================================================================================================
120 // Constants
121 //===========================================================================================================================
122
123 // Menus
124
125 enum
126 {
127 kChooserMenuIndexFile = 0,
128 kChooserMenuIndexHelp = 1
129 };
130
131 // Domain List
132
133 #define kDomainListDefaultDomainColumnWidth 164
134
135 // Service List
136
137 #define kServiceListDefaultServiceColumnTypeWidth 146
138 #define kServiceListDefaultServiceColumnDescWidth 230
139
140 // Chooser List
141
142 #define kChooserListDefaultNameColumnWidth 190
143 #define kChooserListDefaultIPColumnWidth 120
144
145 // Windows User Messages
146
147 #define WM_USER_DOMAIN_ADD ( WM_USER + 0x100 )
148 #define WM_USER_DOMAIN_REMOVE ( WM_USER + 0x101 )
149 #define WM_USER_SERVICE_ADD ( WM_USER + 0x102 )
150 #define WM_USER_SERVICE_REMOVE ( WM_USER + 0x103 )
151 #define WM_USER_RESOLVE ( WM_USER + 0x104 )
152
153 #if 0
154 #pragma mark == Constants - Service Table ==
155 #endif
156
157 //===========================================================================================================================
158 // Constants - Service Table
159 //===========================================================================================================================
160
161 struct KnownServiceEntry
162 {
163 const char * serviceType;
164 const char * description;
165 const char * urlScheme;
166 bool useText;
167 };
168
169 static const KnownServiceEntry kKnownServiceTable[] =
170 {
171 { "_accountedge._tcp.", "MYOB AccountEdge", "", false },
172 { "_aecoretech._tcp.", "Apple Application Engineering Services", "", false },
173 { "_afpovertcp._tcp.", "Apple File Sharing (AFP)", "afp://", false },
174 { "_airport._tcp.", "AirPort Base Station", "", false },
175 { "_apple-sasl._tcp.", "Apple Password Server", "", false },
176 { "_aquamon._tcp.", "AquaMon", "", false },
177 { "_async._tcp", "address-o-sync", "", false },
178 { "_auth._tcp.", "Authentication Service", "", false },
179 { "_bootps._tcp.", "Bootstrap Protocol Server", "", false },
180 { "_bousg._tcp.", "Bag Of Unusual Strategy Games", "", false },
181 { "_browse._udp.", "DNS Service Discovery", "", false },
182 { "_cheat._tcp.", "The Cheat", "", false },
183 { "_chess._tcp", "Project Gridlock", "", false },
184 { "_chfts._tcp", "Fluid Theme Server", "", false },
185 { "_clipboard._tcp", "Clipboard Sharing", "", false },
186 { "_contactserver._tcp.", "Now Up-to-Date & Contact", "", false },
187 { "_cvspserver._tcp", "CVS PServer", "", false },
188 { "_cytv._tcp.", "CyTV Network streaming for Elgato EyeTV", "", false },
189 { "_daap._tcp.", "Digital Audio Access Protocol (iTunes)", "daap://", false },
190 { "_distcc._tcp", "Distributed Compiler", "", false },
191 { "_dns-sd._udp", "DNS Service Discovery", "", false },
192 { "_dpap._tcp.", "Digital Picture Access Protocol (iPhoto)", "", false },
193 { "_earphoria._tcp.", "Earphoria", "", false },
194 { "_ecbyesfsgksc._tcp.", "Net Monitor Anti-Piracy Service", "", false },
195 { "_eheap._tcp.", "Interactive Room Software", "", false },
196 { "_embrace._tcp.", "DataEnvoy", "", false },
197 { "_eppc._tcp.", "Remote AppleEvents", "eppc://", false },
198 { "_exec._tcp.", "Remote Process Execution", "", false },
199 { "_facespan._tcp.", "FaceSpan", "", false },
200 { "_fjork._tcp.", "Fjork", "", false },
201 { "_ftp._tcp.", "File Transfer (FTP)", "ftp://", false },
202 { "_ftpcroco._tcp.", "Crocodile FTP Server", "", false },
203 { "_gbs-smp._tcp.", "SnapMail", "", false },
204 { "_gbs-stp._tcp.", "SnapTalk", "", false },
205 { "_grillezvous._tcp.", "Roxio ToastAnywhere(tm) Recorder Sharing", "", false },
206 { "_h323._tcp.", "H.323", "", false },
207 { "_hotwayd._tcp", "Hotwayd", "", false },
208 { "_http._tcp.", "Web Server (HTTP)", "http://", true },
209 { "_hydra._tcp", "SubEthaEdit", "", false },
210 { "_ica-networking._tcp.", "Image Capture Networking", "", false },
211 { "_ichalkboard._tcp.", "iChalk", "", false },
212 { "_ichat._tcp.", "iChat", "ichat://", false },
213 { "_iconquer._tcp.", "iConquer", "", false },
214 { "_imap._tcp.", "Internet Message Access Protocol", "", false },
215 { "_imidi._tcp.", "iMidi", "", false },
216 { "_ipp._tcp.", "Printer (IPP)", "ipp://", false },
217 { "_ishare._tcp.", "iShare", "", false },
218 { "_isparx._tcp.", "iSparx", "", false },
219 { "_istorm._tcp", "iStorm", "", false },
220 { "_iwork._tcp.", "iWork Server", "", false },
221 { "_liaison._tcp.", "Liaison", "", false },
222 { "_login._tcp.", "Remote Login a la Telnet", "", false },
223 { "_lontalk._tcp.", "LonTalk over IP (ANSI 852)", "", false },
224 { "_lonworks._tcp.", "Echelon LNS Remote Client", "", false },
225 { "_macfoh-remote._tcp.", "MacFOH Remote", "", false },
226 { "_moneyworks._tcp.", "MoneyWorks", "", false },
227 { "_mp3sushi._tcp", "MP3 Sushi", "", false },
228 { "_mttp._tcp.", "MenuTunes Sharing", "", false },
229 { "_ncbroadcast._tcp.", "Network Clipboard Broadcasts", "", false },
230 { "_ncdirect._tcp.", "Network Clipboard Direct Transfers", "", false },
231 { "_ncsyncserver._tcp.", "Network Clipboard Sync Server", "", false },
232 { "_newton-dock._tcp.", "Escale", "", false },
233 { "_nfs._tcp", "NFS", "", false },
234 { "_nssocketport._tcp.", "DO over NSSocketPort", "", false },
235 { "_omni-bookmark._tcp.", "OmniWeb", "", false },
236 { "_openbase._tcp.", "OpenBase SQL", "", false },
237 { "_p2pchat._tcp.", "Peer-to-Peer Chat", "", false },
238 { "_pdl-datastream._tcp.", "Printer (PDL)", "pdl://", false },
239 { "_poch._tcp.", "Parallel OperatiOn and Control Heuristic", "", false },
240 { "_pop_2_ambrosia._tcp.", "Pop-Pop", "", false },
241 { "_pop3._tcp", "POP3 Server", "", false },
242 { "_postgresql._tcp", "PostgreSQL Server", "", false },
243 { "_presence._tcp", "iChat AV", "", false },
244 { "_printer._tcp.", "Printer (LPR)", "lpr://", false },
245 { "_ptp._tcp.", "Picture Transfer (PTP)", "ptp://", false },
246 { "_register._tcp", "DNS Service Discovery", "", false },
247 { "_rendezvouspong._tcp", "RendezvousPong", "", false },
248 { "_rfb._tcp.", "Remote Frame Buffer", "", false },
249 { "_riousbprint._tcp.", "Remote I/O USB Printer Protocol", "", false },
250 { "_rtsp._tcp.", "Real Time Stream Control Protocol", "", false },
251 { "_safarimenu._tcp", "Safari Menu", "", false },
252 { "_scone._tcp", "Scone", "", false },
253 { "_sdsharing._tcp.", "Speed Download", "", false },
254 { "_seeCard._tcp.", "seeCard", "", false },
255 { "_services._udp.", "DNS Service Discovery", "", false },
256 { "_shell._tcp.", "like exec, but automatic authentication", "", false },
257 { "_shout._tcp.", "Shout", "", false },
258 { "_shoutcast._tcp", "Nicecast", "", false },
259 { "_smb._tcp.", "Windows File Sharing (SMB)", "smb://", false },
260 { "_soap._tcp.", "Simple Object Access Protocol", "", false },
261 { "_spincrisis._tcp.", "Spin Crisis", "", false },
262 { "_spl-itunes._tcp.", "launchTunes", "", false },
263 { "_spr-itunes._tcp.", "netTunes", "", false },
264 { "_ssh._tcp.", "Secure Shell (SSH)", "ssh://", false },
265 { "_ssscreenshare._tcp", "Screen Sharing", "", false },
266 { "_sge-exec._tcp", "Sun Grid Engine (Execution Host)", "", false },
267 { "_sge-qmaster._tcp", "Sun Grid Engine (Master)", "", false },
268 { "_stickynotes._tcp", "Sticky Notes", "", false },
269 { "_strateges._tcp", "Strateges", "", false },
270 { "_sxqdea._tcp", "Synchronize! Pro X", "", false },
271 { "_sybase-tds._tcp", "Sybase Server", "", false },
272 { "_tce._tcp", "Power Card", "", false },
273 { "_teamlist._tcp", "ARTIS Team Task", "", false },
274 { "_teleport._tcp", "teleport", "", false },
275 { "_telnet._tcp.", "Telnet", "telnet://", false },
276 { "_tftp._tcp.", "Trivial File Transfer (TFTP)", "tftp://", false },
277 { "_tinavigator._tcp.", "TI Navigator", "", false },
278 { "_tivo_servemedia._tcp", "TiVo", "", false },
279 { "_upnp._tcp.", "Universal Plug and Play", "", false },
280 { "_utest._tcp.", "uTest", "", false },
281 { "_vue4rendercow._tcp", "VueProRenderCow", "", false },
282 { "_webdav._tcp.", "WebDAV", "webdav://", false },
283 { "_whamb._tcp.", "Whamb", "", false },
284 { "_workstation._tcp", "Macintosh Manager", "", false },
285 { "_ws._tcp", "Web Services", "", false },
286 { "_xserveraid._tcp.", "Xserve RAID", "xsr://", false },
287 { "_xsync._tcp.", "Xserve RAID Synchronization", "", false },
288
289 { "", "", "", false },
290
291 // Unofficial and invalid service types that will be phased out:
292
293 { "_clipboardsharing._tcp.", "ClipboardSharing", "", false },
294 { "_MacOSXDupSuppress._tcp.", "Mac OS X Duplicate Suppression", "", false },
295 { "_netmonitorserver._tcp.", "Net Monitor Server", "", false },
296 { "_networkclipboard._tcp.", "Network Clipboard", "", false },
297 { "_slimdevices_slimp3_cli._tcp.", "SliMP3 Server Command-Line Interface", "", false },
298 { "_slimdevices_slimp3_http._tcp.", "SliMP3 Server Web Interface", "", false },
299 { "_tieducationalhandhelddevice._tcp.", "TI Connect Manager", "", false },
300 { "_tivo_servemedia._tcp.", "TiVo", "", false },
301
302 { NULL, NULL, NULL, false },
303 };
304
305 #if 0
306 #pragma mark == Structures ==
307 #endif
308
309 //===========================================================================================================================
310 // Structures
311 //===========================================================================================================================
312
313 struct DomainEventInfo
314 {
315 DNSBrowserEventType eventType;
316 CString domain;
317 DNSNetworkAddress ifIP;
318 };
319
320 struct ServiceEventInfo
321 {
322 DNSBrowserEventType eventType;
323 std::string name;
324 std::string type;
325 std::string domain;
326 DNSNetworkAddress ifIP;
327 };
328
329 #if 0
330 #pragma mark == Prototypes ==
331 #endif
332
333 //===========================================================================================================================
334 // Prototypes
335 //===========================================================================================================================
336
337 static void
338 BrowserCallBack(
339 void * inContext,
340 DNSBrowserRef inRef,
341 DNSStatus inStatusCode,
342 const DNSBrowserEvent * inEvent );
343
344 static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString );
345
346 static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject );
347 static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 );
348
349 #if 0
350 #pragma mark == Message Map ==
351 #endif
352
353 //===========================================================================================================================
354 // Message Map
355 //===========================================================================================================================
356
357 BEGIN_MESSAGE_MAP(ChooserDialog, CDialog)
358 //{{AFX_MSG_MAP(ChooserDialog)
359 ON_WM_SYSCOMMAND()
360 ON_NOTIFY(LVN_ITEMCHANGED, IDC_DOMAIN_LIST, OnDomainListChanged)
361 ON_NOTIFY(LVN_ITEMCHANGED, IDC_SERVICE_LIST, OnServiceListChanged)
362 ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHOOSER_LIST, OnChooserListChanged)
363 ON_NOTIFY(NM_DBLCLK, IDC_CHOOSER_LIST, OnChooserListDoubleClick)
364 ON_COMMAND(ID_HELP_ABOUT, OnAbout)
365 ON_WM_INITMENUPOPUP()
366 ON_WM_ACTIVATE()
367 ON_COMMAND(ID_FILE_CLOSE, OnFileClose)
368 ON_COMMAND(ID_FILE_EXIT, OnExit)
369 ON_WM_CLOSE()
370 ON_WM_NCDESTROY()
371 //}}AFX_MSG_MAP
372 ON_MESSAGE( WM_USER_DOMAIN_ADD, OnDomainAdd )
373 ON_MESSAGE( WM_USER_DOMAIN_REMOVE, OnDomainRemove )
374 ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
375 ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
376 ON_MESSAGE( WM_USER_RESOLVE, OnResolve )
377 END_MESSAGE_MAP()
378
379 #if 0
380 #pragma mark == Routines ==
381 #endif
382
383 //===========================================================================================================================
384 // ChooserDialog
385 //===========================================================================================================================
386
387 ChooserDialog::ChooserDialog( CWnd *inParent )
388 : CDialog( ChooserDialog::IDD, inParent)
389 {
390 //{{AFX_DATA_INIT(ChooserDialog)
391 // NOTE: the ClassWizard will add member initialization here
392 //}}AFX_DATA_INIT
393
394 // Load menu accelerator table.
395
396 mMenuAcceleratorTable = ::LoadAccelerators( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_CHOOSER_DIALOG_MENU_ACCELERATORS ) );
397 assert( mMenuAcceleratorTable );
398
399 mBrowser = NULL;
400 mIsServiceBrowsing = false;
401 }
402
403 //===========================================================================================================================
404 // ~ChooserDialog
405 //===========================================================================================================================
406
407 ChooserDialog::~ChooserDialog( void )
408 {
409 if( mBrowser )
410 {
411 DNSStatus err;
412
413 err = DNSBrowserRelease( mBrowser, 0 );
414 assert( err == kDNSNoErr );
415 }
416 }
417
418 //===========================================================================================================================
419 // DoDataExchange
420 //===========================================================================================================================
421
422 void ChooserDialog::DoDataExchange( CDataExchange *pDX )
423 {
424 CDialog::DoDataExchange(pDX);
425
426 //{{AFX_DATA_MAP(ChooserDialog)
427 DDX_Control(pDX, IDC_SERVICE_LIST, mServiceList);
428 DDX_Control(pDX, IDC_DOMAIN_LIST, mDomainList);
429 DDX_Control(pDX, IDC_CHOOSER_LIST, mChooserList);
430 //}}AFX_DATA_MAP
431 }
432
433 //===========================================================================================================================
434 // OnInitDialog
435 //===========================================================================================================================
436
437 BOOL ChooserDialog::OnInitDialog( void )
438 {
439 HICON icon;
440 BOOL result;
441 CString tempString;
442 DNSStatus err;
443
444 // Initialize our parent.
445
446 CDialog::OnInitDialog();
447
448 // Set up the window icon.
449
450 icon = AfxGetApp()->LoadIcon( IDR_MAIN_ICON );
451 assert( icon );
452 if( icon )
453 {
454 SetIcon( icon, TRUE ); // Set big icon
455 SetIcon( icon, FALSE ); // Set small icon
456 }
457
458 // Set up the Domain List.
459
460 result = tempString.LoadString( IDS_CHOOSER_DOMAIN_COLUMN_NAME );
461 assert( result );
462 mDomainList.InsertColumn( 0, tempString, LVCFMT_LEFT, kDomainListDefaultDomainColumnWidth );
463
464 // Set up the Service List.
465
466 result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_TYPE );
467 assert( result );
468 mServiceList.InsertColumn( 0, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnTypeWidth );
469
470 result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_DESC );
471 assert( result );
472 mServiceList.InsertColumn( 1, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnDescWidth );
473
474 PopulateServicesList();
475
476 // Set up the Chooser List.
477
478 result = tempString.LoadString( IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME );
479 assert( result );
480 mChooserList.InsertColumn( 0, tempString, LVCFMT_LEFT, kChooserListDefaultNameColumnWidth );
481
482 result = tempString.LoadString( IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME );
483 assert( result );
484 mChooserList.InsertColumn( 1, tempString, LVCFMT_LEFT, kChooserListDefaultIPColumnWidth );
485
486 // Set up the other controls.
487
488 UpdateInfoDisplay();
489
490 // Start browsing for domains.
491
492 err = DNSBrowserCreate( 0, BrowserCallBack, this, &mBrowser );
493 assert( err == kDNSNoErr );
494
495 err = DNSBrowserStartDomainSearch( mBrowser, 0 );
496 assert( err == kDNSNoErr );
497
498 return( true );
499 }
500
501 //===========================================================================================================================
502 // OnFileClose
503 //===========================================================================================================================
504
505 void ChooserDialog::OnFileClose()
506 {
507 OnClose();
508 }
509
510 //===========================================================================================================================
511 // OnActivate
512 //===========================================================================================================================
513
514 void ChooserDialog::OnActivate( UINT nState, CWnd* pWndOther, BOOL bMinimized )
515 {
516 // Always make the active window the "main" window so modal dialogs work better and the app quits after closing
517 // the last window.
518
519 gApp.m_pMainWnd = this;
520
521 CDialog::OnActivate(nState, pWndOther, bMinimized);
522 }
523
524 //===========================================================================================================================
525 // PostNcDestroy
526 //===========================================================================================================================
527
528 void ChooserDialog::PostNcDestroy()
529 {
530 // Call the base class to do the normal cleanup.
531
532 delete this;
533 }
534
535 //===========================================================================================================================
536 // PreTranslateMessage
537 //===========================================================================================================================
538
539 BOOL ChooserDialog::PreTranslateMessage(MSG* pMsg)
540 {
541 BOOL result;
542
543 result = false;
544 assert( mMenuAcceleratorTable );
545 if( mMenuAcceleratorTable )
546 {
547 result = ::TranslateAccelerator( m_hWnd, mMenuAcceleratorTable, pMsg );
548 }
549 if( !result )
550 {
551 result = CDialog::PreTranslateMessage( pMsg );
552 }
553 return( result );
554 }
555
556 //===========================================================================================================================
557 // OnInitMenuPopup
558 //===========================================================================================================================
559
560 void ChooserDialog::OnInitMenuPopup( CMenu *pPopupMenu, UINT nIndex, BOOL bSysMenu )
561 {
562 CDialog::OnInitMenuPopup( pPopupMenu, nIndex, bSysMenu );
563
564 switch( nIndex )
565 {
566 case kChooserMenuIndexFile:
567 break;
568
569 case kChooserMenuIndexHelp:
570 break;
571
572 default:
573 break;
574 }
575 }
576
577 //===========================================================================================================================
578 // OnExit
579 //===========================================================================================================================
580
581 void ChooserDialog::OnExit()
582 {
583 OnClose();
584 }
585
586 //===========================================================================================================================
587 // OnAbout
588 //===========================================================================================================================
589
590 void ChooserDialog::OnAbout()
591 {
592 AboutDialog dialog;
593
594 dialog.DoModal();
595 }
596
597 //===========================================================================================================================
598 // OnSysCommand
599 //===========================================================================================================================
600
601 void ChooserDialog::OnSysCommand( UINT inID, LPARAM inParam )
602 {
603 CDialog::OnSysCommand( inID, inParam );
604 }
605
606 //===========================================================================================================================
607 // OnClose
608 //===========================================================================================================================
609
610 void ChooserDialog::OnClose()
611 {
612 StopBrowsing();
613
614 gApp.m_pMainWnd = this;
615 DestroyWindow();
616 }
617
618 //===========================================================================================================================
619 // OnNcDestroy
620 //===========================================================================================================================
621
622 void ChooserDialog::OnNcDestroy()
623 {
624 gApp.m_pMainWnd = this;
625
626 CDialog::OnNcDestroy();
627 }
628
629 //===========================================================================================================================
630 // OnDomainListChanged
631 //===========================================================================================================================
632
633 void ChooserDialog::OnDomainListChanged( NMHDR *pNMHDR, LRESULT *pResult )
634 {
635 UNUSED_ALWAYS( pNMHDR );
636
637 // Domain list changes have similar effects to service list changes so reuse that code path by calling it here.
638
639 OnServiceListChanged( NULL, NULL );
640
641 *pResult = 0;
642 }
643
644 //===========================================================================================================================
645 // OnServiceListChanged
646 //===========================================================================================================================
647
648 void ChooserDialog::OnServiceListChanged( NMHDR *pNMHDR, LRESULT *pResult )
649 {
650 int selectedType;
651 int selectedDomain;
652
653 UNUSED_ALWAYS( pNMHDR );
654
655 // Stop any existing service search.
656
657 StopBrowsing();
658
659 // If a domain and service type are selected, start searching for the service type on the domain.
660
661 selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
662 selectedDomain = mDomainList.GetNextItem( -1, LVNI_SELECTED );
663
664 if( ( selectedType >= 0 ) && ( selectedDomain >= 0 ) )
665 {
666 CString s;
667 std::string utf8;
668 const char * type;
669
670 s = mDomainList.GetItemText( selectedDomain, 0 );
671 StringObjectToUTF8String( s, utf8 );
672 type = mServiceTypes[ selectedType ].serviceType.c_str();
673 if( *type != '\0' )
674 {
675 StartBrowsing( type, utf8.c_str() );
676 }
677 }
678
679 if( pResult )
680 {
681 *pResult = 0;
682 }
683 }
684
685 //===========================================================================================================================
686 // OnChooserListChanged
687 //===========================================================================================================================
688
689 void ChooserDialog::OnChooserListChanged( NMHDR *pNMHDR, LRESULT *pResult )
690 {
691 UNUSED_ALWAYS( pNMHDR );
692
693 UpdateInfoDisplay();
694 *pResult = 0;
695 }
696
697 //===========================================================================================================================
698 // OnChooserListDoubleClick
699 //===========================================================================================================================
700
701 void ChooserDialog::OnChooserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
702 {
703 int selectedItem;
704
705 UNUSED_ALWAYS( pNMHDR );
706
707 // Display the service instance if it is selected. Otherwise, clear all the info.
708
709 selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
710 if( selectedItem >= 0 )
711 {
712 ServiceInstanceInfo * p;
713 CString url;
714 const KnownServiceEntry * service;
715
716 assert( selectedItem < (int) mServiceInstances.size() );
717 p = &mServiceInstances[ selectedItem ];
718
719 // Search for a known service type entry that matches.
720
721 for( service = kKnownServiceTable; service->serviceType; ++service )
722 {
723 if( p->type == service->serviceType )
724 {
725 break;
726 }
727 }
728 if( service->serviceType )
729 {
730 const char * text;
731
732 // Create a URL representing the service instance.
733
734 if( strcmp( service->serviceType, "_smb._tcp." ) == 0 )
735 {
736 // Special case for SMB (no port number).
737
738 url.Format( TEXT( "%s%s/" ), service->urlScheme, (const char *) p->ip.c_str() );
739 }
740 else if( strcmp( service->serviceType, "_ftp._tcp." ) == 0 )
741 {
742 // Special case for FTP to get login info.
743
744 LoginDialog dialog;
745 CString username;
746 CString password;
747
748 if( !dialog.GetLogin( username, password ) )
749 {
750 goto exit;
751 }
752
753 // Build URL in the following format:
754 //
755 // ftp://[username[:password]@]<ip>
756
757 url += service->urlScheme;
758 if( username.GetLength() > 0 )
759 {
760 url += username;
761 if( password.GetLength() > 0 )
762 {
763 url += ':';
764 url += password;
765 }
766 url += '@';
767 }
768 url += p->ip.c_str();
769 }
770 else if( strcmp( service->serviceType, "_http._tcp." ) == 0 )
771 {
772 // Special case for HTTP to exclude "path=" if present.
773
774 text = service->useText ? p->text.c_str() : "";
775 if( strncmp( text, "path=", 5 ) == 0 )
776 {
777 text += 5;
778 }
779 if( *text != '/' )
780 {
781 url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
782 }
783 else
784 {
785 url.Format( TEXT( "%s%s%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
786 }
787 }
788 else
789 {
790 text = service->useText ? p->text.c_str() : "";
791 url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
792 }
793
794 // Let the system open the URL in the correct app.
795
796 {
797 CWaitCursor waitCursor;
798
799 ShellExecute( NULL, TEXT( "open" ), url, TEXT( "" ), TEXT( "c:\\" ), SW_SHOWNORMAL );
800 }
801 }
802 }
803
804 exit:
805 *pResult = 0;
806 }
807
808 //===========================================================================================================================
809 // OnCancel
810 //===========================================================================================================================
811
812 void ChooserDialog::OnCancel()
813 {
814 // Do nothing.
815 }
816
817 //===========================================================================================================================
818 // PopulateServicesList
819 //===========================================================================================================================
820
821 void ChooserDialog::PopulateServicesList( void )
822 {
823 ServiceTypeVector::iterator i;
824 CString type;
825 CString desc;
826 std::string tmp;
827
828 // Add a fixed list of known services.
829
830 if( mServiceTypes.empty() )
831 {
832 const KnownServiceEntry * service;
833
834 for( service = kKnownServiceTable; service->serviceType; ++service )
835 {
836 ServiceTypeInfo info;
837
838 info.serviceType = service->serviceType;
839 info.description = service->description;
840 info.urlScheme = service->urlScheme;
841 mServiceTypes.push_back( info );
842 }
843 }
844
845 // Add each service to the list.
846
847 for( i = mServiceTypes.begin(); i != mServiceTypes.end(); ++i )
848 {
849 const char * p;
850 const char * q;
851
852 p = ( *i ).serviceType.c_str();
853 if( *p == '_' ) ++p; // Skip leading '_'.
854 q = strchr( p, '.' ); // Find first '.'.
855 if( q ) tmp.assign( p, (size_t)( q - p ) ); // Use only up to the first '.'.
856 else tmp.assign( p ); // No '.' so use the entire string.
857 UTF8StringToStringObject( tmp.c_str(), type );
858 UTF8StringToStringObject( ( *i ).description.c_str(), desc );
859
860 int n;
861
862 n = mServiceList.GetItemCount();
863 mServiceList.InsertItem( n, type );
864 mServiceList.SetItemText( n, 1, desc );
865 }
866
867 // Select the first service type by default.
868
869 if( !mServiceTypes.empty() )
870 {
871 mServiceList.SetItemState( 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
872 }
873 }
874
875 //===========================================================================================================================
876 // UpdateInfoDisplay
877 //===========================================================================================================================
878
879 void ChooserDialog::UpdateInfoDisplay( void )
880 {
881 int selectedItem;
882 std::string name;
883 CString s;
884 std::string ip;
885 std::string ifIP;
886 std::string text;
887 std::string textNewLines;
888 std::string hostName;
889 CWnd * item;
890 std::string::iterator i;
891
892 // Display the service instance if it is selected. Otherwise, clear all the info.
893
894 selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
895 if( selectedItem >= 0 )
896 {
897 ServiceInstanceInfo * p;
898
899 assert( selectedItem < (int) mServiceInstances.size() );
900 p = &mServiceInstances[ selectedItem ];
901
902 name = p->name;
903 ip = p->ip;
904 ifIP = p->ifIP;
905 text = p->text;
906 hostName = p->hostName;
907
908 // Sync up the list items with the actual data (IP address may change).
909
910 UTF8StringToStringObject( ip.c_str(), s );
911 mChooserList.SetItemText( selectedItem, 1, s );
912 }
913
914 // Name
915
916 item = (CWnd *) this->GetDlgItem( IDC_INFO_NAME_TEXT );
917 assert( item );
918 UTF8StringToStringObject( name.c_str(), s );
919 item->SetWindowText( s );
920
921 // IP
922
923 item = (CWnd *) this->GetDlgItem( IDC_INFO_IP_TEXT );
924 assert( item );
925 UTF8StringToStringObject( ip.c_str(), s );
926 item->SetWindowText( s );
927
928 // Interface
929
930 item = (CWnd *) this->GetDlgItem( IDC_INFO_INTERFACE_TEXT );
931 assert( item );
932 UTF8StringToStringObject( ifIP.c_str(), s );
933 item->SetWindowText( s );
934
935
936 item = (CWnd *) this->GetDlgItem( IDC_INFO_HOST_NAME_TEXT );
937 assert( item );
938 UTF8StringToStringObject( hostName.c_str(), s );
939 item->SetWindowText( s );
940
941 // Text
942
943 item = (CWnd *) this->GetDlgItem( IDC_INFO_TEXT_TEXT );
944 assert( item );
945 for( i = text.begin(); i != text.end(); ++i )
946 {
947 if( *i == '\1' )
948 {
949 textNewLines += "\r\n";
950 }
951 else
952 {
953 textNewLines += *i;
954 }
955 }
956 UTF8StringToStringObject( textNewLines.c_str(), s );
957 item->SetWindowText( s );
958 }
959
960 #if 0
961 #pragma mark -
962 #endif
963
964 //===========================================================================================================================
965 // OnDomainAdd
966 //===========================================================================================================================
967
968 LONG ChooserDialog::OnDomainAdd( WPARAM inWParam, LPARAM inLParam )
969 {
970 DomainEventInfo * p;
971 std::auto_ptr < DomainEventInfo > pAutoPtr;
972 int n;
973 int i;
974 CString domain;
975 CString s;
976 bool found;
977
978 UNUSED_ALWAYS( inWParam );
979
980 assert( inLParam );
981 p = reinterpret_cast <DomainEventInfo *> ( inLParam );
982 pAutoPtr.reset( p );
983
984 // Search to see if we already know about this domain. If not, add it to the list.
985
986 found = false;
987 domain = p->domain;
988 n = mDomainList.GetItemCount();
989 for( i = 0; i < n; ++i )
990 {
991 s = mDomainList.GetItemText( i, 0 );
992 if( s == domain )
993 {
994 found = true;
995 break;
996 }
997 }
998 if( !found )
999 {
1000 int selectedItem;
1001
1002 mDomainList.InsertItem( n, domain );
1003
1004 // If no domains are selected and the domain being added is a default domain, select it.
1005
1006 selectedItem = mDomainList.GetNextItem( -1, LVNI_SELECTED );
1007 if( ( selectedItem < 0 ) && ( p->eventType == kDNSBrowserEventTypeAddDefaultDomain ) )
1008 {
1009 mDomainList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
1010 }
1011 }
1012 return( 0 );
1013 }
1014
1015 //===========================================================================================================================
1016 // OnDomainRemove
1017 //===========================================================================================================================
1018
1019 LONG ChooserDialog::OnDomainRemove( WPARAM inWParam, LPARAM inLParam )
1020 {
1021 DomainEventInfo * p;
1022 std::auto_ptr < DomainEventInfo > pAutoPtr;
1023 int n;
1024 int i;
1025 CString domain;
1026 CString s;
1027 bool found;
1028
1029 UNUSED_ALWAYS( inWParam );
1030
1031 assert( inLParam );
1032 p = reinterpret_cast <DomainEventInfo *> ( inLParam );
1033 pAutoPtr.reset( p );
1034
1035 // Search to see if we know about this domain. If so, remove it from the list.
1036
1037 found = false;
1038 domain = p->domain;
1039 n = mDomainList.GetItemCount();
1040 for( i = 0; i < n; ++i )
1041 {
1042 s = mDomainList.GetItemText( i, 0 );
1043 if( s == domain )
1044 {
1045 found = true;
1046 break;
1047 }
1048 }
1049 if( found )
1050 {
1051 mDomainList.DeleteItem( i );
1052 }
1053 return( 0 );
1054 }
1055
1056 //===========================================================================================================================
1057 // OnServiceAdd
1058 //===========================================================================================================================
1059
1060 LONG ChooserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
1061 {
1062 ServiceEventInfo * p;
1063 std::auto_ptr < ServiceEventInfo > pAutoPtr;
1064
1065 UNUSED_ALWAYS( inWParam );
1066
1067 assert( inLParam );
1068 p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
1069 pAutoPtr.reset( p );
1070
1071 return( 0 );
1072 }
1073
1074 //===========================================================================================================================
1075 // OnServiceRemove
1076 //===========================================================================================================================
1077
1078 LONG ChooserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
1079 {
1080 ServiceEventInfo * p;
1081 std::auto_ptr < ServiceEventInfo > pAutoPtr;
1082 bool found;
1083 int n;
1084 int i;
1085
1086 UNUSED_ALWAYS( inWParam );
1087
1088 assert( inLParam );
1089 p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
1090 pAutoPtr.reset( p );
1091
1092 // Search to see if we know about this service instance. If so, remove it from the list.
1093
1094 found = false;
1095 n = (int) mServiceInstances.size();
1096 for( i = 0; i < n; ++i )
1097 {
1098 ServiceInstanceInfo * q;
1099
1100 // If the name, type, domain, and interface match, treat it as the same service instance.
1101
1102 q = &mServiceInstances[ i ];
1103 if( ( p->name == q->name ) &&
1104 ( p->type == q->type ) &&
1105 ( p->domain == q->domain ) )
1106 {
1107 found = true;
1108 break;
1109 }
1110 }
1111 if( found )
1112 {
1113 mChooserList.DeleteItem( i );
1114 assert( i < (int) mServiceInstances.size() );
1115 mServiceInstances.erase( mServiceInstances.begin() + i );
1116 }
1117 return( 0 );
1118 }
1119
1120 //===========================================================================================================================
1121 // OnResolve
1122 //===========================================================================================================================
1123
1124 LONG ChooserDialog::OnResolve( WPARAM inWParam, LPARAM inLParam )
1125 {
1126 ServiceInstanceInfo * p;
1127 std::auto_ptr < ServiceInstanceInfo > pAutoPtr;
1128 int selectedType;
1129 int n;
1130 int i;
1131 bool found;
1132
1133 UNUSED_ALWAYS( inWParam );
1134
1135 assert( inLParam );
1136 p = reinterpret_cast <ServiceInstanceInfo *> ( inLParam );
1137 pAutoPtr.reset( p );
1138
1139 // Make sure it is for an item of the correct type. This handles any resolves that may have been queued up.
1140
1141 selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
1142 assert( selectedType >= 0 );
1143 if( selectedType >= 0 )
1144 {
1145 assert( selectedType <= (int) mServiceTypes.size() );
1146 if( p->type != mServiceTypes[ selectedType ].serviceType )
1147 {
1148 goto exit;
1149 }
1150 }
1151
1152 // Search to see if we know about this service instance. If so, update its info. Otherwise, add it to the list.
1153
1154 found = false;
1155 n = (int) mServiceInstances.size();
1156 for( i = 0; i < n; ++i )
1157 {
1158 ServiceInstanceInfo * q;
1159
1160 // If the name, type, domain, and interface matches, treat it as the same service instance.
1161
1162 q = &mServiceInstances[ i ];
1163 if( ( p->name == q->name ) &&
1164 ( p->type == q->type ) &&
1165 ( p->domain == q->domain ) &&
1166 ( p->ifIP == q->ifIP ) )
1167 {
1168 found = true;
1169 break;
1170 }
1171 }
1172 if( found )
1173 {
1174 mServiceInstances[ i ] = *p;
1175 }
1176 else
1177 {
1178 CString s;
1179
1180 mServiceInstances.push_back( *p );
1181 UTF8StringToStringObject( p->name.c_str(), s );
1182 mChooserList.InsertItem( n, s );
1183
1184 UTF8StringToStringObject( p->ip.c_str(), s );
1185 mChooserList.SetItemText( n, 1, s );
1186
1187 // If this is the only item, select it.
1188
1189 if( n == 0 )
1190 {
1191 mChooserList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
1192 }
1193 }
1194 UpdateInfoDisplay();
1195
1196 exit:
1197 return( 0 );
1198 }
1199
1200 //===========================================================================================================================
1201 // StartBrowsing
1202 //===========================================================================================================================
1203
1204 void ChooserDialog::StartBrowsing( const char *inType, const char *inDomain )
1205 {
1206 DNSStatus err;
1207
1208 assert( mServiceInstances.empty() );
1209 assert( mChooserList.GetItemCount() == 0 );
1210 assert( !mIsServiceBrowsing );
1211
1212 mChooserList.DeleteAllItems();
1213 mServiceInstances.clear();
1214
1215 mIsServiceBrowsing = true;
1216 err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, inType, inDomain );
1217 assert( err == kDNSNoErr );
1218 }
1219
1220 //===========================================================================================================================
1221 // StopBrowsing
1222 //===========================================================================================================================
1223
1224 void ChooserDialog::StopBrowsing( void )
1225 {
1226 // If searching, stop.
1227
1228 if( mIsServiceBrowsing )
1229 {
1230 DNSStatus err;
1231
1232 mIsServiceBrowsing = false;
1233 err = DNSBrowserStopServiceSearch( mBrowser, 0 );
1234 assert( err == kDNSNoErr );
1235 }
1236
1237 // Remove all service instances.
1238
1239 mChooserList.DeleteAllItems();
1240 assert( mChooserList.GetItemCount() == 0 );
1241 mServiceInstances.clear();
1242 assert( mServiceInstances.empty() );
1243 UpdateInfoDisplay();
1244 }
1245
1246 #if 0
1247 #pragma mark -
1248 #endif
1249
1250 //===========================================================================================================================
1251 // BrowserCallBack
1252 //===========================================================================================================================
1253
1254 static void
1255 BrowserCallBack(
1256 void * inContext,
1257 DNSBrowserRef inRef,
1258 DNSStatus inStatusCode,
1259 const DNSBrowserEvent * inEvent )
1260 {
1261 ChooserDialog * dialog;
1262 UINT message;
1263 BOOL posted;
1264
1265 UNUSED_ALWAYS( inStatusCode );
1266 UNUSED_ALWAYS( inRef );
1267
1268 // Check parameters.
1269
1270 assert( inContext );
1271 dialog = reinterpret_cast <ChooserDialog *> ( inContext );
1272
1273 try
1274 {
1275 switch( inEvent->type )
1276 {
1277 case kDNSBrowserEventTypeRelease:
1278 break;
1279
1280 // Domains
1281
1282 case kDNSBrowserEventTypeAddDomain:
1283 case kDNSBrowserEventTypeAddDefaultDomain:
1284 case kDNSBrowserEventTypeRemoveDomain:
1285 {
1286 DomainEventInfo * domain;
1287 std::auto_ptr < DomainEventInfo > domainAutoPtr;
1288
1289 domain = new DomainEventInfo;
1290 domainAutoPtr.reset( domain );
1291
1292 domain->eventType = inEvent->type;
1293 domain->domain = inEvent->data.addDomain.domain;
1294 domain->ifIP = inEvent->data.addDomain.interfaceIP;
1295
1296 message = ( inEvent->type == kDNSBrowserEventTypeRemoveDomain ) ? WM_USER_DOMAIN_REMOVE : WM_USER_DOMAIN_ADD;
1297 posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) domain );
1298 assert( posted );
1299 if( posted )
1300 {
1301 domainAutoPtr.release();
1302 }
1303 break;
1304 }
1305
1306 // Services
1307
1308 case kDNSBrowserEventTypeAddService:
1309 case kDNSBrowserEventTypeRemoveService:
1310 {
1311 ServiceEventInfo * service;
1312 std::auto_ptr < ServiceEventInfo > serviceAutoPtr;
1313
1314 service = new ServiceEventInfo;
1315 serviceAutoPtr.reset( service );
1316
1317 service->eventType = inEvent->type;
1318 service->name = inEvent->data.addService.name;
1319 service->type = inEvent->data.addService.type;
1320 service->domain = inEvent->data.addService.domain;
1321 service->ifIP = inEvent->data.addService.interfaceIP;
1322
1323 message = ( inEvent->type == kDNSBrowserEventTypeAddService ) ? WM_USER_SERVICE_ADD : WM_USER_SERVICE_REMOVE;
1324 posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) service );
1325 assert( posted );
1326 if( posted )
1327 {
1328 serviceAutoPtr.release();
1329 }
1330 break;
1331 }
1332
1333 // Resolves
1334
1335 case kDNSBrowserEventTypeResolved:
1336 if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4 )
1337 {
1338 ServiceInstanceInfo * serviceInstance;
1339 std::auto_ptr < ServiceInstanceInfo > serviceInstanceAutoPtr;
1340 char s[ 32 ];
1341
1342 serviceInstance = new ServiceInstanceInfo;
1343 serviceInstanceAutoPtr.reset( serviceInstance );
1344
1345 serviceInstance->name = inEvent->data.resolved->name;
1346 serviceInstance->type = inEvent->data.resolved->type;
1347 serviceInstance->domain = inEvent->data.resolved->domain;
1348 serviceInstance->ip = DNSNetworkAddressToString( &inEvent->data.resolved->address, s );
1349 serviceInstance->ifIP = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, s );
1350 serviceInstance->text = inEvent->data.resolved->textRecord;
1351 serviceInstance->hostName = inEvent->data.resolved->hostName;
1352
1353 posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_RESOLVE, 0, (LPARAM) serviceInstance );
1354 assert( posted );
1355 if( posted )
1356 {
1357 serviceInstanceAutoPtr.release();
1358 }
1359 }
1360 break;
1361
1362 default:
1363 break;
1364 }
1365 }
1366 catch( ... )
1367 {
1368 // Don't let exceptions escape.
1369 }
1370 }
1371
1372 //===========================================================================================================================
1373 // DNSNetworkAddressToString
1374 //
1375 // Note: Currently only supports IPv4 network addresses.
1376 //===========================================================================================================================
1377
1378 static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString )
1379 {
1380 const DNSUInt8 * p;
1381 DNSUInt16 port;
1382
1383 p = inAddr->u.ipv4.addr.v8;
1384 port = ntohs( inAddr->u.ipv4.port.v16 );
1385 if( port != kDNSPortInvalid )
1386 {
1387 sprintf( outString, "%u.%u.%u.%u:%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ], port );
1388 }
1389 else
1390 {
1391 sprintf( outString, "%u.%u.%u.%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] );
1392 }
1393 return( outString );
1394 }
1395
1396 //===========================================================================================================================
1397 // UTF8StringToStringObject
1398 //===========================================================================================================================
1399
1400 static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject )
1401 {
1402 DWORD err;
1403 int n;
1404 BSTR unicode;
1405
1406 unicode = NULL;
1407
1408 n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
1409 if( n > 0 )
1410 {
1411 unicode = (BSTR) malloc( (size_t)( n * sizeof( wchar_t ) ) );
1412 if( !unicode )
1413 {
1414 err = ERROR_INSUFFICIENT_BUFFER;
1415 goto exit;
1416 }
1417
1418 n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
1419 try
1420 {
1421 inObject = unicode;
1422 }
1423 catch( ... )
1424 {
1425 err = ERROR_NO_UNICODE_TRANSLATION;
1426 goto exit;
1427 }
1428 }
1429 else
1430 {
1431 inObject = "";
1432 }
1433 err = 0;
1434
1435 exit:
1436 if( unicode )
1437 {
1438 free( unicode );
1439 }
1440 return( err );
1441 }
1442
1443 //===========================================================================================================================
1444 // StringObjectToUTF8String
1445 //===========================================================================================================================
1446
1447 static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 )
1448 {
1449 DWORD err;
1450 BSTR unicode;
1451 int nUnicode;
1452 int n;
1453 char * utf8;
1454
1455 unicode = NULL;
1456 utf8 = NULL;
1457
1458 nUnicode = inObject.GetLength();
1459 if( nUnicode > 0 )
1460 {
1461 unicode = inObject.AllocSysString();
1462 n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, NULL, 0, NULL, NULL );
1463 assert( n > 0 );
1464
1465 utf8 = (char *) malloc( (size_t) n );
1466 assert( utf8 );
1467 if( !utf8 ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; }
1468
1469 n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, utf8, n, NULL, NULL );
1470 assert( n > 0 );
1471
1472 try
1473 {
1474 outUTF8.assign( utf8, n );
1475 }
1476 catch( ... )
1477 {
1478 err = ERROR_NO_UNICODE_TRANSLATION;
1479 goto exit;
1480 }
1481 }
1482 else
1483 {
1484 outUTF8.clear();
1485 }
1486 err = 0;
1487
1488 exit:
1489 if( unicode )
1490 {
1491 SysFreeString( unicode );
1492 }
1493 if( utf8 )
1494 {
1495 free( utf8 );
1496 }
1497 return( err );
1498 }