Home | History | Annotate | Download | only in Sources
      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 
     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 
     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 
     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 
    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
    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 
    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 
    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 
    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