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.
29 #include "DNSServices.h"
31 #include "Application.h"
32 #include "AboutDialog.h"
33 #include "LoginDialog.h"
36 #include "ChooserDialog.h"
41 static char THIS_FILE
[] = __FILE__
;
45 #pragma mark == Constants ==
48 //===========================================================================================================================
50 //===========================================================================================================================
56 kChooserMenuIndexFile
= 0,
57 kChooserMenuIndexHelp
= 1
62 #define kDomainListDefaultDomainColumnWidth 164
66 #define kServiceListDefaultServiceColumnTypeWidth 146
67 #define kServiceListDefaultServiceColumnDescWidth 230
71 #define kChooserListDefaultNameColumnWidth 190
72 #define kChooserListDefaultIPColumnWidth 120
74 // Windows User Messages
76 #define WM_USER_DOMAIN_ADD ( WM_USER + 0x100 )
77 #define WM_USER_DOMAIN_REMOVE ( WM_USER + 0x101 )
78 #define WM_USER_SERVICE_ADD ( WM_USER + 0x102 )
79 #define WM_USER_SERVICE_REMOVE ( WM_USER + 0x103 )
80 #define WM_USER_RESOLVE ( WM_USER + 0x104 )
83 #pragma mark == Constants - Service Table ==
86 //===========================================================================================================================
87 // Constants - Service Table
88 //===========================================================================================================================
90 struct KnownServiceEntry
92 const char * serviceType
;
93 const char * description
;
94 const char * urlScheme
;
98 static const KnownServiceEntry kKnownServiceTable
[] =
100 { "_accountedge._tcp.", "MYOB AccountEdge", "", false },
101 { "_aecoretech._tcp.", "Apple Application Engineering Services", "", false },
102 { "_afpovertcp._tcp.", "Apple File Sharing (AFP)", "afp://", false },
103 { "_airport._tcp.", "AirPort Base Station", "", false },
104 { "_apple-sasl._tcp.", "Apple Password Server", "", false },
105 { "_aquamon._tcp.", "AquaMon", "", false },
106 { "_async._tcp", "address-o-sync", "", false },
107 { "_auth._tcp.", "Authentication Service", "", false },
108 { "_bootps._tcp.", "Bootstrap Protocol Server", "", false },
109 { "_bousg._tcp.", "Bag Of Unusual Strategy Games", "", false },
110 { "_browse._udp.", "DNS Service Discovery", "", false },
111 { "_cheat._tcp.", "The Cheat", "", false },
112 { "_chess._tcp", "Project Gridlock", "", false },
113 { "_chfts._tcp", "Fluid Theme Server", "", false },
114 { "_clipboard._tcp", "Clipboard Sharing", "", false },
115 { "_contactserver._tcp.", "Now Up-to-Date & Contact", "", false },
116 { "_cvspserver._tcp", "CVS PServer", "", false },
117 { "_cytv._tcp.", "CyTV Network streaming for Elgato EyeTV", "", false },
118 { "_daap._tcp.", "Digital Audio Access Protocol (iTunes)", "daap://", false },
119 { "_distcc._tcp", "Distributed Compiler", "", false },
120 { "_dns-sd._udp", "DNS Service Discovery", "", false },
121 { "_dpap._tcp.", "Digital Picture Access Protocol (iPhoto)", "", false },
122 { "_earphoria._tcp.", "Earphoria", "", false },
123 { "_ecbyesfsgksc._tcp.", "Net Monitor Anti-Piracy Service", "", false },
124 { "_eheap._tcp.", "Interactive Room Software", "", false },
125 { "_embrace._tcp.", "DataEnvoy", "", false },
126 { "_eppc._tcp.", "Remote AppleEvents", "eppc://", false },
127 { "_exec._tcp.", "Remote Process Execution", "", false },
128 { "_facespan._tcp.", "FaceSpan", "", false },
129 { "_fjork._tcp.", "Fjork", "", false },
130 { "_ftp._tcp.", "File Transfer (FTP)", "ftp://", false },
131 { "_ftpcroco._tcp.", "Crocodile FTP Server", "", false },
132 { "_gbs-smp._tcp.", "SnapMail", "", false },
133 { "_gbs-stp._tcp.", "SnapTalk", "", false },
134 { "_grillezvous._tcp.", "Roxio ToastAnywhere(tm) Recorder Sharing", "", false },
135 { "_h323._tcp.", "H.323", "", false },
136 { "_hotwayd._tcp", "Hotwayd", "", false },
137 { "_http._tcp.", "Web Server (HTTP)", "http://", true },
138 { "_hydra._tcp", "SubEthaEdit", "", false },
139 { "_ica-networking._tcp.", "Image Capture Networking", "", false },
140 { "_ichalkboard._tcp.", "iChalk", "", false },
141 { "_ichat._tcp.", "iChat", "ichat://", false },
142 { "_iconquer._tcp.", "iConquer", "", false },
143 { "_imap._tcp.", "Internet Message Access Protocol", "", false },
144 { "_imidi._tcp.", "iMidi", "", false },
145 { "_ipp._tcp.", "Printer (IPP)", "ipp://", false },
146 { "_ishare._tcp.", "iShare", "", false },
147 { "_isparx._tcp.", "iSparx", "", false },
148 { "_istorm._tcp", "iStorm", "", false },
149 { "_iwork._tcp.", "iWork Server", "", false },
150 { "_liaison._tcp.", "Liaison", "", false },
151 { "_login._tcp.", "Remote Login a la Telnet", "", false },
152 { "_lontalk._tcp.", "LonTalk over IP (ANSI 852)", "", false },
153 { "_lonworks._tcp.", "Echelon LNS Remote Client", "", false },
154 { "_macfoh-remote._tcp.", "MacFOH Remote", "", false },
155 { "_moneyworks._tcp.", "MoneyWorks", "", false },
156 { "_mp3sushi._tcp", "MP3 Sushi", "", false },
157 { "_mttp._tcp.", "MenuTunes Sharing", "", false },
158 { "_ncbroadcast._tcp.", "Network Clipboard Broadcasts", "", false },
159 { "_ncdirect._tcp.", "Network Clipboard Direct Transfers", "", false },
160 { "_ncsyncserver._tcp.", "Network Clipboard Sync Server", "", false },
161 { "_newton-dock._tcp.", "Escale", "", false },
162 { "_nfs._tcp", "NFS", "", false },
163 { "_nssocketport._tcp.", "DO over NSSocketPort", "", false },
164 { "_omni-bookmark._tcp.", "OmniWeb", "", false },
165 { "_openbase._tcp.", "OpenBase SQL", "", false },
166 { "_p2pchat._tcp.", "Peer-to-Peer Chat", "", false },
167 { "_pdl-datastream._tcp.", "Printer (PDL)", "pdl://", false },
168 { "_poch._tcp.", "Parallel OperatiOn and Control Heuristic", "", false },
169 { "_pop_2_ambrosia._tcp.", "Pop-Pop", "", false },
170 { "_pop3._tcp", "POP3 Server", "", false },
171 { "_postgresql._tcp", "PostgreSQL Server", "", false },
172 { "_presence._tcp", "iChat AV", "", false },
173 { "_printer._tcp.", "Printer (LPR)", "lpr://", false },
174 { "_ptp._tcp.", "Picture Transfer (PTP)", "ptp://", false },
175 { "_register._tcp", "DNS Service Discovery", "", false },
176 { "_rfb._tcp.", "Remote Frame Buffer", "", false },
177 { "_riousbprint._tcp.", "Remote I/O USB Printer Protocol", "", false },
178 { "_rtsp._tcp.", "Real Time Stream Control Protocol", "", false },
179 { "_safarimenu._tcp", "Safari Menu", "", false },
180 { "_scone._tcp", "Scone", "", false },
181 { "_sdsharing._tcp.", "Speed Download", "", false },
182 { "_seeCard._tcp.", "seeCard", "", false },
183 { "_services._udp.", "DNS Service Discovery", "", false },
184 { "_shell._tcp.", "like exec, but automatic authentication", "", false },
185 { "_shout._tcp.", "Shout", "", false },
186 { "_shoutcast._tcp", "Nicecast", "", false },
187 { "_smb._tcp.", "Windows File Sharing (SMB)", "smb://", false },
188 { "_soap._tcp.", "Simple Object Access Protocol", "", false },
189 { "_spincrisis._tcp.", "Spin Crisis", "", false },
190 { "_spl-itunes._tcp.", "launchTunes", "", false },
191 { "_spr-itunes._tcp.", "netTunes", "", false },
192 { "_ssh._tcp.", "Secure Shell (SSH)", "ssh://", false },
193 { "_ssscreenshare._tcp", "Screen Sharing", "", false },
194 { "_sge-exec._tcp", "Sun Grid Engine (Execution Host)", "", false },
195 { "_sge-qmaster._tcp", "Sun Grid Engine (Master)", "", false },
196 { "_stickynotes._tcp", "Sticky Notes", "", false },
197 { "_strateges._tcp", "Strateges", "", false },
198 { "_sxqdea._tcp", "Synchronize! Pro X", "", false },
199 { "_sybase-tds._tcp", "Sybase Server", "", false },
200 { "_tce._tcp", "Power Card", "", false },
201 { "_teamlist._tcp", "ARTIS Team Task", "", false },
202 { "_teleport._tcp", "teleport", "", false },
203 { "_telnet._tcp.", "Telnet", "telnet://", false },
204 { "_tftp._tcp.", "Trivial File Transfer (TFTP)", "tftp://", false },
205 { "_tinavigator._tcp.", "TI Navigator", "", false },
206 { "_tivo_servemedia._tcp", "TiVo", "", false },
207 { "_upnp._tcp.", "Universal Plug and Play", "", false },
208 { "_utest._tcp.", "uTest", "", false },
209 { "_vue4rendercow._tcp", "VueProRenderCow", "", false },
210 { "_webdav._tcp.", "WebDAV", "webdav://", false },
211 { "_whamb._tcp.", "Whamb", "", false },
212 { "_workstation._tcp", "Macintosh Manager", "", false },
213 { "_ws._tcp", "Web Services", "", false },
214 { "_xserveraid._tcp.", "Xserve RAID", "xsr://", false },
215 { "_xsync._tcp.", "Xserve RAID Synchronization", "", false },
217 { "", "", "", false },
219 // Unofficial and invalid service types that will be phased out:
221 { "_clipboardsharing._tcp.", "ClipboardSharing", "", false },
222 { "_MacOSXDupSuppress._tcp.", "Mac OS X Duplicate Suppression", "", false },
223 { "_netmonitorserver._tcp.", "Net Monitor Server", "", false },
224 { "_networkclipboard._tcp.", "Network Clipboard", "", false },
225 { "_slimdevices_slimp3_cli._tcp.", "SliMP3 Server Command-Line Interface", "", false },
226 { "_slimdevices_slimp3_http._tcp.", "SliMP3 Server Web Interface", "", false },
227 { "_tieducationalhandhelddevice._tcp.", "TI Connect Manager", "", false },
228 { "_tivo_servemedia._tcp.", "TiVo", "", false },
230 { NULL
, NULL
, NULL
, false },
234 #pragma mark == Structures ==
237 //===========================================================================================================================
239 //===========================================================================================================================
241 struct DomainEventInfo
243 DNSBrowserEventType eventType
;
245 DNSNetworkAddress ifIP
;
248 struct ServiceEventInfo
250 DNSBrowserEventType eventType
;
254 DNSNetworkAddress ifIP
;
258 #pragma mark == Prototypes ==
261 //===========================================================================================================================
263 //===========================================================================================================================
269 DNSStatus inStatusCode
,
270 const DNSBrowserEvent
* inEvent
);
272 static char * DNSNetworkAddressToString( const DNSNetworkAddress
*inAddr
, char *outString
);
274 static DWORD
UTF8StringToStringObject( const char *inUTF8
, CString
&inObject
);
275 static DWORD
StringObjectToUTF8String( CString
&inObject
, std::string
&outUTF8
);
278 #pragma mark == Message Map ==
281 //===========================================================================================================================
283 //===========================================================================================================================
285 BEGIN_MESSAGE_MAP(ChooserDialog
, CDialog
)
286 //{{AFX_MSG_MAP(ChooserDialog)
288 ON_NOTIFY(LVN_ITEMCHANGED
, IDC_DOMAIN_LIST
, OnDomainListChanged
)
289 ON_NOTIFY(LVN_ITEMCHANGED
, IDC_SERVICE_LIST
, OnServiceListChanged
)
290 ON_NOTIFY(LVN_ITEMCHANGED
, IDC_CHOOSER_LIST
, OnChooserListChanged
)
291 ON_NOTIFY(NM_DBLCLK
, IDC_CHOOSER_LIST
, OnChooserListDoubleClick
)
292 ON_COMMAND(ID_HELP_ABOUT
, OnAbout
)
293 ON_WM_INITMENUPOPUP()
295 ON_COMMAND(ID_FILE_CLOSE
, OnFileClose
)
296 ON_COMMAND(ID_FILE_EXIT
, OnExit
)
300 ON_MESSAGE( WM_USER_DOMAIN_ADD
, OnDomainAdd
)
301 ON_MESSAGE( WM_USER_DOMAIN_REMOVE
, OnDomainRemove
)
302 ON_MESSAGE( WM_USER_SERVICE_ADD
, OnServiceAdd
)
303 ON_MESSAGE( WM_USER_SERVICE_REMOVE
, OnServiceRemove
)
304 ON_MESSAGE( WM_USER_RESOLVE
, OnResolve
)
308 #pragma mark == Routines ==
311 //===========================================================================================================================
313 //===========================================================================================================================
315 ChooserDialog::ChooserDialog( CWnd
*inParent
)
316 : CDialog( ChooserDialog::IDD
, inParent
)
318 //{{AFX_DATA_INIT(ChooserDialog)
319 // Note: the ClassWizard will add member initialization here
322 // Load menu accelerator table.
324 mMenuAcceleratorTable
= ::LoadAccelerators( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_CHOOSER_DIALOG_MENU_ACCELERATORS
) );
325 assert( mMenuAcceleratorTable
);
328 mIsServiceBrowsing
= false;
331 //===========================================================================================================================
333 //===========================================================================================================================
335 ChooserDialog::~ChooserDialog( void )
341 err
= DNSBrowserRelease( mBrowser
, 0 );
342 assert( err
== kDNSNoErr
);
346 //===========================================================================================================================
348 //===========================================================================================================================
350 void ChooserDialog::DoDataExchange( CDataExchange
*pDX
)
352 CDialog::DoDataExchange(pDX
);
354 //{{AFX_DATA_MAP(ChooserDialog)
355 DDX_Control(pDX
, IDC_SERVICE_LIST
, mServiceList
);
356 DDX_Control(pDX
, IDC_DOMAIN_LIST
, mDomainList
);
357 DDX_Control(pDX
, IDC_CHOOSER_LIST
, mChooserList
);
361 //===========================================================================================================================
363 //===========================================================================================================================
365 BOOL
ChooserDialog::OnInitDialog( void )
372 // Initialize our parent.
374 CDialog::OnInitDialog();
376 // Set up the window icon.
378 icon
= AfxGetApp()->LoadIcon( IDR_MAIN_ICON
);
382 SetIcon( icon
, TRUE
); // Set big icon
383 SetIcon( icon
, FALSE
); // Set small icon
386 // Set up the Domain List.
388 result
= tempString
.LoadString( IDS_CHOOSER_DOMAIN_COLUMN_NAME
);
390 mDomainList
.InsertColumn( 0, tempString
, LVCFMT_LEFT
, kDomainListDefaultDomainColumnWidth
);
392 // Set up the Service List.
394 result
= tempString
.LoadString( IDS_CHOOSER_SERVICE_COLUMN_TYPE
);
396 mServiceList
.InsertColumn( 0, tempString
, LVCFMT_LEFT
, kServiceListDefaultServiceColumnTypeWidth
);
398 result
= tempString
.LoadString( IDS_CHOOSER_SERVICE_COLUMN_DESC
);
400 mServiceList
.InsertColumn( 1, tempString
, LVCFMT_LEFT
, kServiceListDefaultServiceColumnDescWidth
);
402 PopulateServicesList();
404 // Set up the Chooser List.
406 result
= tempString
.LoadString( IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME
);
408 mChooserList
.InsertColumn( 0, tempString
, LVCFMT_LEFT
, kChooserListDefaultNameColumnWidth
);
410 result
= tempString
.LoadString( IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME
);
412 mChooserList
.InsertColumn( 1, tempString
, LVCFMT_LEFT
, kChooserListDefaultIPColumnWidth
);
414 // Set up the other controls.
418 // Start browsing for domains.
420 err
= DNSBrowserCreate( 0, BrowserCallBack
, this, &mBrowser
);
421 assert( err
== kDNSNoErr
);
423 err
= DNSBrowserStartDomainSearch( mBrowser
, 0 );
424 assert( err
== kDNSNoErr
);
429 //===========================================================================================================================
431 //===========================================================================================================================
433 void ChooserDialog::OnFileClose()
438 //===========================================================================================================================
440 //===========================================================================================================================
442 void ChooserDialog::OnActivate( UINT nState
, CWnd
* pWndOther
, BOOL bMinimized
)
444 // Always make the active window the "main" window so modal dialogs work better and the app quits after closing
447 gApp
.m_pMainWnd
= this;
449 CDialog::OnActivate(nState
, pWndOther
, bMinimized
);
452 //===========================================================================================================================
454 //===========================================================================================================================
456 void ChooserDialog::PostNcDestroy()
458 // Call the base class to do the normal cleanup.
463 //===========================================================================================================================
464 // PreTranslateMessage
465 //===========================================================================================================================
467 BOOL
ChooserDialog::PreTranslateMessage(MSG
* pMsg
)
472 assert( mMenuAcceleratorTable
);
473 if( mMenuAcceleratorTable
)
475 result
= ::TranslateAccelerator( m_hWnd
, mMenuAcceleratorTable
, pMsg
);
479 result
= CDialog::PreTranslateMessage( pMsg
);
484 //===========================================================================================================================
486 //===========================================================================================================================
488 void ChooserDialog::OnInitMenuPopup( CMenu
*pPopupMenu
, UINT nIndex
, BOOL bSysMenu
)
490 CDialog::OnInitMenuPopup( pPopupMenu
, nIndex
, bSysMenu
);
494 case kChooserMenuIndexFile
:
497 case kChooserMenuIndexHelp
:
505 //===========================================================================================================================
507 //===========================================================================================================================
509 void ChooserDialog::OnExit()
514 //===========================================================================================================================
516 //===========================================================================================================================
518 void ChooserDialog::OnAbout()
525 //===========================================================================================================================
527 //===========================================================================================================================
529 void ChooserDialog::OnSysCommand( UINT inID
, LPARAM inParam
)
531 CDialog::OnSysCommand( inID
, inParam
);
534 //===========================================================================================================================
536 //===========================================================================================================================
538 void ChooserDialog::OnClose()
542 gApp
.m_pMainWnd
= this;
546 //===========================================================================================================================
548 //===========================================================================================================================
550 void ChooserDialog::OnNcDestroy()
552 gApp
.m_pMainWnd
= this;
554 CDialog::OnNcDestroy();
557 //===========================================================================================================================
558 // OnDomainListChanged
559 //===========================================================================================================================
561 void ChooserDialog::OnDomainListChanged( NMHDR
*pNMHDR
, LRESULT
*pResult
)
563 UNUSED_ALWAYS( pNMHDR
);
565 // Domain list changes have similar effects to service list changes so reuse that code path by calling it here.
567 OnServiceListChanged( NULL
, NULL
);
572 //===========================================================================================================================
573 // OnServiceListChanged
574 //===========================================================================================================================
576 void ChooserDialog::OnServiceListChanged( NMHDR
*pNMHDR
, LRESULT
*pResult
)
581 UNUSED_ALWAYS( pNMHDR
);
583 // Stop any existing service search.
587 // If a domain and service type are selected, start searching for the service type on the domain.
589 selectedType
= mServiceList
.GetNextItem( -1, LVNI_SELECTED
);
590 selectedDomain
= mDomainList
.GetNextItem( -1, LVNI_SELECTED
);
592 if( ( selectedType
>= 0 ) && ( selectedDomain
>= 0 ) )
598 s
= mDomainList
.GetItemText( selectedDomain
, 0 );
599 StringObjectToUTF8String( s
, utf8
);
600 type
= mServiceTypes
[ selectedType
].serviceType
.c_str();
603 StartBrowsing( type
, utf8
.c_str() );
613 //===========================================================================================================================
614 // OnChooserListChanged
615 //===========================================================================================================================
617 void ChooserDialog::OnChooserListChanged( NMHDR
*pNMHDR
, LRESULT
*pResult
)
619 UNUSED_ALWAYS( pNMHDR
);
625 //===========================================================================================================================
626 // OnChooserListDoubleClick
627 //===========================================================================================================================
629 void ChooserDialog::OnChooserListDoubleClick( NMHDR
*pNMHDR
, LRESULT
*pResult
)
633 UNUSED_ALWAYS( pNMHDR
);
635 // Display the service instance if it is selected. Otherwise, clear all the info.
637 selectedItem
= mChooserList
.GetNextItem( -1, LVNI_SELECTED
);
638 if( selectedItem
>= 0 )
640 ServiceInstanceInfo
* p
;
642 const KnownServiceEntry
* service
;
644 assert( selectedItem
< (int) mServiceInstances
.size() );
645 p
= &mServiceInstances
[ selectedItem
];
647 // Search for a known service type entry that matches.
649 for( service
= kKnownServiceTable
; service
->serviceType
; ++service
)
651 if( p
->type
== service
->serviceType
)
656 if( service
->serviceType
)
660 // Create a URL representing the service instance.
662 if( strcmp( service
->serviceType
, "_smb._tcp." ) == 0 )
664 // Special case for SMB (no port number).
666 url
.Format( TEXT( "%s%s/" ), service
->urlScheme
, (const char *) p
->ip
.c_str() );
668 else if( strcmp( service
->serviceType
, "_ftp._tcp." ) == 0 )
670 // Special case for FTP to get login info.
676 if( !dialog
.GetLogin( username
, password
) )
681 // Build URL in the following format:
683 // ftp://[username[:password]@]<ip>
685 url
+= service
->urlScheme
;
686 if( username
.GetLength() > 0 )
689 if( password
.GetLength() > 0 )
696 url
+= p
->ip
.c_str();
698 else if( strcmp( service
->serviceType
, "_http._tcp." ) == 0 )
700 // Special case for HTTP to exclude "path=" if present.
702 text
= service
->useText
? p
->text
.c_str() : "";
703 if( strncmp( text
, "path=", 5 ) == 0 )
709 url
.Format( TEXT( "%s%s/%s" ), service
->urlScheme
, (const char *) p
->ip
.c_str(), text
);
713 url
.Format( TEXT( "%s%s%s" ), service
->urlScheme
, (const char *) p
->ip
.c_str(), text
);
718 text
= service
->useText
? p
->text
.c_str() : "";
719 url
.Format( TEXT( "%s%s/%s" ), service
->urlScheme
, (const char *) p
->ip
.c_str(), text
);
722 // Let the system open the URL in the correct app.
725 CWaitCursor waitCursor
;
727 ShellExecute( NULL
, TEXT( "open" ), url
, TEXT( "" ), TEXT( "c:\\" ), SW_SHOWNORMAL
);
736 //===========================================================================================================================
738 //===========================================================================================================================
740 void ChooserDialog::OnCancel()
745 //===========================================================================================================================
746 // PopulateServicesList
747 //===========================================================================================================================
749 void ChooserDialog::PopulateServicesList( void )
751 ServiceTypeVector::iterator i
;
756 // Add a fixed list of known services.
758 if( mServiceTypes
.empty() )
760 const KnownServiceEntry
* service
;
762 for( service
= kKnownServiceTable
; service
->serviceType
; ++service
)
764 ServiceTypeInfo info
;
766 info
.serviceType
= service
->serviceType
;
767 info
.description
= service
->description
;
768 info
.urlScheme
= service
->urlScheme
;
769 mServiceTypes
.push_back( info
);
773 // Add each service to the list.
775 for( i
= mServiceTypes
.begin(); i
!= mServiceTypes
.end(); ++i
)
780 p
= ( *i
).serviceType
.c_str();
781 if( *p
== '_' ) ++p
; // Skip leading '_'.
782 q
= strchr( p
, '.' ); // Find first '.'.
783 if( q
) tmp
.assign( p
, (size_t)( q
- p
) ); // Use only up to the first '.'.
784 else tmp
.assign( p
); // No '.' so use the entire string.
785 UTF8StringToStringObject( tmp
.c_str(), type
);
786 UTF8StringToStringObject( ( *i
).description
.c_str(), desc
);
790 n
= mServiceList
.GetItemCount();
791 mServiceList
.InsertItem( n
, type
);
792 mServiceList
.SetItemText( n
, 1, desc
);
795 // Select the first service type by default.
797 if( !mServiceTypes
.empty() )
799 mServiceList
.SetItemState( 0, LVIS_SELECTED
| LVIS_FOCUSED
, LVIS_SELECTED
| LVIS_FOCUSED
);
803 //===========================================================================================================================
805 //===========================================================================================================================
807 void ChooserDialog::UpdateInfoDisplay( void )
815 std::string textNewLines
;
816 std::string hostName
;
818 std::string::iterator i
;
820 // Display the service instance if it is selected. Otherwise, clear all the info.
822 selectedItem
= mChooserList
.GetNextItem( -1, LVNI_SELECTED
);
823 if( selectedItem
>= 0 )
825 ServiceInstanceInfo
* p
;
827 assert( selectedItem
< (int) mServiceInstances
.size() );
828 p
= &mServiceInstances
[ selectedItem
];
834 hostName
= p
->hostName
;
836 // Sync up the list items with the actual data (IP address may change).
838 UTF8StringToStringObject( ip
.c_str(), s
);
839 mChooserList
.SetItemText( selectedItem
, 1, s
);
844 item
= (CWnd
*) this->GetDlgItem( IDC_INFO_NAME_TEXT
);
846 UTF8StringToStringObject( name
.c_str(), s
);
847 item
->SetWindowText( s
);
851 item
= (CWnd
*) this->GetDlgItem( IDC_INFO_IP_TEXT
);
853 UTF8StringToStringObject( ip
.c_str(), s
);
854 item
->SetWindowText( s
);
858 item
= (CWnd
*) this->GetDlgItem( IDC_INFO_INTERFACE_TEXT
);
860 UTF8StringToStringObject( ifIP
.c_str(), s
);
861 item
->SetWindowText( s
);
864 item
= (CWnd
*) this->GetDlgItem( IDC_INFO_HOST_NAME_TEXT
);
866 UTF8StringToStringObject( hostName
.c_str(), s
);
867 item
->SetWindowText( s
);
871 item
= (CWnd
*) this->GetDlgItem( IDC_INFO_TEXT_TEXT
);
873 for( i
= text
.begin(); i
!= text
.end(); ++i
)
877 textNewLines
+= "\r\n";
884 UTF8StringToStringObject( textNewLines
.c_str(), s
);
885 item
->SetWindowText( s
);
892 //===========================================================================================================================
894 //===========================================================================================================================
896 LONG
ChooserDialog::OnDomainAdd( WPARAM inWParam
, LPARAM inLParam
)
899 std::auto_ptr
< DomainEventInfo
> pAutoPtr
;
906 UNUSED_ALWAYS( inWParam
);
909 p
= reinterpret_cast <DomainEventInfo
*> ( inLParam
);
912 // Search to see if we already know about this domain. If not, add it to the list.
916 n
= mDomainList
.GetItemCount();
917 for( i
= 0; i
< n
; ++i
)
919 s
= mDomainList
.GetItemText( i
, 0 );
930 mDomainList
.InsertItem( n
, domain
);
932 // If no domains are selected and the domain being added is a default domain, select it.
934 selectedItem
= mDomainList
.GetNextItem( -1, LVNI_SELECTED
);
935 if( ( selectedItem
< 0 ) && ( p
->eventType
== kDNSBrowserEventTypeAddDefaultDomain
) )
937 mDomainList
.SetItemState( n
, LVIS_SELECTED
| LVIS_FOCUSED
, LVIS_SELECTED
| LVIS_FOCUSED
);
943 //===========================================================================================================================
945 //===========================================================================================================================
947 LONG
ChooserDialog::OnDomainRemove( WPARAM inWParam
, LPARAM inLParam
)
950 std::auto_ptr
< DomainEventInfo
> pAutoPtr
;
957 UNUSED_ALWAYS( inWParam
);
960 p
= reinterpret_cast <DomainEventInfo
*> ( inLParam
);
963 // Search to see if we know about this domain. If so, remove it from the list.
967 n
= mDomainList
.GetItemCount();
968 for( i
= 0; i
< n
; ++i
)
970 s
= mDomainList
.GetItemText( i
, 0 );
979 mDomainList
.DeleteItem( i
);
984 //===========================================================================================================================
986 //===========================================================================================================================
988 LONG
ChooserDialog::OnServiceAdd( WPARAM inWParam
, LPARAM inLParam
)
990 ServiceEventInfo
* p
;
991 std::auto_ptr
< ServiceEventInfo
> pAutoPtr
;
993 UNUSED_ALWAYS( inWParam
);
996 p
= reinterpret_cast <ServiceEventInfo
*> ( inLParam
);
1002 //===========================================================================================================================
1004 //===========================================================================================================================
1006 LONG
ChooserDialog::OnServiceRemove( WPARAM inWParam
, LPARAM inLParam
)
1008 ServiceEventInfo
* p
;
1009 std::auto_ptr
< ServiceEventInfo
> pAutoPtr
;
1014 UNUSED_ALWAYS( inWParam
);
1017 p
= reinterpret_cast <ServiceEventInfo
*> ( inLParam
);
1018 pAutoPtr
.reset( p
);
1020 // Search to see if we know about this service instance. If so, remove it from the list.
1023 n
= (int) mServiceInstances
.size();
1024 for( i
= 0; i
< n
; ++i
)
1026 ServiceInstanceInfo
* q
;
1028 // If the name, type, domain, and interface match, treat it as the same service instance.
1030 q
= &mServiceInstances
[ i
];
1031 if( ( p
->name
== q
->name
) &&
1032 ( p
->type
== q
->type
) &&
1033 ( p
->domain
== q
->domain
) )
1041 mChooserList
.DeleteItem( i
);
1042 assert( i
< (int) mServiceInstances
.size() );
1043 mServiceInstances
.erase( mServiceInstances
.begin() + i
);
1048 //===========================================================================================================================
1050 //===========================================================================================================================
1052 LONG
ChooserDialog::OnResolve( WPARAM inWParam
, LPARAM inLParam
)
1054 ServiceInstanceInfo
* p
;
1055 std::auto_ptr
< ServiceInstanceInfo
> pAutoPtr
;
1061 UNUSED_ALWAYS( inWParam
);
1064 p
= reinterpret_cast <ServiceInstanceInfo
*> ( inLParam
);
1065 pAutoPtr
.reset( p
);
1067 // Make sure it is for an item of the correct type. This handles any resolves that may have been queued up.
1069 selectedType
= mServiceList
.GetNextItem( -1, LVNI_SELECTED
);
1070 assert( selectedType
>= 0 );
1071 if( selectedType
>= 0 )
1073 assert( selectedType
<= (int) mServiceTypes
.size() );
1074 if( p
->type
!= mServiceTypes
[ selectedType
].serviceType
)
1080 // Search to see if we know about this service instance. If so, update its info. Otherwise, add it to the list.
1083 n
= (int) mServiceInstances
.size();
1084 for( i
= 0; i
< n
; ++i
)
1086 ServiceInstanceInfo
* q
;
1088 // If the name, type, domain, and interface matches, treat it as the same service instance.
1090 q
= &mServiceInstances
[ i
];
1091 if( ( p
->name
== q
->name
) &&
1092 ( p
->type
== q
->type
) &&
1093 ( p
->domain
== q
->domain
) &&
1094 ( p
->ifIP
== q
->ifIP
) )
1102 mServiceInstances
[ i
] = *p
;
1108 mServiceInstances
.push_back( *p
);
1109 UTF8StringToStringObject( p
->name
.c_str(), s
);
1110 mChooserList
.InsertItem( n
, s
);
1112 UTF8StringToStringObject( p
->ip
.c_str(), s
);
1113 mChooserList
.SetItemText( n
, 1, s
);
1115 // If this is the only item, select it.
1119 mChooserList
.SetItemState( n
, LVIS_SELECTED
| LVIS_FOCUSED
, LVIS_SELECTED
| LVIS_FOCUSED
);
1122 UpdateInfoDisplay();
1128 //===========================================================================================================================
1130 //===========================================================================================================================
1132 void ChooserDialog::StartBrowsing( const char *inType
, const char *inDomain
)
1136 assert( mServiceInstances
.empty() );
1137 assert( mChooserList
.GetItemCount() == 0 );
1138 assert( !mIsServiceBrowsing
);
1140 mChooserList
.DeleteAllItems();
1141 mServiceInstances
.clear();
1143 mIsServiceBrowsing
= true;
1144 err
= DNSBrowserStartServiceSearch( mBrowser
, kDNSBrowserFlagAutoResolve
, inType
, inDomain
);
1145 assert( err
== kDNSNoErr
);
1148 //===========================================================================================================================
1150 //===========================================================================================================================
1152 void ChooserDialog::StopBrowsing( void )
1154 // If searching, stop.
1156 if( mIsServiceBrowsing
)
1160 mIsServiceBrowsing
= false;
1161 err
= DNSBrowserStopServiceSearch( mBrowser
, 0 );
1162 assert( err
== kDNSNoErr
);
1165 // Remove all service instances.
1167 mChooserList
.DeleteAllItems();
1168 assert( mChooserList
.GetItemCount() == 0 );
1169 mServiceInstances
.clear();
1170 assert( mServiceInstances
.empty() );
1171 UpdateInfoDisplay();
1178 //===========================================================================================================================
1180 //===========================================================================================================================
1185 DNSBrowserRef inRef
,
1186 DNSStatus inStatusCode
,
1187 const DNSBrowserEvent
* inEvent
)
1189 ChooserDialog
* dialog
;
1193 UNUSED_ALWAYS( inStatusCode
);
1194 UNUSED_ALWAYS( inRef
);
1196 // Check parameters.
1198 assert( inContext
);
1199 dialog
= reinterpret_cast <ChooserDialog
*> ( inContext
);
1203 switch( inEvent
->type
)
1205 case kDNSBrowserEventTypeRelease
:
1210 case kDNSBrowserEventTypeAddDomain
:
1211 case kDNSBrowserEventTypeAddDefaultDomain
:
1212 case kDNSBrowserEventTypeRemoveDomain
:
1214 DomainEventInfo
* domain
;
1215 std::auto_ptr
< DomainEventInfo
> domainAutoPtr
;
1217 domain
= new DomainEventInfo
;
1218 domainAutoPtr
.reset( domain
);
1220 domain
->eventType
= inEvent
->type
;
1221 domain
->domain
= inEvent
->data
.addDomain
.domain
;
1222 domain
->ifIP
= inEvent
->data
.addDomain
.interfaceIP
;
1224 message
= ( inEvent
->type
== kDNSBrowserEventTypeRemoveDomain
) ? WM_USER_DOMAIN_REMOVE
: WM_USER_DOMAIN_ADD
;
1225 posted
= ::PostMessage( dialog
->GetSafeHwnd(), message
, 0, (LPARAM
) domain
);
1229 domainAutoPtr
.release();
1236 case kDNSBrowserEventTypeAddService
:
1237 case kDNSBrowserEventTypeRemoveService
:
1239 ServiceEventInfo
* service
;
1240 std::auto_ptr
< ServiceEventInfo
> serviceAutoPtr
;
1242 service
= new ServiceEventInfo
;
1243 serviceAutoPtr
.reset( service
);
1245 service
->eventType
= inEvent
->type
;
1246 service
->name
= inEvent
->data
.addService
.name
;
1247 service
->type
= inEvent
->data
.addService
.type
;
1248 service
->domain
= inEvent
->data
.addService
.domain
;
1249 service
->ifIP
= inEvent
->data
.addService
.interfaceIP
;
1251 message
= ( inEvent
->type
== kDNSBrowserEventTypeAddService
) ? WM_USER_SERVICE_ADD
: WM_USER_SERVICE_REMOVE
;
1252 posted
= ::PostMessage( dialog
->GetSafeHwnd(), message
, 0, (LPARAM
) service
);
1256 serviceAutoPtr
.release();
1263 case kDNSBrowserEventTypeResolved
:
1264 if( inEvent
->data
.resolved
->address
.addressType
== kDNSNetworkAddressTypeIPv4
)
1266 ServiceInstanceInfo
* serviceInstance
;
1267 std::auto_ptr
< ServiceInstanceInfo
> serviceInstanceAutoPtr
;
1270 serviceInstance
= new ServiceInstanceInfo
;
1271 serviceInstanceAutoPtr
.reset( serviceInstance
);
1273 serviceInstance
->name
= inEvent
->data
.resolved
->name
;
1274 serviceInstance
->type
= inEvent
->data
.resolved
->type
;
1275 serviceInstance
->domain
= inEvent
->data
.resolved
->domain
;
1276 serviceInstance
->ip
= DNSNetworkAddressToString( &inEvent
->data
.resolved
->address
, s
);
1277 serviceInstance
->ifIP
= DNSNetworkAddressToString( &inEvent
->data
.resolved
->interfaceIP
, s
);
1278 serviceInstance
->text
= inEvent
->data
.resolved
->textRecord
;
1279 serviceInstance
->hostName
= inEvent
->data
.resolved
->hostName
;
1281 posted
= ::PostMessage( dialog
->GetSafeHwnd(), WM_USER_RESOLVE
, 0, (LPARAM
) serviceInstance
);
1285 serviceInstanceAutoPtr
.release();
1296 // Don't let exceptions escape.
1300 //===========================================================================================================================
1301 // DNSNetworkAddressToString
1303 // Note: Currently only supports IPv4 network addresses.
1304 //===========================================================================================================================
1306 static char * DNSNetworkAddressToString( const DNSNetworkAddress
*inAddr
, char *outString
)
1311 p
= inAddr
->u
.ipv4
.addr
.v8
;
1312 port
= ntohs( inAddr
->u
.ipv4
.port
.v16
);
1313 if( port
!= kDNSPortInvalid
)
1315 sprintf( outString
, "%u.%u.%u.%u:%u", p
[ 0 ], p
[ 1 ], p
[ 2 ], p
[ 3 ], port
);
1319 sprintf( outString
, "%u.%u.%u.%u", p
[ 0 ], p
[ 1 ], p
[ 2 ], p
[ 3 ] );
1321 return( outString
);
1324 //===========================================================================================================================
1325 // UTF8StringToStringObject
1326 //===========================================================================================================================
1328 static DWORD
UTF8StringToStringObject( const char *inUTF8
, CString
&inObject
)
1336 n
= MultiByteToWideChar( CP_UTF8
, 0, inUTF8
, -1, NULL
, 0 );
1339 unicode
= (BSTR
) malloc( (size_t)( n
* sizeof( wchar_t ) ) );
1342 err
= ERROR_INSUFFICIENT_BUFFER
;
1346 n
= MultiByteToWideChar( CP_UTF8
, 0, inUTF8
, -1, unicode
, n
);
1353 err
= ERROR_NO_UNICODE_TRANSLATION
;
1371 //===========================================================================================================================
1372 // StringObjectToUTF8String
1373 //===========================================================================================================================
1375 static DWORD
StringObjectToUTF8String( CString
&inObject
, std::string
&outUTF8
)
1386 nUnicode
= inObject
.GetLength();
1389 unicode
= inObject
.AllocSysString();
1390 n
= WideCharToMultiByte( CP_UTF8
, 0, unicode
, nUnicode
, NULL
, 0, NULL
, NULL
);
1393 utf8
= (char *) malloc( (size_t) n
);
1395 if( !utf8
) { err
= ERROR_INSUFFICIENT_BUFFER
; goto exit
; }
1397 n
= WideCharToMultiByte( CP_UTF8
, 0, unicode
, nUnicode
, utf8
, n
, NULL
, NULL
);
1402 outUTF8
.assign( utf8
, n
);
1406 err
= ERROR_NO_UNICODE_TRANSLATION
;
1419 SysFreeString( unicode
);