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