You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1427 lines
44 KiB
1427 lines
44 KiB
/* -*- Mode: C; tab-width: 4 -*-
|
|
*
|
|
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "DNSServices.h"
|
|
|
|
#include "Application.h"
|
|
#include "AboutDialog.h"
|
|
#include "LoginDialog.h"
|
|
#include "Resource.h"
|
|
|
|
#include "ChooserDialog.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#if 0
|
|
#pragma mark == Constants ==
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// Constants
|
|
//===========================================================================================================================
|
|
|
|
// Menus
|
|
|
|
enum
|
|
{
|
|
kChooserMenuIndexFile = 0,
|
|
kChooserMenuIndexHelp = 1
|
|
};
|
|
|
|
// Domain List
|
|
|
|
#define kDomainListDefaultDomainColumnWidth 164
|
|
|
|
// Service List
|
|
|
|
#define kServiceListDefaultServiceColumnTypeWidth 146
|
|
#define kServiceListDefaultServiceColumnDescWidth 230
|
|
|
|
// Chooser List
|
|
|
|
#define kChooserListDefaultNameColumnWidth 190
|
|
#define kChooserListDefaultIPColumnWidth 120
|
|
|
|
// Windows User Messages
|
|
|
|
#define WM_USER_DOMAIN_ADD ( WM_USER + 0x100 )
|
|
#define WM_USER_DOMAIN_REMOVE ( WM_USER + 0x101 )
|
|
#define WM_USER_SERVICE_ADD ( WM_USER + 0x102 )
|
|
#define WM_USER_SERVICE_REMOVE ( WM_USER + 0x103 )
|
|
#define WM_USER_RESOLVE ( WM_USER + 0x104 )
|
|
|
|
#if 0
|
|
#pragma mark == Constants - Service Table ==
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// Constants - Service Table
|
|
//===========================================================================================================================
|
|
|
|
struct KnownServiceEntry
|
|
{
|
|
const char * serviceType;
|
|
const char * description;
|
|
const char * urlScheme;
|
|
bool useText;
|
|
};
|
|
|
|
static const KnownServiceEntry kKnownServiceTable[] =
|
|
{
|
|
{ "_accountedge._tcp.", "MYOB AccountEdge", "", false },
|
|
{ "_aecoretech._tcp.", "Apple Application Engineering Services", "", false },
|
|
{ "_afpovertcp._tcp.", "Apple File Sharing (AFP)", "afp://", false },
|
|
{ "_airport._tcp.", "AirPort Base Station", "", false },
|
|
{ "_apple-sasl._tcp.", "Apple Password Server", "", false },
|
|
{ "_aquamon._tcp.", "AquaMon", "", false },
|
|
{ "_async._tcp", "address-o-sync", "", false },
|
|
{ "_auth._tcp.", "Authentication Service", "", false },
|
|
{ "_bootps._tcp.", "Bootstrap Protocol Server", "", false },
|
|
{ "_bousg._tcp.", "Bag Of Unusual Strategy Games", "", false },
|
|
{ "_browse._udp.", "DNS Service Discovery", "", false },
|
|
{ "_cheat._tcp.", "The Cheat", "", false },
|
|
{ "_chess._tcp", "Project Gridlock", "", false },
|
|
{ "_chfts._tcp", "Fluid Theme Server", "", false },
|
|
{ "_clipboard._tcp", "Clipboard Sharing", "", false },
|
|
{ "_contactserver._tcp.", "Now Up-to-Date & Contact", "", false },
|
|
{ "_cvspserver._tcp", "CVS PServer", "", false },
|
|
{ "_cytv._tcp.", "CyTV Network streaming for Elgato EyeTV", "", false },
|
|
{ "_daap._tcp.", "Digital Audio Access Protocol (iTunes)", "daap://", false },
|
|
{ "_distcc._tcp", "Distributed Compiler", "", false },
|
|
{ "_dns-sd._udp", "DNS Service Discovery", "", false },
|
|
{ "_dpap._tcp.", "Digital Picture Access Protocol (iPhoto)", "", false },
|
|
{ "_earphoria._tcp.", "Earphoria", "", false },
|
|
{ "_ecbyesfsgksc._tcp.", "Net Monitor Anti-Piracy Service", "", false },
|
|
{ "_eheap._tcp.", "Interactive Room Software", "", false },
|
|
{ "_embrace._tcp.", "DataEnvoy", "", false },
|
|
{ "_eppc._tcp.", "Remote AppleEvents", "eppc://", false },
|
|
{ "_exec._tcp.", "Remote Process Execution", "", false },
|
|
{ "_facespan._tcp.", "FaceSpan", "", false },
|
|
{ "_fjork._tcp.", "Fjork", "", false },
|
|
{ "_ftp._tcp.", "File Transfer (FTP)", "ftp://", false },
|
|
{ "_ftpcroco._tcp.", "Crocodile FTP Server", "", false },
|
|
{ "_gbs-smp._tcp.", "SnapMail", "", false },
|
|
{ "_gbs-stp._tcp.", "SnapTalk", "", false },
|
|
{ "_grillezvous._tcp.", "Roxio ToastAnywhere(tm) Recorder Sharing", "", false },
|
|
{ "_h323._tcp.", "H.323", "", false },
|
|
{ "_hotwayd._tcp", "Hotwayd", "", false },
|
|
{ "_http._tcp.", "Web Server (HTTP)", "http://", true },
|
|
{ "_hydra._tcp", "SubEthaEdit", "", false },
|
|
{ "_ica-networking._tcp.", "Image Capture Networking", "", false },
|
|
{ "_ichalkboard._tcp.", "iChalk", "", false },
|
|
{ "_ichat._tcp.", "iChat", "ichat://", false },
|
|
{ "_iconquer._tcp.", "iConquer", "", false },
|
|
{ "_imap._tcp.", "Internet Message Access Protocol", "", false },
|
|
{ "_imidi._tcp.", "iMidi", "", false },
|
|
{ "_ipp._tcp.", "Printer (IPP)", "ipp://", false },
|
|
{ "_ishare._tcp.", "iShare", "", false },
|
|
{ "_isparx._tcp.", "iSparx", "", false },
|
|
{ "_istorm._tcp", "iStorm", "", false },
|
|
{ "_iwork._tcp.", "iWork Server", "", false },
|
|
{ "_liaison._tcp.", "Liaison", "", false },
|
|
{ "_login._tcp.", "Remote Login a la Telnet", "", false },
|
|
{ "_lontalk._tcp.", "LonTalk over IP (ANSI 852)", "", false },
|
|
{ "_lonworks._tcp.", "Echelon LNS Remote Client", "", false },
|
|
{ "_macfoh-remote._tcp.", "MacFOH Remote", "", false },
|
|
{ "_moneyworks._tcp.", "MoneyWorks", "", false },
|
|
{ "_mp3sushi._tcp", "MP3 Sushi", "", false },
|
|
{ "_mttp._tcp.", "MenuTunes Sharing", "", false },
|
|
{ "_ncbroadcast._tcp.", "Network Clipboard Broadcasts", "", false },
|
|
{ "_ncdirect._tcp.", "Network Clipboard Direct Transfers", "", false },
|
|
{ "_ncsyncserver._tcp.", "Network Clipboard Sync Server", "", false },
|
|
{ "_newton-dock._tcp.", "Escale", "", false },
|
|
{ "_nfs._tcp", "NFS", "", false },
|
|
{ "_nssocketport._tcp.", "DO over NSSocketPort", "", false },
|
|
{ "_omni-bookmark._tcp.", "OmniWeb", "", false },
|
|
{ "_openbase._tcp.", "OpenBase SQL", "", false },
|
|
{ "_p2pchat._tcp.", "Peer-to-Peer Chat", "", false },
|
|
{ "_pdl-datastream._tcp.", "Printer (PDL)", "pdl://", false },
|
|
{ "_poch._tcp.", "Parallel OperatiOn and Control Heuristic", "", false },
|
|
{ "_pop_2_ambrosia._tcp.", "Pop-Pop", "", false },
|
|
{ "_pop3._tcp", "POP3 Server", "", false },
|
|
{ "_postgresql._tcp", "PostgreSQL Server", "", false },
|
|
{ "_presence._tcp", "iChat AV", "", false },
|
|
{ "_printer._tcp.", "Printer (LPR)", "lpr://", false },
|
|
{ "_ptp._tcp.", "Picture Transfer (PTP)", "ptp://", false },
|
|
{ "_register._tcp", "DNS Service Discovery", "", false },
|
|
{ "_rfb._tcp.", "Remote Frame Buffer", "", false },
|
|
{ "_riousbprint._tcp.", "Remote I/O USB Printer Protocol", "", false },
|
|
{ "_rtsp._tcp.", "Real Time Stream Control Protocol", "", false },
|
|
{ "_safarimenu._tcp", "Safari Menu", "", false },
|
|
{ "_scone._tcp", "Scone", "", false },
|
|
{ "_sdsharing._tcp.", "Speed Download", "", false },
|
|
{ "_seeCard._tcp.", "seeCard", "", false },
|
|
{ "_services._udp.", "DNS Service Discovery", "", false },
|
|
{ "_shell._tcp.", "like exec, but automatic authentication", "", false },
|
|
{ "_shout._tcp.", "Shout", "", false },
|
|
{ "_shoutcast._tcp", "Nicecast", "", false },
|
|
{ "_smb._tcp.", "Windows File Sharing (SMB)", "smb://", false },
|
|
{ "_soap._tcp.", "Simple Object Access Protocol", "", false },
|
|
{ "_spincrisis._tcp.", "Spin Crisis", "", false },
|
|
{ "_spl-itunes._tcp.", "launchTunes", "", false },
|
|
{ "_spr-itunes._tcp.", "netTunes", "", false },
|
|
{ "_ssh._tcp.", "Secure Shell (SSH)", "ssh://", false },
|
|
{ "_ssscreenshare._tcp", "Screen Sharing", "", false },
|
|
{ "_sge-exec._tcp", "Sun Grid Engine (Execution Host)", "", false },
|
|
{ "_sge-qmaster._tcp", "Sun Grid Engine (Master)", "", false },
|
|
{ "_stickynotes._tcp", "Sticky Notes", "", false },
|
|
{ "_strateges._tcp", "Strateges", "", false },
|
|
{ "_sxqdea._tcp", "Synchronize! Pro X", "", false },
|
|
{ "_sybase-tds._tcp", "Sybase Server", "", false },
|
|
{ "_tce._tcp", "Power Card", "", false },
|
|
{ "_teamlist._tcp", "ARTIS Team Task", "", false },
|
|
{ "_teleport._tcp", "teleport", "", false },
|
|
{ "_telnet._tcp.", "Telnet", "telnet://", false },
|
|
{ "_tftp._tcp.", "Trivial File Transfer (TFTP)", "tftp://", false },
|
|
{ "_tinavigator._tcp.", "TI Navigator", "", false },
|
|
{ "_tivo_servemedia._tcp", "TiVo", "", false },
|
|
{ "_upnp._tcp.", "Universal Plug and Play", "", false },
|
|
{ "_utest._tcp.", "uTest", "", false },
|
|
{ "_vue4rendercow._tcp", "VueProRenderCow", "", false },
|
|
{ "_webdav._tcp.", "WebDAV", "webdav://", false },
|
|
{ "_whamb._tcp.", "Whamb", "", false },
|
|
{ "_workstation._tcp", "Macintosh Manager", "", false },
|
|
{ "_ws._tcp", "Web Services", "", false },
|
|
{ "_xserveraid._tcp.", "Xserve RAID", "xsr://", false },
|
|
{ "_xsync._tcp.", "Xserve RAID Synchronization", "", false },
|
|
|
|
{ "", "", "", false },
|
|
|
|
// Unofficial and invalid service types that will be phased out:
|
|
|
|
{ "_clipboardsharing._tcp.", "ClipboardSharing", "", false },
|
|
{ "_MacOSXDupSuppress._tcp.", "Mac OS X Duplicate Suppression", "", false },
|
|
{ "_netmonitorserver._tcp.", "Net Monitor Server", "", false },
|
|
{ "_networkclipboard._tcp.", "Network Clipboard", "", false },
|
|
{ "_slimdevices_slimp3_cli._tcp.", "SliMP3 Server Command-Line Interface", "", false },
|
|
{ "_slimdevices_slimp3_http._tcp.", "SliMP3 Server Web Interface", "", false },
|
|
{ "_tieducationalhandhelddevice._tcp.", "TI Connect Manager", "", false },
|
|
{ "_tivo_servemedia._tcp.", "TiVo", "", false },
|
|
|
|
{ NULL, NULL, NULL, false },
|
|
};
|
|
|
|
#if 0
|
|
#pragma mark == Structures ==
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// Structures
|
|
//===========================================================================================================================
|
|
|
|
struct DomainEventInfo
|
|
{
|
|
DNSBrowserEventType eventType;
|
|
CString domain;
|
|
DNSNetworkAddress ifIP;
|
|
};
|
|
|
|
struct ServiceEventInfo
|
|
{
|
|
DNSBrowserEventType eventType;
|
|
std::string name;
|
|
std::string type;
|
|
std::string domain;
|
|
DNSNetworkAddress ifIP;
|
|
};
|
|
|
|
#if 0
|
|
#pragma mark == Prototypes ==
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// Prototypes
|
|
//===========================================================================================================================
|
|
|
|
static void
|
|
BrowserCallBack(
|
|
void * inContext,
|
|
DNSBrowserRef inRef,
|
|
DNSStatus inStatusCode,
|
|
const DNSBrowserEvent * inEvent );
|
|
|
|
static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString );
|
|
|
|
static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject );
|
|
static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 );
|
|
|
|
#if 0
|
|
#pragma mark == Message Map ==
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// Message Map
|
|
//===========================================================================================================================
|
|
|
|
BEGIN_MESSAGE_MAP(ChooserDialog, CDialog)
|
|
//{{AFX_MSG_MAP(ChooserDialog)
|
|
ON_WM_SYSCOMMAND()
|
|
ON_NOTIFY(LVN_ITEMCHANGED, IDC_DOMAIN_LIST, OnDomainListChanged)
|
|
ON_NOTIFY(LVN_ITEMCHANGED, IDC_SERVICE_LIST, OnServiceListChanged)
|
|
ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHOOSER_LIST, OnChooserListChanged)
|
|
ON_NOTIFY(NM_DBLCLK, IDC_CHOOSER_LIST, OnChooserListDoubleClick)
|
|
ON_COMMAND(ID_HELP_ABOUT, OnAbout)
|
|
ON_WM_INITMENUPOPUP()
|
|
ON_WM_ACTIVATE()
|
|
ON_COMMAND(ID_FILE_CLOSE, OnFileClose)
|
|
ON_COMMAND(ID_FILE_EXIT, OnExit)
|
|
ON_WM_CLOSE()
|
|
ON_WM_NCDESTROY()
|
|
//}}AFX_MSG_MAP
|
|
ON_MESSAGE( WM_USER_DOMAIN_ADD, OnDomainAdd )
|
|
ON_MESSAGE( WM_USER_DOMAIN_REMOVE, OnDomainRemove )
|
|
ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
|
|
ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
|
|
ON_MESSAGE( WM_USER_RESOLVE, OnResolve )
|
|
END_MESSAGE_MAP()
|
|
|
|
#if 0
|
|
#pragma mark == Routines ==
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// ChooserDialog
|
|
//===========================================================================================================================
|
|
|
|
ChooserDialog::ChooserDialog( CWnd *inParent )
|
|
: CDialog( ChooserDialog::IDD, inParent)
|
|
{
|
|
//{{AFX_DATA_INIT(ChooserDialog)
|
|
// Note: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
|
|
// Load menu accelerator table.
|
|
|
|
mMenuAcceleratorTable = ::LoadAccelerators( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_CHOOSER_DIALOG_MENU_ACCELERATORS ) );
|
|
assert( mMenuAcceleratorTable );
|
|
|
|
mBrowser = NULL;
|
|
mIsServiceBrowsing = false;
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// ~ChooserDialog
|
|
//===========================================================================================================================
|
|
|
|
ChooserDialog::~ChooserDialog( void )
|
|
{
|
|
if( mBrowser )
|
|
{
|
|
DNSStatus err;
|
|
|
|
err = DNSBrowserRelease( mBrowser, 0 );
|
|
assert( err == kDNSNoErr );
|
|
}
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// DoDataExchange
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::DoDataExchange( CDataExchange *pDX )
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
|
|
//{{AFX_DATA_MAP(ChooserDialog)
|
|
DDX_Control(pDX, IDC_SERVICE_LIST, mServiceList);
|
|
DDX_Control(pDX, IDC_DOMAIN_LIST, mDomainList);
|
|
DDX_Control(pDX, IDC_CHOOSER_LIST, mChooserList);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnInitDialog
|
|
//===========================================================================================================================
|
|
|
|
BOOL ChooserDialog::OnInitDialog( void )
|
|
{
|
|
HICON icon;
|
|
BOOL result;
|
|
CString tempString;
|
|
DNSStatus err;
|
|
|
|
// Initialize our parent.
|
|
|
|
CDialog::OnInitDialog();
|
|
|
|
// Set up the window icon.
|
|
|
|
icon = AfxGetApp()->LoadIcon( IDR_MAIN_ICON );
|
|
assert( icon );
|
|
if( icon )
|
|
{
|
|
SetIcon( icon, TRUE ); // Set big icon
|
|
SetIcon( icon, FALSE ); // Set small icon
|
|
}
|
|
|
|
// Set up the Domain List.
|
|
|
|
result = tempString.LoadString( IDS_CHOOSER_DOMAIN_COLUMN_NAME );
|
|
assert( result );
|
|
mDomainList.InsertColumn( 0, tempString, LVCFMT_LEFT, kDomainListDefaultDomainColumnWidth );
|
|
|
|
// Set up the Service List.
|
|
|
|
result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_TYPE );
|
|
assert( result );
|
|
mServiceList.InsertColumn( 0, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnTypeWidth );
|
|
|
|
result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_DESC );
|
|
assert( result );
|
|
mServiceList.InsertColumn( 1, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnDescWidth );
|
|
|
|
PopulateServicesList();
|
|
|
|
// Set up the Chooser List.
|
|
|
|
result = tempString.LoadString( IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME );
|
|
assert( result );
|
|
mChooserList.InsertColumn( 0, tempString, LVCFMT_LEFT, kChooserListDefaultNameColumnWidth );
|
|
|
|
result = tempString.LoadString( IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME );
|
|
assert( result );
|
|
mChooserList.InsertColumn( 1, tempString, LVCFMT_LEFT, kChooserListDefaultIPColumnWidth );
|
|
|
|
// Set up the other controls.
|
|
|
|
UpdateInfoDisplay();
|
|
|
|
// Start browsing for domains.
|
|
|
|
err = DNSBrowserCreate( 0, BrowserCallBack, this, &mBrowser );
|
|
assert( err == kDNSNoErr );
|
|
|
|
err = DNSBrowserStartDomainSearch( mBrowser, 0 );
|
|
assert( err == kDNSNoErr );
|
|
|
|
return( true );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnFileClose
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnFileClose()
|
|
{
|
|
OnClose();
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnActivate
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnActivate( UINT nState, CWnd* pWndOther, BOOL bMinimized )
|
|
{
|
|
// Always make the active window the "main" window so modal dialogs work better and the app quits after closing
|
|
// the last window.
|
|
|
|
gApp.m_pMainWnd = this;
|
|
|
|
CDialog::OnActivate(nState, pWndOther, bMinimized);
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// PostNcDestroy
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::PostNcDestroy()
|
|
{
|
|
// Call the base class to do the normal cleanup.
|
|
|
|
delete this;
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// PreTranslateMessage
|
|
//===========================================================================================================================
|
|
|
|
BOOL ChooserDialog::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
BOOL result;
|
|
|
|
result = false;
|
|
assert( mMenuAcceleratorTable );
|
|
if( mMenuAcceleratorTable )
|
|
{
|
|
result = ::TranslateAccelerator( m_hWnd, mMenuAcceleratorTable, pMsg );
|
|
}
|
|
if( !result )
|
|
{
|
|
result = CDialog::PreTranslateMessage( pMsg );
|
|
}
|
|
return( result );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnInitMenuPopup
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnInitMenuPopup( CMenu *pPopupMenu, UINT nIndex, BOOL bSysMenu )
|
|
{
|
|
CDialog::OnInitMenuPopup( pPopupMenu, nIndex, bSysMenu );
|
|
|
|
switch( nIndex )
|
|
{
|
|
case kChooserMenuIndexFile:
|
|
break;
|
|
|
|
case kChooserMenuIndexHelp:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnExit
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnExit()
|
|
{
|
|
OnClose();
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnAbout
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnAbout()
|
|
{
|
|
AboutDialog dialog;
|
|
|
|
dialog.DoModal();
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnSysCommand
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnSysCommand( UINT inID, LPARAM inParam )
|
|
{
|
|
CDialog::OnSysCommand( inID, inParam );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnClose
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnClose()
|
|
{
|
|
StopBrowsing();
|
|
|
|
gApp.m_pMainWnd = this;
|
|
DestroyWindow();
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnNcDestroy
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnNcDestroy()
|
|
{
|
|
gApp.m_pMainWnd = this;
|
|
|
|
CDialog::OnNcDestroy();
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnDomainListChanged
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnDomainListChanged( NMHDR *pNMHDR, LRESULT *pResult )
|
|
{
|
|
UNUSED_ALWAYS( pNMHDR );
|
|
|
|
// Domain list changes have similar effects to service list changes so reuse that code path by calling it here.
|
|
|
|
OnServiceListChanged( NULL, NULL );
|
|
|
|
*pResult = 0;
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnServiceListChanged
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnServiceListChanged( NMHDR *pNMHDR, LRESULT *pResult )
|
|
{
|
|
int selectedType;
|
|
int selectedDomain;
|
|
|
|
UNUSED_ALWAYS( pNMHDR );
|
|
|
|
// Stop any existing service search.
|
|
|
|
StopBrowsing();
|
|
|
|
// If a domain and service type are selected, start searching for the service type on the domain.
|
|
|
|
selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
|
|
selectedDomain = mDomainList.GetNextItem( -1, LVNI_SELECTED );
|
|
|
|
if( ( selectedType >= 0 ) && ( selectedDomain >= 0 ) )
|
|
{
|
|
CString s;
|
|
std::string utf8;
|
|
const char * type;
|
|
|
|
s = mDomainList.GetItemText( selectedDomain, 0 );
|
|
StringObjectToUTF8String( s, utf8 );
|
|
type = mServiceTypes[ selectedType ].serviceType.c_str();
|
|
if( *type != '\0' )
|
|
{
|
|
StartBrowsing( type, utf8.c_str() );
|
|
}
|
|
}
|
|
|
|
if( pResult )
|
|
{
|
|
*pResult = 0;
|
|
}
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnChooserListChanged
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnChooserListChanged( NMHDR *pNMHDR, LRESULT *pResult )
|
|
{
|
|
UNUSED_ALWAYS( pNMHDR );
|
|
|
|
UpdateInfoDisplay();
|
|
*pResult = 0;
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnChooserListDoubleClick
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnChooserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
|
|
{
|
|
int selectedItem;
|
|
|
|
UNUSED_ALWAYS( pNMHDR );
|
|
|
|
// Display the service instance if it is selected. Otherwise, clear all the info.
|
|
|
|
selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
|
|
if( selectedItem >= 0 )
|
|
{
|
|
ServiceInstanceInfo * p;
|
|
CString url;
|
|
const KnownServiceEntry * service;
|
|
|
|
assert( selectedItem < (int) mServiceInstances.size() );
|
|
p = &mServiceInstances[ selectedItem ];
|
|
|
|
// Search for a known service type entry that matches.
|
|
|
|
for( service = kKnownServiceTable; service->serviceType; ++service )
|
|
{
|
|
if( p->type == service->serviceType )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if( service->serviceType )
|
|
{
|
|
const char * text;
|
|
|
|
// Create a URL representing the service instance.
|
|
|
|
if( strcmp( service->serviceType, "_smb._tcp." ) == 0 )
|
|
{
|
|
// Special case for SMB (no port number).
|
|
|
|
url.Format( TEXT( "%s%s/" ), service->urlScheme, (const char *) p->ip.c_str() );
|
|
}
|
|
else if( strcmp( service->serviceType, "_ftp._tcp." ) == 0 )
|
|
{
|
|
// Special case for FTP to get login info.
|
|
|
|
LoginDialog dialog;
|
|
CString username;
|
|
CString password;
|
|
|
|
if( !dialog.GetLogin( username, password ) )
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Build URL in the following format:
|
|
//
|
|
// ftp://[username[:password]@]<ip>
|
|
|
|
url += service->urlScheme;
|
|
if( username.GetLength() > 0 )
|
|
{
|
|
url += username;
|
|
if( password.GetLength() > 0 )
|
|
{
|
|
url += ':';
|
|
url += password;
|
|
}
|
|
url += '@';
|
|
}
|
|
url += p->ip.c_str();
|
|
}
|
|
else if( strcmp( service->serviceType, "_http._tcp." ) == 0 )
|
|
{
|
|
// Special case for HTTP to exclude "path=" if present.
|
|
|
|
text = service->useText ? p->text.c_str() : "";
|
|
if( strncmp( text, "path=", 5 ) == 0 )
|
|
{
|
|
text += 5;
|
|
}
|
|
if( *text != '/' )
|
|
{
|
|
url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
|
|
}
|
|
else
|
|
{
|
|
url.Format( TEXT( "%s%s%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
text = service->useText ? p->text.c_str() : "";
|
|
url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
|
|
}
|
|
|
|
// Let the system open the URL in the correct app.
|
|
|
|
{
|
|
CWaitCursor waitCursor;
|
|
|
|
ShellExecute( NULL, TEXT( "open" ), url, TEXT( "" ), TEXT( "c:\\" ), SW_SHOWNORMAL );
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
*pResult = 0;
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnCancel
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::OnCancel()
|
|
{
|
|
// Do nothing.
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// PopulateServicesList
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::PopulateServicesList( void )
|
|
{
|
|
ServiceTypeVector::iterator i;
|
|
CString type;
|
|
CString desc;
|
|
std::string tmp;
|
|
|
|
// Add a fixed list of known services.
|
|
|
|
if( mServiceTypes.empty() )
|
|
{
|
|
const KnownServiceEntry * service;
|
|
|
|
for( service = kKnownServiceTable; service->serviceType; ++service )
|
|
{
|
|
ServiceTypeInfo info;
|
|
|
|
info.serviceType = service->serviceType;
|
|
info.description = service->description;
|
|
info.urlScheme = service->urlScheme;
|
|
mServiceTypes.push_back( info );
|
|
}
|
|
}
|
|
|
|
// Add each service to the list.
|
|
|
|
for( i = mServiceTypes.begin(); i != mServiceTypes.end(); ++i )
|
|
{
|
|
const char * p;
|
|
const char * q;
|
|
|
|
p = ( *i ).serviceType.c_str();
|
|
if( *p == '_' ) ++p; // Skip leading '_'.
|
|
q = strchr( p, '.' ); // Find first '.'.
|
|
if( q ) tmp.assign( p, (size_t)( q - p ) ); // Use only up to the first '.'.
|
|
else tmp.assign( p ); // No '.' so use the entire string.
|
|
UTF8StringToStringObject( tmp.c_str(), type );
|
|
UTF8StringToStringObject( ( *i ).description.c_str(), desc );
|
|
|
|
int n;
|
|
|
|
n = mServiceList.GetItemCount();
|
|
mServiceList.InsertItem( n, type );
|
|
mServiceList.SetItemText( n, 1, desc );
|
|
}
|
|
|
|
// Select the first service type by default.
|
|
|
|
if( !mServiceTypes.empty() )
|
|
{
|
|
mServiceList.SetItemState( 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
|
|
}
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// UpdateInfoDisplay
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::UpdateInfoDisplay( void )
|
|
{
|
|
int selectedItem;
|
|
std::string name;
|
|
CString s;
|
|
std::string ip;
|
|
std::string ifIP;
|
|
std::string text;
|
|
std::string textNewLines;
|
|
std::string hostName;
|
|
CWnd * item;
|
|
std::string::iterator i;
|
|
|
|
// Display the service instance if it is selected. Otherwise, clear all the info.
|
|
|
|
selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
|
|
if( selectedItem >= 0 )
|
|
{
|
|
ServiceInstanceInfo * p;
|
|
|
|
assert( selectedItem < (int) mServiceInstances.size() );
|
|
p = &mServiceInstances[ selectedItem ];
|
|
|
|
name = p->name;
|
|
ip = p->ip;
|
|
ifIP = p->ifIP;
|
|
text = p->text;
|
|
hostName = p->hostName;
|
|
|
|
// Sync up the list items with the actual data (IP address may change).
|
|
|
|
UTF8StringToStringObject( ip.c_str(), s );
|
|
mChooserList.SetItemText( selectedItem, 1, s );
|
|
}
|
|
|
|
// Name
|
|
|
|
item = (CWnd *) this->GetDlgItem( IDC_INFO_NAME_TEXT );
|
|
assert( item );
|
|
UTF8StringToStringObject( name.c_str(), s );
|
|
item->SetWindowText( s );
|
|
|
|
// IP
|
|
|
|
item = (CWnd *) this->GetDlgItem( IDC_INFO_IP_TEXT );
|
|
assert( item );
|
|
UTF8StringToStringObject( ip.c_str(), s );
|
|
item->SetWindowText( s );
|
|
|
|
// Interface
|
|
|
|
item = (CWnd *) this->GetDlgItem( IDC_INFO_INTERFACE_TEXT );
|
|
assert( item );
|
|
UTF8StringToStringObject( ifIP.c_str(), s );
|
|
item->SetWindowText( s );
|
|
|
|
|
|
item = (CWnd *) this->GetDlgItem( IDC_INFO_HOST_NAME_TEXT );
|
|
assert( item );
|
|
UTF8StringToStringObject( hostName.c_str(), s );
|
|
item->SetWindowText( s );
|
|
|
|
// Text
|
|
|
|
item = (CWnd *) this->GetDlgItem( IDC_INFO_TEXT_TEXT );
|
|
assert( item );
|
|
for( i = text.begin(); i != text.end(); ++i )
|
|
{
|
|
if( *i == '\1' )
|
|
{
|
|
textNewLines += "\r\n";
|
|
}
|
|
else
|
|
{
|
|
textNewLines += *i;
|
|
}
|
|
}
|
|
UTF8StringToStringObject( textNewLines.c_str(), s );
|
|
item->SetWindowText( s );
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// OnDomainAdd
|
|
//===========================================================================================================================
|
|
|
|
LONG ChooserDialog::OnDomainAdd( WPARAM inWParam, LPARAM inLParam )
|
|
{
|
|
DomainEventInfo * p;
|
|
std::auto_ptr < DomainEventInfo > pAutoPtr;
|
|
int n;
|
|
int i;
|
|
CString domain;
|
|
CString s;
|
|
bool found;
|
|
|
|
UNUSED_ALWAYS( inWParam );
|
|
|
|
assert( inLParam );
|
|
p = reinterpret_cast <DomainEventInfo *> ( inLParam );
|
|
pAutoPtr.reset( p );
|
|
|
|
// Search to see if we already know about this domain. If not, add it to the list.
|
|
|
|
found = false;
|
|
domain = p->domain;
|
|
n = mDomainList.GetItemCount();
|
|
for( i = 0; i < n; ++i )
|
|
{
|
|
s = mDomainList.GetItemText( i, 0 );
|
|
if( s == domain )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if( !found )
|
|
{
|
|
int selectedItem;
|
|
|
|
mDomainList.InsertItem( n, domain );
|
|
|
|
// If no domains are selected and the domain being added is a default domain, select it.
|
|
|
|
selectedItem = mDomainList.GetNextItem( -1, LVNI_SELECTED );
|
|
if( ( selectedItem < 0 ) && ( p->eventType == kDNSBrowserEventTypeAddDefaultDomain ) )
|
|
{
|
|
mDomainList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
|
|
}
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnDomainRemove
|
|
//===========================================================================================================================
|
|
|
|
LONG ChooserDialog::OnDomainRemove( WPARAM inWParam, LPARAM inLParam )
|
|
{
|
|
DomainEventInfo * p;
|
|
std::auto_ptr < DomainEventInfo > pAutoPtr;
|
|
int n;
|
|
int i;
|
|
CString domain;
|
|
CString s;
|
|
bool found;
|
|
|
|
UNUSED_ALWAYS( inWParam );
|
|
|
|
assert( inLParam );
|
|
p = reinterpret_cast <DomainEventInfo *> ( inLParam );
|
|
pAutoPtr.reset( p );
|
|
|
|
// Search to see if we know about this domain. If so, remove it from the list.
|
|
|
|
found = false;
|
|
domain = p->domain;
|
|
n = mDomainList.GetItemCount();
|
|
for( i = 0; i < n; ++i )
|
|
{
|
|
s = mDomainList.GetItemText( i, 0 );
|
|
if( s == domain )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if( found )
|
|
{
|
|
mDomainList.DeleteItem( i );
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnServiceAdd
|
|
//===========================================================================================================================
|
|
|
|
LONG ChooserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
|
|
{
|
|
ServiceEventInfo * p;
|
|
std::auto_ptr < ServiceEventInfo > pAutoPtr;
|
|
|
|
UNUSED_ALWAYS( inWParam );
|
|
|
|
assert( inLParam );
|
|
p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
|
|
pAutoPtr.reset( p );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnServiceRemove
|
|
//===========================================================================================================================
|
|
|
|
LONG ChooserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
|
|
{
|
|
ServiceEventInfo * p;
|
|
std::auto_ptr < ServiceEventInfo > pAutoPtr;
|
|
bool found;
|
|
int n;
|
|
int i;
|
|
|
|
UNUSED_ALWAYS( inWParam );
|
|
|
|
assert( inLParam );
|
|
p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
|
|
pAutoPtr.reset( p );
|
|
|
|
// Search to see if we know about this service instance. If so, remove it from the list.
|
|
|
|
found = false;
|
|
n = (int) mServiceInstances.size();
|
|
for( i = 0; i < n; ++i )
|
|
{
|
|
ServiceInstanceInfo * q;
|
|
|
|
// If the name, type, domain, and interface match, treat it as the same service instance.
|
|
|
|
q = &mServiceInstances[ i ];
|
|
if( ( p->name == q->name ) &&
|
|
( p->type == q->type ) &&
|
|
( p->domain == q->domain ) )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if( found )
|
|
{
|
|
mChooserList.DeleteItem( i );
|
|
assert( i < (int) mServiceInstances.size() );
|
|
mServiceInstances.erase( mServiceInstances.begin() + i );
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// OnResolve
|
|
//===========================================================================================================================
|
|
|
|
LONG ChooserDialog::OnResolve( WPARAM inWParam, LPARAM inLParam )
|
|
{
|
|
ServiceInstanceInfo * p;
|
|
std::auto_ptr < ServiceInstanceInfo > pAutoPtr;
|
|
int selectedType;
|
|
int n;
|
|
int i;
|
|
bool found;
|
|
|
|
UNUSED_ALWAYS( inWParam );
|
|
|
|
assert( inLParam );
|
|
p = reinterpret_cast <ServiceInstanceInfo *> ( inLParam );
|
|
pAutoPtr.reset( p );
|
|
|
|
// Make sure it is for an item of the correct type. This handles any resolves that may have been queued up.
|
|
|
|
selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
|
|
assert( selectedType >= 0 );
|
|
if( selectedType >= 0 )
|
|
{
|
|
assert( selectedType <= (int) mServiceTypes.size() );
|
|
if( p->type != mServiceTypes[ selectedType ].serviceType )
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Search to see if we know about this service instance. If so, update its info. Otherwise, add it to the list.
|
|
|
|
found = false;
|
|
n = (int) mServiceInstances.size();
|
|
for( i = 0; i < n; ++i )
|
|
{
|
|
ServiceInstanceInfo * q;
|
|
|
|
// If the name, type, domain, and interface matches, treat it as the same service instance.
|
|
|
|
q = &mServiceInstances[ i ];
|
|
if( ( p->name == q->name ) &&
|
|
( p->type == q->type ) &&
|
|
( p->domain == q->domain ) &&
|
|
( p->ifIP == q->ifIP ) )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if( found )
|
|
{
|
|
mServiceInstances[ i ] = *p;
|
|
}
|
|
else
|
|
{
|
|
CString s;
|
|
|
|
mServiceInstances.push_back( *p );
|
|
UTF8StringToStringObject( p->name.c_str(), s );
|
|
mChooserList.InsertItem( n, s );
|
|
|
|
UTF8StringToStringObject( p->ip.c_str(), s );
|
|
mChooserList.SetItemText( n, 1, s );
|
|
|
|
// If this is the only item, select it.
|
|
|
|
if( n == 0 )
|
|
{
|
|
mChooserList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
|
|
}
|
|
}
|
|
UpdateInfoDisplay();
|
|
|
|
exit:
|
|
return( 0 );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// StartBrowsing
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::StartBrowsing( const char *inType, const char *inDomain )
|
|
{
|
|
DNSStatus err;
|
|
|
|
assert( mServiceInstances.empty() );
|
|
assert( mChooserList.GetItemCount() == 0 );
|
|
assert( !mIsServiceBrowsing );
|
|
|
|
mChooserList.DeleteAllItems();
|
|
mServiceInstances.clear();
|
|
|
|
mIsServiceBrowsing = true;
|
|
err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, inType, inDomain );
|
|
assert( err == kDNSNoErr );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// StopBrowsing
|
|
//===========================================================================================================================
|
|
|
|
void ChooserDialog::StopBrowsing( void )
|
|
{
|
|
// If searching, stop.
|
|
|
|
if( mIsServiceBrowsing )
|
|
{
|
|
DNSStatus err;
|
|
|
|
mIsServiceBrowsing = false;
|
|
err = DNSBrowserStopServiceSearch( mBrowser, 0 );
|
|
assert( err == kDNSNoErr );
|
|
}
|
|
|
|
// Remove all service instances.
|
|
|
|
mChooserList.DeleteAllItems();
|
|
assert( mChooserList.GetItemCount() == 0 );
|
|
mServiceInstances.clear();
|
|
assert( mServiceInstances.empty() );
|
|
UpdateInfoDisplay();
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// BrowserCallBack
|
|
//===========================================================================================================================
|
|
|
|
static void
|
|
BrowserCallBack(
|
|
void * inContext,
|
|
DNSBrowserRef inRef,
|
|
DNSStatus inStatusCode,
|
|
const DNSBrowserEvent * inEvent )
|
|
{
|
|
ChooserDialog * dialog;
|
|
UINT message;
|
|
BOOL posted;
|
|
|
|
UNUSED_ALWAYS( inStatusCode );
|
|
UNUSED_ALWAYS( inRef );
|
|
|
|
// Check parameters.
|
|
|
|
assert( inContext );
|
|
dialog = reinterpret_cast <ChooserDialog *> ( inContext );
|
|
|
|
try
|
|
{
|
|
switch( inEvent->type )
|
|
{
|
|
case kDNSBrowserEventTypeRelease:
|
|
break;
|
|
|
|
// Domains
|
|
|
|
case kDNSBrowserEventTypeAddDomain:
|
|
case kDNSBrowserEventTypeAddDefaultDomain:
|
|
case kDNSBrowserEventTypeRemoveDomain:
|
|
{
|
|
DomainEventInfo * domain;
|
|
std::auto_ptr < DomainEventInfo > domainAutoPtr;
|
|
|
|
domain = new DomainEventInfo;
|
|
domainAutoPtr.reset( domain );
|
|
|
|
domain->eventType = inEvent->type;
|
|
domain->domain = inEvent->data.addDomain.domain;
|
|
domain->ifIP = inEvent->data.addDomain.interfaceIP;
|
|
|
|
message = ( inEvent->type == kDNSBrowserEventTypeRemoveDomain ) ? WM_USER_DOMAIN_REMOVE : WM_USER_DOMAIN_ADD;
|
|
posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) domain );
|
|
assert( posted );
|
|
if( posted )
|
|
{
|
|
domainAutoPtr.release();
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Services
|
|
|
|
case kDNSBrowserEventTypeAddService:
|
|
case kDNSBrowserEventTypeRemoveService:
|
|
{
|
|
ServiceEventInfo * service;
|
|
std::auto_ptr < ServiceEventInfo > serviceAutoPtr;
|
|
|
|
service = new ServiceEventInfo;
|
|
serviceAutoPtr.reset( service );
|
|
|
|
service->eventType = inEvent->type;
|
|
service->name = inEvent->data.addService.name;
|
|
service->type = inEvent->data.addService.type;
|
|
service->domain = inEvent->data.addService.domain;
|
|
service->ifIP = inEvent->data.addService.interfaceIP;
|
|
|
|
message = ( inEvent->type == kDNSBrowserEventTypeAddService ) ? WM_USER_SERVICE_ADD : WM_USER_SERVICE_REMOVE;
|
|
posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) service );
|
|
assert( posted );
|
|
if( posted )
|
|
{
|
|
serviceAutoPtr.release();
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Resolves
|
|
|
|
case kDNSBrowserEventTypeResolved:
|
|
if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4 )
|
|
{
|
|
ServiceInstanceInfo * serviceInstance;
|
|
std::auto_ptr < ServiceInstanceInfo > serviceInstanceAutoPtr;
|
|
char s[ 32 ];
|
|
|
|
serviceInstance = new ServiceInstanceInfo;
|
|
serviceInstanceAutoPtr.reset( serviceInstance );
|
|
|
|
serviceInstance->name = inEvent->data.resolved->name;
|
|
serviceInstance->type = inEvent->data.resolved->type;
|
|
serviceInstance->domain = inEvent->data.resolved->domain;
|
|
serviceInstance->ip = DNSNetworkAddressToString( &inEvent->data.resolved->address, s );
|
|
serviceInstance->ifIP = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, s );
|
|
serviceInstance->text = inEvent->data.resolved->textRecord;
|
|
serviceInstance->hostName = inEvent->data.resolved->hostName;
|
|
|
|
posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_RESOLVE, 0, (LPARAM) serviceInstance );
|
|
assert( posted );
|
|
if( posted )
|
|
{
|
|
serviceInstanceAutoPtr.release();
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
catch( ... )
|
|
{
|
|
// Don't let exceptions escape.
|
|
}
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// DNSNetworkAddressToString
|
|
//
|
|
// Note: Currently only supports IPv4 network addresses.
|
|
//===========================================================================================================================
|
|
|
|
static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString )
|
|
{
|
|
const DNSUInt8 * p;
|
|
DNSUInt16 port;
|
|
|
|
p = inAddr->u.ipv4.addr.v8;
|
|
port = ntohs( inAddr->u.ipv4.port.v16 );
|
|
if( port != kDNSPortInvalid )
|
|
{
|
|
sprintf( outString, "%u.%u.%u.%u:%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ], port );
|
|
}
|
|
else
|
|
{
|
|
sprintf( outString, "%u.%u.%u.%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] );
|
|
}
|
|
return( outString );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// UTF8StringToStringObject
|
|
//===========================================================================================================================
|
|
|
|
static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject )
|
|
{
|
|
DWORD err;
|
|
int n;
|
|
BSTR unicode;
|
|
|
|
unicode = NULL;
|
|
|
|
n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
|
|
if( n > 0 )
|
|
{
|
|
unicode = (BSTR) malloc( (size_t)( n * sizeof( wchar_t ) ) );
|
|
if( !unicode )
|
|
{
|
|
err = ERROR_INSUFFICIENT_BUFFER;
|
|
goto exit;
|
|
}
|
|
|
|
n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
|
|
try
|
|
{
|
|
inObject = unicode;
|
|
}
|
|
catch( ... )
|
|
{
|
|
err = ERROR_NO_UNICODE_TRANSLATION;
|
|
goto exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
inObject = "";
|
|
}
|
|
err = 0;
|
|
|
|
exit:
|
|
if( unicode )
|
|
{
|
|
free( unicode );
|
|
}
|
|
return( err );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// StringObjectToUTF8String
|
|
//===========================================================================================================================
|
|
|
|
static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 )
|
|
{
|
|
DWORD err;
|
|
BSTR unicode;
|
|
int nUnicode;
|
|
int n;
|
|
char * utf8;
|
|
|
|
unicode = NULL;
|
|
utf8 = NULL;
|
|
|
|
nUnicode = inObject.GetLength();
|
|
if( nUnicode > 0 )
|
|
{
|
|
unicode = inObject.AllocSysString();
|
|
n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, NULL, 0, NULL, NULL );
|
|
assert( n > 0 );
|
|
|
|
utf8 = (char *) malloc( (size_t) n );
|
|
assert( utf8 );
|
|
if( !utf8 ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; }
|
|
|
|
n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, utf8, n, NULL, NULL );
|
|
assert( n > 0 );
|
|
|
|
try
|
|
{
|
|
outUTF8.assign( utf8, n );
|
|
}
|
|
catch( ... )
|
|
{
|
|
err = ERROR_NO_UNICODE_TRANSLATION;
|
|
goto exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
outUTF8.clear();
|
|
}
|
|
err = 0;
|
|
|
|
exit:
|
|
if( unicode )
|
|
{
|
|
SysFreeString( unicode );
|
|
}
|
|
if( utf8 )
|
|
{
|
|
free( utf8 );
|
|
}
|
|
return( err );
|
|
}
|