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