| /* -*- Mode: C; tab-width: 4 -*- |
| * |
| * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "stdafx.h" |
| |
| #include "Application.h" |
| |
| #include "DNSServices.h" |
| |
| #include "BrowserDialog.h" |
| |
| #ifdef _DEBUG |
| #define new DEBUG_NEW |
| #undef THIS_FILE |
| static char THIS_FILE[] = __FILE__; |
| #endif |
| |
| //=========================================================================================================================== |
| // Constants |
| //=========================================================================================================================== |
| |
| #define WM_USER_SERVICE_ADD ( WM_USER + 0x100 ) |
| #define WM_USER_SERVICE_REMOVE ( WM_USER + 0x101 ) |
| |
| //=========================================================================================================================== |
| // Message Map |
| //=========================================================================================================================== |
| |
| BEGIN_MESSAGE_MAP(BrowserDialog, CDialog) |
| //{{AFX_MSG_MAP(BrowserDialog) |
| ON_NOTIFY(NM_CLICK, IDC_BROWSE_LIST, OnBrowserListDoubleClick) |
| ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd ) |
| ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove ) |
| //}}AFX_MSG_MAP |
| END_MESSAGE_MAP() |
| |
| static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject ); |
| |
| //=========================================================================================================================== |
| // BrowserDialog |
| //=========================================================================================================================== |
| |
| BrowserDialog::BrowserDialog( CWnd *inParent ) |
| : CDialog( BrowserDialog::IDD, inParent ) |
| { |
| //{{AFX_DATA_INIT(BrowserDialog) |
| // Note: the ClassWizard will add member initialization here |
| //}}AFX_DATA_INIT |
| |
| // Note that LoadIcon does not require a subsequent DestroyIcon in Win32. |
| |
| mIcon = AfxGetApp()->LoadIcon( IDR_MAINFRAME ); |
| ASSERT( mIcon ); |
| } |
| |
| //=========================================================================================================================== |
| // DoDataExchange |
| //=========================================================================================================================== |
| |
| void BrowserDialog::DoDataExchange( CDataExchange *pDX ) |
| { |
| CDialog::DoDataExchange(pDX); |
| //{{AFX_DATA_MAP(BrowserDialog) |
| DDX_Control(pDX, IDC_BROWSE_LIST, mBrowserList); |
| //}}AFX_DATA_MAP |
| } |
| |
| //=========================================================================================================================== |
| // OnInitDialog |
| //=========================================================================================================================== |
| |
| BOOL BrowserDialog::OnInitDialog() |
| { |
| CString s; |
| |
| CDialog::OnInitDialog(); |
| |
| // Set the icon for this dialog. The framework does this automatically when the application's main window is not a dialog. |
| |
| SetIcon( mIcon, TRUE ); // Set big icon |
| SetIcon( mIcon, FALSE ); // Set small icon |
| |
| CenterWindow( GetDesktopWindow() ); |
| |
| // Set up the list. |
| |
| CRect rect; |
| |
| s.LoadString( IDS_BROWSER_LIST_COLUMN_NAME ); |
| mBrowserList.GetWindowRect( rect ); |
| mBrowserList.InsertColumn( 0, s, LVCFMT_LEFT, rect.Width() - 8 ); |
| |
| // Start browsing for services. |
| |
| DNSStatus err; |
| |
| err = DNSBrowserCreate( 0, OnBrowserCallBack, this, &mBrowser ); |
| if( err ) |
| { |
| AfxMessageBox( IDP_SOCKETS_INIT_FAILED ); |
| goto exit; |
| } |
| |
| err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, "_http._tcp", NULL ); |
| if( err ) |
| { |
| AfxMessageBox( IDP_SOCKETS_INIT_FAILED ); |
| goto exit; |
| } |
| |
| exit: |
| return( TRUE ); |
| } |
| |
| |
| //=========================================================================================================================== |
| // OnBrowserListDoubleClick |
| //=========================================================================================================================== |
| |
| void BrowserDialog::OnBrowserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult ) |
| { |
| int selectedItem; |
| |
| (void) pNMHDR; // Unused |
| |
| selectedItem = mBrowserList.GetNextItem( -1, LVNI_SELECTED ); |
| if( selectedItem >= 0 ) |
| { |
| BrowserEntry * entry; |
| CString temp; |
| CString url; |
| |
| // Build the URL from the IP and optional TXT record. |
| |
| entry = &mBrowserEntries[ selectedItem ]; |
| url += "http://" + entry->ip; |
| temp = entry->text; |
| if( temp.Find( TEXT( "path=" ) ) == 0 ) |
| { |
| temp.Delete( 0, 5 ); |
| } |
| if( temp.Find( '/' ) != 0 ) |
| { |
| url += '/'; |
| } |
| url += temp; |
| |
| // Let the system open the URL in the correct app. |
| |
| SHELLEXECUTEINFO info; |
| |
| info.cbSize = sizeof( info ); |
| info.fMask = 0; |
| info.hwnd = NULL; |
| info.lpVerb = NULL; |
| info.lpFile = url; |
| info.lpParameters = NULL; |
| info.lpDirectory = NULL; |
| info.nShow = SW_SHOWNORMAL; |
| info.hInstApp = NULL; |
| |
| ShellExecuteEx( &info ); |
| } |
| *pResult = 0; |
| } |
| |
| //=========================================================================================================================== |
| // OnBrowserCallBack [static] |
| //=========================================================================================================================== |
| |
| void |
| BrowserDialog::OnBrowserCallBack( |
| void * inContext, |
| DNSBrowserRef inRef, |
| DNSStatus inStatusCode, |
| const DNSBrowserEvent * inEvent ) |
| { |
| BrowserDialog * dialog; |
| BrowserEntry * entry; |
| BOOL posted; |
| |
| DNS_UNUSED( inStatusCode ); |
| dialog = reinterpret_cast < BrowserDialog * > ( inContext ); |
| ASSERT( dialog ); |
| |
| switch( inEvent->type ) |
| { |
| case kDNSBrowserEventTypeResolved: |
| if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4 ) |
| { |
| char ip[ 64 ]; |
| |
| sprintf( ip, "%u.%u.%u.%u:%u", |
| inEvent->data.resolved->address.u.ipv4.addr.v8[ 0 ], |
| inEvent->data.resolved->address.u.ipv4.addr.v8[ 1 ], |
| inEvent->data.resolved->address.u.ipv4.addr.v8[ 2 ], |
| inEvent->data.resolved->address.u.ipv4.addr.v8[ 3 ], |
| ( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) | |
| inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ] ); |
| |
| entry = new BrowserEntry; |
| ASSERT( entry ); |
| if( entry ) |
| { |
| UTF8StringToStringObject( inEvent->data.resolved->name, entry->name ); |
| UTF8StringToStringObject( ip, entry->ip ); |
| UTF8StringToStringObject( inEvent->data.resolved->textRecord, entry->text ); |
| |
| posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_ADD, 0, (LPARAM) entry ); |
| ASSERT( posted ); |
| if( !posted ) |
| { |
| delete entry; |
| } |
| } |
| } |
| break; |
| |
| case kDNSBrowserEventTypeRemoveService: |
| entry = new BrowserEntry; |
| ASSERT( entry ); |
| if( entry ) |
| { |
| UTF8StringToStringObject( inEvent->data.removeService.name, entry->name ); |
| |
| posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_REMOVE, 0, (LPARAM) entry ); |
| ASSERT( posted ); |
| if( !posted ) |
| { |
| delete entry; |
| } |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| //=========================================================================================================================== |
| // BrowserAddService |
| //=========================================================================================================================== |
| |
| LONG BrowserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam ) |
| { |
| BrowserEntry * entry; |
| INT_PTR lo; |
| INT_PTR hi; |
| INT_PTR mid; |
| int result; |
| |
| (void) inWParam; // Unused |
| |
| entry = reinterpret_cast < BrowserEntry * > ( inLParam ); |
| ASSERT( entry ); |
| |
| result = -1; |
| mid = 0; |
| lo = 0; |
| hi = mBrowserEntries.GetSize() - 1; |
| while( lo <= hi ) |
| { |
| mid = ( lo + hi ) / 2; |
| result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name ); |
| if( result == 0 ) |
| { |
| break; |
| } |
| else if( result < 0 ) |
| { |
| hi = mid - 1; |
| } |
| else |
| { |
| lo = mid + 1; |
| } |
| } |
| if( result == 0 ) |
| { |
| mBrowserEntries[ mid ].ip = entry->ip; |
| mBrowserEntries[ mid ].text = entry->text; |
| } |
| else |
| { |
| if( result > 0 ) |
| { |
| mid += 1; |
| } |
| mBrowserEntries.InsertAt( mid, *entry ); |
| mBrowserList.InsertItem( mid, entry->name ); |
| } |
| delete entry; |
| return( 0 ); |
| } |
| |
| //=========================================================================================================================== |
| // OnServiceRemove |
| //=========================================================================================================================== |
| |
| LONG BrowserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam ) |
| { |
| BrowserEntry * entry; |
| INT_PTR hi; |
| INT_PTR lo; |
| INT_PTR mid; |
| int result; |
| |
| (void) inWParam; // Unused |
| |
| entry = reinterpret_cast < BrowserEntry * > ( inLParam ); |
| ASSERT( entry ); |
| |
| result = -1; |
| mid = 0; |
| lo = 0; |
| hi = mBrowserEntries.GetSize() - 1; |
| while( lo <= hi ) |
| { |
| mid = ( lo + hi ) / 2; |
| result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name ); |
| if( result == 0 ) |
| { |
| break; |
| } |
| else if( result < 0 ) |
| { |
| hi = mid - 1; |
| } |
| else |
| { |
| lo = mid + 1; |
| } |
| } |
| if( result == 0 ) |
| { |
| mBrowserList.DeleteItem( mid ); |
| mBrowserEntries.RemoveAt( mid ); |
| } |
| delete entry; |
| return( 0 ); |
| } |
| |
| #if 0 |
| #pragma mark - |
| #endif |
| |
| //=========================================================================================================================== |
| // UTF8StringToStringObject |
| //=========================================================================================================================== |
| |
| static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject ) |
| { |
| DWORD err; |
| int n; |
| wchar_t * unicode; |
| |
| unicode = NULL; |
| |
| n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 ); |
| if( n > 0 ) |
| { |
| unicode = (wchar_t *) malloc( (size_t)( n * sizeof( wchar_t ) ) ); |
| if( !unicode ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; }; |
| |
| n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n ); |
| inObject = unicode; |
| } |
| else |
| { |
| inObject = ""; |
| } |
| err = 0; |
| |
| exit: |
| if( unicode ) |
| { |
| free( unicode ); |
| } |
| return( err ); |
| } |