]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
mDNSResponder-66.3.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / Applications / DNSServiceBrowser / WindowsCE / Sources / BrowserDialog.cpp
1 /*
2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: BrowserDialog.cpp,v $
28 Revision 1.5 2004/01/30 02:56:33 bradley
29 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
30
31 Revision 1.4 2003/10/16 09:21:56 bradley
32 Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
33
34 Revision 1.3 2003/10/14 03:28:50 bradley
35 Insert services in sorted order to make them easier to find. Defer service adds/removes to the main
36 thread to avoid potential problems with multi-threaded MFC message map access. Added some asserts.
37
38 Revision 1.2 2003/10/10 03:43:34 bradley
39 Added support for launching a web browser to go to the browsed web site on a single-tap.
40
41 Revision 1.1 2003/08/21 02:16:10 bradley
42 Rendezvous Browser for HTTP services for Windows CE/PocketPC.
43
44 */
45
46 #include "stdafx.h"
47
48 #include "Application.h"
49
50 #include "DNSServices.h"
51
52 #include "BrowserDialog.h"
53
54 #ifdef _DEBUG
55 #define new DEBUG_NEW
56 #undef THIS_FILE
57 static char THIS_FILE[] = __FILE__;
58 #endif
59
60 //===========================================================================================================================
61 // Constants
62 //===========================================================================================================================
63
64 #define WM_USER_SERVICE_ADD ( WM_USER + 0x100 )
65 #define WM_USER_SERVICE_REMOVE ( WM_USER + 0x101 )
66
67 //===========================================================================================================================
68 // Message Map
69 //===========================================================================================================================
70
71 BEGIN_MESSAGE_MAP(BrowserDialog, CDialog)
72 //{{AFX_MSG_MAP(BrowserDialog)
73 ON_NOTIFY(NM_CLICK, IDC_BROWSE_LIST, OnBrowserListDoubleClick)
74 ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
75 ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
76 //}}AFX_MSG_MAP
77 END_MESSAGE_MAP()
78
79 static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject );
80
81 //===========================================================================================================================
82 // BrowserDialog
83 //===========================================================================================================================
84
85 BrowserDialog::BrowserDialog( CWnd *inParent )
86 : CDialog( BrowserDialog::IDD, inParent )
87 {
88 //{{AFX_DATA_INIT(BrowserDialog)
89 // NOTE: the ClassWizard will add member initialization here
90 //}}AFX_DATA_INIT
91
92 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32.
93
94 mIcon = AfxGetApp()->LoadIcon( IDR_MAINFRAME );
95 ASSERT( mIcon );
96 }
97
98 //===========================================================================================================================
99 // DoDataExchange
100 //===========================================================================================================================
101
102 void BrowserDialog::DoDataExchange( CDataExchange *pDX )
103 {
104 CDialog::DoDataExchange(pDX);
105 //{{AFX_DATA_MAP(BrowserDialog)
106 DDX_Control(pDX, IDC_BROWSE_LIST, mBrowserList);
107 //}}AFX_DATA_MAP
108 }
109
110 //===========================================================================================================================
111 // OnInitDialog
112 //===========================================================================================================================
113
114 BOOL BrowserDialog::OnInitDialog()
115 {
116 CString s;
117
118 CDialog::OnInitDialog();
119
120 // Set the icon for this dialog. The framework does this automatically when the application's main window is not a dialog.
121
122 SetIcon( mIcon, TRUE ); // Set big icon
123 SetIcon( mIcon, FALSE ); // Set small icon
124
125 CenterWindow( GetDesktopWindow() );
126
127 // Set up the list.
128
129 CRect rect;
130
131 s.LoadString( IDS_BROWSER_LIST_COLUMN_NAME );
132 mBrowserList.GetWindowRect( rect );
133 mBrowserList.InsertColumn( 0, s, LVCFMT_LEFT, rect.Width() - 8 );
134
135 // Start browsing for services.
136
137 DNSStatus err;
138
139 err = DNSBrowserCreate( 0, OnBrowserCallBack, this, &mBrowser );
140 if( err )
141 {
142 AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
143 goto exit;
144 }
145
146 err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, "_http._tcp", NULL );
147 if( err )
148 {
149 AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
150 goto exit;
151 }
152
153 exit:
154 return( TRUE );
155 }
156
157
158 //===========================================================================================================================
159 // OnBrowserListDoubleClick
160 //===========================================================================================================================
161
162 void BrowserDialog::OnBrowserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
163 {
164 int selectedItem;
165
166 (void) pNMHDR; // Unused
167
168 selectedItem = mBrowserList.GetNextItem( -1, LVNI_SELECTED );
169 if( selectedItem >= 0 )
170 {
171 BrowserEntry * entry;
172 CString temp;
173 CString url;
174
175 // Build the URL from the IP and optional TXT record.
176
177 entry = &mBrowserEntries[ selectedItem ];
178 url += "http://" + entry->ip;
179 temp = entry->text;
180 if( temp.Find( TEXT( "path=" ) ) == 0 )
181 {
182 temp.Delete( 0, 5 );
183 }
184 if( temp.Find( '/' ) != 0 )
185 {
186 url += '/';
187 }
188 url += temp;
189
190 // Let the system open the URL in the correct app.
191
192 SHELLEXECUTEINFO info;
193
194 info.cbSize = sizeof( info );
195 info.fMask = 0;
196 info.hwnd = NULL;
197 info.lpVerb = NULL;
198 info.lpFile = url;
199 info.lpParameters = NULL;
200 info.lpDirectory = NULL;
201 info.nShow = SW_SHOWNORMAL;
202 info.hInstApp = NULL;
203
204 ShellExecuteEx( &info );
205 }
206 *pResult = 0;
207 }
208
209 //===========================================================================================================================
210 // OnBrowserCallBack [static]
211 //===========================================================================================================================
212
213 void
214 BrowserDialog::OnBrowserCallBack(
215 void * inContext,
216 DNSBrowserRef inRef,
217 DNSStatus inStatusCode,
218 const DNSBrowserEvent * inEvent )
219 {
220 BrowserDialog * dialog;
221 BrowserEntry * entry;
222 BOOL posted;
223
224 DNS_UNUSED( inStatusCode );
225 dialog = reinterpret_cast < BrowserDialog * > ( inContext );
226 ASSERT( dialog );
227
228 switch( inEvent->type )
229 {
230 case kDNSBrowserEventTypeResolved:
231 if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4 )
232 {
233 char ip[ 64 ];
234
235 sprintf( ip, "%u.%u.%u.%u:%u",
236 inEvent->data.resolved->address.u.ipv4.addr.v8[ 0 ],
237 inEvent->data.resolved->address.u.ipv4.addr.v8[ 1 ],
238 inEvent->data.resolved->address.u.ipv4.addr.v8[ 2 ],
239 inEvent->data.resolved->address.u.ipv4.addr.v8[ 3 ],
240 ( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) |
241 inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ] );
242
243 entry = new BrowserEntry;
244 ASSERT( entry );
245 if( entry )
246 {
247 UTF8StringToStringObject( inEvent->data.resolved->name, entry->name );
248 UTF8StringToStringObject( ip, entry->ip );
249 UTF8StringToStringObject( inEvent->data.resolved->textRecord, entry->text );
250
251 posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_ADD, 0, (LPARAM) entry );
252 ASSERT( posted );
253 if( !posted )
254 {
255 delete entry;
256 }
257 }
258 }
259 break;
260
261 case kDNSBrowserEventTypeRemoveService:
262 entry = new BrowserEntry;
263 ASSERT( entry );
264 if( entry )
265 {
266 UTF8StringToStringObject( inEvent->data.removeService.name, entry->name );
267
268 posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_REMOVE, 0, (LPARAM) entry );
269 ASSERT( posted );
270 if( !posted )
271 {
272 delete entry;
273 }
274 }
275 break;
276
277 default:
278 break;
279 }
280 }
281
282 //===========================================================================================================================
283 // BrowserAddService
284 //===========================================================================================================================
285
286 LONG BrowserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
287 {
288 BrowserEntry * entry;
289 INT_PTR lo;
290 INT_PTR hi;
291 INT_PTR mid;
292 int result;
293
294 (void) inWParam; // Unused
295
296 entry = reinterpret_cast < BrowserEntry * > ( inLParam );
297 ASSERT( entry );
298
299 result = -1;
300 mid = 0;
301 lo = 0;
302 hi = mBrowserEntries.GetSize() - 1;
303 while( lo <= hi )
304 {
305 mid = ( lo + hi ) / 2;
306 result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name );
307 if( result == 0 )
308 {
309 break;
310 }
311 else if( result < 0 )
312 {
313 hi = mid - 1;
314 }
315 else
316 {
317 lo = mid + 1;
318 }
319 }
320 if( result == 0 )
321 {
322 mBrowserEntries[ mid ].ip = entry->ip;
323 mBrowserEntries[ mid ].text = entry->text;
324 }
325 else
326 {
327 if( result > 0 )
328 {
329 mid += 1;
330 }
331 mBrowserEntries.InsertAt( mid, *entry );
332 mBrowserList.InsertItem( mid, entry->name );
333 }
334 delete entry;
335 return( 0 );
336 }
337
338 //===========================================================================================================================
339 // OnServiceRemove
340 //===========================================================================================================================
341
342 LONG BrowserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
343 {
344 BrowserEntry * entry;
345 INT_PTR hi;
346 INT_PTR lo;
347 INT_PTR mid;
348 int result;
349
350 (void) inWParam; // Unused
351
352 entry = reinterpret_cast < BrowserEntry * > ( inLParam );
353 ASSERT( entry );
354
355 result = -1;
356 mid = 0;
357 lo = 0;
358 hi = mBrowserEntries.GetSize() - 1;
359 while( lo <= hi )
360 {
361 mid = ( lo + hi ) / 2;
362 result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name );
363 if( result == 0 )
364 {
365 break;
366 }
367 else if( result < 0 )
368 {
369 hi = mid - 1;
370 }
371 else
372 {
373 lo = mid + 1;
374 }
375 }
376 if( result == 0 )
377 {
378 mBrowserList.DeleteItem( mid );
379 mBrowserEntries.RemoveAt( mid );
380 }
381 delete entry;
382 return( 0 );
383 }
384
385 #if 0
386 #pragma mark -
387 #endif
388
389 //===========================================================================================================================
390 // UTF8StringToStringObject
391 //===========================================================================================================================
392
393 static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject )
394 {
395 DWORD err;
396 int n;
397 wchar_t * unicode;
398
399 unicode = NULL;
400
401 n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
402 if( n > 0 )
403 {
404 unicode = (wchar_t *) malloc( (size_t)( n * sizeof( wchar_t ) ) );
405 if( !unicode ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; };
406
407 n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
408 inObject = unicode;
409 }
410 else
411 {
412 inObject = "";
413 }
414 err = 0;
415
416 exit:
417 if( unicode )
418 {
419 free( unicode );
420 }
421 return( err );
422 }