/* * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * 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. * * 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 * 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 Remove references to description key Bug #: 3906182 Revision 1.5 2004/12/30 01:02:47 shersche 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 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 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" #include "PrinterSetupWizardSheet.h" #include "SecondPage.h" #include "DebugServices.h" #include "WinServices.h" #include // 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 ) { m_psp.dwFlags &= ~(PSP_HASHELP); m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; 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; } void CSecondPage::InitBrowseList() { CPrinterSetupWizardSheet * psheet; CString text; psheet = reinterpret_cast(GetParent()); require_quiet( psheet, exit ); // // load the no rendezvous printers message until something shows up in the browse list // text.LoadString(IDS_NO_RENDEZVOUS_PRINTERS); LoadTextAndDisableWindow( text ); // // disable the next button until there's a printer to select // psheet->SetWizardButtons(PSWIZB_BACK); // // disable the printer information box // SetPrinterInformationState( FALSE ); exit: return; } 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 ); while ( item ) { Printer * printer; DWORD_PTR data; data = m_browseList.GetItemData( item ); printer = reinterpret_cast(data); if ( printer && ( printer->name == inName ) ) { return printer; } 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(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(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 ) { OSStatus err; check( service->serviceRef ); err = StopOperation( service->serviceRef ); require_noerr( err, exit ); service->printer->resolving--; exit: return err; } void CSecondPage::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); DDX_Control(pDX, IDC_BROWSE_LIST, m_browseList); DDX_Control(pDX, IDC_PRINTER_INFORMATION, m_printerInformation); DDX_Control(pDX, IDC_DESCRIPTION_LABEL, m_descriptionLabel); DDX_Control(pDX, IDC_DESCRIPTION_FIELD, m_descriptionField); DDX_Control(pDX, IDC_LOCATION_LABEL, m_locationLabel); DDX_Control(pDX, IDC_LOCATION_FIELD, m_locationField); } afx_msg BOOL CSecondPage::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message) { DEBUG_UNUSED(pWnd); DEBUG_UNUSED(nHitTest); DEBUG_UNUSED(message); CPrinterSetupWizardSheet * psheet; psheet = reinterpret_cast(GetParent()); require_quiet( psheet, exit ); SetCursor(psheet->GetCursor()); exit: return TRUE; } BOOL CSecondPage::OnSetActive() { CPrinterSetupWizardSheet * psheet; Printer * printer; OSStatus err = kNoErr; psheet = reinterpret_cast(GetParent()); require_action( psheet, exit, err = kUnknownErr ); if ( ( printer = psheet->GetSelectedPrinter() ) != NULL ) { psheet->SetSelectedPrinter( NULL ); delete printer; } // // initialize the browse list...this will remove everything currently // in it, and add the no rendezvous printers item // InitBrowseList(); // // start browing // err = StartBrowse(); require_noerr( err, exit ); exit: if ( err != kNoErr ) { 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); } } return CPropertyPage::OnSetActive(); } BOOL CSecondPage::OnKillActive() { OSStatus err = kNoErr; if ( m_selected ) { CPrinterSetupWizardSheet * psheet; psheet = reinterpret_cast(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 ( inContext ); require_quiet( self, exit ); if ( inFlags & kDNSServiceFlagsAdd ) { self->OnAddPrinter( inInterfaceIndex, inName, inType, inDomain, moreComing ); } else { self->OnRemovePrinter( inName, inType, inDomain, moreComing ); } 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( 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 ); // // remove the trailing dot on hostname // idx = service->hostname.ReverseFind('.'); if ((idx > 1) && ((service->hostname.GetLength() - 1) == idx)) { service->hostname.Delete(idx, 1); } // // 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 { // // 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 ); } exit: return; } 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) { DEBUG_UNUSED( inTTL ); DEBUG_UNUSED( inRRClass ); DEBUG_UNUSED( inRRType ); DEBUG_UNUSED( inFullName ); DEBUG_UNUSED( inInterfaceIndex ); DEBUG_UNUSED( inRef ); 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( inContext ); require_quiet( service, exit); self = service->printer->window; require_quiet( self, exit ); if ( ( inFlags & kDNSServiceFlagsAdd ) && ( inRDLen > 0 ) && ( inRData != 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 ); } } exit: if ( err && service && ( service->serviceRef != NULL ) ) { service->printer->window->StopOperation( service->serviceRef ); } return; } BEGIN_MESSAGE_MAP(CSecondPage, CPropertyPage) ON_MESSAGE( WM_SERVICE_EVENT, OnServiceEvent ) ON_NOTIFY(TVN_SELCHANGED, IDC_BROWSE_LIST, OnTvnSelchangedBrowseList) ON_WM_SETCURSOR() 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; Service * service; CPrinterSetupWizardSheet * psheet; DWORD printerNameCount; bool newPrinter = false; OSStatus err = kNoErr; check( IsWindow( m_hWnd ) ); m_browseList.SetRedraw(FALSE); psheet = reinterpret_cast(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 { 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 // 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 // get rid of it // // note that order is important here. Insert the printer // item before removing the placeholder so we always have // an item in the list to avoid experiencing the bug // in Microsoft's implementation of CTreeCtrl // if (m_emptyListItem != NULL) { m_browseList.DeleteItem(m_emptyListItem); m_emptyListItem = NULL; m_browseList.EnableWindow(TRUE); } } exit: if (!moreComing) { m_browseList.SetRedraw(TRUE); m_browseList.Invalidate(); } return err; } OSStatus CSecondPage::OnRemovePrinter( const char * inName, const char * inType, const char * inDomain, bool moreComing) { DEBUG_UNUSED( inDomain ); DEBUG_UNUSED( inType ); Printer * printer; OSStatus err = kNoErr; check( IsWindow( m_hWnd ) ); m_browseList.SetRedraw(FALSE); printer = Lookup( inName ); if ( printer ) { Service * service; service = printer->LookupService( inType ); if ( service && ( --service->refs == 0 ) ) { if ( service->serviceRef != NULL ) { err = StopResolve( service ); require_noerr( err, exit ); } printer->services.remove( service ); delete service; } if ( printer->services.size() == 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 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; } } exit: if (!moreComing) { m_browseList.SetRedraw(TRUE); m_browseList.Invalidate(); } return err; } void CSecondPage::OnResolveService( Service * service ) { CPrinterSetupWizardSheet * psheet = reinterpret_cast(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. // service->printer->services.sort( OrderServiceFunc ); // // and set it to selected // m_selected = service->printer; m_selectedName = service->printer->name; // // and update the printer information box // SetPrinterInformationState( TRUE ); m_descriptionField.SetWindowText( service->description ); m_locationField.SetWindowText( service->location ); psheet->SetWizardButtons( PSWIZB_BACK|PSWIZB_NEXT ); // // reset the cursor // psheet->m_active = psheet->m_arrow; SetCursor(psheet->m_active); } exit: return; } LONG CSecondPage::OnServiceEvent(WPARAM inWParam, LPARAM inLParam) { 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++; check(ref != NULL); if ((SOCKET) DNSServiceRefSockFD(ref) == sock) { DNSServiceProcessResult(ref); break; } } } return ( 0 ); } void CSecondPage::OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast(pNMHDR); CPrinterSetupWizardSheet * psheet; int err = 0; HTREEITEM item = m_browseList.GetSelectedItem(); require_quiet( item, exit ); psheet = reinterpret_cast(GetParent()); require_action( psheet, exit, err = kUnknownErr ); Printer * printer; printer = reinterpret_cast(m_browseList.GetItemData( item ) ); require_quiet( printer, exit ); // // this call will trigger a resolve. When the resolve is complete, // our OnResolve will be called. // err = StartResolve( printer ); require_noerr( err, exit ); // // And clear out the printer information box // SetPrinterInformationState( FALSE ); m_descriptionField.SetWindowText(L""); m_locationField.SetWindowText(L""); exit: if (err != 0) { CString text; CString caption; text.LoadString(IDS_ERROR_SELECTING_PRINTER_TEXT); caption.LoadString(IDS_ERROR_SELECTING_PRINTER_CAPTION); MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION); } *pResult = 0; } bool CSecondPage::OrderServiceFunc( const Service * a, const Service * b ) { Queue * q1, * q2; q1 = (a->queues.size() > 0) ? a->queues.front() : NULL; q2 = (b->queues.size() > 0) ? b->queues.front() : NULL; 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; } } bool CSecondPage::OrderQueueFunc( const Queue * q1, const Queue * q2 ) { return ( q1->priority <= q2->priority ) ? true : false; } void CSecondPage::LoadTextAndDisableWindow( CString & text ) { m_emptyListItem = m_browseList.InsertItem( text, 0, 0, NULL, TVI_FIRST ); m_browseList.SelectItem( NULL ); // // this will remove everything else in the list...we might be navigating // back to this window, and the browse list might have changed since // we last displayed it. // if ( m_emptyListItem ) { HTREEITEM item = m_browseList.GetNextVisibleItem( m_emptyListItem ); while ( item ) { m_browseList.DeleteItem( item ); item = m_browseList.GetNextVisibleItem( m_emptyListItem ); } } m_browseList.EnableWindow( FALSE ); } void CSecondPage::SetPrinterInformationState( BOOL state ) { m_printerInformation.EnableWindow( state ); m_descriptionLabel.EnableWindow( state ); m_descriptionField.EnableWindow( state ); m_locationLabel.EnableWindow( state ); m_locationField.EnableWindow( state ); } 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]; unsigned char num = *inTXT; check( (int) num < inTXTSize ); 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); } } } inTXTSize -= (num + 1); inTXT += (num + 1); } exit: if ( rpOnly ) { qtotalDefined = true; } return err; }