• 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	"stdafx.h"
19 
20 #include	"Application.h"
21 
22 #include	"DNSServices.h"
23 
24 #include	"BrowserDialog.h"
25 
26 #ifdef _DEBUG
27 #define new DEBUG_NEW
28 #undef THIS_FILE
29 static char THIS_FILE[] = __FILE__;
30 #endif
31 
32 //===========================================================================================================================
33 //	Constants
34 //===========================================================================================================================
35 
36 #define	WM_USER_SERVICE_ADD			( WM_USER + 0x100 )
37 #define	WM_USER_SERVICE_REMOVE		( WM_USER + 0x101 )
38 
39 //===========================================================================================================================
40 //	Message Map
41 //===========================================================================================================================
42 
43 BEGIN_MESSAGE_MAP(BrowserDialog, CDialog)
44 	//{{AFX_MSG_MAP(BrowserDialog)
45 	ON_NOTIFY(NM_CLICK, IDC_BROWSE_LIST, OnBrowserListDoubleClick)
46 	ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
47 	ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
48 	//}}AFX_MSG_MAP
49 END_MESSAGE_MAP()
50 
51 static DWORD	UTF8StringToStringObject( const char *inUTF8, CString &inObject );
52 
53 //===========================================================================================================================
54 //	BrowserDialog
55 //===========================================================================================================================
56 
BrowserDialog(CWnd * inParent)57 BrowserDialog::BrowserDialog( CWnd *inParent )
58 	: CDialog( BrowserDialog::IDD, inParent )
59 {
60 	//{{AFX_DATA_INIT(BrowserDialog)
61 		// Note: the ClassWizard will add member initialization here
62 	//}}AFX_DATA_INIT
63 
64 	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32.
65 
66 	mIcon = AfxGetApp()->LoadIcon( IDR_MAINFRAME );
67 	ASSERT( mIcon );
68 }
69 
70 //===========================================================================================================================
71 //	DoDataExchange
72 //===========================================================================================================================
73 
DoDataExchange(CDataExchange * pDX)74 void	BrowserDialog::DoDataExchange( CDataExchange *pDX )
75 {
76 	CDialog::DoDataExchange(pDX);
77 	//{{AFX_DATA_MAP(BrowserDialog)
78 	DDX_Control(pDX, IDC_BROWSE_LIST, mBrowserList);
79 	//}}AFX_DATA_MAP
80 }
81 
82 //===========================================================================================================================
83 //	OnInitDialog
84 //===========================================================================================================================
85 
OnInitDialog()86 BOOL	BrowserDialog::OnInitDialog()
87 {
88 	CString		s;
89 
90 	CDialog::OnInitDialog();
91 
92 	// Set the icon for this dialog. The framework does this automatically when the application's main window is not a dialog.
93 
94 	SetIcon( mIcon, TRUE );		// Set big icon
95 	SetIcon( mIcon, FALSE );	// Set small icon
96 
97 	CenterWindow( GetDesktopWindow() );
98 
99 	// Set up the list.
100 
101 	CRect		rect;
102 
103 	s.LoadString( IDS_BROWSER_LIST_COLUMN_NAME );
104 	mBrowserList.GetWindowRect( rect );
105 	mBrowserList.InsertColumn( 0, s, LVCFMT_LEFT, rect.Width() - 8 );
106 
107 	// Start browsing for services.
108 
109 	DNSStatus		err;
110 
111 	err = DNSBrowserCreate( 0, OnBrowserCallBack, this, &mBrowser );
112 	if( err )
113 	{
114 		AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
115 		goto exit;
116 	}
117 
118 	err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, "_http._tcp", NULL );
119 	if( err )
120 	{
121 		AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
122 		goto exit;
123 	}
124 
125 exit:
126 	return( TRUE );
127 }
128 
129 
130 //===========================================================================================================================
131 //	OnBrowserListDoubleClick
132 //===========================================================================================================================
133 
OnBrowserListDoubleClick(NMHDR * pNMHDR,LRESULT * pResult)134 void	BrowserDialog::OnBrowserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
135 {
136 	int		selectedItem;
137 
138 	(void) pNMHDR;	// Unused
139 
140 	selectedItem = mBrowserList.GetNextItem( -1, LVNI_SELECTED );
141 	if( selectedItem >= 0 )
142 	{
143 		BrowserEntry *		entry;
144 		CString				temp;
145 		CString				url;
146 
147 		// Build the URL from the IP and optional TXT record.
148 
149 		entry = &mBrowserEntries[ selectedItem ];
150 		url += "http://" + entry->ip;
151 		temp = entry->text;
152 		if( temp.Find( TEXT( "path=" ) ) == 0 )
153 		{
154 			temp.Delete( 0, 5 );
155 		}
156 		if( temp.Find( '/' ) != 0 )
157 		{
158 			url += '/';
159 		}
160 		url += temp;
161 
162 		// Let the system open the URL in the correct app.
163 
164 		SHELLEXECUTEINFO		info;
165 
166 		info.cbSize			= sizeof( info );
167 		info.fMask 			= 0;
168 		info.hwnd 			= NULL;
169 		info.lpVerb 		= NULL;
170 		info.lpFile 		= url;
171 		info.lpParameters 	= NULL;
172 		info.lpDirectory 	= NULL;
173 		info.nShow 			= SW_SHOWNORMAL;
174 		info.hInstApp 		= NULL;
175 
176 		ShellExecuteEx( &info );
177 	}
178 	*pResult = 0;
179 }
180 
181 //===========================================================================================================================
182 //	OnBrowserCallBack [static]
183 //===========================================================================================================================
184 
185 void
OnBrowserCallBack(void * inContext,DNSBrowserRef inRef,DNSStatus inStatusCode,const DNSBrowserEvent * inEvent)186 	BrowserDialog::OnBrowserCallBack(
187 		void *					inContext,
188 		DNSBrowserRef			inRef,
189 		DNSStatus				inStatusCode,
190 		const DNSBrowserEvent *	inEvent )
191 {
192 	BrowserDialog *		dialog;
193 	BrowserEntry *		entry;
194 	BOOL				posted;
195 
196 	DNS_UNUSED( inStatusCode );
197 	dialog = reinterpret_cast < BrowserDialog * > ( inContext );
198 	ASSERT( dialog );
199 
200 	switch( inEvent->type )
201 	{
202 		case kDNSBrowserEventTypeResolved:
203 			if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4  )
204 			{
205 				char		ip[ 64 ];
206 
207 				sprintf( ip, "%u.%u.%u.%u:%u",
208 					inEvent->data.resolved->address.u.ipv4.addr.v8[ 0 ],
209 					inEvent->data.resolved->address.u.ipv4.addr.v8[ 1 ],
210 					inEvent->data.resolved->address.u.ipv4.addr.v8[ 2 ],
211 					inEvent->data.resolved->address.u.ipv4.addr.v8[ 3 ],
212 					( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) |
213 					  inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ] );
214 
215 				entry = new BrowserEntry;
216 				ASSERT( entry );
217 				if( entry )
218 				{
219 					UTF8StringToStringObject( inEvent->data.resolved->name, entry->name );
220 					UTF8StringToStringObject( ip, entry->ip );
221 					UTF8StringToStringObject( inEvent->data.resolved->textRecord, entry->text );
222 
223 					posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_ADD, 0, (LPARAM) entry );
224 					ASSERT( posted );
225 					if( !posted )
226 					{
227 						delete entry;
228 					}
229 				}
230 			}
231 			break;
232 
233 		case kDNSBrowserEventTypeRemoveService:
234 			entry = new BrowserEntry;
235 			ASSERT( entry );
236 			if( entry )
237 			{
238 				UTF8StringToStringObject( inEvent->data.removeService.name, entry->name );
239 
240 				posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_REMOVE, 0, (LPARAM) entry );
241 				ASSERT( posted );
242 				if( !posted )
243 				{
244 					delete entry;
245 				}
246 			}
247 			break;
248 
249 		default:
250 			break;
251 	}
252 }
253 
254 //===========================================================================================================================
255 //	BrowserAddService
256 //===========================================================================================================================
257 
OnServiceAdd(WPARAM inWParam,LPARAM inLParam)258 LONG	BrowserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
259 {
260 	BrowserEntry *		entry;
261 	INT_PTR				lo;
262 	INT_PTR				hi;
263 	INT_PTR				mid;
264 	int					result;
265 
266 	(void) inWParam;	// Unused
267 
268 	entry = reinterpret_cast < BrowserEntry * > ( inLParam );
269 	ASSERT( entry );
270 
271 	result 	= -1;
272 	mid		= 0;
273 	lo 		= 0;
274 	hi 		= mBrowserEntries.GetSize() - 1;
275 	while( lo <= hi )
276 	{
277 		mid = ( lo + hi ) / 2;
278 		result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name );
279 		if( result == 0 )
280 		{
281 			break;
282 		}
283 		else if( result < 0 )
284 		{
285 			hi = mid - 1;
286 		}
287 		else
288 		{
289 			lo = mid + 1;
290 		}
291 	}
292 	if( result == 0 )
293 	{
294 		mBrowserEntries[ mid ].ip	= entry->ip;
295 		mBrowserEntries[ mid ].text	= entry->text;
296 	}
297 	else
298 	{
299 		if( result > 0 )
300 		{
301 			mid += 1;
302 		}
303 		mBrowserEntries.InsertAt( mid, *entry );
304 		mBrowserList.InsertItem( mid, entry->name );
305 	}
306 	delete entry;
307 	return( 0 );
308 }
309 
310 //===========================================================================================================================
311 //	OnServiceRemove
312 //===========================================================================================================================
313 
OnServiceRemove(WPARAM inWParam,LPARAM inLParam)314 LONG	BrowserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
315 {
316 	BrowserEntry *		entry;
317 	INT_PTR				hi;
318 	INT_PTR				lo;
319 	INT_PTR				mid;
320 	int					result;
321 
322 	(void) inWParam;	// Unused
323 
324 	entry = reinterpret_cast < BrowserEntry * > ( inLParam );
325 	ASSERT( entry );
326 
327 	result 	= -1;
328 	mid		= 0;
329 	lo 		= 0;
330 	hi 		= mBrowserEntries.GetSize() - 1;
331 	while( lo <= hi )
332 	{
333 		mid = ( lo + hi ) / 2;
334 		result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name );
335 		if( result == 0 )
336 		{
337 			break;
338 		}
339 		else if( result < 0 )
340 		{
341 			hi = mid - 1;
342 		}
343 		else
344 		{
345 			lo = mid + 1;
346 		}
347 	}
348 	if( result == 0 )
349 	{
350 		mBrowserList.DeleteItem( mid );
351 		mBrowserEntries.RemoveAt( mid );
352 	}
353 	delete entry;
354 	return( 0 );
355 }
356 
357 #if 0
358 #pragma mark -
359 #endif
360 
361 //===========================================================================================================================
362 //	UTF8StringToStringObject
363 //===========================================================================================================================
364 
UTF8StringToStringObject(const char * inUTF8,CString & inObject)365 static DWORD	UTF8StringToStringObject( const char *inUTF8, CString &inObject )
366 {
367 	DWORD			err;
368 	int				n;
369 	wchar_t *		unicode;
370 
371 	unicode = NULL;
372 
373 	n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
374 	if( n > 0 )
375 	{
376 		unicode = (wchar_t *) malloc( (size_t)( n * sizeof( wchar_t ) ) );
377 		if( !unicode ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; };
378 
379 		n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
380 		inObject = unicode;
381 	}
382 	else
383 	{
384 		inObject = "";
385 	}
386 	err = 0;
387 
388 exit:
389 	if( unicode )
390 	{
391 		free( unicode );
392 	}
393 	return( err );
394 }
395