1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
19 $Log: BrowserDialog.cpp,v $
20 Revision 1.3 2006/08/14 23:25:55 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.2 2004/07/13 21:24:27 rpantos
24 Fix for <rdar://problem/3701120>.
26 Revision 1.1 2004/06/18 04:04:37 rpantos
29 Revision 1.5 2004/01/30 02:56:33 bradley
30 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
32 Revision 1.4 2003/10/16 09:21:56 bradley
33 Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
35 Revision 1.3 2003/10/14 03:28:50 bradley
36 Insert services in sorted order to make them easier to find. Defer service adds/removes to the main
37 thread to avoid potential problems with multi-threaded MFC message map access. Added some asserts.
39 Revision 1.2 2003/10/10 03:43:34 bradley
40 Added support for launching a web browser to go to the browsed web site on a single-tap.
42 Revision 1.1 2003/08/21 02:16:10 bradley
43 DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
49 #include "Application.h"
51 #include "DNSServices.h"
53 #include "BrowserDialog.h"
58 static char THIS_FILE
[] = __FILE__
;
61 //===========================================================================================================================
63 //===========================================================================================================================
65 #define WM_USER_SERVICE_ADD ( WM_USER + 0x100 )
66 #define WM_USER_SERVICE_REMOVE ( WM_USER + 0x101 )
68 //===========================================================================================================================
70 //===========================================================================================================================
72 BEGIN_MESSAGE_MAP(BrowserDialog
, CDialog
)
73 //{{AFX_MSG_MAP(BrowserDialog)
74 ON_NOTIFY(NM_CLICK
, IDC_BROWSE_LIST
, OnBrowserListDoubleClick
)
75 ON_MESSAGE( WM_USER_SERVICE_ADD
, OnServiceAdd
)
76 ON_MESSAGE( WM_USER_SERVICE_REMOVE
, OnServiceRemove
)
80 static DWORD
UTF8StringToStringObject( const char *inUTF8
, CString
&inObject
);
82 //===========================================================================================================================
84 //===========================================================================================================================
86 BrowserDialog::BrowserDialog( CWnd
*inParent
)
87 : CDialog( BrowserDialog::IDD
, inParent
)
89 //{{AFX_DATA_INIT(BrowserDialog)
90 // NOTE: the ClassWizard will add member initialization here
93 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32.
95 mIcon
= AfxGetApp()->LoadIcon( IDR_MAINFRAME
);
99 //===========================================================================================================================
101 //===========================================================================================================================
103 void BrowserDialog::DoDataExchange( CDataExchange
*pDX
)
105 CDialog::DoDataExchange(pDX
);
106 //{{AFX_DATA_MAP(BrowserDialog)
107 DDX_Control(pDX
, IDC_BROWSE_LIST
, mBrowserList
);
111 //===========================================================================================================================
113 //===========================================================================================================================
115 BOOL
BrowserDialog::OnInitDialog()
119 CDialog::OnInitDialog();
121 // Set the icon for this dialog. The framework does this automatically when the application's main window is not a dialog.
123 SetIcon( mIcon
, TRUE
); // Set big icon
124 SetIcon( mIcon
, FALSE
); // Set small icon
126 CenterWindow( GetDesktopWindow() );
132 s
.LoadString( IDS_BROWSER_LIST_COLUMN_NAME
);
133 mBrowserList
.GetWindowRect( rect
);
134 mBrowserList
.InsertColumn( 0, s
, LVCFMT_LEFT
, rect
.Width() - 8 );
136 // Start browsing for services.
140 err
= DNSBrowserCreate( 0, OnBrowserCallBack
, this, &mBrowser
);
143 AfxMessageBox( IDP_SOCKETS_INIT_FAILED
);
147 err
= DNSBrowserStartServiceSearch( mBrowser
, kDNSBrowserFlagAutoResolve
, "_http._tcp", NULL
);
150 AfxMessageBox( IDP_SOCKETS_INIT_FAILED
);
159 //===========================================================================================================================
160 // OnBrowserListDoubleClick
161 //===========================================================================================================================
163 void BrowserDialog::OnBrowserListDoubleClick( NMHDR
*pNMHDR
, LRESULT
*pResult
)
167 (void) pNMHDR
; // Unused
169 selectedItem
= mBrowserList
.GetNextItem( -1, LVNI_SELECTED
);
170 if( selectedItem
>= 0 )
172 BrowserEntry
* entry
;
176 // Build the URL from the IP and optional TXT record.
178 entry
= &mBrowserEntries
[ selectedItem
];
179 url
+= "http://" + entry
->ip
;
181 if( temp
.Find( TEXT( "path=" ) ) == 0 )
185 if( temp
.Find( '/' ) != 0 )
191 // Let the system open the URL in the correct app.
193 SHELLEXECUTEINFO info
;
195 info
.cbSize
= sizeof( info
);
200 info
.lpParameters
= NULL
;
201 info
.lpDirectory
= NULL
;
202 info
.nShow
= SW_SHOWNORMAL
;
203 info
.hInstApp
= NULL
;
205 ShellExecuteEx( &info
);
210 //===========================================================================================================================
211 // OnBrowserCallBack [static]
212 //===========================================================================================================================
215 BrowserDialog::OnBrowserCallBack(
218 DNSStatus inStatusCode
,
219 const DNSBrowserEvent
* inEvent
)
221 BrowserDialog
* dialog
;
222 BrowserEntry
* entry
;
225 DNS_UNUSED( inStatusCode
);
226 dialog
= reinterpret_cast < BrowserDialog
* > ( inContext
);
229 switch( inEvent
->type
)
231 case kDNSBrowserEventTypeResolved
:
232 if( inEvent
->data
.resolved
->address
.addressType
== kDNSNetworkAddressTypeIPv4
)
236 sprintf( ip
, "%u.%u.%u.%u:%u",
237 inEvent
->data
.resolved
->address
.u
.ipv4
.addr
.v8
[ 0 ],
238 inEvent
->data
.resolved
->address
.u
.ipv4
.addr
.v8
[ 1 ],
239 inEvent
->data
.resolved
->address
.u
.ipv4
.addr
.v8
[ 2 ],
240 inEvent
->data
.resolved
->address
.u
.ipv4
.addr
.v8
[ 3 ],
241 ( inEvent
->data
.resolved
->address
.u
.ipv4
.port
.v8
[ 0 ] << 8 ) |
242 inEvent
->data
.resolved
->address
.u
.ipv4
.port
.v8
[ 1 ] );
244 entry
= new BrowserEntry
;
248 UTF8StringToStringObject( inEvent
->data
.resolved
->name
, entry
->name
);
249 UTF8StringToStringObject( ip
, entry
->ip
);
250 UTF8StringToStringObject( inEvent
->data
.resolved
->textRecord
, entry
->text
);
252 posted
= ::PostMessage( dialog
->GetSafeHwnd(), WM_USER_SERVICE_ADD
, 0, (LPARAM
) entry
);
262 case kDNSBrowserEventTypeRemoveService
:
263 entry
= new BrowserEntry
;
267 UTF8StringToStringObject( inEvent
->data
.removeService
.name
, entry
->name
);
269 posted
= ::PostMessage( dialog
->GetSafeHwnd(), WM_USER_SERVICE_REMOVE
, 0, (LPARAM
) entry
);
283 //===========================================================================================================================
285 //===========================================================================================================================
287 LONG
BrowserDialog::OnServiceAdd( WPARAM inWParam
, LPARAM inLParam
)
289 BrowserEntry
* entry
;
295 (void) inWParam
; // Unused
297 entry
= reinterpret_cast < BrowserEntry
* > ( inLParam
);
303 hi
= mBrowserEntries
.GetSize() - 1;
306 mid
= ( lo
+ hi
) / 2;
307 result
= entry
->name
.CompareNoCase( mBrowserEntries
[ mid
].name
);
312 else if( result
< 0 )
323 mBrowserEntries
[ mid
].ip
= entry
->ip
;
324 mBrowserEntries
[ mid
].text
= entry
->text
;
332 mBrowserEntries
.InsertAt( mid
, *entry
);
333 mBrowserList
.InsertItem( mid
, entry
->name
);
339 //===========================================================================================================================
341 //===========================================================================================================================
343 LONG
BrowserDialog::OnServiceRemove( WPARAM inWParam
, LPARAM inLParam
)
345 BrowserEntry
* entry
;
351 (void) inWParam
; // Unused
353 entry
= reinterpret_cast < BrowserEntry
* > ( inLParam
);
359 hi
= mBrowserEntries
.GetSize() - 1;
362 mid
= ( lo
+ hi
) / 2;
363 result
= entry
->name
.CompareNoCase( mBrowserEntries
[ mid
].name
);
368 else if( result
< 0 )
379 mBrowserList
.DeleteItem( mid
);
380 mBrowserEntries
.RemoveAt( mid
);
390 //===========================================================================================================================
391 // UTF8StringToStringObject
392 //===========================================================================================================================
394 static DWORD
UTF8StringToStringObject( const char *inUTF8
, CString
&inObject
)
402 n
= MultiByteToWideChar( CP_UTF8
, 0, inUTF8
, -1, NULL
, 0 );
405 unicode
= (wchar_t *) malloc( (size_t)( n
* sizeof( wchar_t ) ) );
406 if( !unicode
) { err
= ERROR_INSUFFICIENT_BUFFER
; goto exit
; };
408 n
= MultiByteToWideChar( CP_UTF8
, 0, inUTF8
, -1, unicode
, n
);