]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/ExplorerPlugin/ExplorerBarWindow.cpp
mDNSResponder-98.tar.gz
[apple/mdnsresponder.git] / Clients / ExplorerPlugin / ExplorerBarWindow.cpp
1 /*
2 * Copyright (c) 2003-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: ExplorerBarWindow.cpp,v $
26 Revision 1.15 2005/01/27 22:38:27 shersche
27 add About item to tree list
28
29 Revision 1.14 2005/01/25 17:55:39 shersche
30 <rdar://problem/3911084> Get bitmaps from non-localizable resource module
31 Bug #: 3911084
32
33 Revision 1.13 2005/01/06 21:13:09 shersche
34 <rdar://problem/3796779> Handle kDNSServiceErr_Firewall return codes
35 Bug #: 3796779
36
37 Revision 1.12 2004/10/26 00:56:03 cheshire
38 Use "#if 0" instead of commenting out code
39
40 Revision 1.11 2004/10/18 23:49:17 shersche
41 <rdar://problem/3841564> Remove trailing dot from hostname, because some flavors of Windows have difficulty parsing hostnames with a trailing dot.
42 Bug #: 3841564
43
44 Revision 1.10 2004/09/02 02:18:58 cheshire
45 Minor textual cleanup to improve readability
46
47 Revision 1.9 2004/09/02 02:11:56 cheshire
48 <rdar://problem/3783611> Fix incorrect testing of MoreComing flag
49
50 Revision 1.8 2004/07/26 05:47:31 shersche
51 use TXTRecord APIs, fix bug in locating service to be removed
52
53 Revision 1.7 2004/07/22 16:08:20 shersche
54 clean up debug print statements, re-enable code inadvertently commented out
55
56 Revision 1.6 2004/07/22 05:27:20 shersche
57 <rdar://problem/3735827> Check to make sure error isn't WSAEWOULDBLOCK when canceling browse
58 Bug #: 3735827
59
60 Revision 1.5 2004/07/20 06:49:18 shersche
61 clean up socket handling code
62
63 Revision 1.4 2004/07/13 21:24:21 rpantos
64 Fix for <rdar://problem/3701120>.
65
66 Revision 1.3 2004/06/27 14:59:59 shersche
67 reference count service info to handle multi-homed hosts
68
69 Revision 1.2 2004/06/23 16:09:34 shersche
70 Add the resolve DNSServiceRef to list of extant refs. This fixes the "doesn't resolve when double clicking" problem
71
72 Submitted by: Scott Herscher
73
74 Revision 1.1 2004/06/18 04:34:59 rpantos
75 Move to Clients from mDNSWindows
76
77 Revision 1.5 2004/04/15 01:00:05 bradley
78 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
79 without .local name resolving support will need to manually query for A/AAAA records as needed.
80
81 Revision 1.4 2004/04/09 21:03:15 bradley
82 Changed port numbers to use network byte order for consistency with other platforms.
83
84 Revision 1.3 2004/04/08 09:43:43 bradley
85 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
86
87 Revision 1.2 2004/02/21 04:36:19 bradley
88 Enable dot local name lookups now that the NSP is being installed.
89
90 Revision 1.1 2004/01/30 03:01:56 bradley
91 Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
92
93 */
94
95 #include "StdAfx.h"
96
97 #include "CommonServices.h"
98 #include "DebugServices.h"
99 #include "WinServices.h"
100 #include "dns_sd.h"
101
102 #include "ExplorerBar.h"
103 #include "LoginDialog.h"
104 #include "Resource.h"
105
106 #include "ExplorerBarWindow.h"
107 #include "ExplorerPlugin.h"
108
109 // MFC Debugging
110
111 #ifdef _DEBUG
112 #define new DEBUG_NEW
113 #undef THIS_FILE
114 static char THIS_FILE[] = __FILE__;
115 #endif
116
117 #if 0
118 #pragma mark == Constants ==
119 #endif
120
121 //===========================================================================================================================
122 // Constants
123 //===========================================================================================================================
124
125 // Control IDs
126
127 #define IDC_EXPLORER_TREE 1234
128
129 // Private Messages
130
131 #define WM_PRIVATE_SERVICE_EVENT ( WM_USER + 0x100 )
132
133 // TXT records
134
135 #define kTXTRecordKeyPath "path"
136
137
138 #if 0
139 #pragma mark == Prototypes ==
140 #endif
141
142 //===========================================================================================================================
143 // Prototypes
144 //===========================================================================================================================
145
146 DEBUG_LOCAL int FindServiceArrayIndex( const ServiceInfoArray &inArray, const ServiceInfo &inService, int &outIndex );
147
148 #if 0
149 #pragma mark == Message Map ==
150 #endif
151
152 //===========================================================================================================================
153 // Message Map
154 //===========================================================================================================================
155
156 BEGIN_MESSAGE_MAP( ExplorerBarWindow, CWnd )
157 ON_WM_CREATE()
158 ON_WM_DESTROY()
159 ON_WM_SIZE()
160 ON_NOTIFY( NM_DBLCLK, IDC_EXPLORER_TREE, OnDoubleClick )
161 ON_MESSAGE( WM_PRIVATE_SERVICE_EVENT, OnServiceEvent )
162 END_MESSAGE_MAP()
163
164 #if 0
165 #pragma mark -
166 #endif
167
168 //===========================================================================================================================
169 // ExplorerBarWindow
170 //===========================================================================================================================
171
172 ExplorerBarWindow::ExplorerBarWindow( void )
173 {
174 mOwner = NULL;
175 mResolveServiceRef = NULL;
176 }
177
178 //===========================================================================================================================
179 // ~ExplorerBarWindow
180 //===========================================================================================================================
181
182 ExplorerBarWindow::~ExplorerBarWindow( void )
183 {
184 //
185 }
186
187 #if 0
188 #pragma mark -
189 #endif
190
191 //===========================================================================================================================
192 // OnCreate
193 //===========================================================================================================================
194
195 int ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
196 {
197 AFX_MANAGE_STATE( AfxGetStaticModuleState() );
198
199 OSStatus err;
200 CRect rect;
201 CBitmap bitmap;
202 CString s;
203
204 err = CWnd::OnCreate( inCreateStruct );
205 require_noerr( err, exit );
206
207 GetClientRect( rect );
208 mTree.Create( WS_TABSTOP | WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_NOHSCROLL , rect, this,
209 IDC_EXPLORER_TREE );
210
211 s.LoadString( IDS_ABOUT );
212 m_about = mTree.InsertItem( s, 0, 0 );
213
214 ServiceHandlerEntry * e;
215
216 // Web Site Handler
217
218 e = new ServiceHandlerEntry;
219 check( e );
220 e->type = "_http._tcp";
221 e->urlScheme = "http://";
222 e->ref = NULL;
223 e->treeItem = NULL;
224 e->treeFirst = true;
225 e->obj = this;
226 e->needsLogin = false;
227 mServiceHandlers.Add( e );
228
229 s.LoadString( IDS_WEB_SITES );
230 e->treeItem = mTree.InsertItem( s, 1, 1 );
231 mTree.Expand( e->treeItem, TVE_EXPAND );
232
233 err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
234 require_noerr( err, exit );
235
236 err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(e->ref), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
237 require_noerr( err, exit );
238
239 m_serviceRefs.push_back(e->ref);
240
241 // FTP Site Handler
242
243 e = new ServiceHandlerEntry;
244 check( e );
245 e->type = "_ftp._tcp";
246 e->urlScheme = "ftp://";
247 e->ref = NULL;
248 e->treeItem = NULL;
249 e->treeFirst = true;
250 e->obj = this;
251 e->needsLogin = true;
252 mServiceHandlers.Add( e );
253
254 s.LoadString( IDS_FTP_SITES );
255 e->treeItem = mTree.InsertItem( s, 1, 1 );
256 mTree.Expand( e->treeItem, TVE_EXPAND );
257
258 err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
259 require_noerr( err, exit );
260
261 err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(e->ref), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
262 require_noerr( err, exit );
263
264 m_serviceRefs.push_back(e->ref);
265
266 m_imageList.Create( 16, 16, ILC_COLORDDB, 2, 0);
267 bitmap.Attach( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_GLOBE ) ) );
268 m_imageList.Add( &bitmap, (CBitmap*) NULL );
269 bitmap.Detach();
270 bitmap.Attach( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_LOGO ) ) );
271 m_imageList.Add( &bitmap, (CBitmap*) NULL );
272
273 mTree.SetImageList(&m_imageList, TVSIL_NORMAL);
274
275 exit:
276
277 // Cannot talk to the mDNSResponder service. Show the error message and exit (with kNoErr so they can see it).
278 if ( err )
279 {
280 if ( err == kDNSServiceErr_Firewall )
281 {
282 s.LoadString( IDS_FIREWALL );
283 }
284 else
285 {
286 s.LoadString( IDS_MDNSRESPONDER_NOT_AVAILABLE );
287 }
288
289 mTree.DeleteAllItems();
290 mTree.InsertItem( s, 0, 0, TVI_ROOT, TVI_LAST );
291
292 err = kNoErr;
293 }
294
295 return( err );
296 }
297
298 //===========================================================================================================================
299 // OnDestroy
300 //===========================================================================================================================
301
302 void ExplorerBarWindow::OnDestroy( void )
303 {
304 // Stop any resolves that may still be pending (shouldn't be any).
305
306 StopResolve();
307
308 // Clean up the extant browses
309 while (m_serviceRefs.size() > 0)
310 {
311 //
312 // take the head of the list
313 //
314 DNSServiceRef ref = m_serviceRefs.front();
315
316 //
317 // Stop will remove it from the list
318 //
319 Stop( ref );
320 }
321
322 // Clean up the service handlers.
323
324 int i;
325 int n;
326
327 n = (int) mServiceHandlers.GetSize();
328 for( i = 0; i < n; ++i )
329 {
330 delete mServiceHandlers[ i ];
331 }
332
333 CWnd::OnDestroy();
334 }
335
336 //===========================================================================================================================
337 // OnSize
338 //===========================================================================================================================
339
340 void ExplorerBarWindow::OnSize( UINT inType, int inX, int inY )
341 {
342 CWnd::OnSize( inType, inX, inY );
343 mTree.MoveWindow( 0, 0, inX, inY );
344 }
345
346 //===========================================================================================================================
347 // OnDoubleClick
348 //===========================================================================================================================
349
350 void ExplorerBarWindow::OnDoubleClick( NMHDR *inNMHDR, LRESULT *outResult )
351 {
352 HTREEITEM item;
353 ServiceInfo * service;
354 OSStatus err;
355
356 DEBUG_UNUSED( inNMHDR );
357
358 item = mTree.GetSelectedItem();
359 require( item, exit );
360
361 // Tell Internet Explorer to go to the URL if it's about item
362
363 if ( item == m_about )
364 {
365 CString url;
366
367 check( mOwner );
368
369 url.LoadString( IDS_ABOUT_URL );
370 mOwner->GoToURL( url );
371 }
372 else
373 {
374 service = reinterpret_cast < ServiceInfo * > ( mTree.GetItemData( item ) );
375 require_quiet( service, exit );
376
377 err = StartResolve( service );
378 require_noerr( err, exit );
379 }
380
381 exit:
382 *outResult = 0;
383 }
384
385
386 //===========================================================================================================================
387 // OnServiceEvent
388 //===========================================================================================================================
389
390 LONG
391 ExplorerBarWindow::OnServiceEvent(WPARAM inWParam, LPARAM inLParam)
392 {
393 if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
394 {
395 dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
396 }
397 else
398 {
399 SOCKET sock = (SOCKET) inWParam;
400
401 // iterate thru list
402 ServiceRefList::iterator it;
403
404 for (it = m_serviceRefs.begin(); it != m_serviceRefs.end(); it++)
405 {
406 DNSServiceRef ref = *it;
407
408 check(ref != NULL);
409
410 if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
411 {
412 DNSServiceErrorType err;
413
414 err = DNSServiceProcessResult(ref);
415
416 if (err != 0)
417 {
418 CString s;
419
420 s.LoadString( IDS_MDNSRESPONDER_NOT_AVAILABLE );
421 mTree.DeleteAllItems();
422 mTree.InsertItem( s, 0, 0, TVI_ROOT, TVI_LAST );
423
424 Stop(ref);
425 }
426
427 break;
428 }
429 }
430 }
431
432 return ( 0 );
433 }
434
435 #if 0
436 #pragma mark -
437 #endif
438
439 //===========================================================================================================================
440 // BrowseCallBack
441 //===========================================================================================================================
442
443 void DNSSD_API
444 ExplorerBarWindow::BrowseCallBack(
445 DNSServiceRef inRef,
446 DNSServiceFlags inFlags,
447 uint32_t inInterfaceIndex,
448 DNSServiceErrorType inErrorCode,
449 const char * inName,
450 const char * inType,
451 const char * inDomain,
452 void * inContext )
453 {
454 ServiceHandlerEntry * obj;
455 ServiceInfo * service;
456 OSStatus err;
457
458 DEBUG_UNUSED( inRef );
459
460 obj = NULL;
461 service = NULL;
462
463 require_noerr( inErrorCode, exit );
464 obj = reinterpret_cast < ServiceHandlerEntry * > ( inContext );
465 check( obj );
466 check( obj->obj );
467
468 //
469 // set the UI to hold off on updates
470 //
471 obj->obj->mTree.SetRedraw(FALSE);
472
473 try
474 {
475 service = new ServiceInfo;
476 require_action( service, exit, err = kNoMemoryErr );
477
478 err = UTF8StringToStringObject( inName, service->displayName );
479 check_noerr( err );
480
481 service->name = strdup( inName );
482 require_action( service->name, exit, err = kNoMemoryErr );
483
484 service->type = strdup( inType );
485 require_action( service->type, exit, err = kNoMemoryErr );
486
487 service->domain = strdup( inDomain );
488 require_action( service->domain, exit, err = kNoMemoryErr );
489
490 service->ifi = inInterfaceIndex;
491 service->handler = obj;
492
493 service->refs = 1;
494
495 if (inFlags & kDNSServiceFlagsAdd) obj->obj->OnServiceAdd (service);
496 else obj->obj->OnServiceRemove(service);
497
498 service = NULL;
499 }
500 catch( ... )
501 {
502 dlog( kDebugLevelError, "BrowseCallBack: exception thrown\n" );
503 }
504
505 exit:
506 //
507 // If no more coming, then update UI
508 //
509 if (obj && obj->obj && ((inFlags & kDNSServiceFlagsMoreComing) == 0))
510 {
511 obj->obj->mTree.SetRedraw(TRUE);
512 obj->obj->mTree.Invalidate();
513 }
514
515 if( service )
516 {
517 delete service;
518 }
519 }
520
521 //===========================================================================================================================
522 // OnServiceAdd
523 //===========================================================================================================================
524
525 LONG ExplorerBarWindow::OnServiceAdd( ServiceInfo * service )
526 {
527 ServiceHandlerEntry * handler;
528 int cmp;
529 int index;
530
531
532 check( service );
533 handler = service->handler;
534 check( handler );
535
536 cmp = FindServiceArrayIndex( handler->array, *service, index );
537 if( cmp == 0 )
538 {
539 // Found a match so update the item. The index is index + 1 so subtract 1.
540
541 index -= 1;
542 check( index < handler->array.GetSize() );
543
544 handler->array[ index ]->refs++;
545
546 delete service;
547 }
548 else
549 {
550 HTREEITEM afterItem;
551
552 // Insert the new item in sorted order.
553
554 afterItem = ( index > 0 ) ? handler->array[ index - 1 ]->item : TVI_FIRST;
555 handler->array.InsertAt( index, service );
556 service->item = mTree.InsertItem( service->displayName, 1, 1, handler->treeItem, afterItem );
557 mTree.SetItemData( service->item, (DWORD_PTR) service );
558
559 // Make sure the item is visible if this is the first time a service was added.
560
561 if( handler->treeFirst )
562 {
563 handler->treeFirst = false;
564 mTree.EnsureVisible( service->item );
565 }
566 }
567 return( 0 );
568 }
569
570 //===========================================================================================================================
571 // OnServiceRemove
572 //===========================================================================================================================
573
574 LONG ExplorerBarWindow::OnServiceRemove( ServiceInfo * service )
575 {
576 ServiceHandlerEntry * handler;
577 int cmp;
578 int index;
579
580
581 check( service );
582 handler = service->handler;
583 check( handler );
584
585 // Search to see if we know about this service instance. If so, remove it from the list.
586
587 cmp = FindServiceArrayIndex( handler->array, *service, index );
588 check( cmp == 0 );
589
590 if( cmp == 0 )
591 {
592 // Possibly found a match remove the item. The index
593 // is index + 1 so subtract 1.
594 index -= 1;
595 check( index < handler->array.GetSize() );
596
597 if ( --handler->array[ index ]->refs == 0 )
598 {
599 mTree.DeleteItem( handler->array[ index ]->item );
600 delete handler->array[ index ];
601 handler->array.RemoveAt( index );
602 }
603 }
604
605 delete service;
606 return( 0 );
607 }
608
609 #if 0
610 #pragma mark -
611 #endif
612
613 //===========================================================================================================================
614 // StartResolve
615 //===========================================================================================================================
616
617 OSStatus ExplorerBarWindow::StartResolve( ServiceInfo *inService )
618 {
619 OSStatus err;
620
621 check( inService );
622
623 // Stop any current resolve that may be in progress.
624
625 StopResolve();
626
627 // Resolve the service.
628 err = DNSServiceResolve( &mResolveServiceRef, 0, 0,
629 inService->name, inService->type, inService->domain, (DNSServiceResolveReply) ResolveCallBack, inService->handler );
630 require_noerr( err, exit );
631
632 err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(mResolveServiceRef), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
633 require_noerr( err, exit );
634
635 m_serviceRefs.push_back(mResolveServiceRef);
636
637 exit:
638 return( err );
639 }
640
641 //===========================================================================================================================
642 // StopResolve
643 //===========================================================================================================================
644
645 void ExplorerBarWindow::StopResolve( void )
646 {
647 if( mResolveServiceRef )
648 {
649 Stop( mResolveServiceRef );
650 mResolveServiceRef = NULL;
651 }
652 }
653
654 //===========================================================================================================================
655 // ResolveCallBack
656 //===========================================================================================================================
657
658 void DNSSD_API
659 ExplorerBarWindow::ResolveCallBack(
660 DNSServiceRef inRef,
661 DNSServiceFlags inFlags,
662 uint32_t inInterfaceIndex,
663 DNSServiceErrorType inErrorCode,
664 const char * inFullName,
665 const char * inHostName,
666 uint16_t inPort,
667 uint16_t inTXTSize,
668 const char * inTXT,
669 void * inContext )
670 {
671 ExplorerBarWindow * obj;
672 ServiceHandlerEntry * handler;
673 OSStatus err;
674
675 DEBUG_UNUSED( inRef );
676 DEBUG_UNUSED( inFlags );
677 DEBUG_UNUSED( inErrorCode );
678 DEBUG_UNUSED( inFullName );
679
680 require_noerr( inErrorCode, exit );
681 handler = (ServiceHandlerEntry *) inContext;
682 check( handler );
683 obj = handler->obj;
684 check( obj );
685
686 try
687 {
688 ResolveInfo * resolve;
689 int idx;
690
691 dlog( kDebugLevelNotice, "resolved %s on ifi %d to %s\n", inFullName, inInterfaceIndex, inHostName );
692
693 // Stop resolving after the first good result.
694
695 obj->StopResolve();
696
697 // Post a message to the main thread so it can handle it since MFC is not thread safe.
698
699 resolve = new ResolveInfo;
700 require_action( resolve, exit, err = kNoMemoryErr );
701
702 UTF8StringToStringObject( inHostName, resolve->host );
703
704 // rdar://problem/3841564
705 //
706 // strip trailing dot from hostname because some flavors of Windows
707 // have trouble parsing it.
708
709 idx = resolve->host.ReverseFind('.');
710
711 if ((idx > 1) && ((resolve->host.GetLength() - 1) == idx))
712 {
713 resolve->host.Delete(idx, 1);
714 }
715
716 resolve->port = ntohs( inPort );
717 resolve->ifi = inInterfaceIndex;
718 resolve->handler = handler;
719
720 err = resolve->txt.SetData( inTXT, inTXTSize );
721 check_noerr( err );
722
723 obj->OnResolve(resolve);
724 }
725 catch( ... )
726 {
727 dlog( kDebugLevelError, "ResolveCallBack: exception thrown\n" );
728 }
729
730 exit:
731 return;
732 }
733
734 //===========================================================================================================================
735 // OnResolve
736 //===========================================================================================================================
737
738 LONG ExplorerBarWindow::OnResolve( ResolveInfo * resolve )
739 {
740 CString url;
741 uint8_t * path;
742 uint8_t pathSize;
743 char * pathPrefix;
744 CString username;
745 CString password;
746
747
748 check( resolve );
749
750 // Get login info if needed.
751
752 if( resolve->handler->needsLogin )
753 {
754 LoginDialog dialog;
755
756 if( !dialog.GetLogin( username, password ) )
757 {
758 goto exit;
759 }
760 }
761
762 // If the HTTP TXT record is a "path=" entry, use it as the resource path. Otherwise, use "/".
763
764 pathPrefix = "";
765 if( strcmp( resolve->handler->type, "_http._tcp" ) == 0 )
766 {
767 uint8_t * txtData;
768 uint16_t txtLen;
769
770 resolve->txt.GetData( &txtData, &txtLen );
771
772 path = (uint8_t*) TXTRecordGetValuePtr(txtLen, txtData, kTXTRecordKeyPath, &pathSize);
773
774 if (path == NULL)
775 {
776 path = (uint8_t*) "";
777 pathSize = 1;
778 }
779 }
780 else
781 {
782 path = (uint8_t *) "";
783 pathSize = 1;
784 }
785
786 // Build the URL in the following format:
787 //
788 // <urlScheme>[<username>[:<password>]@]<name/ip>[<path>]
789
790 url.AppendFormat( TEXT( "%S" ), resolve->handler->urlScheme ); // URL Scheme
791 if( username.GetLength() > 0 )
792 {
793 url.AppendFormat( TEXT( "%s" ), username ); // Username
794 if( password.GetLength() > 0 )
795 {
796 url.AppendFormat( TEXT( ":%s" ), password ); // Password
797 }
798 url.AppendFormat( TEXT( "@" ) );
799 }
800
801 url += resolve->host; // Host
802 url.AppendFormat( TEXT( ":%d" ), resolve->port ); // :Port
803 url.AppendFormat( TEXT( "%S" ), pathPrefix ); // Path Prefix ("/" or empty).
804 url.AppendFormat( TEXT( "%.*S" ), (int) pathSize, (char *) path ); // Path (possibly empty).
805
806 // Tell Internet Explorer to go to the URL.
807
808 check( mOwner );
809 mOwner->GoToURL( url );
810
811 exit:
812 delete resolve;
813 return( 0 );
814 }
815
816 //===========================================================================================================================
817 // Stop
818 //===========================================================================================================================
819 void ExplorerBarWindow::Stop( DNSServiceRef ref )
820 {
821 m_serviceRefs.remove( ref );
822
823 WSAAsyncSelect(DNSServiceRefSockFD( ref ), m_hWnd, WM_PRIVATE_SERVICE_EVENT, 0);
824
825 DNSServiceRefDeallocate( ref );
826 }
827
828
829 #if 0
830 #pragma mark -
831 #endif
832
833 //===========================================================================================================================
834 // FindServiceArrayIndex
835 //===========================================================================================================================
836
837 DEBUG_LOCAL int FindServiceArrayIndex( const ServiceInfoArray &inArray, const ServiceInfo &inService, int &outIndex )
838 {
839 int result;
840 int lo;
841 int hi;
842 int mid;
843
844 result = -1;
845 mid = 0;
846 lo = 0;
847 hi = (int)( inArray.GetSize() - 1 );
848 while( lo <= hi )
849 {
850 mid = ( lo + hi ) / 2;
851 result = inService.displayName.CompareNoCase( inArray[ mid ]->displayName );
852 #if 0
853 if( result == 0 )
854 {
855 result = ( (int) inService.ifi ) - ( (int) inArray[ mid ]->ifi );
856 }
857 #endif
858 if( result == 0 )
859 {
860 break;
861 }
862 else if( result < 0 )
863 {
864 hi = mid - 1;
865 }
866 else
867 {
868 lo = mid + 1;
869 }
870 }
871 if( result == 0 )
872 {
873 mid += 1; // Bump index so new item is inserted after matching item.
874 }
875 else if( result > 0 )
876 {
877 mid += 1;
878 }
879 outIndex = mid;
880 return( result );
881 }