]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - Clients/PrinterSetupWizard/SecondPage.cpp
mDNSResponder-878.200.35.tar.gz
[apple/mdnsresponder.git] / Clients / PrinterSetupWizard / SecondPage.cpp
index 9e3720a6777c62577a024b5e740652171d2152c0..1521d0d917bb40ba7373fdb1aeae44fef068b762 100644 (file)
@@ -1,67 +1,19 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * 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
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * 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.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-    
-$Log: SecondPage.cpp,v $
-Revision 1.10  2005/01/20 19:54:38  shersche
-Fix parse error when text record is NULL
-
-Revision 1.9  2005/01/06 08:13:50  shersche
-Don't use moreComing flag to determine number of text record, disregard queue name if qtotal isn't defined, don't disregard queue name if "rp" is the only key specified
-
-Revision 1.8  2005/01/04 21:09:14  shersche
-Fix problems in parsing text records. Fix problems in remove event handling. Ensure that the same service can't be resolved more than once.
-
-Revision 1.7  2004/12/31 07:25:27  shersche
-Tidy up printer management, and fix memory leaks when hitting 'Cancel'
-
-Revision 1.6  2004/12/30 01:24:02  shersche
-<rdar://problem/3906182> Remove references to description key
-Bug #: 3906182
-
-Revision 1.5  2004/12/30 01:02:47  shersche
-<rdar://problem/3734478> Add Printer information box that displays description and location information when printer name is selected
-Bug #: 3734478
-
-Revision 1.4  2004/12/29 18:53:38  shersche
-<rdar://problem/3725106>
-<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
-Bug #: 3725106, 3737413
-
-Revision 1.3  2004/09/13 21:26:15  shersche
-<rdar://problem/3796483> Use the moreComing flag to determine whether drawing should take place in OnAddPrinter and OnRemovePrinter callbacks
-Bug #: 3796483
-
-Revision 1.2  2004/06/26 03:19:57  shersche
-clean up warning messages
-
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #include "stdafx.h"
 #include "PrinterSetupWizardApp.h"
@@ -74,17 +26,11 @@ First checked in
 // local variable is initialize but not referenced
 #pragma warning(disable:4189)
 
-#define WM_SERVICE_EVENT       ( WM_USER + 0x101 )
-
 // CSecondPage dialog
 
 IMPLEMENT_DYNAMIC(CSecondPage, CPropertyPage)
 CSecondPage::CSecondPage()
-       : CPropertyPage(CSecondPage::IDD),
-       m_pdlBrowser( NULL ),
-       m_lprBrowser( NULL ),
-       m_ippBrowser( NULL ),
-       m_selected( NULL )
+       : CPropertyPage(CSecondPage::IDD)
 {
        m_psp.dwFlags &= ~(PSP_HASHELP);
        m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
@@ -92,71 +38,14 @@ CSecondPage::CSecondPage()
        m_psp.pszHeaderTitle    = MAKEINTRESOURCE(IDS_BROWSE_TITLE);
        m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_BROWSE_SUBTITLE);
 
-       m_resolver                      =       NULL;
        m_emptyListItem         =       NULL;
        m_initialized           =       false;
        m_waiting                       =       false;
-
-       LoadPrinterNames();
 }
 
 
 CSecondPage::~CSecondPage()
 {
-       StopBrowse();
-}
-
-
-OSStatus
-CSecondPage::LoadPrinterNames()
-{
-       PBYTE           buffer  =       NULL;
-       OSStatus        err             = 0;
-
-       //
-       // rdar://problem/3701926 - Printer can't be installed twice
-       //
-       // First thing we want to do is make sure the printer isn't already installed.
-       // If the printer name is found, we'll try and rename it until we
-       // find a unique name
-       //
-       DWORD dwNeeded = 0, dwNumPrinters = 0;
-
-       BOOL ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &dwNeeded, &dwNumPrinters);
-       err = translate_errno( ok, errno_compat(), kUnknownErr );
-
-       if ((err == ERROR_INSUFFICIENT_BUFFER) && (dwNeeded > 0))
-       {
-               try
-               {
-                       buffer = new unsigned char[dwNeeded];
-               }
-               catch (...)
-               {
-                       buffer = NULL;
-               }
-       
-               require_action( buffer, exit, kNoMemoryErr );
-               ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, buffer, dwNeeded, &dwNeeded, &dwNumPrinters);
-               err = translate_errno( ok, errno_compat(), kUnknownErr );
-               require_noerr( err, exit );
-
-               for (DWORD index = 0; index < dwNumPrinters; index++)
-               {
-                       PRINTER_INFO_4 * lppi4 = (PRINTER_INFO_4*) (buffer + index * sizeof(PRINTER_INFO_4));
-
-                       m_printerNames[lppi4->pPrinterName] = lppi4->pPrinterName;
-               }
-       }
-
-exit:
-
-       if (buffer != NULL)
-       {
-               delete [] buffer;
-       }
-
-       return err;
 }
 
 
@@ -169,10 +58,16 @@ CSecondPage::InitBrowseList()
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
        require_quiet( psheet, exit );
 
+       // Initialize so that nothing is selected when we add to the list
+
+       psheet->SetSelectedPrinter( NULL );
+       m_gotChoice = false;
+       m_browseList.Select( NULL, TVGN_FIRSTVISIBLE );
+
        //
-       // load the no rendezvous printers message until something shows up in the browse list
+       // load the no printers message until something shows up in the browse list
        //
-       text.LoadString(IDS_NO_RENDEZVOUS_PRINTERS);
+       text.LoadString(IDS_NO_PRINTERS);
 
        LoadTextAndDisableWindow( text );
 
@@ -185,6 +80,8 @@ CSecondPage::InitBrowseList()
        // disable the printer information box
        //
        SetPrinterInformationState( FALSE );
+       m_descriptionField.SetWindowText( L"" );
+       m_locationField.SetWindowText( L"" );
 
 exit:
 
@@ -192,267 +89,20 @@ exit:
 }
 
 
-OSStatus
-CSecondPage::StartOperation( DNSServiceRef ref )
-{
-       OSStatus err;
-
-       err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(ref), m_hWnd, WM_SERVICE_EVENT, FD_READ|FD_CLOSE);
-       require_noerr( err, exit );
-
-       m_serviceRefList.push_back( ref );
-
-exit:
-
-       return err;
-}
-
-
-OSStatus
-CSecondPage::StopOperation( DNSServiceRef & ref )
-{
-       OSStatus err = kNoErr;
-
-       if ( ref )
-       {
-               m_serviceRefList.remove( ref );
-
-               if ( IsWindow( m_hWnd ) )
-               {
-                       err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD( ref ), m_hWnd, 0, 0 );
-                       require_noerr( err, exit );
-               }
-
-               DNSServiceRefDeallocate( ref );
-               ref = NULL;
-       }
-
-exit:
-
-       return err;
-}
-
-
-Printer*
-CSecondPage::Lookup(const char * inName)
-{
-       check( IsWindow( m_hWnd ) );
-       check( inName );
-
-       HTREEITEM item = m_browseList.GetChildItem( TVI_ROOT );\r
-       while ( item )\r
-       {\r
-               Printer *       printer;\r
-               DWORD_PTR       data;\r
-\r
-               data = m_browseList.GetItemData( item );\r
-               printer = reinterpret_cast<Printer*>(data);\r
-\r
-               if ( printer && ( printer->name == inName ) )
-               {
-                       return printer;
-               }
-\r
-               item = m_browseList.GetNextItem( item, TVGN_NEXT );
-       }
-
-       return NULL;
-}
-
-
-OSStatus
-CSecondPage::StartBrowse()
-{
-       OSStatus err;
-
-       //
-       // setup the DNS-SD browsing
-       //
-       err = DNSServiceBrowse( &m_pdlBrowser, 0, 0, kPDLServiceType, NULL, OnBrowse, this );
-       require_noerr( err, exit );
-
-       err = StartOperation( m_pdlBrowser );
-       require_noerr( err, exit );
-
-       err = DNSServiceBrowse( &m_lprBrowser, 0, 0, kLPRServiceType, NULL, OnBrowse, this );
-       require_noerr( err, exit );
-
-       err = StartOperation( m_lprBrowser );
-       require_noerr( err, exit );
-
-       err = DNSServiceBrowse( &m_ippBrowser, 0, 0, kIPPServiceType, NULL, OnBrowse, this );
-       require_noerr( err, exit );
-
-       err = StartOperation( m_ippBrowser );
-       require_noerr( err, exit );
-
-exit:
-
-       return err;
-}
-
-
-OSStatus
-CSecondPage::StopBrowse()
-{
-       OSStatus err;
-
-       err = StopOperation( m_pdlBrowser );
-       require_noerr( err, exit );
-
-       err = StopOperation( m_lprBrowser );
-       require_noerr( err, exit );
-
-       err = StopOperation( m_ippBrowser );
-       require_noerr( err, exit );
-
-       while ( m_printers.size() > 0 )
-       {
-               Printer * printer = m_printers.front();
-
-               m_printers.pop_front();
-
-               if ( printer->resolving )
-               {
-                       StopResolve( printer );
-               }
-
-               delete printer;
-       }
-
-exit:
-
-       return err;
-}
-
-
-OSStatus
-CSecondPage::StartResolve( Printer * printer )
-{
-       CPrinterSetupWizardSheet        *       psheet;
-       OSStatus                                                err = kNoErr;
-       Services::iterator                              it;
-
-       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_quiet( psheet, exit );
-
-       check( printer );
-
-       for ( it = printer->services.begin(); it != printer->services.end(); it++ )
-       {
-               if ( (*it)->serviceRef == NULL )
-               {
-                       err = StartResolve( *it );
-                       require_noerr( err, exit );
-               }
-       }
-
-exit:
-
-       return err;
-}
-
-
-OSStatus
-CSecondPage::StartResolve( Service * service )
-{
-       CPrinterSetupWizardSheet        *       psheet;
-       OSStatus                                                err = kNoErr;
-
-       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_quiet( psheet, exit );
-
-       check( service->serviceRef == NULL );
-
-       //
-       // clean out any queues that were collected during a previous
-       // resolve
-       //
-
-       service->EmptyQueues();
-
-       //
-       // now start the new resolve
-       //
-
-       err = DNSServiceResolve( &service->serviceRef, 0, 0, service->printer->name.c_str(), service->type.c_str(), service->domain.c_str(), (DNSServiceResolveReply) OnResolve, service );
-       require_noerr( err, exit );
-
-       err = StartOperation( service->serviceRef );
-       require_noerr( err, exit );
-
-       //
-       // If we're not currently resolving, then disable the next button
-       // and set the cursor to hourglass
-       //
-
-       if ( !service->printer->resolving )
-       {
-               psheet->SetWizardButtons( PSWIZB_BACK );
-
-               psheet->m_active = psheet->m_wait;
-               SetCursor(psheet->m_active);
-       }
-
-       service->printer->resolving++;
-
-exit:
-
-       return err;
-}
-
-
-OSStatus
-CSecondPage::StopResolve(Printer * printer)
-{
-       OSStatus err = kNoErr;
-
-       check( printer );
-
-       Services::iterator it;
-
-       for ( it = printer->services.begin(); it != printer->services.end(); it++ )
-       {
-               if ( (*it)->serviceRef )
-               {
-                       err = StopResolve( *it );
-                       require_noerr( err, exit );
-               }
-       }
-
-exit:
-
-       return err;
-}
-
-
-OSStatus
-CSecondPage::StopResolve( Service * service )
+void CSecondPage::DoDataExchange(CDataExchange* pDX)
 {
-       OSStatus err;
-
-       check( service->serviceRef );
-
-       err = StopOperation( service->serviceRef );
-       require_noerr( err, exit );
+       CPropertyPage::DoDataExchange(pDX);
+       DDX_Control(pDX, IDC_BROWSE_LIST, m_browseList);
+       DDX_Control(pDX, IDC_PRINTER_INFORMATION, m_printerInformation);
 
-       service->printer->resolving--;
+       DDX_Control(pDX, IDC_DESCRIPTION_LABEL, m_descriptionLabel);
 
-exit:
+       DDX_Control(pDX, IDC_DESCRIPTION_FIELD, m_descriptionField);
 
-       return err;
-}
+       DDX_Control(pDX, IDC_LOCATION_LABEL, m_locationLabel);
 
+       DDX_Control(pDX, IDC_LOCATION_FIELD, m_locationField);
 
-void CSecondPage::DoDataExchange(CDataExchange* pDX)
-{
-       CPropertyPage::DoDataExchange(pDX);
-       DDX_Control(pDX, IDC_BROWSE_LIST, m_browseList);
-       DDX_Control(pDX, IDC_PRINTER_INFORMATION, m_printerInformation);\r
-       DDX_Control(pDX, IDC_DESCRIPTION_LABEL, m_descriptionLabel);\r
-       DDX_Control(pDX, IDC_DESCRIPTION_FIELD, m_descriptionField);\r
-       DDX_Control(pDX, IDC_LOCATION_LABEL, m_locationLabel);\r
-       DDX_Control(pDX, IDC_LOCATION_FIELD, m_locationField);\r
 }
 
 
@@ -481,344 +131,89 @@ CSecondPage::OnSetActive()
 {
        CPrinterSetupWizardSheet        *       psheet;
        Printer                                         *       printer;
+       CWnd                                            *       pWnd;
+       Printers::iterator                              it;
        OSStatus                                                err = kNoErr;
+       BOOL                                                    b;
+
+       b = CPropertyPage::OnSetActive();
 
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
        require_action( psheet, exit, err = kUnknownErr );
 
-       if ( ( printer = psheet->GetSelectedPrinter() ) != NULL )
-       {
-               psheet->SetSelectedPrinter( NULL );
-               delete printer;
-       }
+       // Stash the selected printer if any
+
+       printer = psheet->GetSelectedPrinter();
 
-       //
        // initialize the browse list...this will remove everything currently
-       // in it, and add the no rendezvous printers item
-       //
-       InitBrowseList();
+       // in it, and add the no printers item
 
-       //
-       // start browing
-       //
-       err = StartBrowse();
-       require_noerr( err, exit );
+       InitBrowseList();
 
-exit:
+       // Populate the list with any printers that we currently know about
 
-       if ( err != kNoErr )
+       for ( it = psheet->m_printers.begin(); it != psheet->m_printers.end(); it++ )
        {
-               if ( err == kDNSServiceErr_Firewall )
-               {
-                       CString text, caption;
-
-                       text.LoadString( IDS_FIREWALL );
-                       caption.LoadString( IDS_FIREWALL_CAPTION );
-
-                       MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION);
-               }
-               else
-               {
-                       CPrinterSetupWizardSheet::WizardException exc;
-                       
-                       exc.text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT );
-                       exc.caption.LoadString( IDS_ERROR_CAPTION );
-                       
-                       throw(exc);
-               }
+               OnAddPrinter( *it, false );
        }
 
-       return CPropertyPage::OnSetActive();
-}
-
-
-BOOL
-CSecondPage::OnKillActive()
-{
-       OSStatus err = kNoErr;
-
-       if ( m_selected )
+       if ( ( !printer && ( psheet->m_printers.size() > 0 ) ) || ( printer != psheet->GetSelectedPrinter() ) )
        {
-               CPrinterSetupWizardSheet * psheet;
-
-               psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-               require_quiet( psheet, exit );
-
-               psheet->SetSelectedPrinter( m_selected );
-               m_printers.remove( m_selected );
-               m_selected = NULL;
-       }
-
-       err = StopBrowse();
-       require_noerr( err, exit );
-
-exit:
-
-       return CPropertyPage::OnKillActive();
-}
-
-
-void DNSSD_API
-CSecondPage::OnBrowse(
-                               DNSServiceRef                   inRef,
-                               DNSServiceFlags                 inFlags,
-                               uint32_t                                inInterfaceIndex,
-                               DNSServiceErrorType     inErrorCode,
-                               const char *                    inName, 
-                               const char *                    inType, 
-                               const char *                    inDomain,       
-                               void *                                  inContext )
-{
-       DEBUG_UNUSED(inRef);
-
-       CSecondPage     *       self;
-       bool                    moreComing = (bool) (inFlags & kDNSServiceFlagsMoreComing);
-
-       require_noerr( inErrorCode, exit );
-       
-       self = reinterpret_cast <CSecondPage*>( inContext );
-       require_quiet( self, exit );
+               if ( !printer )
+               {
+                       printer = psheet->m_printers.front();
+               }
 
-       if ( inFlags & kDNSServiceFlagsAdd )
-       {
-               self->OnAddPrinter( inInterfaceIndex, inName, inType, inDomain, moreComing );
-       }
-       else
-       {
-               self->OnRemovePrinter( inName, inType, inDomain, moreComing );
+               psheet->SetSelectedPrinter( printer );
        }
-
-exit:
-       
-       return;
-}
-
-
-void DNSSD_API
-CSecondPage::OnResolve(
-                               DNSServiceRef                   inRef,
-                               DNSServiceFlags                 inFlags,
-                               uint32_t                                inInterfaceIndex,
-                               DNSServiceErrorType             inErrorCode,
-                               const char *                    inFullName,     
-                               const char *                    inHostName, 
-                               uint16_t                                inPort,
-                               uint16_t                                inTXTSize,
-                               const char *                    inTXT,
-                               void *                                  inContext )
-{
-       DEBUG_UNUSED(inFullName);
-       DEBUG_UNUSED(inInterfaceIndex);
-       DEBUG_UNUSED(inFlags);
-       DEBUG_UNUSED(inRef);
-
-       CSecondPage     *       self;
-       Service         *       service;
-       Queue           *       q;
-       bool                    qtotalDefined = false;
-       uint32_t                qpriority = kDefaultPriority;
-       CString                 qname;
-       int                             idx;
-       OSStatus                err;
-
-       require_noerr( inErrorCode, exit );
-
-       service = reinterpret_cast<Service*>( inContext );
-       require_quiet( service, exit);
-
-       check( service->refs != 0 );
-
-       self = service->printer->window;
-       require_quiet( self, exit );
-
-       err = self->StopOperation( service->serviceRef );
-       require_noerr( err, exit );
        
-       //
-       // hold on to the hostname...
-       //
-       err = UTF8StringToStringObject( inHostName, service->hostname );
-       require_noerr( err, exit );
-
-       //
-       // <rdar://problem/3739200> remove the trailing dot on hostname
-       //
-       idx = service->hostname.ReverseFind('.');
-
-       if ((idx > 1) && ((service->hostname.GetLength() - 1) == idx))
+       if ( printer )
        {
-               service->hostname.Delete(idx, 1);
+               m_browseList.SelectItem( printer->item );
+               ::SetFocus( m_browseList );
        }
 
-       //
-       // hold on to the port
-       //
-       service->portNumber = ntohs(inPort);
-
-       //
-       // parse the text record.
-       //
-
-       err = self->ParseTextRecord( service, inTXTSize, inTXT, qtotalDefined, qname, qpriority );
-       require_noerr( err, exit );
-
-       if ( service->qtotal == 1 )
-       {       
-               //
-               // create a new queue
-               //
-               try
-               {
-                       q = new Queue;
-               }
-               catch (...)
-               {
-                       q = NULL;
-               }
-
-               require_action( q, exit, err = E_OUTOFMEMORY );
-
-               if ( qtotalDefined )
-               {
-                       q->name = qname;
-               }
-
-               q->priority = qpriority;
-               
-               service->queues.push_back( q );
-
-               //
-               // we've completely resolved this service
-               //
-
-               self->OnResolveService( service );
-       }
-       else
+       // Hide the back button
+       pWnd = ((CPropertySheet*)GetParent())->GetDlgItem(ID_WIZBACK);
+       if ( pWnd != NULL )
        {
-               //
-               // if qtotal is more than 1, then we need to get additional
-               // text records.  if not, then this service is considered
-               // resolved
-               //
-
-               err = DNSServiceQueryRecord(&service->serviceRef, 0, inInterfaceIndex, inFullName, kDNSServiceType_TXT, kDNSServiceClass_IN, OnQuery, (void*) service );
-               require_noerr( err, exit );
-
-               err = self->StartOperation( service->serviceRef );
-               require_noerr( err, exit );
+               pWnd->ShowWindow(SW_HIDE);
        }
 
 exit:
 
-       return;
+       return b;
 }
 
 
-void DNSSD_API
-CSecondPage::OnQuery(
-                               DNSServiceRef           inRef, 
-                               DNSServiceFlags         inFlags, 
-                               uint32_t                        inInterfaceIndex, 
-                               DNSServiceErrorType inErrorCode,
-                               const char              *       inFullName, 
-                               uint16_t                        inRRType, 
-                               uint16_t                        inRRClass, 
-                               uint16_t                        inRDLen, 
-                               const void              *       inRData, 
-                               uint32_t                        inTTL, 
-                               void                    *       inContext)
+BOOL
+CSecondPage::OnKillActive()
 {
-       DEBUG_UNUSED( inTTL );
-       DEBUG_UNUSED( inRRClass );
-       DEBUG_UNUSED( inRRType );
-       DEBUG_UNUSED( inFullName );
-       DEBUG_UNUSED( inInterfaceIndex );
-       DEBUG_UNUSED( inRef );
+       CPrinterSetupWizardSheet        * psheet;
+       CWnd                                            * pWnd;
 
-       Service         *       service = NULL;
-       Queue           *       q;
-       CSecondPage     *       self;
-       bool                    qtotalDefined = false;
-       bool                    moreComing = (bool) (inFlags & kDNSServiceFlagsMoreComing);
-       OSStatus                err = kNoErr;
-
-       require_noerr( inErrorCode, exit );
-
-       service = reinterpret_cast<Service*>( inContext );
-       require_quiet( service, exit);
-
-       self = service->printer->window;
-       require_quiet( self, exit );
+       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_quiet( psheet, exit );   
+   
+       psheet->SetLastPage(this);
 
-       if ( ( inFlags & kDNSServiceFlagsAdd ) && ( inRDLen > 0 ) && ( inRData != NULL ) )
+       // Show the back button
+       pWnd = ((CPropertySheet*)GetParent())->GetDlgItem(ID_WIZBACK);
+       if ( pWnd != NULL )
        {
-               const char * inTXT = ( const char * ) inRData;
-
-               //
-               // create a new queue
-               //
-               try
-               {
-                       q = new Queue;
-               }
-               catch (...)
-               {
-                       q = NULL;
-               }
-
-               require_action( q, exit, err = E_OUTOFMEMORY );
-
-               err = service->printer->window->ParseTextRecord( service, inRDLen, inTXT, qtotalDefined, q->name, q->priority );
-               require_noerr( err, exit );
-
-               if ( !qtotalDefined )
-               {
-                       q->name = L"";
-               }
-
-               //
-               // add this queue
-               //
-
-               service->queues.push_back( q );
-
-               if ( service->queues.size() == service->qtotal )
-               {
-                       //
-                       // else if moreComing is not set, then we're going
-                       // to assume that we're done
-                       //
-
-                       self->StopOperation( service->serviceRef );
-
-                       //
-                       // sort the queues
-                       //
-
-                       service->queues.sort( OrderQueueFunc );
-
-                       //
-                       // we've completely resolved this service
-                       //
-
-                       self->OnResolveService( service );
-               }
+               pWnd->ShowWindow(SW_SHOW);
        }
 
 exit:
 
-       if ( err && service && ( service->serviceRef != NULL ) )
-       {
-               service->printer->window->StopOperation( service->serviceRef );
-       }
-
-       return;
+       return CPropertyPage::OnKillActive();
 }
 
 
 BEGIN_MESSAGE_MAP(CSecondPage, CPropertyPage)
-       ON_MESSAGE( WM_SERVICE_EVENT, OnServiceEvent )
        ON_NOTIFY(TVN_SELCHANGED, IDC_BROWSE_LIST, OnTvnSelchangedBrowseList)
+       ON_NOTIFY(NM_CLICK, IDC_BROWSE_LIST, OnNmClickBrowseList)
+       ON_NOTIFY(TVN_KEYDOWN, IDC_BROWSE_LIST, OnTvnKeyDownBrowseList)
        ON_WM_SETCURSOR()
 END_MESSAGE_MAP()
 
@@ -826,17 +221,11 @@ END_MESSAGE_MAP()
 // Printer::EventHandler implementation
 OSStatus
 CSecondPage::OnAddPrinter(
-                               uint32_t                inInterfaceIndex,
-                               const char *    inName, 
-                               const char *    inType, 
-                               const char *    inDomain,
-                               bool                    moreComing)
+                                       Printer *       printer,
+                                       bool            moreComing )
 {
-       Printer                                         *       printer;
-       Service                                         *       service;
        CPrinterSetupWizardSheet        *       psheet;
-       DWORD                                                   printerNameCount;
-       bool                                                    newPrinter = false;
+       Printer                                         *       selectedPrinter;
        OSStatus                                                err = kNoErr;
 
        check( IsWindow( m_hWnd ) );
@@ -846,115 +235,15 @@ CSecondPage::OnAddPrinter(
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
        require_quiet( psheet, exit );
 
-       printer = Lookup( inName );
-
-       if (printer == NULL)
-       {
-               try
-               {
-                       printer = new Printer;
-               }
-               catch (...)
-               {
-                       printer = NULL;
-               }
-
-               require_action( printer, exit, err = E_OUTOFMEMORY );
-
-               printer->window         =       this;
-               printer->name           =       inName;
-               
-               err = UTF8StringToStringObject(inName, printer->displayName);
-               check_noerr( err );
-               printer->actualName     =       printer->displayName;
-               printer->installed      =       false;
-               printer->deflt          =       false;
-               printer->resolving      =       0;
-
-               //
-               // Compare this name against printers that are already installed
-               // to avoid name clashes.  Rename as necessary
-               // to come up with a unique name.
-               //
-               printerNameCount = 2;
-
-               for (;;)
-               {
-                       PrinterNameMap::iterator it;
-
-                       it = m_printerNames.find(printer->actualName);
-
-                       if (it != m_printerNames.end())
-                       {
-                               printer->actualName.Format(L"%s (%d)", printer->displayName, printerNameCount);
-                       }
-                       else
-                       {
-                               break;
-                       }
-
-                       printerNameCount++;
-               }
-
-               newPrinter = true;
-       }
-
-       check( printer );
-
-       service = printer->LookupService( inType );
-
-       if ( service != NULL )
-       {
-               service->refs++;
-       }
-       else
+       if ( printer )
        {
-               try
-               {
-                       service = new Service;
-               }
-               catch (...)
-               {
-                       service = NULL;
-               }
-
-               require_action( service, exit, err = E_OUTOFMEMORY );
-               
-               service->printer        =       printer;
-               service->ifi            =       inInterfaceIndex;
-               service->type           =       inType;
-               service->domain         =       inDomain;
-               service->qtotal         =       1;
-               service->refs           =       1;
-               service->serviceRef     =       NULL;
-
-               printer->services.push_back( service );
-
-               //
-               // if the printer is selected, then we'll want to start a
-               // resolve on this guy
-               //
+               selectedPrinter = psheet->GetSelectedPrinter();
 
-               if ( m_selected == printer )
-               {
-                       StartResolve( service );
-               }
-       }
-       
-       if ( newPrinter )
-       {
                printer->item = m_browseList.InsertItem(printer->displayName);
 
                m_browseList.SetItemData( printer->item, (DWORD_PTR) printer );
 
-               m_printers.push_back( printer );
-               
                m_browseList.SortChildren(TVI_ROOT);
-               
-               if ( printer->name == m_selectedName )
-               {
-                       m_browseList.SelectItem( printer->item );
-               }
 
                //
                // if the searching item is still in the list
@@ -971,6 +260,13 @@ CSecondPage::OnAddPrinter(
                        m_emptyListItem = NULL;
                        m_browseList.EnableWindow(TRUE);
                }
+
+               if ( !selectedPrinter )
+               {
+                       psheet->SetSelectedPrinter( printer );
+                       m_browseList.SelectItem( printer->item );
+                       ::SetFocus( m_browseList );
+               }
        }
 
 exit:
@@ -987,80 +283,47 @@ exit:
 
 OSStatus
 CSecondPage::OnRemovePrinter(
-                               const char *    inName, 
-                               const char *    inType, 
-                               const char *    inDomain,
-                               bool                    moreComing)
+                               Printer *       printer,
+                               bool            moreComing)
 {
-       DEBUG_UNUSED( inDomain );
-       DEBUG_UNUSED( inType );
-
-       Printer *       printer;
-       OSStatus        err = kNoErr;
+       CPrinterSetupWizardSheet        *       psheet;
+       OSStatus                                                err = kNoErr;
 
        check( IsWindow( m_hWnd ) );
+       check( printer );
 
-       m_browseList.SetRedraw(FALSE);
+       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_quiet( psheet, exit );
 
-       printer = Lookup( inName );
+       m_browseList.SetRedraw(FALSE);
 
        if ( printer )
        {
-               Service * service;
-
-               service = printer->LookupService( inType );
-
-               if ( service && ( --service->refs == 0 ) )
+               //
+               // check to make sure if we're the only item in the control...i.e.
+               // the list size is 1.
+               //
+               if (m_browseList.GetCount() > 1)
                {
-                       if ( service->serviceRef != NULL )
-                       {
-                               err = StopResolve( service );
-                               require_noerr( err, exit );
-                       }
-
-                       printer->services.remove( service );
-
-                       delete service;
+                       //
+                       // if we're not the only thing in the list, then
+                       // simply remove it from the list
+                       //
+                       m_browseList.DeleteItem( printer->item );
                }
-
-               if ( printer->services.size() == 0 )
+               else
                {
                        //
-                       // check to make sure if we're the only item in the control...i.e.
-                       // the list size is 1.
+                       // if we're the only thing in the list, then redisplay
+                       // it with the no printers message
                        //
-                       if (m_browseList.GetCount() > 1)
-                       {
-                               //
-                               // if we're not the only thing in the list, then
-                               // simply remove it from the list
-                               //
-                               m_browseList.DeleteItem( printer->item );
-                       }
-                       else
-                       {
-                               //
-                               // if we're the only thing in the list, then redisplay
-                               // it with the no rendezvous printers message
-                               //
-                               InitBrowseList();
-                       }
-
-                       m_printers.remove( printer );
-
-                       if ( m_selected == printer )
-                       {
-                               m_selected              = NULL;
-                               m_selectedName  = "";
-                       }
-
-                       delete printer;
+                       InitBrowseList();
                }
        }
 
 exit:
 
-       if (!moreComing)
+       if ( !moreComing )
        {
                m_browseList.SetRedraw(TRUE);
                m_browseList.Invalidate();
@@ -1075,43 +338,33 @@ CSecondPage::OnResolveService( Service * service )
 {
        CPrinterSetupWizardSheet * psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
        require_quiet( psheet, exit );
-       
-       check( service );
 
-       if ( !--service->printer->resolving )
-       {
-               //
-               // sort the services now.  we want the service that
-               // has the highest priority queue to be first in
-               // the list.
-               //
+       check( service );
 
-               service->printer->services.sort( OrderServiceFunc );
+       Queue * q = service->SelectedQueue();
 
-               //
-               // and set it to selected
-               //
+       check( q );
+       
 
-               m_selected              = service->printer;
-               m_selectedName  = service->printer->name;
+       //
+       // and set it to selected
+       //
 
-               //
-               // and update the printer information box
-               //
-               SetPrinterInformationState( TRUE );
+       m_selectedName  = service->printer->name;
 
-               m_descriptionField.SetWindowText( service->description );
-               m_locationField.SetWindowText( service->location );
+       //
+       // and update the printer information box
+       //
+       SetPrinterInformationState( TRUE );
 
-               psheet->SetWizardButtons( PSWIZB_BACK|PSWIZB_NEXT );
+       m_descriptionField.SetWindowText( q->description );
+       m_locationField.SetWindowText( q->location );
 
-               //
-               // reset the cursor
-               //
+       //
+       // reset the cursor
+       //
 
-               psheet->m_active = psheet->m_arrow;
-               SetCursor(psheet->m_active);
-       }
+       SetCursor(psheet->m_active);
 
 exit:
 
@@ -1119,53 +372,48 @@ exit:
 }
 
 
-LONG
-CSecondPage::OnServiceEvent(WPARAM inWParam, LPARAM inLParam)
+void CSecondPage::OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
 {
-       if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
-    {
-               dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
-    }
-    else
-    {
-               SOCKET sock = (SOCKET) inWParam;
-
-               // iterate thru list
-               ServiceRefList::iterator begin = m_serviceRefList.begin();
-               ServiceRefList::iterator end   = m_serviceRefList.end();
-
-               while (begin != end)
-               {
-                       DNSServiceRef ref = *begin++;
+       LPNMTREEVIEW                                    pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
+       CPrinterSetupWizardSheet        *       psheet;
+       Printer                                         *       printer;
+       int                                                             err = 0;
 
-                       check(ref != NULL);
+       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_action( psheet, exit, err = kUnknownErr );
+
+       // The strange code here is to workaround a bug in the CTreeCtrl, whereupon the item
+       // we selected isn't passed through correctly to this callback routine.
+
+       if ( !m_gotChoice )
+       {
+               printer = psheet->GetSelectedPrinter();
+
+               // If we really haven't selected a printer, then re-select NULL and exit
+
+               if ( !printer )
+               {
+                       m_browseList.SelectItem( NULL );
 
-                       if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
-                       {
-                               DNSServiceProcessResult(ref);
-                               break;
-                       }
+                       goto exit;
                }
-       }
 
-       return ( 0 );
-}
+               // If we already have selected a printer, fake like we've clicked on it, but only
+               // if the CTreeCtrl hasn't already selected it
+               
+               else if ( printer->item != m_browseList.GetSelectedItem() )
+               {
+                       m_gotChoice = true;
 
+                       m_browseList.SelectItem( printer->item );
 
-void CSecondPage::OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
-{
-       LPNMTREEVIEW                                    pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
-       CPrinterSetupWizardSheet        *       psheet;
-       int                                                             err = 0;
+                       goto exit;
+               }
+       }
 
        HTREEITEM item = m_browseList.GetSelectedItem();
        require_quiet( item, exit );
 
-       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_action( psheet, exit, err = kUnknownErr );      
-
-       Printer * printer;
-
        printer = reinterpret_cast<Printer*>(m_browseList.GetItemData( item ) );
        require_quiet( printer, exit );
 
@@ -1173,7 +421,7 @@ void CSecondPage::OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
        // this call will trigger a resolve.  When the resolve is complete,
        // our OnResolve will be called.
        //
-       err = StartResolve( printer );
+       err = psheet->StartResolve( printer );
        require_noerr( err, exit );
 
        //
@@ -1200,50 +448,23 @@ exit:
 }
 
 
-bool
-CSecondPage::OrderServiceFunc( const Service * a, const Service * b )
+void CSecondPage::OnNmClickBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
 {
-       Queue * q1, * q2;
-
-       q1 = (a->queues.size() > 0) ? a->queues.front() : NULL;
+       DEBUG_UNUSED( pNMHDR );
 
-       q2 = (b->queues.size() > 0) ? b->queues.front() : NULL;
+       m_gotChoice = true;
 
-       if ( !q1 && !q2 )
-       {
-               return true;
-       }
-       else if ( q1 && !q2 )
-       {
-               return true;
-       }
-       else if ( !q1 && q2 )
-       {
-               return false;
-       }
-       else if ( q1->priority < q2->priority )
-       {
-               return true;
-       }
-       else if ( q1->priority > q2->priority )
-       {
-               return false;
-       }
-       else if ( ( a->type == kPDLServiceType ) || ( ( a->type == kLPRServiceType ) && ( b->type == kIPPServiceType ) ) )
-       {
-               return true;
-       }
-       else
-       {
-               return false;
-       }
+       *pResult = 0;
 }
 
 
-bool
-CSecondPage::OrderQueueFunc( const Queue * q1, const Queue * q2 )
+void CSecondPage::OnTvnKeyDownBrowseList( NMHDR * pNMHDR, LRESULT * pResult)
 {
-       return ( q1->priority <= q2->priority ) ? true : false;
+       DEBUG_UNUSED( pNMHDR );
+
+       m_gotChoice = true;
+
+       *pResult = 0;
 }
 
 
@@ -1276,96 +497,17 @@ CSecondPage::LoadTextAndDisableWindow( CString & text )
 void
 CSecondPage::SetPrinterInformationState( BOOL state )
 {
-       m_printerInformation.EnableWindow( state );\r
-       m_descriptionLabel.EnableWindow( state );\r
-       m_descriptionField.EnableWindow( state );\r
-       m_locationLabel.EnableWindow( state );\r
-       m_locationField.EnableWindow( state );\r
-}\r
-\r
-\r
-OSStatus
-CSecondPage::ParseTextRecord( Service * service, uint16_t inTXTSize, const char * inTXT, bool & qtotalDefined, CString & qname, uint32_t & qpriority )
-{
-       bool            rpOnly = true;
-       OSStatus        err = kNoErr;
-       
-       while (inTXTSize)
-       {
-               char buf[256];
+       m_printerInformation.EnableWindow( state );
 
-               unsigned char num = *inTXT;
-               check( (int) num < inTXTSize );
+       m_descriptionLabel.EnableWindow( state );
 
-               if ( num )
-               {
-                       memset(buf, 0, sizeof(buf));
-                       memcpy(buf, inTXT + 1, num);
-
-                       CString elem;
-
-                       err = UTF8StringToStringObject( buf, elem );
-                       require_noerr( err, exit );
-
-                       int curPos = 0;
-
-                       CString key = elem.Tokenize(L"=", curPos);
-                       CString val = elem.Tokenize(L"=", curPos);
-
-                       key.MakeLower();
-
-                       if ( key == L"rp" )
-                       {
-                               qname = val;
-                       }
-                       else
-                       {
-                               rpOnly = false;
-
-                               if ((key == L"usb_mfg") || (key == L"usb_manufacturer"))
-                               {
-                                       service->usb_MFG = val;
-                               }
-                               else if ((key == L"usb_mdl") || (key == L"usb_model"))
-                               {
-                                       service->usb_MDL = val;
-                               }
-                               else if (key == L"ty")
-                               {
-                                       service->description = val;
-                               }
-                               else if (key == L"product")
-                               {
-                                       service->product = val;
-                               }
-                               else if (key == L"note")
-                               {
-                                       service->location = val;
-                               }
-                               else if (key == L"qtotal")
-                               {
-                                       service->qtotal = (unsigned short) _ttoi((LPCTSTR) val);
-                                       qtotalDefined = true;
-                               }
-                               else if (key == L"priority")
-                               {
-                                       qpriority = _ttoi((LPCTSTR) val);
-                               }
-                       }
-               }
+       m_descriptionField.EnableWindow( state );
 
-               inTXTSize -= (num + 1);
-               inTXT += (num + 1);
-       }
+       m_locationLabel.EnableWindow( state );
 
-exit:
+       m_locationField.EnableWindow( state );
 
-       if ( rpOnly )
-       {
-               qtotalDefined = true;
-       }
-
-       return err;
 }
 
 
+