]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
mDNSResponder-212.1.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / DNSServiceBrowser / Windows / Sources / ChooserDialog.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: ChooserDialog.cpp,v $
20 Revision 1.5 2008/10/23 22:33:26 cheshire
21 Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
22
23 Revision 1.4 2006/08/14 23:25:49 cheshire
24 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
25
26 Revision 1.3 2005/02/10 22:35:35 cheshire
27 <rdar://problem/3727944> Update name
28
29 Revision 1.2 2004/07/13 21:24:26 rpantos
30 Fix for <rdar://problem/3701120>.
31
32 Revision 1.1 2004/06/18 04:04:36 rpantos
33 Move up one level
34
35 Revision 1.10 2004/04/23 01:19:41 bradley
36 Changed TXT record new line delimiter from \n to \r\n so it works now that it is an edit text.
37
38 Revision 1.9 2004/03/07 05:51:04 bradley
39 Updated service type list table to include all service types from dns-sd.org as of 2004-03-06.
40 Added separate Service Type and Service Description columns so both are show in the window.
41
42 Revision 1.8 2004/01/30 02:56:32 bradley
43 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
44
45 Revision 1.7 2003/12/25 03:42:04 bradley
46 Added login dialog to get username/password when going to FTP sites. Added more services.
47
48 Revision 1.6 2003/10/31 12:18:30 bradley
49 Added display of the resolved host name. Show separate TXT record entries on separate lines.
50
51 Revision 1.5 2003/10/16 09:21:56 bradley
52 Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
53
54 Revision 1.4 2003/10/10 03:41:29 bradley
55 Changed HTTP double-click handling to work with or without the path= prefix in the TXT record.
56
57 Revision 1.3 2003/10/09 19:50:40 bradley
58 Sort service type list by description.
59
60 Revision 1.2 2003/10/09 19:41:29 bradley
61 Changed quit handling to go through normal close path so dialog is freed on quit. Integrated changes
62 from Andrew van der Stock for the addition of an _rfb._tcp service type for a VNC Remote Framebuffer
63 Server for KDE support. Widened service type list to handle larger service type descriptions.
64
65 Revision 1.1 2003/08/21 02:06:47 bradley
66 Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
67
68 Revision 1.7 2003/08/20 06:45:56 bradley
69 Updated for IP address changes in DNSServices. Added support for browsing for Xserve RAID.
70
71 Revision 1.6 2003/08/12 19:56:28 cheshire
72 Update to APSL 2.0
73
74 Revision 1.5 2003/07/13 01:03:55 cheshire
75 Diffs provided by Bob Bradley to provide provide proper display of Unicode names
76
77 Revision 1.4 2003/07/02 21:20:06 cheshire
78 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
79
80 Revision 1.3 2002/09/21 20:44:55 zarzycki
81 Added APSL info
82
83 Revision 1.2 2002/09/20 08:39:21 bradley
84 Make sure each resolved item matches the selected service type to handle resolved that may have
85 been queued up on the Windows Message Loop. Reduce column to fit when scrollbar is present.
86
87 Revision 1.1 2002/09/20 06:12:52 bradley
88 DNSServiceBrowser for Windows
89
90 */
91
92 #include <assert.h>
93 #include <stdio.h>
94 #include <stdlib.h>
95 #include <string.h>
96 #include <time.h>
97
98 #include <algorithm>
99 #include <memory>
100
101 #include "stdafx.h"
102
103 #include "DNSServices.h"
104
105 #include "Application.h"
106 #include "AboutDialog.h"
107 #include "LoginDialog.h"
108 #include "Resource.h"
109
110 #include "ChooserDialog.h"
111
112 #ifdef _DEBUG
113 #define new DEBUG_NEW
114 #undef THIS_FILE
115 static char THIS_FILE[] = __FILE__;
116 #endif
117
118 #if 0
119 #pragma mark == Constants ==
120 #endif
121
122 //===========================================================================================================================
123 // Constants
124 //===========================================================================================================================
125
126 // Menus
127
128 enum
129 {
130 kChooserMenuIndexFile = 0,
131 kChooserMenuIndexHelp = 1
132 };
133
134 // Domain List
135
136 #define kDomainListDefaultDomainColumnWidth 164
137
138 // Service List
139
140 #define kServiceListDefaultServiceColumnTypeWidth 146
141 #define kServiceListDefaultServiceColumnDescWidth 230
142
143 // Chooser List
144
145 #define kChooserListDefaultNameColumnWidth 190
146 #define kChooserListDefaultIPColumnWidth 120
147
148 // Windows User Messages
149
150 #define WM_USER_DOMAIN_ADD ( WM_USER + 0x100 )
151 #define WM_USER_DOMAIN_REMOVE ( WM_USER + 0x101 )
152 #define WM_USER_SERVICE_ADD ( WM_USER + 0x102 )
153 #define WM_USER_SERVICE_REMOVE ( WM_USER + 0x103 )
154 #define WM_USER_RESOLVE ( WM_USER + 0x104 )
155
156 #if 0
157 #pragma mark == Constants - Service Table ==
158 #endif
159
160 //===========================================================================================================================
161 // Constants - Service Table
162 //===========================================================================================================================
163
164 struct KnownServiceEntry
165 {
166 const char * serviceType;
167 const char * description;
168 const char * urlScheme;
169 bool useText;
170 };
171
172 static const KnownServiceEntry kKnownServiceTable[] =
173 {
174 { "_accountedge._tcp.", "MYOB AccountEdge", "", false },
175 { "_aecoretech._tcp.", "Apple Application Engineering Services", "", false },
176 { "_afpovertcp._tcp.", "Apple File Sharing (AFP)", "afp://", false },
177 { "_airport._tcp.", "AirPort Base Station", "", false },
178 { "_apple-sasl._tcp.", "Apple Password Server", "", false },
179 { "_aquamon._tcp.", "AquaMon", "", false },
180 { "_async._tcp", "address-o-sync", "", false },
181 { "_auth._tcp.", "Authentication Service", "", false },
182 { "_bootps._tcp.", "Bootstrap Protocol Server", "", false },
183 { "_bousg._tcp.", "Bag Of Unusual Strategy Games", "", false },
184 { "_browse._udp.", "DNS Service Discovery", "", false },
185 { "_cheat._tcp.", "The Cheat", "", false },
186 { "_chess._tcp", "Project Gridlock", "", false },
187 { "_chfts._tcp", "Fluid Theme Server", "", false },
188 { "_clipboard._tcp", "Clipboard Sharing", "", false },
189 { "_contactserver._tcp.", "Now Up-to-Date & Contact", "", false },
190 { "_cvspserver._tcp", "CVS PServer", "", false },
191 { "_cytv._tcp.", "CyTV Network streaming for Elgato EyeTV", "", false },
192 { "_daap._tcp.", "Digital Audio Access Protocol (iTunes)", "daap://", false },
193 { "_distcc._tcp", "Distributed Compiler", "", false },
194 { "_dns-sd._udp", "DNS Service Discovery", "", false },
195 { "_dpap._tcp.", "Digital Picture Access Protocol (iPhoto)", "", false },
196 { "_earphoria._tcp.", "Earphoria", "", false },
197 { "_ecbyesfsgksc._tcp.", "Net Monitor Anti-Piracy Service", "", false },
198 { "_eheap._tcp.", "Interactive Room Software", "", false },
199 { "_embrace._tcp.", "DataEnvoy", "", false },
200 { "_eppc._tcp.", "Remote AppleEvents", "eppc://", false },
201 { "_exec._tcp.", "Remote Process Execution", "", false },
202 { "_facespan._tcp.", "FaceSpan", "", false },
203 { "_fjork._tcp.", "Fjork", "", false },
204 { "_ftp._tcp.", "File Transfer (FTP)", "ftp://", false },
205 { "_ftpcroco._tcp.", "Crocodile FTP Server", "", false },
206 { "_gbs-smp._tcp.", "SnapMail", "", false },
207 { "_gbs-stp._tcp.", "SnapTalk", "", false },
208 { "_grillezvous._tcp.", "Roxio ToastAnywhere(tm) Recorder Sharing", "", false },
209 { "_h323._tcp.", "H.323", "", false },
210 { "_hotwayd._tcp", "Hotwayd", "", false },
211 { "_http._tcp.", "Web Server (HTTP)", "http://", true },
212 { "_hydra._tcp", "SubEthaEdit", "", false },
213 { "_ica-networking._tcp.", "Image Capture Networking", "", false },
214 { "_ichalkboard._tcp.", "iChalk", "", false },
215 { "_ichat._tcp.", "iChat", "ichat://", false },
216 { "_iconquer._tcp.", "iConquer", "", false },
217 { "_imap._tcp.", "Internet Message Access Protocol", "", false },
218 { "_imidi._tcp.", "iMidi", "", false },
219 { "_ipp._tcp.", "Printer (IPP)", "ipp://", false },
220 { "_ishare._tcp.", "iShare", "", false },
221 { "_isparx._tcp.", "iSparx", "", false },
222 { "_istorm._tcp", "iStorm", "", false },
223 { "_iwork._tcp.", "iWork Server", "", false },
224 { "_liaison._tcp.", "Liaison", "", false },
225 { "_login._tcp.", "Remote Login a la Telnet", "", false },
226 { "_lontalk._tcp.", "LonTalk over IP (ANSI 852)", "", false },
227 { "_lonworks._tcp.", "Echelon LNS Remote Client", "", false },
228 { "_macfoh-remote._tcp.", "MacFOH Remote", "", false },
229 { "_moneyworks._tcp.", "MoneyWorks", "", false },
230 { "_mp3sushi._tcp", "MP3 Sushi", "", false },
231 { "_mttp._tcp.", "MenuTunes Sharing", "", false },
232 { "_ncbroadcast._tcp.", "Network Clipboard Broadcasts", "", false },
233 { "_ncdirect._tcp.", "Network Clipboard Direct Transfers", "", false },
234 { "_ncsyncserver._tcp.", "Network Clipboard Sync Server", "", false },
235 { "_newton-dock._tcp.", "Escale", "", false },
236 { "_nfs._tcp", "NFS", "", false },
237 { "_nssocketport._tcp.", "DO over NSSocketPort", "", false },
238 { "_omni-bookmark._tcp.", "OmniWeb", "", false },
239 { "_openbase._tcp.", "OpenBase SQL", "", false },
240 { "_p2pchat._tcp.", "Peer-to-Peer Chat", "", false },
241 { "_pdl-datastream._tcp.", "Printer (PDL)", "pdl://", false },
242 { "_poch._tcp.", "Parallel OperatiOn and Control Heuristic", "", false },
243 { "_pop_2_ambrosia._tcp.", "Pop-Pop", "", false },
244 { "_pop3._tcp", "POP3 Server", "", false },
245 { "_postgresql._tcp", "PostgreSQL Server", "", false },
246 { "_presence._tcp", "iChat AV", "", false },
247 { "_printer._tcp.", "Printer (LPR)", "lpr://", false },
248 { "_ptp._tcp.", "Picture Transfer (PTP)", "ptp://", false },
249 { "_register._tcp", "DNS Service Discovery", "", false },
250 { "_rfb._tcp.", "Remote Frame Buffer", "", false },
251 { "_riousbprint._tcp.", "Remote I/O USB Printer Protocol", "", false },
252 { "_rtsp._tcp.", "Real Time Stream Control Protocol", "", false },
253 { "_safarimenu._tcp", "Safari Menu", "", false },
254 { "_scone._tcp", "Scone", "", false },
255 { "_sdsharing._tcp.", "Speed Download", "", false },
256 { "_seeCard._tcp.", "seeCard", "", false },
257 { "_services._udp.", "DNS Service Discovery", "", false },
258 { "_shell._tcp.", "like exec, but automatic authentication", "", false },
259 { "_shout._tcp.", "Shout", "", false },
260 { "_shoutcast._tcp", "Nicecast", "", false },
261 { "_smb._tcp.", "Windows File Sharing (SMB)", "smb://", false },
262 { "_soap._tcp.", "Simple Object Access Protocol", "", false },
263 { "_spincrisis._tcp.", "Spin Crisis", "", false },
264 { "_spl-itunes._tcp.", "launchTunes", "", false },
265 { "_spr-itunes._tcp.", "netTunes", "", false },
266 { "_ssh._tcp.", "Secure Shell (SSH)", "ssh://", false },
267 { "_ssscreenshare._tcp", "Screen Sharing", "", false },
268 { "_sge-exec._tcp", "Sun Grid Engine (Execution Host)", "", false },
269 { "_sge-qmaster._tcp", "Sun Grid Engine (Master)", "", false },
270 { "_stickynotes._tcp", "Sticky Notes", "", false },
271 { "_strateges._tcp", "Strateges", "", false },
272 { "_sxqdea._tcp", "Synchronize! Pro X", "", false },
273 { "_sybase-tds._tcp", "Sybase Server", "", false },
274 { "_tce._tcp", "Power Card", "", false },
275 { "_teamlist._tcp", "ARTIS Team Task", "", false },
276 { "_teleport._tcp", "teleport", "", false },
277 { "_telnet._tcp.", "Telnet", "telnet://", false },
278 { "_tftp._tcp.", "Trivial File Transfer (TFTP)", "tftp://", false },
279 { "_tinavigator._tcp.", "TI Navigator", "", false },
280 { "_tivo_servemedia._tcp", "TiVo", "", false },
281 { "_upnp._tcp.", "Universal Plug and Play", "", false },
282 { "_utest._tcp.", "uTest", "", false },
283 { "_vue4rendercow._tcp", "VueProRenderCow", "", false },
284 { "_webdav._tcp.", "WebDAV", "webdav://", false },
285 { "_whamb._tcp.", "Whamb", "", false },
286 { "_workstation._tcp", "Macintosh Manager", "", false },
287 { "_ws._tcp", "Web Services", "", false },
288 { "_xserveraid._tcp.", "Xserve RAID", "xsr://", false },
289 { "_xsync._tcp.", "Xserve RAID Synchronization", "", false },
290
291 { "", "", "", false },
292
293 // Unofficial and invalid service types that will be phased out:
294
295 { "_clipboardsharing._tcp.", "ClipboardSharing", "", false },
296 { "_MacOSXDupSuppress._tcp.", "Mac OS X Duplicate Suppression", "", false },
297 { "_netmonitorserver._tcp.", "Net Monitor Server", "", false },
298 { "_networkclipboard._tcp.", "Network Clipboard", "", false },
299 { "_slimdevices_slimp3_cli._tcp.", "SliMP3 Server Command-Line Interface", "", false },
300 { "_slimdevices_slimp3_http._tcp.", "SliMP3 Server Web Interface", "", false },
301 { "_tieducationalhandhelddevice._tcp.", "TI Connect Manager", "", false },
302 { "_tivo_servemedia._tcp.", "TiVo", "", false },
303
304 { NULL, NULL, NULL, false },
305 };
306
307 #if 0
308 #pragma mark == Structures ==
309 #endif
310
311 //===========================================================================================================================
312 // Structures
313 //===========================================================================================================================
314
315 struct DomainEventInfo
316 {
317 DNSBrowserEventType eventType;
318 CString domain;
319 DNSNetworkAddress ifIP;
320 };
321
322 struct ServiceEventInfo
323 {
324 DNSBrowserEventType eventType;
325 std::string name;
326 std::string type;
327 std::string domain;
328 DNSNetworkAddress ifIP;
329 };
330
331 #if 0
332 #pragma mark == Prototypes ==
333 #endif
334
335 //===========================================================================================================================
336 // Prototypes
337 //===========================================================================================================================
338
339 static void
340 BrowserCallBack(
341 void * inContext,
342 DNSBrowserRef inRef,
343 DNSStatus inStatusCode,
344 const DNSBrowserEvent * inEvent );
345
346 static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString );
347
348 static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject );
349 static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 );
350
351 #if 0
352 #pragma mark == Message Map ==
353 #endif
354
355 //===========================================================================================================================
356 // Message Map
357 //===========================================================================================================================
358
359 BEGIN_MESSAGE_MAP(ChooserDialog, CDialog)
360 //{{AFX_MSG_MAP(ChooserDialog)
361 ON_WM_SYSCOMMAND()
362 ON_NOTIFY(LVN_ITEMCHANGED, IDC_DOMAIN_LIST, OnDomainListChanged)
363 ON_NOTIFY(LVN_ITEMCHANGED, IDC_SERVICE_LIST, OnServiceListChanged)
364 ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHOOSER_LIST, OnChooserListChanged)
365 ON_NOTIFY(NM_DBLCLK, IDC_CHOOSER_LIST, OnChooserListDoubleClick)
366 ON_COMMAND(ID_HELP_ABOUT, OnAbout)
367 ON_WM_INITMENUPOPUP()
368 ON_WM_ACTIVATE()
369 ON_COMMAND(ID_FILE_CLOSE, OnFileClose)
370 ON_COMMAND(ID_FILE_EXIT, OnExit)
371 ON_WM_CLOSE()
372 ON_WM_NCDESTROY()
373 //}}AFX_MSG_MAP
374 ON_MESSAGE( WM_USER_DOMAIN_ADD, OnDomainAdd )
375 ON_MESSAGE( WM_USER_DOMAIN_REMOVE, OnDomainRemove )
376 ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
377 ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
378 ON_MESSAGE( WM_USER_RESOLVE, OnResolve )
379 END_MESSAGE_MAP()
380
381 #if 0
382 #pragma mark == Routines ==
383 #endif
384
385 //===========================================================================================================================
386 // ChooserDialog
387 //===========================================================================================================================
388
389 ChooserDialog::ChooserDialog( CWnd *inParent )
390 : CDialog( ChooserDialog::IDD, inParent)
391 {
392 //{{AFX_DATA_INIT(ChooserDialog)
393 // Note: the ClassWizard will add member initialization here
394 //}}AFX_DATA_INIT
395
396 // Load menu accelerator table.
397
398 mMenuAcceleratorTable = ::LoadAccelerators( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_CHOOSER_DIALOG_MENU_ACCELERATORS ) );
399 assert( mMenuAcceleratorTable );
400
401 mBrowser = NULL;
402 mIsServiceBrowsing = false;
403 }
404
405 //===========================================================================================================================
406 // ~ChooserDialog
407 //===========================================================================================================================
408
409 ChooserDialog::~ChooserDialog( void )
410 {
411 if( mBrowser )
412 {
413 DNSStatus err;
414
415 err = DNSBrowserRelease( mBrowser, 0 );
416 assert( err == kDNSNoErr );
417 }
418 }
419
420 //===========================================================================================================================
421 // DoDataExchange
422 //===========================================================================================================================
423
424 void ChooserDialog::DoDataExchange( CDataExchange *pDX )
425 {
426 CDialog::DoDataExchange(pDX);
427
428 //{{AFX_DATA_MAP(ChooserDialog)
429 DDX_Control(pDX, IDC_SERVICE_LIST, mServiceList);
430 DDX_Control(pDX, IDC_DOMAIN_LIST, mDomainList);
431 DDX_Control(pDX, IDC_CHOOSER_LIST, mChooserList);
432 //}}AFX_DATA_MAP
433 }
434
435 //===========================================================================================================================
436 // OnInitDialog
437 //===========================================================================================================================
438
439 BOOL ChooserDialog::OnInitDialog( void )
440 {
441 HICON icon;
442 BOOL result;
443 CString tempString;
444 DNSStatus err;
445
446 // Initialize our parent.
447
448 CDialog::OnInitDialog();
449
450 // Set up the window icon.
451
452 icon = AfxGetApp()->LoadIcon( IDR_MAIN_ICON );
453 assert( icon );
454 if( icon )
455 {
456 SetIcon( icon, TRUE ); // Set big icon
457 SetIcon( icon, FALSE ); // Set small icon
458 }
459
460 // Set up the Domain List.
461
462 result = tempString.LoadString( IDS_CHOOSER_DOMAIN_COLUMN_NAME );
463 assert( result );
464 mDomainList.InsertColumn( 0, tempString, LVCFMT_LEFT, kDomainListDefaultDomainColumnWidth );
465
466 // Set up the Service List.
467
468 result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_TYPE );
469 assert( result );
470 mServiceList.InsertColumn( 0, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnTypeWidth );
471
472 result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_DESC );
473 assert( result );
474 mServiceList.InsertColumn( 1, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnDescWidth );
475
476 PopulateServicesList();
477
478 // Set up the Chooser List.
479
480 result = tempString.LoadString( IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME );
481 assert( result );
482 mChooserList.InsertColumn( 0, tempString, LVCFMT_LEFT, kChooserListDefaultNameColumnWidth );
483
484 result = tempString.LoadString( IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME );
485 assert( result );
486 mChooserList.InsertColumn( 1, tempString, LVCFMT_LEFT, kChooserListDefaultIPColumnWidth );
487
488 // Set up the other controls.
489
490 UpdateInfoDisplay();
491
492 // Start browsing for domains.
493
494 err = DNSBrowserCreate( 0, BrowserCallBack, this, &mBrowser );
495 assert( err == kDNSNoErr );
496
497 err = DNSBrowserStartDomainSearch( mBrowser, 0 );
498 assert( err == kDNSNoErr );
499
500 return( true );
501 }
502
503 //===========================================================================================================================
504 // OnFileClose
505 //===========================================================================================================================
506
507 void ChooserDialog::OnFileClose()
508 {
509 OnClose();
510 }
511
512 //===========================================================================================================================
513 // OnActivate
514 //===========================================================================================================================
515
516 void ChooserDialog::OnActivate( UINT nState, CWnd* pWndOther, BOOL bMinimized )
517 {
518 // Always make the active window the "main" window so modal dialogs work better and the app quits after closing
519 // the last window.
520
521 gApp.m_pMainWnd = this;
522
523 CDialog::OnActivate(nState, pWndOther, bMinimized);
524 }
525
526 //===========================================================================================================================
527 // PostNcDestroy
528 //===========================================================================================================================
529
530 void ChooserDialog::PostNcDestroy()
531 {
532 // Call the base class to do the normal cleanup.
533
534 delete this;
535 }
536
537 //===========================================================================================================================
538 // PreTranslateMessage
539 //===========================================================================================================================
540
541 BOOL ChooserDialog::PreTranslateMessage(MSG* pMsg)
542 {
543 BOOL result;
544
545 result = false;
546 assert( mMenuAcceleratorTable );
547 if( mMenuAcceleratorTable )
548 {
549 result = ::TranslateAccelerator( m_hWnd, mMenuAcceleratorTable, pMsg );
550 }
551 if( !result )
552 {
553 result = CDialog::PreTranslateMessage( pMsg );
554 }
555 return( result );
556 }
557
558 //===========================================================================================================================
559 // OnInitMenuPopup
560 //===========================================================================================================================
561
562 void ChooserDialog::OnInitMenuPopup( CMenu *pPopupMenu, UINT nIndex, BOOL bSysMenu )
563 {
564 CDialog::OnInitMenuPopup( pPopupMenu, nIndex, bSysMenu );
565
566 switch( nIndex )
567 {
568 case kChooserMenuIndexFile:
569 break;
570
571 case kChooserMenuIndexHelp:
572 break;
573
574 default:
575 break;
576 }
577 }
578
579 //===========================================================================================================================
580 // OnExit
581 //===========================================================================================================================
582
583 void ChooserDialog::OnExit()
584 {
585 OnClose();
586 }
587
588 //===========================================================================================================================
589 // OnAbout
590 //===========================================================================================================================
591
592 void ChooserDialog::OnAbout()
593 {
594 AboutDialog dialog;
595
596 dialog.DoModal();
597 }
598
599 //===========================================================================================================================
600 // OnSysCommand
601 //===========================================================================================================================
602
603 void ChooserDialog::OnSysCommand( UINT inID, LPARAM inParam )
604 {
605 CDialog::OnSysCommand( inID, inParam );
606 }
607
608 //===========================================================================================================================
609 // OnClose
610 //===========================================================================================================================
611
612 void ChooserDialog::OnClose()
613 {
614 StopBrowsing();
615
616 gApp.m_pMainWnd = this;
617 DestroyWindow();
618 }
619
620 //===========================================================================================================================
621 // OnNcDestroy
622 //===========================================================================================================================
623
624 void ChooserDialog::OnNcDestroy()
625 {
626 gApp.m_pMainWnd = this;
627
628 CDialog::OnNcDestroy();
629 }
630
631 //===========================================================================================================================
632 // OnDomainListChanged
633 //===========================================================================================================================
634
635 void ChooserDialog::OnDomainListChanged( NMHDR *pNMHDR, LRESULT *pResult )
636 {
637 UNUSED_ALWAYS( pNMHDR );
638
639 // Domain list changes have similar effects to service list changes so reuse that code path by calling it here.
640
641 OnServiceListChanged( NULL, NULL );
642
643 *pResult = 0;
644 }
645
646 //===========================================================================================================================
647 // OnServiceListChanged
648 //===========================================================================================================================
649
650 void ChooserDialog::OnServiceListChanged( NMHDR *pNMHDR, LRESULT *pResult )
651 {
652 int selectedType;
653 int selectedDomain;
654
655 UNUSED_ALWAYS( pNMHDR );
656
657 // Stop any existing service search.
658
659 StopBrowsing();
660
661 // If a domain and service type are selected, start searching for the service type on the domain.
662
663 selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
664 selectedDomain = mDomainList.GetNextItem( -1, LVNI_SELECTED );
665
666 if( ( selectedType >= 0 ) && ( selectedDomain >= 0 ) )
667 {
668 CString s;
669 std::string utf8;
670 const char * type;
671
672 s = mDomainList.GetItemText( selectedDomain, 0 );
673 StringObjectToUTF8String( s, utf8 );
674 type = mServiceTypes[ selectedType ].serviceType.c_str();
675 if( *type != '\0' )
676 {
677 StartBrowsing( type, utf8.c_str() );
678 }
679 }
680
681 if( pResult )
682 {
683 *pResult = 0;
684 }
685 }
686
687 //===========================================================================================================================
688 // OnChooserListChanged
689 //===========================================================================================================================
690
691 void ChooserDialog::OnChooserListChanged( NMHDR *pNMHDR, LRESULT *pResult )
692 {
693 UNUSED_ALWAYS( pNMHDR );
694
695 UpdateInfoDisplay();
696 *pResult = 0;
697 }
698
699 //===========================================================================================================================
700 // OnChooserListDoubleClick
701 //===========================================================================================================================
702
703 void ChooserDialog::OnChooserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
704 {
705 int selectedItem;
706
707 UNUSED_ALWAYS( pNMHDR );
708
709 // Display the service instance if it is selected. Otherwise, clear all the info.
710
711 selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
712 if( selectedItem >= 0 )
713 {
714 ServiceInstanceInfo * p;
715 CString url;
716 const KnownServiceEntry * service;
717
718 assert( selectedItem < (int) mServiceInstances.size() );
719 p = &mServiceInstances[ selectedItem ];
720
721 // Search for a known service type entry that matches.
722
723 for( service = kKnownServiceTable; service->serviceType; ++service )
724 {
725 if( p->type == service->serviceType )
726 {
727 break;
728 }
729 }
730 if( service->serviceType )
731 {
732 const char * text;
733
734 // Create a URL representing the service instance.
735
736 if( strcmp( service->serviceType, "_smb._tcp." ) == 0 )
737 {
738 // Special case for SMB (no port number).
739
740 url.Format( TEXT( "%s%s/" ), service->urlScheme, (const char *) p->ip.c_str() );
741 }
742 else if( strcmp( service->serviceType, "_ftp._tcp." ) == 0 )
743 {
744 // Special case for FTP to get login info.
745
746 LoginDialog dialog;
747 CString username;
748 CString password;
749
750 if( !dialog.GetLogin( username, password ) )
751 {
752 goto exit;
753 }
754
755 // Build URL in the following format:
756 //
757 // ftp://[username[:password]@]<ip>
758
759 url += service->urlScheme;
760 if( username.GetLength() > 0 )
761 {
762 url += username;
763 if( password.GetLength() > 0 )
764 {
765 url += ':';
766 url += password;
767 }
768 url += '@';
769 }
770 url += p->ip.c_str();
771 }
772 else if( strcmp( service->serviceType, "_http._tcp." ) == 0 )
773 {
774 // Special case for HTTP to exclude "path=" if present.
775
776 text = service->useText ? p->text.c_str() : "";
777 if( strncmp( text, "path=", 5 ) == 0 )
778 {
779 text += 5;
780 }
781 if( *text != '/' )
782 {
783 url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
784 }
785 else
786 {
787 url.Format( TEXT( "%s%s%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
788 }
789 }
790 else
791 {
792 text = service->useText ? p->text.c_str() : "";
793 url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
794 }
795
796 // Let the system open the URL in the correct app.
797
798 {
799 CWaitCursor waitCursor;
800
801 ShellExecute( NULL, TEXT( "open" ), url, TEXT( "" ), TEXT( "c:\\" ), SW_SHOWNORMAL );
802 }
803 }
804 }
805
806 exit:
807 *pResult = 0;
808 }
809
810 //===========================================================================================================================
811 // OnCancel
812 //===========================================================================================================================
813
814 void ChooserDialog::OnCancel()
815 {
816 // Do nothing.
817 }
818
819 //===========================================================================================================================
820 // PopulateServicesList
821 //===========================================================================================================================
822
823 void ChooserDialog::PopulateServicesList( void )
824 {
825 ServiceTypeVector::iterator i;
826 CString type;
827 CString desc;
828 std::string tmp;
829
830 // Add a fixed list of known services.
831
832 if( mServiceTypes.empty() )
833 {
834 const KnownServiceEntry * service;
835
836 for( service = kKnownServiceTable; service->serviceType; ++service )
837 {
838 ServiceTypeInfo info;
839
840 info.serviceType = service->serviceType;
841 info.description = service->description;
842 info.urlScheme = service->urlScheme;
843 mServiceTypes.push_back( info );
844 }
845 }
846
847 // Add each service to the list.
848
849 for( i = mServiceTypes.begin(); i != mServiceTypes.end(); ++i )
850 {
851 const char * p;
852 const char * q;
853
854 p = ( *i ).serviceType.c_str();
855 if( *p == '_' ) ++p; // Skip leading '_'.
856 q = strchr( p, '.' ); // Find first '.'.
857 if( q ) tmp.assign( p, (size_t)( q - p ) ); // Use only up to the first '.'.
858 else tmp.assign( p ); // No '.' so use the entire string.
859 UTF8StringToStringObject( tmp.c_str(), type );
860 UTF8StringToStringObject( ( *i ).description.c_str(), desc );
861
862 int n;
863
864 n = mServiceList.GetItemCount();
865 mServiceList.InsertItem( n, type );
866 mServiceList.SetItemText( n, 1, desc );
867 }
868
869 // Select the first service type by default.
870
871 if( !mServiceTypes.empty() )
872 {
873 mServiceList.SetItemState( 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
874 }
875 }
876
877 //===========================================================================================================================
878 // UpdateInfoDisplay
879 //===========================================================================================================================
880
881 void ChooserDialog::UpdateInfoDisplay( void )
882 {
883 int selectedItem;
884 std::string name;
885 CString s;
886 std::string ip;
887 std::string ifIP;
888 std::string text;
889 std::string textNewLines;
890 std::string hostName;
891 CWnd * item;
892 std::string::iterator i;
893
894 // Display the service instance if it is selected. Otherwise, clear all the info.
895
896 selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
897 if( selectedItem >= 0 )
898 {
899 ServiceInstanceInfo * p;
900
901 assert( selectedItem < (int) mServiceInstances.size() );
902 p = &mServiceInstances[ selectedItem ];
903
904 name = p->name;
905 ip = p->ip;
906 ifIP = p->ifIP;
907 text = p->text;
908 hostName = p->hostName;
909
910 // Sync up the list items with the actual data (IP address may change).
911
912 UTF8StringToStringObject( ip.c_str(), s );
913 mChooserList.SetItemText( selectedItem, 1, s );
914 }
915
916 // Name
917
918 item = (CWnd *) this->GetDlgItem( IDC_INFO_NAME_TEXT );
919 assert( item );
920 UTF8StringToStringObject( name.c_str(), s );
921 item->SetWindowText( s );
922
923 // IP
924
925 item = (CWnd *) this->GetDlgItem( IDC_INFO_IP_TEXT );
926 assert( item );
927 UTF8StringToStringObject( ip.c_str(), s );
928 item->SetWindowText( s );
929
930 // Interface
931
932 item = (CWnd *) this->GetDlgItem( IDC_INFO_INTERFACE_TEXT );
933 assert( item );
934 UTF8StringToStringObject( ifIP.c_str(), s );
935 item->SetWindowText( s );
936
937
938 item = (CWnd *) this->GetDlgItem( IDC_INFO_HOST_NAME_TEXT );
939 assert( item );
940 UTF8StringToStringObject( hostName.c_str(), s );
941 item->SetWindowText( s );
942
943 // Text
944
945 item = (CWnd *) this->GetDlgItem( IDC_INFO_TEXT_TEXT );
946 assert( item );
947 for( i = text.begin(); i != text.end(); ++i )
948 {
949 if( *i == '\1' )
950 {
951 textNewLines += "\r\n";
952 }
953 else
954 {
955 textNewLines += *i;
956 }
957 }
958 UTF8StringToStringObject( textNewLines.c_str(), s );
959 item->SetWindowText( s );
960 }
961
962 #if 0
963 #pragma mark -
964 #endif
965
966 //===========================================================================================================================
967 // OnDomainAdd
968 //===========================================================================================================================
969
970 LONG ChooserDialog::OnDomainAdd( WPARAM inWParam, LPARAM inLParam )
971 {
972 DomainEventInfo * p;
973 std::auto_ptr < DomainEventInfo > pAutoPtr;
974 int n;
975 int i;
976 CString domain;
977 CString s;
978 bool found;
979
980 UNUSED_ALWAYS( inWParam );
981
982 assert( inLParam );
983 p = reinterpret_cast <DomainEventInfo *> ( inLParam );
984 pAutoPtr.reset( p );
985
986 // Search to see if we already know about this domain. If not, add it to the list.
987
988 found = false;
989 domain = p->domain;
990 n = mDomainList.GetItemCount();
991 for( i = 0; i < n; ++i )
992 {
993 s = mDomainList.GetItemText( i, 0 );
994 if( s == domain )
995 {
996 found = true;
997 break;
998 }
999 }
1000 if( !found )
1001 {
1002 int selectedItem;
1003
1004 mDomainList.InsertItem( n, domain );
1005
1006 // If no domains are selected and the domain being added is a default domain, select it.
1007
1008 selectedItem = mDomainList.GetNextItem( -1, LVNI_SELECTED );
1009 if( ( selectedItem < 0 ) && ( p->eventType == kDNSBrowserEventTypeAddDefaultDomain ) )
1010 {
1011 mDomainList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
1012 }
1013 }
1014 return( 0 );
1015 }
1016
1017 //===========================================================================================================================
1018 // OnDomainRemove
1019 //===========================================================================================================================
1020
1021 LONG ChooserDialog::OnDomainRemove( WPARAM inWParam, LPARAM inLParam )
1022 {
1023 DomainEventInfo * p;
1024 std::auto_ptr < DomainEventInfo > pAutoPtr;
1025 int n;
1026 int i;
1027 CString domain;
1028 CString s;
1029 bool found;
1030
1031 UNUSED_ALWAYS( inWParam );
1032
1033 assert( inLParam );
1034 p = reinterpret_cast <DomainEventInfo *> ( inLParam );
1035 pAutoPtr.reset( p );
1036
1037 // Search to see if we know about this domain. If so, remove it from the list.
1038
1039 found = false;
1040 domain = p->domain;
1041 n = mDomainList.GetItemCount();
1042 for( i = 0; i < n; ++i )
1043 {
1044 s = mDomainList.GetItemText( i, 0 );
1045 if( s == domain )
1046 {
1047 found = true;
1048 break;
1049 }
1050 }
1051 if( found )
1052 {
1053 mDomainList.DeleteItem( i );
1054 }
1055 return( 0 );
1056 }
1057
1058 //===========================================================================================================================
1059 // OnServiceAdd
1060 //===========================================================================================================================
1061
1062 LONG ChooserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
1063 {
1064 ServiceEventInfo * p;
1065 std::auto_ptr < ServiceEventInfo > pAutoPtr;
1066
1067 UNUSED_ALWAYS( inWParam );
1068
1069 assert( inLParam );
1070 p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
1071 pAutoPtr.reset( p );
1072
1073 return( 0 );
1074 }
1075
1076 //===========================================================================================================================
1077 // OnServiceRemove
1078 //===========================================================================================================================
1079
1080 LONG ChooserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
1081 {
1082 ServiceEventInfo * p;
1083 std::auto_ptr < ServiceEventInfo > pAutoPtr;
1084 bool found;
1085 int n;
1086 int i;
1087
1088 UNUSED_ALWAYS( inWParam );
1089
1090 assert( inLParam );
1091 p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
1092 pAutoPtr.reset( p );
1093
1094 // Search to see if we know about this service instance. If so, remove it from the list.
1095
1096 found = false;
1097 n = (int) mServiceInstances.size();
1098 for( i = 0; i < n; ++i )
1099 {
1100 ServiceInstanceInfo * q;
1101
1102 // If the name, type, domain, and interface match, treat it as the same service instance.
1103
1104 q = &mServiceInstances[ i ];
1105 if( ( p->name == q->name ) &&
1106 ( p->type == q->type ) &&
1107 ( p->domain == q->domain ) )
1108 {
1109 found = true;
1110 break;
1111 }
1112 }
1113 if( found )
1114 {
1115 mChooserList.DeleteItem( i );
1116 assert( i < (int) mServiceInstances.size() );
1117 mServiceInstances.erase( mServiceInstances.begin() + i );
1118 }
1119 return( 0 );
1120 }
1121
1122 //===========================================================================================================================
1123 // OnResolve
1124 //===========================================================================================================================
1125
1126 LONG ChooserDialog::OnResolve( WPARAM inWParam, LPARAM inLParam )
1127 {
1128 ServiceInstanceInfo * p;
1129 std::auto_ptr < ServiceInstanceInfo > pAutoPtr;
1130 int selectedType;
1131 int n;
1132 int i;
1133 bool found;
1134
1135 UNUSED_ALWAYS( inWParam );
1136
1137 assert( inLParam );
1138 p = reinterpret_cast <ServiceInstanceInfo *> ( inLParam );
1139 pAutoPtr.reset( p );
1140
1141 // Make sure it is for an item of the correct type. This handles any resolves that may have been queued up.
1142
1143 selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
1144 assert( selectedType >= 0 );
1145 if( selectedType >= 0 )
1146 {
1147 assert( selectedType <= (int) mServiceTypes.size() );
1148 if( p->type != mServiceTypes[ selectedType ].serviceType )
1149 {
1150 goto exit;
1151 }
1152 }
1153
1154 // Search to see if we know about this service instance. If so, update its info. Otherwise, add it to the list.
1155
1156 found = false;
1157 n = (int) mServiceInstances.size();
1158 for( i = 0; i < n; ++i )
1159 {
1160 ServiceInstanceInfo * q;
1161
1162 // If the name, type, domain, and interface matches, treat it as the same service instance.
1163
1164 q = &mServiceInstances[ i ];
1165 if( ( p->name == q->name ) &&
1166 ( p->type == q->type ) &&
1167 ( p->domain == q->domain ) &&
1168 ( p->ifIP == q->ifIP ) )
1169 {
1170 found = true;
1171 break;
1172 }
1173 }
1174 if( found )
1175 {
1176 mServiceInstances[ i ] = *p;
1177 }
1178 else
1179 {
1180 CString s;
1181
1182 mServiceInstances.push_back( *p );
1183 UTF8StringToStringObject( p->name.c_str(), s );
1184 mChooserList.InsertItem( n, s );
1185
1186 UTF8StringToStringObject( p->ip.c_str(), s );
1187 mChooserList.SetItemText( n, 1, s );
1188
1189 // If this is the only item, select it.
1190
1191 if( n == 0 )
1192 {
1193 mChooserList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
1194 }
1195 }
1196 UpdateInfoDisplay();
1197
1198 exit:
1199 return( 0 );
1200 }
1201
1202 //===========================================================================================================================
1203 // StartBrowsing
1204 //===========================================================================================================================
1205
1206 void ChooserDialog::StartBrowsing( const char *inType, const char *inDomain )
1207 {
1208 DNSStatus err;
1209
1210 assert( mServiceInstances.empty() );
1211 assert( mChooserList.GetItemCount() == 0 );
1212 assert( !mIsServiceBrowsing );
1213
1214 mChooserList.DeleteAllItems();
1215 mServiceInstances.clear();
1216
1217 mIsServiceBrowsing = true;
1218 err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, inType, inDomain );
1219 assert( err == kDNSNoErr );
1220 }
1221
1222 //===========================================================================================================================
1223 // StopBrowsing
1224 //===========================================================================================================================
1225
1226 void ChooserDialog::StopBrowsing( void )
1227 {
1228 // If searching, stop.
1229
1230 if( mIsServiceBrowsing )
1231 {
1232 DNSStatus err;
1233
1234 mIsServiceBrowsing = false;
1235 err = DNSBrowserStopServiceSearch( mBrowser, 0 );
1236 assert( err == kDNSNoErr );
1237 }
1238
1239 // Remove all service instances.
1240
1241 mChooserList.DeleteAllItems();
1242 assert( mChooserList.GetItemCount() == 0 );
1243 mServiceInstances.clear();
1244 assert( mServiceInstances.empty() );
1245 UpdateInfoDisplay();
1246 }
1247
1248 #if 0
1249 #pragma mark -
1250 #endif
1251
1252 //===========================================================================================================================
1253 // BrowserCallBack
1254 //===========================================================================================================================
1255
1256 static void
1257 BrowserCallBack(
1258 void * inContext,
1259 DNSBrowserRef inRef,
1260 DNSStatus inStatusCode,
1261 const DNSBrowserEvent * inEvent )
1262 {
1263 ChooserDialog * dialog;
1264 UINT message;
1265 BOOL posted;
1266
1267 UNUSED_ALWAYS( inStatusCode );
1268 UNUSED_ALWAYS( inRef );
1269
1270 // Check parameters.
1271
1272 assert( inContext );
1273 dialog = reinterpret_cast <ChooserDialog *> ( inContext );
1274
1275 try
1276 {
1277 switch( inEvent->type )
1278 {
1279 case kDNSBrowserEventTypeRelease:
1280 break;
1281
1282 // Domains
1283
1284 case kDNSBrowserEventTypeAddDomain:
1285 case kDNSBrowserEventTypeAddDefaultDomain:
1286 case kDNSBrowserEventTypeRemoveDomain:
1287 {
1288 DomainEventInfo * domain;
1289 std::auto_ptr < DomainEventInfo > domainAutoPtr;
1290
1291 domain = new DomainEventInfo;
1292 domainAutoPtr.reset( domain );
1293
1294 domain->eventType = inEvent->type;
1295 domain->domain = inEvent->data.addDomain.domain;
1296 domain->ifIP = inEvent->data.addDomain.interfaceIP;
1297
1298 message = ( inEvent->type == kDNSBrowserEventTypeRemoveDomain ) ? WM_USER_DOMAIN_REMOVE : WM_USER_DOMAIN_ADD;
1299 posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) domain );
1300 assert( posted );
1301 if( posted )
1302 {
1303 domainAutoPtr.release();
1304 }
1305 break;
1306 }
1307
1308 // Services
1309
1310 case kDNSBrowserEventTypeAddService:
1311 case kDNSBrowserEventTypeRemoveService:
1312 {
1313 ServiceEventInfo * service;
1314 std::auto_ptr < ServiceEventInfo > serviceAutoPtr;
1315
1316 service = new ServiceEventInfo;
1317 serviceAutoPtr.reset( service );
1318
1319 service->eventType = inEvent->type;
1320 service->name = inEvent->data.addService.name;
1321 service->type = inEvent->data.addService.type;
1322 service->domain = inEvent->data.addService.domain;
1323 service->ifIP = inEvent->data.addService.interfaceIP;
1324
1325 message = ( inEvent->type == kDNSBrowserEventTypeAddService ) ? WM_USER_SERVICE_ADD : WM_USER_SERVICE_REMOVE;
1326 posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) service );
1327 assert( posted );
1328 if( posted )
1329 {
1330 serviceAutoPtr.release();
1331 }
1332 break;
1333 }
1334
1335 // Resolves
1336
1337 case kDNSBrowserEventTypeResolved:
1338 if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4 )
1339 {
1340 ServiceInstanceInfo * serviceInstance;
1341 std::auto_ptr < ServiceInstanceInfo > serviceInstanceAutoPtr;
1342 char s[ 32 ];
1343
1344 serviceInstance = new ServiceInstanceInfo;
1345 serviceInstanceAutoPtr.reset( serviceInstance );
1346
1347 serviceInstance->name = inEvent->data.resolved->name;
1348 serviceInstance->type = inEvent->data.resolved->type;
1349 serviceInstance->domain = inEvent->data.resolved->domain;
1350 serviceInstance->ip = DNSNetworkAddressToString( &inEvent->data.resolved->address, s );
1351 serviceInstance->ifIP = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, s );
1352 serviceInstance->text = inEvent->data.resolved->textRecord;
1353 serviceInstance->hostName = inEvent->data.resolved->hostName;
1354
1355 posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_RESOLVE, 0, (LPARAM) serviceInstance );
1356 assert( posted );
1357 if( posted )
1358 {
1359 serviceInstanceAutoPtr.release();
1360 }
1361 }
1362 break;
1363
1364 default:
1365 break;
1366 }
1367 }
1368 catch( ... )
1369 {
1370 // Don't let exceptions escape.
1371 }
1372 }
1373
1374 //===========================================================================================================================
1375 // DNSNetworkAddressToString
1376 //
1377 // Note: Currently only supports IPv4 network addresses.
1378 //===========================================================================================================================
1379
1380 static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString )
1381 {
1382 const DNSUInt8 * p;
1383 DNSUInt16 port;
1384
1385 p = inAddr->u.ipv4.addr.v8;
1386 port = ntohs( inAddr->u.ipv4.port.v16 );
1387 if( port != kDNSPortInvalid )
1388 {
1389 sprintf( outString, "%u.%u.%u.%u:%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ], port );
1390 }
1391 else
1392 {
1393 sprintf( outString, "%u.%u.%u.%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] );
1394 }
1395 return( outString );
1396 }
1397
1398 //===========================================================================================================================
1399 // UTF8StringToStringObject
1400 //===========================================================================================================================
1401
1402 static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject )
1403 {
1404 DWORD err;
1405 int n;
1406 BSTR unicode;
1407
1408 unicode = NULL;
1409
1410 n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
1411 if( n > 0 )
1412 {
1413 unicode = (BSTR) malloc( (size_t)( n * sizeof( wchar_t ) ) );
1414 if( !unicode )
1415 {
1416 err = ERROR_INSUFFICIENT_BUFFER;
1417 goto exit;
1418 }
1419
1420 n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
1421 try
1422 {
1423 inObject = unicode;
1424 }
1425 catch( ... )
1426 {
1427 err = ERROR_NO_UNICODE_TRANSLATION;
1428 goto exit;
1429 }
1430 }
1431 else
1432 {
1433 inObject = "";
1434 }
1435 err = 0;
1436
1437 exit:
1438 if( unicode )
1439 {
1440 free( unicode );
1441 }
1442 return( err );
1443 }
1444
1445 //===========================================================================================================================
1446 // StringObjectToUTF8String
1447 //===========================================================================================================================
1448
1449 static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 )
1450 {
1451 DWORD err;
1452 BSTR unicode;
1453 int nUnicode;
1454 int n;
1455 char * utf8;
1456
1457 unicode = NULL;
1458 utf8 = NULL;
1459
1460 nUnicode = inObject.GetLength();
1461 if( nUnicode > 0 )
1462 {
1463 unicode = inObject.AllocSysString();
1464 n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, NULL, 0, NULL, NULL );
1465 assert( n > 0 );
1466
1467 utf8 = (char *) malloc( (size_t) n );
1468 assert( utf8 );
1469 if( !utf8 ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; }
1470
1471 n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, utf8, n, NULL, NULL );
1472 assert( n > 0 );
1473
1474 try
1475 {
1476 outUTF8.assign( utf8, n );
1477 }
1478 catch( ... )
1479 {
1480 err = ERROR_NO_UNICODE_TRANSLATION;
1481 goto exit;
1482 }
1483 }
1484 else
1485 {
1486 outUTF8.clear();
1487 }
1488 err = 0;
1489
1490 exit:
1491 if( unicode )
1492 {
1493 SysFreeString( unicode );
1494 }
1495 if( utf8 )
1496 {
1497 free( utf8 );
1498 }
1499 return( err );
1500 }