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