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