Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/unx/generic/printer/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 32 kB image not shown  

Quelle  printerinfomanager.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <config_cpdb.h>
#include <config_cups.h>

#if ENABLE_CPDB
#include <unx/cpdmgr.hxx>
#endif

#if ENABLE_CUPS
#include <unx/cupsmgr.hxx>
#endif

#include <unx/gendata.hxx>
#include <unx/helper.hxx>

#include <tools/urlobj.hxx>
#include <tools/config.hxx>

#include <i18nutil/paper.hxx>
#include <rtl/strbuf.hxx>
#include <sal/log.hxx>

#include <osl/file.hxx>
#include <osl/thread.hxx>
#include <o3tl/string_view.hxx>

// filename of configuration files
constexpr OUString PRINT_FILENAME = u"psprint.conf"_ustr;
// the group of the global defaults
constexpr OString GLOBAL_DEFAULTS_GROUP = "__Global_Printer_Defaults__"_ostr;

#include <cstddef>
#include <mutex>
#include <unordered_set>

using namespace psp;
using namespace osl;

namespace psp
{
    class SystemQueueInfo final : public Thread
    {
        mutable std::mutex          m_aMutex;
        bool                        m_bChanged;
        std::vector< PrinterInfoManager::SystemPrintQueue >
                                    m_aQueues;
        OUString                    m_aCommand;

        virtual void SAL_CALL run() override;

        public:
        SystemQueueInfo();
        virtual ~SystemQueueInfo() override;

        bool hasChanged() const;
        OUString getCommand() const;

        // sets changed status to false; therefore not const
        void getSystemQueues( std::vector< PrinterInfoManager::SystemPrintQueue >& rQueues );
    };
// namespace

/*
*  class PrinterInfoManager
*/


PrinterInfoManager& PrinterInfoManager::get()
{
    // can't move to GenericUnixSalData, because of vcl/null/printerinfomanager.cxx
    GenericUnixSalData* pSalData = GetGenericUnixSalData();
    PrinterInfoManager* pPIM = pSalData->m_pPrinterInfoManager.get();
    if (pPIM)
        return *pPIM;

#if ENABLE_CPDB
    pPIM = CPDManager::tryLoadCPD();
#endif
#if ENABLE_CUPS
    if (!pPIM)
        pPIM = CUPSManager::tryLoadCUPS();
#endif
    if (!pPIM)
        pPIM = new PrinterInfoManager();
    pSalData->m_pPrinterInfoManager.reset(pPIM);
    pPIM->initialize();

    SAL_INFO("vcl.unx.print""created PrinterInfoManager of type "
                               << static_cast<int>(pPIM->getType()));
    return *pPIM;
}

PrinterInfoManager::PrinterInfoManager( Type eType ) :
    m_eType( eType ),
    m_aSystemDefaultPaper( u"A4"_ustr )
{
    if( eType == Type::Default )
        m_pQueueInfo.reset( new SystemQueueInfo );

    m_aSystemDefaultPaper = OStringToOUString(
        PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()),
        RTL_TEXTENCODING_UTF8);
}

PrinterInfoManager::~PrinterInfoManager()
{
#if OSL_DEBUG_LEVEL > 1
    SAL_INFO("vcl.unx.print""PrinterInfoManager: "
            << "destroyed Manager of type "
            << ((int) getType()));
#endif
}

bool PrinterInfoManager::checkPrintersChanged( bool bWait )
{
    // check if files were created, deleted or modified since initialize()
    bool bChanged = false;
    for (auto const& watchFile : m_aWatchFiles)
    {
        DirectoryItem aItem;
        if( DirectoryItem::get( watchFile.m_aFilePath, aItem ) )
        {
            if( watchFile.m_aModified.Seconds != 0 )
            {
                bChanged = true// file probably has vanished
                break;
            }
        }
        else
        {
            FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
            if( aItem.getFileStatus( aStatus ) )
            {
                bChanged = true// unlikely but not impossible
                break;
            }
            else
            {
                TimeValue aModified = aStatus.getModifyTime();
                if( aModified.Seconds != watchFile.m_aModified.Seconds )
                {
                    bChanged = true;
                    break;
                }
            }
        }
    }

    if( bWait && m_pQueueInfo )
    {
#if OSL_DEBUG_LEVEL > 1
        SAL_INFO("vcl.unx.print""syncing printer discovery thread.");
#endif
        m_pQueueInfo->join();
#if OSL_DEBUG_LEVEL > 1
        SAL_INFO("vcl.unx.print""done: syncing printer discovery thread.");
#endif
    }

    if( ! bChanged && m_pQueueInfo )
        bChanged = m_pQueueInfo->hasChanged();
    if( bChanged )
    {
        initialize();
    }

    return bChanged;
}

void PrinterInfoManager::initialize()
{
    m_aPrinters.clear();
    m_aWatchFiles.clear();
    OUString aDefaultPrinter;

    // first initialize the global defaults
    // have to iterate over all possible files
    // there should be only one global setup section in all
    // available config files
    m_aGlobalDefaults = PrinterInfo();

    // need a parser for the PPDContext. generic printer should do.
    m_aGlobalDefaults.m_pParser = PPDParser::getParser( u"SGENPRT"_ustr );
    m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser );

    if( ! m_aGlobalDefaults.m_pParser )
    {
#if OSL_DEBUG_LEVEL > 1
        SAL_INFO("vcl.unx.print""Error: no default PPD file "
                << "SGENPRT available, shutting down psprint...");
#endif
        return;
    }

    std::vector< OUString > aDirList;
    psp::getPrinterPathList( aDirList, nullptr );
    for (auto const& printDir : aDirList)
    {
        INetURLObject aFile( printDir, INetProtocol::File, INetURLObject::EncodeMechanism::All );
        aFile.Append( PRINT_FILENAME );
        Config aConfig( aFile.PathToFileName() );
        if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) )
        {
#if OSL_DEBUG_LEVEL > 1
            SAL_INFO("vcl.unx.print""found global defaults in "
                    << aFile.PathToFileName());
#endif
            aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP );

            OString aValue( aConfig.ReadKey( "Copies"_ostr ) );
            if (!aValue.isEmpty())
                m_aGlobalDefaults.m_nCopies = aValue.toInt32();

            aValue = aConfig.ReadKey( "Orientation"_ostr );
            if (!aValue.isEmpty())
                m_aGlobalDefaults.m_eOrientation = aValue.equalsIgnoreAsciiCase("Landscape") ? orientation::Landscape : orientation::Portrait;

            aValue = aConfig.ReadKey( "MarginAdjust"_ostr );
            if (!aValue.isEmpty())
            {
                sal_Int32 nIdx {0};
                m_aGlobalDefaults.m_nLeftMarginAdjust = o3tl::toInt32(o3tl::getToken(aValue, 0, ','nIdx));
                m_aGlobalDefaults.m_nRightMarginAdjust = o3tl::toInt32(o3tl::getToken(aValue, 0, ',', nIdx));
                m_aGlobalDefaults.m_nTopMarginAdjust = o3tl::toInt32(o3tl::getToken(aValue, 0, ',', nIdx));
                m_aGlobalDefaults.m_nBottomMarginAdjust = o3tl::toInt32(o3tl::getToken(aValue, 0, ',', nIdx));
            }

            aValue = aConfig.ReadKey( "ColorDepth"_ostr, "24"_ostr );
            if (!aValue.isEmpty())
                m_aGlobalDefaults.m_nColorDepth = aValue.toInt32();

            aValue = aConfig.ReadKey( "ColorDevice"_ostr );
            if (!aValue.isEmpty())
                m_aGlobalDefaults.m_nColorDevice = aValue.toInt32();

            // get the PPDContext of global JobData
            forint nKey = 0; nKey < aConfig.GetKeyCount(); ++nKey )
            {
                OString aKey( aConfig.GetKeyName( nKey ) );
                if (aKey.startsWith("PPD_"))
                {
                    aValue = aConfig.ReadKey( aKey );
                    const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey(OStringToOUString(aKey.subView(4), RTL_TEXTENCODING_ISO_8859_1));
                    if( pKey )
                    {
                        m_aGlobalDefaults.m_aContext.
                        setValue( pKey,
                                  aValue == "*nil" ? nullptr : pKey->getValue(OStringToOUString(aValue, RTL_TEXTENCODING_ISO_8859_1)),
                                  true );
                    }
                }
            }
        }
    }
    setDefaultPaper( m_aGlobalDefaults.m_aContext );

    // now collect all available printers
    for (auto const& printDir : aDirList)
    {
        INetURLObject aDir( printDir, INetProtocol::File, INetURLObject::EncodeMechanism::All );
        INetURLObject aFile( aDir );
        aFile.Append( PRINT_FILENAME );

        // check directory validity
        OUString aUniPath;
        FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath );
        Directory aDirectory( aUniPath );
        if( aDirectory.open() )
            continue;
        aDirectory.close();

        FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath );
        FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
        DirectoryItem aItem;

        // setup WatchFile list
        WatchFile aWatchFile;
        aWatchFile.m_aFilePath = aUniPath;
        if( ! DirectoryItem::get( aUniPath, aItem ) &&
            ! aItem.getFileStatus( aStatus ) )
        {
            aWatchFile.m_aModified = aStatus.getModifyTime();
        }
        else
        {
            aWatchFile.m_aModified.Seconds = 0;
            aWatchFile.m_aModified.Nanosec = 0;
        }
        m_aWatchFiles.push_back( aWatchFile );

        Config aConfig( aFile.PathToFileName() );
        forint nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ )
        {
            aConfig.SetGroup( aConfig.GetGroupName( nGroup ) );
            OString aValue = aConfig.ReadKey( "Printer"_ostr );
            if (!aValue.isEmpty())
            {
                OUString aPrinterName;

                sal_Int32 nNamePos = aValue.indexOf('/');
                // check for valid value of "Printer"
                if (nNamePos == -1)
                    continue;

                Printer aPrinter;
                // initialize to global defaults
                aPrinter.m_aInfo = m_aGlobalDefaults;

                aPrinterName = OStringToOUString(aValue.subView(nNamePos+1),
                    RTL_TEXTENCODING_UTF8);
                aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
                aPrinter.m_aInfo.m_aDriverName = OStringToOUString(aValue.subView(0, nNamePos), RTL_TEXTENCODING_UTF8);

                // set parser, merge settings
                // don't do this for CUPS printers as this is done
                // by the CUPS system itself
                if( !aPrinter.m_aInfo.m_aDriverName.startsWith( "CUPS:" ) )
                {
                    aPrinter.m_aInfo.m_pParser          = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName );
                    aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser );
                    // note: setParser also purges the context

                    // ignore this printer if its driver is not found
                    if( ! aPrinter.m_aInfo.m_pParser )
                        continue;

                    // merge the ppd context keys if the printer has the same keys and values
                    // this is a bit tricky, since it involves mixing two PPDs
                    // without constraints which might end up badly
                    // this feature should be use with caution
                    // it is mainly to select default paper sizes for new printers
                    for( std::size_t nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
                    {
                        const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
                        const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
                        const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : nullptr;
                        if( pDefKey && pPrinterKey )
                            // at least the options exist in both PPDs
                        {
                            if( pDefValue )
                            {
                                const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
                                if( pPrinterValue )
                                    // the printer has a corresponding option for the key
                                    aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
                            }
                            else
                                aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, nullptr );
                        }
                    }

                    aValue = aConfig.ReadKey( "Command"_ostr );
                    // no printer without a command
                    if (aValue.isEmpty())
                    {
                        /*  TODO:
                        *  porters: please append your platform to the Solaris
                        *  case if your platform has SystemV printing per default.
                        */

                        #if defined __sun
                        aValue = "lp";
                        #else
                        aValue = "lpr"_ostr;
                        #endif
                    }
                    aPrinter.m_aInfo.m_aCommand = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
                }

                aValue = aConfig.ReadKey( "QuickCommand"_ostr );
                aPrinter.m_aInfo.m_aQuickCommand = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);

                aValue = aConfig.ReadKey( "Features"_ostr );
                aPrinter.m_aInfo.m_aFeatures = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);

                // override the settings in m_aGlobalDefaults if keys exist
                aValue = aConfig.ReadKey( "DefaultPrinter"_ostr );
                if (aValue != "0" && !aValue.equalsIgnoreAsciiCase("false"))
                    aDefaultPrinter = aPrinterName;

                aValue = aConfig.ReadKey( "Location"_ostr );
                aPrinter.m_aInfo.m_aLocation = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);

                aValue = aConfig.ReadKey( "Comment"_ostr );
                aPrinter.m_aInfo.m_aComment = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);

                aValue = aConfig.ReadKey( "Copies"_ostr );
                if (!aValue.isEmpty())
                    aPrinter.m_aInfo.m_nCopies = aValue.toInt32();

                aValue = aConfig.ReadKey( "Orientation"_ostr );
                if (!aValue.isEmpty())
                    aPrinter.m_aInfo.m_eOrientation = aValue.equalsIgnoreAsciiCase("Landscape") ? orientation::Landscape : orientation::Portrait;

                aValue = aConfig.ReadKey( "MarginAdjust"_ostr );
                if (!aValue.isEmpty())
                {
                    sal_Int32 nIdx {0};
                    aPrinter.m_aInfo.m_nLeftMarginAdjust = o3tl::toInt32(o3tl::getToken(aValue, 0, ',', nIdx));
                    aPrinter.m_aInfo.m_nRightMarginAdjust = o3tl::toInt32(o3tl::getToken(aValue, 0, ','nIdx));
                    aPrinter.m_aInfo.m_nTopMarginAdjust = o3tl::toInt32(o3tl::getToken(aValue, 0, ',', nIdx));
                    aPrinter.m_aInfo.m_nBottomMarginAdjust = o3tl::toInt32(o3tl::getToken(aValue, 0, ',', nIdx));
                }

                aValue = aConfig.ReadKey( "ColorDepth"_ostr );
                if (!aValue.isEmpty())
                    aPrinter.m_aInfo.m_nColorDepth = aValue.toInt32();

                aValue = aConfig.ReadKey( "ColorDevice"_ostr );
                if (!aValue.isEmpty())
                    aPrinter.m_aInfo.m_nColorDevice = aValue.toInt32();

                // now iterate over all keys to extract multi key information:
                // 1. PPDContext information
                forint nKey = 0; nKey < aConfig.GetKeyCount(); ++nKey )
                {
                    OString aKey( aConfig.GetKeyName( nKey ) );
                    if( aKey.startsWith("PPD_") && aPrinter.m_aInfo.m_pParser )
                    {
                        aValue = aConfig.ReadKey( aKey );
                        const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey(OStringToOUString(aKey.subView(4), RTL_TEXTENCODING_ISO_8859_1));
                        if( pKey )
                        {
                            aPrinter.m_aInfo.m_aContext.
                            setValue( pKey,
                                      aValue == "*nil" ? nullptr : pKey->getValue(OStringToOUString(aValue, RTL_TEXTENCODING_ISO_8859_1)),
                                      true );
                        }
                    }
                }

                setDefaultPaper( aPrinter.m_aInfo.m_aContext );

                // finally insert printer
                FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile );
                std::unordered_map< OUString, Printer >::const_iterator find_it =
                m_aPrinters.find( aPrinterName );
                if( find_it != m_aPrinters.end() )
                {
                    aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles;
                    aPrinter.m_aAlternateFiles.insert( find_it->second.m_aFile );
                }
                m_aPrinters[ aPrinterName ] = std::move(aPrinter);
            }
        }
    }

    // set default printer
    if( !m_aPrinters.empty() )
    {
        if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() )
            aDefaultPrinter = m_aPrinters.begin()->first;
    }
    else
        aDefaultPrinter.clear();
    m_aDefaultPrinter = aDefaultPrinter;

    if( m_eType != Type::Default )
        return;

    // add a default printer for every available print queue
    // merge paper default printer, all else from global defaults
    PrinterInfo aMergeInfo( m_aGlobalDefaults );
    aMergeInfo.m_aDriverName    = "SGENPRT";
    aMergeInfo.m_aFeatures      = "autoqueue";

    if( !m_aDefaultPrinter.isEmpty() )
    {
        PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) );

        const PPDKey* pDefKey           = aDefaultInfo.m_pParser->getKey( u"PageSize"_ustr );
        const PPDKey* pMergeKey         = aMergeInfo.m_pParser->getKey( u"PageSize"_ustr );
        const PPDValue* pDefValue       = aDefaultInfo.m_aContext.getValue( pDefKey );
        const PPDValue* pMergeValue     = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : nullptr;
        if( pMergeKey && pMergeValue )
            aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue );
    }

    if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
    {
        m_aSystemPrintCommand = m_pQueueInfo->getCommand();
        m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
        m_pQueueInfo.reset();
    }
    for (auto const& printQueue : m_aSystemPrintQueues)
    {
        OUString aPrinterName = "<" + printQueue.m_aQueue + ">";

        if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() )
            // probably user made this one permanent
            continue;

        OUString aCmd( m_aSystemPrintCommand );
        aCmd = aCmd.replaceAll( "(PRINTER)", printQueue.m_aQueue );

        Printer aPrinter;

        // initialize to merged defaults
        aPrinter.m_aInfo = aMergeInfo;
        aPrinter.m_aInfo.m_aPrinterName     = aPrinterName;
        aPrinter.m_aInfo.m_aCommand         = aCmd;
        aPrinter.m_aInfo.m_aComment         = printQueue.m_aComment;
        aPrinter.m_aInfo.m_aLocation        = printQueue.m_aLocation;

        m_aPrinters[aPrinterName] = std::move(aPrinter);
    }
}

void PrinterInfoManager::listPrinters( ::std::vector< OUString >& rVector ) const
{
    rVector.clear();
    for (auto const& printer : m_aPrinters)
        rVector.push_back(printer.first);
}

const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const
{
    static PrinterInfo aEmptyInfo;
    std::unordered_map< OUString, Printer >::const_iterator it = m_aPrinters.find( rPrinter );

    SAL_WARN_IF( it == m_aPrinters.end(), "vcl""Do not ask for info about nonexistent printers" );

    return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo;
}

bool PrinterInfoManager::checkFeatureToken( const OUString& rPrinterName, std::string_view pToken ) const
{
    const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) );
    sal_Int32 nIndex = 0;
    while( nIndex != -1 )
    {
        OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex );
        if( aOuterToken.getToken( 0, '=' ).equalsIgnoreAsciiCaseAscii( pToken ) )
            return true;
    }
    return false;
}

FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
{
    const PrinterInfo&   rPrinterInfo   = getPrinterInfo (rPrintername);
    const OUString& rCommand       = (bQuickCommand && !rPrinterInfo.m_aQuickCommand.isEmpty() ) ?
                                          rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand;
    OString aShellCommand  = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1) +
        " 2>/dev/null";

    return popen (aShellCommand.getStr(), "w");
}

bool PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/, bool /*bBanner*/, const OUString& /*rFaxNumber*/ )
{
    return (0 == pclose( pFile ));
}

void PrinterInfoManager::setupJobContextData( JobData& rData )
{
    std::unordered_map< OUString, Printer >::iterator it =
    m_aPrinters.find( rData.m_aPrinterName );
    if( it != m_aPrinters.end() )
    {
        rData.m_pParser     = it->second.m_aInfo.m_pParser;
        rData.m_aContext    = it->second.m_aInfo.m_aContext;
    }
}

void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
{
    if(  ! rContext.getParser() )
        return;

    const PPDKey* pPageSizeKey = rContext.getParser()->getKey( u"PageSize"_ustr );
    if( ! pPageSizeKey )
        return;

    std::size_t nModified = rContext.countValuesModified();
    auto set = false;
    for (std::size_t i = 0; i != nModified; ++i) {
        if (rContext.getModifiedKey(i) == pPageSizeKey) {
            set = true;
            break;
        }
    }

    if( set ) // paper was set already, do not modify
    {
#if OSL_DEBUG_LEVEL > 1
        SAL_WARN("vcl.unx.print""not setting default paper, already set "
                << rContext.getValue( pPageSizeKey )->m_aOption);
#endif
        return;
    }

    // paper not set, fill in default value
    const PPDValue* pPaperVal = nullptr;
    int nValues = pPageSizeKey->countValues();
    forint i = 0; i < nValues && ! pPaperVal; i++ )
    {
        const PPDValue* pVal = pPageSizeKey->getValue( i );
        if( pVal->m_aOption.equalsIgnoreAsciiCase( m_aSystemDefaultPaper ) )
            pPaperVal = pVal;
    }
    if( pPaperVal )
    {
#if OSL_DEBUG_LEVEL > 1
        SAL_INFO("vcl.unx.print""setting default paper "
                << pPaperVal->m_aOption);
#endif
        rContext.setValue( pPageSizeKey, pPaperVal );
#if OSL_DEBUG_LEVEL > 1
        SAL_INFO("vcl.unx.print""-> got paper "
                << rContext.getValue( pPageSizeKey )->m_aOption);
#endif
    }
}

SystemQueueInfo::SystemQueueInfo() :
    m_bChanged( false )
{
    create();
}

SystemQueueInfo::~SystemQueueInfo()
{
    static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
    if( ! pNoSyncDetection || !*pNoSyncDetection )
        join();
    else
        terminate();
}

bool SystemQueueInfo::hasChanged() const
{
    std::unique_lock aGuard( m_aMutex );
    return m_bChanged;
}

void SystemQueueInfo::getSystemQueues( std::vector< PrinterInfoManager::SystemPrintQueue >& rQueues )
{
    std::unique_lock aGuard( m_aMutex );
    rQueues = m_aQueues;
    m_bChanged = false;
}

OUString SystemQueueInfo::getCommand() const
{
    std::unique_lock aGuard( m_aMutex );
    return m_aCommand;
}

namespace {

struct SystemCommandParameters;

}

typedef void(* tokenHandler)(const std::vector< OString >&,
                std::vector< PrinterInfoManager::SystemPrintQueue >&,
                const SystemCommandParameters*);

namespace {

struct SystemCommandParameters
{
    const char*     pQueueCommand;
    const char*     pPrintCommand;
    const char*     pForeToken;
    const char*     pAftToken;
    unsigned int    nForeTokenCount;
    tokenHandler    pHandler;
};

}

#if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD))
static void lpgetSysQueueTokenHandler(
    const std::vector< OString >& i_rLines,
    std::vector< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
    const SystemCommandParameters* )
{
    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    std::unordered_set< OUString > aUniqueSet;
    std::unordered_set< OUString > aOnlySet;
    aUniqueSet.insert( u"_all"_ustr );
    aUniqueSet.insert( u"_default"_ustr );

    // the eventual "all" attribute of the "_all" queue tells us, which
    // printers are to be used for this user at all

    // find _all: line
    OString aAllLine( "_all:" );
    OString aAllAttr( "all=" );
    auto it = std::find_if(i_rLines.begin(), i_rLines.end(),
        [&aAllLine](const OString& rLine) { return rLine.indexOf( aAllLine, 0 ) == 0; });
    if( it != i_rLines.end() )
    {
        // now find the "all" attribute
        ++it;
        it = std::find_if(it, i_rLines.end(),
            [&aAllAttr](const OString& rLine) { return WhitespaceToSpace( rLine ).startsWith( aAllAttr ); });
        if( it != i_rLines.end() )
        {
            // insert the comma separated entries into the set of printers to use
            OString aClean( WhitespaceToSpace( *it ) );
            sal_Int32 nPos = aAllAttr.getLength();
            while( nPos != -1 )
            {
                OString aTok( aClean.getToken( 0, ',', nPos ) );
                if( !aTok.isEmpty() )
                    aOnlySet.insert( OStringToOUString( aTok, aEncoding ) );
            }
        }
    }

    bool bInsertAttribute = false;
    OString aDescrStr( "description=" );
    OString aLocStr( "location=" );
    for (auto const& line : i_rLines)
    {
        sal_Int32 nPos = 0;
        // find the begin of a new printer section
        nPos = line.indexOf( ':', 0 );
        if( nPos != -1 )
        {
            OUString aSysQueue( OStringToOUString( line.copy( 0, nPos ), aEncoding ) );
            // do not insert duplicates (e.g. lpstat tends to produce such lines)
            // in case there was a "_all" section, insert only those printer explicitly
            // set in the "all" attribute
            if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() &&
                ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() )
                )
            {
                o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
                o_rQueues.back().m_aQueue = aSysQueue;
                o_rQueues.back().m_aLocation = aSysQueue;
                aUniqueSet.insert( aSysQueue );
                bInsertAttribute = true;
            }
            else
                bInsertAttribute = false;
            continue;
        }
        if( bInsertAttribute && ! o_rQueues.empty() )
        {
            // look for "description" attribute, insert as comment
            nPos = line.indexOf( aDescrStr, 0 );
            if( nPos != -1 )
            {
                OString aComment( WhitespaceToSpace( line.copy(nPos+12) ) );
                if( !aComment.isEmpty() )
                    o_rQueues.back().m_aComment = OStringToOUString(aComment, aEncoding);
                continue;
            }
            // look for "location" attribute, insert as location
            nPos = line.indexOf( aLocStr, 0 );
            if( nPos != -1 )
            {
                OString aLoc( WhitespaceToSpace( line.copy(nPos+9) ) );
                if( !aLoc.isEmpty() )
                    o_rQueues.back().m_aLocation = OStringToOUString(aLoc, aEncoding);
                continue;
            }
        }
    }
}
#endif
static void standardSysQueueTokenHandler(
    const std::vector< OString >& i_rLines,
    std::vector< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
    const SystemCommandParameters* i_pParms)
{
    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    std::unordered_set< OUString > aUniqueSet;
    OString aForeToken( i_pParms->pForeToken );
    OString aAftToken( i_pParms->pAftToken );
    /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
    */

    for (auto const& line : i_rLines)
    {
        sal_Int32 nPos = 0;

        // search for a line describing a printer:
        // find if there are enough tokens before the name
        forunsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ )
        {
            nPos = line.indexOf( aForeToken, nPos );
            if( nPos != -1 && line.getLength() >= nPos+aForeToken.getLength() )
                nPos += aForeToken.getLength();
        }
        if( nPos != -1 )
        {
            // find if there is the token after the queue
            sal_Int32 nAftPos = line.indexOf( aAftToken, nPos );
            if( nAftPos != -1 )
            {
                // get the queue name between fore and aft tokens
                OUString aSysQueue( OStringToOUString( line.subView( nPos, nAftPos - nPos ), aEncoding ) );
                // do not insert duplicates (e.g. lpstat tends to produce such lines)
                if( aUniqueSet.insert( aSysQueue ).second )
                {
                    o_rQueues.emplace_back( );
                    o_rQueues.back().m_aQueue = aSysQueue;
                    o_rQueues.back().m_aLocation = aSysQueue;
                }
            }
        }
    }
}

const struct SystemCommandParameters aParms[] =
{
    #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD)
    { "/usr/sbin/lpc status""lpr -P \"(PRINTER)\""""":", 0, standardSysQueueTokenHandler },
    { "lpc status""lpr -P \"(PRINTER)\""""":", 0, standardSysQueueTokenHandler },
    { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s""lp -d \"(PRINTER)\"""system for "": ", 1, standardSysQueueTokenHandler }
    #else
    { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list""lp -d \"(PRINTER)\""""":", 0, lpgetSysQueueTokenHandler },
    { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s""lp -d \"(PRINTER)\"""system for "": ", 1, standardSysQueueTokenHandler },
    { "/usr/sbin/lpc status""lpr -P \"(PRINTER)\""""":", 0, standardSysQueueTokenHandler },
    { "lpc status""lpr -P \"(PRINTER)\""""":", 0, standardSysQueueTokenHandler }
    #endif
};

void SystemQueueInfo::run()
{
    osl_setThreadName("LPR psp::SystemQueueInfo");

    char pBuffer[1024];
    std::vector< OString > aLines;

    /* Discover which command we can use to get a list of all printer queues */
    for(const auto & rParm : aParms)
    {
        aLines.clear();
#if OSL_DEBUG_LEVEL > 1
        SAL_INFO("vcl.unx.print""trying print queue command \""
                << rParm.pQueueCommand
                << "\" ...");
#endif
        OString aCmdLine = rParm.pQueueCommand + OString::Concat(" 2>/dev/null");
        FILE *pPipe;
        if( (pPipe = popen( aCmdLine.getStr(), "r" )) )
        {
            while( fgets( pBuffer, 1024, pPipe ) )
                aLines.emplace_back( pBuffer );
            if( ! pclose( pPipe ) )
            {
                std::vector< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues;
                rParm.pHandler( aLines, aSysPrintQueues, &rParm );
                std::unique_lock aGuard( m_aMutex );
                m_bChanged  = true;
                m_aQueues   = std::move(aSysPrintQueues);
                m_aCommand  = OUString::createFromAscii( rParm.pPrintCommand );
#if OSL_DEBUG_LEVEL > 1
                SAL_INFO("vcl.unx.print""printing queue command: success.");
#endif
                break;
            }
        }
#if OSL_DEBUG_LEVEL > 1
        SAL_INFO("vcl.unx.print""printing queue command: failed.");
#endif
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=93 H=87 G=89

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.