X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/blobdiff_plain/67c8f8a10700c05d2460d60f5927f23cb5cb9241..2682e09e0dbe18ba42fd4707b09a89e8c34f697c:/Clients/PrinterSetupWizard/ThirdPage.cpp?ds=inline diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp index 4c156fd..6caf55c 100644 --- a/Clients/PrinterSetupWizard/ThirdPage.cpp +++ b/Clients/PrinterSetupWizard/ThirdPage.cpp @@ -13,143 +13,16 @@ * 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. - - Change History (most recent first): - -$Log: ThirdPage.cpp,v $ -Revision 1.37 2007/06/08 06:30:26 herscher - Fix uninitialized pointers when detecting generic PCL and PS drivers - -Revision 1.36 2007/06/06 20:39:10 cheshire - Printer Setup Wizard started crashing in Bonjour104A8, after update to Visual Studio 2005 - -Revision 1.35 2007/06/06 20:08:01 cheshire - mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle -AutoScroll model list as well as manufacturer list - -Revision 1.34 2007/06/06 19:53:48 cheshire - Move build train to Visual Studio 2005 - -Revision 1.33 2007/04/20 22:58:10 herscher - mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2 - -Revision 1.32 2007/04/13 23:42:20 herscher - mDNS: Printers added using Bonjour should be set as the default printer. - -Revision 1.31 2007/04/13 21:38:46 herscher - mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle - -Revision 1.30 2007/04/13 20:23:40 herscher -Fixed mistake in previous checkin that reverted license text for this file - -Revision 1.29 2007/04/13 18:10:24 herscher - mDNS: Don't allow user to choose non-working driver - -Revision 1.28 2006/08/14 23:24:09 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.27 2005/10/05 21:41:45 herscher - Use "application/octet-stream" to determine if CUPS shared queue supports raw - -Revision 1.26 2005/07/11 20:17:15 shersche - UI fixes associated with CUPS printer workaround fix. - -Revision 1.25 2005/07/07 17:53:20 shersche -Fix problems associated with the CUPS printer workaround fix. - -Revision 1.24 2005/06/30 18:02:54 shersche - Workaround for Mac OS X Printer Sharing bug - -Revision 1.23 2005/04/18 02:33:47 shersche - Default printer option cannot be deselected - -Revision 1.22 2005/04/13 17:46:22 shersche - Generic PCL not selected when printers advertise multiple text records - -Revision 1.21 2005/03/30 02:09:55 shersche -Auto-resize the column width to account for differing fonts and font sizes - -Revision 1.20 2005/03/05 02:27:45 shersche - Generic drivers don't do color - -Revision 1.19 2005/02/23 02:08:51 shersche - If we can't match the manufacturer, and select a generic printer, then show all the manufacturers in the manufacturer pane, not just "Generic". - -Revision 1.18 2005/02/15 07:02:51 shersche - Display different UI text when generic printer drivers are selected - -Revision 1.17 2005/02/08 21:45:06 shersche - Default to Generic PostScript or PCL if unable to match driver - -Revision 1.16 2005/02/08 18:56:03 shersche -Fix generated IPP url so that it doesn't add "/printers" string - -Revision 1.15 2005/02/01 01:44:07 shersche -Load ntprint.inf at startup. This will cause the wizard to take a second or two longer to come up, but will eliminate the pause when auto-selecting the print drivers. - -Revision 1.14 2005/01/25 08:55:54 shersche - Load icons at run-time from resource DLL -Bug #: 3911084 - -Revision 1.13 2005/01/06 08:15:45 shersche -Append queue name to end of LPR port name, correctly build port name when queue name is absent - -Revision 1.12 2005/01/05 01:06:12 shersche - Strip the first substring off the product key if an initial match can't be found with the whole product key. -Bug #: 3841218 - -Revision 1.11 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.10 2004/10/11 22:55:34 shersche - Use the IP port number when deriving the printer port name. -Bug #: 3827624 - -Revision 1.9 2004/06/27 23:08:00 shersche -code cleanup, make sure EnumPrintDrivers returns non-zero value, ignore comments in inf files - -Revision 1.8 2004/06/27 08:06:45 shersche -Parse [Strings] section of inf file - -Revision 1.7 2004/06/26 04:00:05 shersche -fix warnings compiling in debug mode -Submitted by: herscher - -Revision 1.6 2004/06/26 03:19:57 shersche -clean up warning messages - -Submitted by: herscher - -Revision 1.5 2004/06/25 05:06:02 shersche -Trim whitespace from key/value pairs when parsing inf files -Submitted by: herscher - -Revision 1.4 2004/06/25 02:44:13 shersche -Tweaked code to handle Xerox Phaser printer identification -Submitted by: herscher - -Revision 1.3 2004/06/25 02:27:58 shersche -Do a CListCtrl::FindItem() before calling CListCtrl::SetItemState(). -Submitted by: herscher - -Revision 1.2 2004/06/23 18:09:23 shersche -Normalize tag names when parsing inf files. -Submitted by: herscher - -Revision 1.1 2004/06/18 04:36:58 rpantos -First checked in -*/ + */ #include "stdafx.h" #include "PrinterSetupWizardApp.h" #include "PrinterSetupWizardSheet.h" #include "ThirdPage.h" -#include "StdioFileEx.h" +#include "tcpxcv.h" #include -#include #include +#include // local variable is initialize but not referenced #pragma warning(disable:4189) @@ -179,16 +52,6 @@ First checked in #define kGenericPCLColorDriver L"HP Color LaserJet 4550 PCL" #define kGenericPCLDriver L"HP LaserJet 4050 Series PCL" -// -// states for parsing ntprint.inf -// -enum PrinterParsingState -{ - Looking, - ParsingManufacturers, - ParsingModels, - ParsingStrings -}; // CThirdPage dialog @@ -275,32 +138,27 @@ exit: return; } -CThirdPage::~CThirdPage() + +void +CThirdPage::FreeManufacturers( Manufacturers & manufacturers ) { - // - // clean up all the printer manufacturers - // - while (m_manufacturers.size()) + for ( Manufacturers::iterator it = manufacturers.begin(); it != manufacturers.end(); it++ ) { - Manufacturers::iterator iter = m_manufacturers.begin(); - - while (iter->second->models.size()) + for ( Models::iterator it2 = it->second->models.begin(); it2 != it->second->models.end(); it2++ ) { - Models::iterator it = iter->second->models.begin(); - - Model * model = *it; - - delete model; - - iter->second->models.erase(it); + delete *it2; } - delete iter->second; - - m_manufacturers.erase(iter); + delete it->second; } } + +CThirdPage::~CThirdPage() +{ + FreeManufacturers( m_manufacturers ); +} + // ---------------------------------------------------- // SelectMatch // @@ -374,6 +232,8 @@ CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Servic void CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufacturer * manufacturer, Model * model ) { + DWORD portNameLen; + printer->manufacturer = manufacturer->name; printer->displayModelName = model->displayName; printer->modelName = model->name; @@ -417,6 +277,18 @@ CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufactu service->protocol = L"IPP"; } + + // If it's not an IPP printr, truncate the portName so that it's valid + + if ( service->type != kIPPServiceType ) + { + portNameLen = printer->portName.GetLength() + 1; + + if ( portNameLen > MAX_PORTNAME_LEN ) + { + printer->portName.Delete( MAX_PORTNAME_LEN - 1, ( portNameLen - MAX_PORTNAME_LEN ) ); + } + } } // -------------------------------------------------------- @@ -478,24 +350,6 @@ CThirdPage::AutoScroll( CListCtrl & list, int nIndex ) // ------------------------------------------------------ // LoadPrintDriverDefsFromFile // -// This function does all the heavy lifting in parsing inf -// files. It is called to parse both ntprint.inf, and driver -// files that might be shipped on a printer's installation -// disk -// -// The inf file is not totally parsed. I only want to determine -// the manufacturer and models that are involved. I leave it -// to printui.dll to actually copy the driver files to the -// right places. -// -// I was aiming to parse as little as I could so as not to -// duplicate the parsing code that is contained in Windows. There -// are no public APIs for parsing inf files. -// -// That part of the inf file that we're interested in has a fairly -// easy format. Tags are strings that are enclosed in brackets. -// We are only interested in [MANUFACTURERS] and models. -// // The only potentially opaque thing about this function is the // checkForDuplicateModels flag. The problem here is that ntprint.inf // doesn't contain duplicate models, and it has hundreds of models @@ -508,345 +362,193 @@ CThirdPage::AutoScroll( CListCtrl & list, int nIndex ) OSStatus CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CString & filename, bool checkForDuplicateModels ) { - PrinterParsingState state = Looking; - Manufacturers::iterator iter = manufacturers.end(); - CStdioFileEx file; - CFileException feError; - CString s; - OSStatus err; - BOOL ok; - - typedef std::map StringMap; + HINF handle = INVALID_HANDLE_VALUE; + const TCHAR * section = TEXT( "Manufacturer" ); + LONG sectionCount; + TCHAR line[ 1000 ]; + CString klass; + INFCONTEXT manufacturerContext; + BOOL ok; + OSStatus err = 0; + + // Make sure we can open the file + handle = SetupOpenInfFile( filename, NULL, INF_STYLE_WIN4, NULL ); + translate_errno( handle != INVALID_HANDLE_VALUE, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - StringMap strings; - - ok = file.Open( filename, CFile::modeRead|CFile::typeText, &feError); - err = translate_errno( ok, errno_compat(), kUnknownErr ); + // Make sure it's a printer file + ok = SetupGetLineText( NULL, handle, TEXT( "Version" ), TEXT( "Class" ), line, sizeof( line ), NULL ); + translate_errno( ok, GetLastError(), kUnknownErr ); require_noerr( err, exit ); + klass = line; + require_action( klass == TEXT( "Printer" ), exit, err = kUnknownErr ); - check ( state == Looking ); - check ( iter == manufacturers.end() ); + sectionCount = SetupGetLineCount( handle, section ); + translate_errno( sectionCount != -1, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - // - // first, parse the file looking for string sections - // - while (file.ReadString(s)) + memset( &manufacturerContext, 0, sizeof( manufacturerContext ) ); + + for ( LONG i = 0; i < sectionCount; i++ ) { - // - // check for comment - // - if (s.Find(';') == 0) - { - continue; - } - - // - // check for tag - // - else if (s.Find('[') == 0) + Manufacturers::iterator iter; + Manufacturer * manufacturer; + CString manufacturerName; + CString temp; + CStringList modelSectionNameDecl; + CString modelSectionName; + CString baseModelName; + CString model; + INFCONTEXT modelContext; + LONG modelCount; + POSITION p; + + if ( i == 0 ) { - // - // handle any capitalization issues here - // - CString tag = s; - - tag.MakeLower(); - - if (tag == L"[strings]") - { - state = ParsingStrings; - } - else - { - state = Looking; - } + ok = SetupFindFirstLine( handle, section, NULL, &manufacturerContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } else { - switch (state) - { - case ParsingStrings: - { - int curPos = 0; - - if (s.GetLength() > 0) - { - CString key = s.Tokenize(L"=",curPos); - CString val = s.Tokenize(L"=",curPos); - - // - // get rid of all delimiters - // - key.Trim(); - val.Remove('"'); - - // - // and store it - // - strings[key] = val; - } - } - break; - } + ok = SetupFindNextLine( &manufacturerContext, &manufacturerContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } - } - - file.Close(); - - ok = file.Open( filename, CFile::modeRead|CFile::typeText, &feError); - err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); - state = Looking; + ok = SetupGetStringField( &manufacturerContext, 0, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + manufacturerName = line; - check ( iter == manufacturers.end() ); + ok = SetupGetLineText( &manufacturerContext, handle, NULL, NULL, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - while (file.ReadString(s)) - { - // - // check for comment + // Try to find some model section name that has entries. Explanation of int file structure + // can be found at: // - if (s.Find(';') == 0) + // + Split( line, ',', modelSectionNameDecl ); + + p = modelSectionNameDecl.GetHeadPosition(); + modelSectionName = modelSectionNameDecl.GetNext( p ); + modelCount = SetupGetLineCount( handle, modelSectionName ); + baseModelName = modelSectionName; + + while ( modelCount <= 0 && p ) { - continue; + CString targetOSVersion; + + targetOSVersion = modelSectionNameDecl.GetNext( p ); + modelSectionName = baseModelName + TEXT( "." ) + targetOSVersion; + modelCount = SetupGetLineCount( handle, modelSectionName ); } - // - // check for tag - // - else if (s.Find('[') == 0) + if ( modelCount > 0 ) { - // - // handle any capitalization issues here - // - CString tag = s; + manufacturerName = NormalizeManufacturerName( manufacturerName ); - tag.MakeLower(); + iter = manufacturers.find( manufacturerName ); - if (tag == L"[manufacturer]") + if ( iter != manufacturers.end() ) { - state = ParsingManufacturers; + manufacturer = iter->second; + require_action( manufacturer, exit, err = kUnknownErr ); } else { - CString name; - int curPos; - - // - // remove the leading and trailing delimiters - // - s.Remove('['); - s.Remove(']'); - - // - // - // - // Ignore decorations in model declarations - // - curPos = 0; - name = s.Tokenize( L".", curPos ); - - // - // check to see if this is a printer entry - // - iter = manufacturers.find( name ); - - if (iter != manufacturers.end()) + try { - state = ParsingModels; + manufacturer = new Manufacturer; } - else + catch (...) { - state = Looking; + manufacturer = NULL; } - } - } - // - // only look at this if the line isn't empty, or - // if it isn't a comment - // - else if ((s.GetLength() > 0) && (s.Find(';') != 0)) - { - switch (state) - { - // - // if we're parsing manufacturers, then we will parse - // an entry of the form key=val, where key is a delimited - // string specifying a manufacturer name, and val is - // a tag that is used later in the file. the key is - // delimited by either '"' (quotes) or '%' (percent sign). - // - // the tag is used further down the file when models are - // declared. this allows multiple manufacturers to exist - // in a single inf file. - // - case ParsingManufacturers: - { - Manufacturer * manufacturer; - int curPos = 0; - - CString key = s.Tokenize(L"=",curPos); - CString val = s.Tokenize(L"=",curPos); - - try - { - manufacturer = new Manufacturer; - } - catch (...) - { - manufacturer = NULL; - } - require_action( manufacturer, exit, err = kNoMemoryErr ); - - // - // if it's a variable, look it up - // - if (key.Find('%') == 0) - { - StringMap::iterator it; - - key.Remove('%'); - - it = strings.find(key); - - if (it != strings.end()) - { - key = it->second; - } - } - else - { - key.Remove('"'); - } - - val.TrimLeft(); - val.TrimRight(); - - // - // why is there no consistency in inf files? - // - if (val.GetLength() == 0) - { - val = key; - } + require_action( manufacturer, exit, err = kNoMemoryErr ); - // - // fix the manufacturer name if necessary - // - curPos = 0; - val = val.Tokenize(L",", curPos); + manufacturer->name = manufacturerName; + manufacturers[ manufacturerName ] = manufacturer; + } - for ( ;; ) - { - CString decoration; - - decoration = val.Tokenize( L",", curPos ); - - if ( decoration.GetLength() > 0 ) - { - manufacturer->decorations.push_back( decoration ); - } - else - { - break; - } - } + memset( &modelContext, 0, sizeof( modelContext ) ); - manufacturer->name = NormalizeManufacturerName( key ); - manufacturer->tag = val; + for ( LONG j = 0; j < modelCount; j++ ) + { + CString modelName; + Model * model; - manufacturers[val] = manufacturer; + if ( j == 0 ) + { + ok = SetupFindFirstLine( handle, modelSectionName, NULL, &modelContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } - break; - - case ParsingModels: + else { - check( iter != manufacturers.end() ); - - Model * model; - int curPos = 0; - - CString name = s.Tokenize(L"=",curPos); - CString description = s.Tokenize(L"=",curPos); - - if (name.Find('%') == 0) - { - StringMap::iterator it; - - name.Remove('%'); + SetupFindNextLine( &modelContext, &modelContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + } - it = strings.find(name); + ok = SetupGetStringField( &modelContext, 0, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - if (it != strings.end()) - { - name = it->second; - } - } - else - { - name.Remove('"'); - } + modelName = line; - name.Trim(); - description.Trim(); - - // - // If true, see if we've seen this guy before - // - if (checkForDuplicateModels == true) - { - if ( MatchModel( iter->second, ConvertToModelName( name ) ) != NULL ) - { - continue; - } - } - - // - // Stock Vista printer inf files embed guids in the model - // declarations for Epson printers. Let's ignore those. - // - if ( name.Find( L"{", 0 ) != -1 ) + if (checkForDuplicateModels == true) + { + if ( MatchModel( manufacturer, ConvertToModelName( modelName ) ) != NULL ) { continue; } + } - try - { - model = new Model; - } - catch (...) - { - model = NULL; - } - - require_action( model, exit, err = kNoMemoryErr ); - - model->infFileName = filename; - model->displayName = name; - model->name = name; - model->driverInstalled = false; - - iter->second->models.push_back(model); + // + // Stock Vista printer inf files embed guids in the model + // declarations for Epson printers. Let's ignore those. + // + if ( modelName.Find( TEXT( "{" ), 0 ) != -1 ) + { + continue; } - break; - default: + try { - // pay no attention if we are in any other state + model = new Model; } - break; + catch (...) + { + model = NULL; + } + + require_action( model, exit, err = kNoMemoryErr ); + + model->infFileName = filename; + model->displayName = modelName; + model->name = modelName; + model->driverInstalled = false; + + manufacturer->models.push_back(model); } } } exit: - file.Close(); + if ( handle != INVALID_HANDLE_VALUE ) + { + SetupCloseInfFile( handle ); + handle = NULL; + } - return (err); + return err; } + // ------------------------------------------------------- // LoadPrintDriverDefs // @@ -1275,7 +977,7 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print useCUPSWorkaround = false; } - if ( useCUPSWorkaround && printer->isSharedFromOSX && hasGenericDriver ) + if ( useCUPSWorkaround && printer->isCUPSPrinter && hasGenericDriver ) { // // mDNS: Don't allow user to choose non-working driver @@ -1285,6 +987,8 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print LoadGenericPrintDriverDefs( genericManufacturers ); SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel ); + + FreeManufacturers( genericManufacturers ); } else { @@ -1302,10 +1006,11 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print if (found) { text.LoadString(IDS_PRINTER_MATCH_GOOD); + err = kNoErr; } else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) ) { - if ( printer->isSharedFromOSX ) + if ( printer->isCUPSPrinter ) { // // mDNS: Don't allow user to choose non-working driver @@ -1317,12 +1022,16 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel ); text.LoadString(IDS_PRINTER_MATCH_GOOD); + + FreeManufacturers( genericManufacturers ); } else { SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel ); text.LoadString(IDS_PRINTER_MATCH_MAYBE); } + + err = kNoErr; } else { @@ -1359,6 +1068,8 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print AutoScroll(m_manufacturerListCtrl, nIndex); } } + + err = kUnknownErr; } m_printerSelectionText.SetWindowText(text); @@ -1622,9 +1333,14 @@ CThirdPage::OnSetActive() // and try and match the printer // - if ( psheet->GetLastPage() == psheet->GetPage(1) ) + if ( psheet->GetLastPage() == psheet->GetPage(0) ) { MatchPrinter( m_manufacturers, printer, service, true ); + + if ( ( m_manufacturerSelected != NULL ) && ( m_modelSelected != NULL ) ) + { + GetParent()->PostMessage(PSM_SETCURSEL, 2 ); + } } else { @@ -1812,10 +1528,29 @@ void CThirdPage::OnBnClickedHaveDisk() { PopulateUI( manufacturers ); - MatchPrinter( manufacturers, printer, service, false ); + if ( MatchPrinter( manufacturers, printer, service, false ) != kNoErr ) + { + CString errorMessage; + CString errorCaption; + + errorMessage.LoadString( IDS_NO_MATCH_INF_FILE ); + errorCaption.LoadString( IDS_NO_MATCH_INF_FILE_CAPTION ); + + MessageBox( errorMessage, errorCaption, MB_OK ); + } break; } + else + { + CString errorMessage; + CString errorCaption; + + errorMessage.LoadString( IDS_BAD_INF_FILE ); + errorCaption.LoadString( IDS_BAD_INF_FILE_CAPTION ); + + MessageBox( errorMessage, errorCaption, MB_OK ); + } } else { @@ -1825,5 +1560,24 @@ void CThirdPage::OnBnClickedHaveDisk() exit: + FreeManufacturers( manufacturers ); return; } + + +void +CThirdPage::Split( const CString & string, TCHAR ch, CStringList & components ) +{ + CString temp; + int n; + + temp = string; + + while ( ( n = temp.Find( ch ) ) != -1 ) + { + components.AddTail( temp.Left( n ) ); + temp = temp.Right( temp.GetLength() - ( n + 1 ) ); + } + + components.AddTail( temp ); +}