Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  cpdmgr.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 <sal/config.h>

#include <cstddef>
#include <unistd.h>

#include <unx/cpdmgr.hxx>

#include <osl/file.h>
#include <osl/thread.h>

#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>

#include <config_dbus.h>
#include <config_gio.h>

using namespace psp;

#if ENABLE_DBUS && ENABLE_GIO
// Function to execute when name is acquired on the bus
void CPDManager::onNameAcquired(GDBusConnection* connection, const gchar*, gpointer user_data)
{
    gchar* contents;
    // Get Interface for introspection
    if (!g_file_get_contents(FRONTEND_INTERFACE, &contents, nullptr, nullptr))
        return;

    GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(contents, nullptr);

    g_dbus_connection_register_object(connection, "/org/libreoffice/PrintDialog",
                                      introspection_data->interfaces[0], nullptr,
                                      nullptr, /* user_data */
                                      nullptr, /* user_data_free_func */
                                      nullptr); /* GError** */
    g_free(contents);
    g_dbus_node_info_unref(introspection_data);

    CPDManager* current = static_cast<CPDManager*>(user_data);
    std::vector<std::pair<std::string, gchar*>> backends = current->getTempBackends();
    for (auto const& backend : backends)
    {
        // Get Interface for introspection
        if (g_file_get_contents(BACKEND_INTERFACE, &contents, nullptr, nullptr))
        {
            introspection_data = g_dbus_node_info_new_for_xml(contents, nullptr);
            GDBusProxy* proxy = g_dbus_proxy_new_sync(
                connection, G_DBUS_PROXY_FLAGS_NONE, introspection_data->interfaces[0],
                backend.first.c_str(), backend.second, "org.openprinting.PrintBackend", nullptr,
                nullptr);
            g_assert(proxy != nullptr);
            g_dbus_proxy_call(proxy, "ActivateBackend", nullptr, G_DBUS_CALL_FLAGS_NONE, -1,
                              nullptr, nullptr, nullptr);

            g_object_unref(proxy);
            g_dbus_node_info_unref(introspection_data);
            g_free(contents);
        }
        g_free(backend.second);
    }
}

void CPDManager::onNameLost(GDBusConnection*, const gchar* name, gpointer)
{
    g_message("Name Lost: %s", name);
}

void CPDManager::printerAdded(GDBusConnection* connection, const gchar* sender_name,
                              const gchar* object_path, const gchar* interface_name, const gchar*,
                              GVariant* parameters, gpointer user_data)
{
    CPDManager* current = static_cast<CPDManager*>(user_data);
    GDBusProxy* proxy;
    proxy = current->getProxy(sender_name);
    if (proxy == nullptr)
    {
        gchar* contents;

        // Get Interface for introspection
        if (g_file_get_contents("/usr/share/dbus-1/interfaces/org.openprinting.Backend.xml",
                                &contents, nullptr, nullptr))
        {
            GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(contents, nullptr);
            proxy = g_dbus_proxy_new_sync(connection, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                                          introspection_data->interfaces[0], sender_name,
                                          object_path, interface_name, nullptr, nullptr);

            g_dbus_node_info_unref(introspection_data);
            std::pair<std::string, GDBusProxy*> new_backend(sender_name, proxy);
            current->addBackend(std::move(new_backend));
            g_free(contents);
        }
    }
    CPDPrinter* pDest = static_cast<CPDPrinter*>(malloc(sizeof(CPDPrinter)));
    pDest->backend = proxy;
    g_variant_get(parameters, "(sssssbss)", &(pDest->id), &(pDest->name), &(pDest->info),
                  &(pDest->location), &(pDest->make_and_model), &(pDest->is_accepting_jobs),
                  &(pDest->printer_state), &(pDest->backend_name));
    std::stringstream printerName;
    printerName << pDest->name << ", " << pDest->backend_name;
    std::stringstream uniqueName;
    uniqueName << pDest->id << ", " << pDest->backend_name;
    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    OUString aPrinterName = OStringToOUString(printerName.str(), aEncoding);
    OUString aUniqueName = OStringToOUString(uniqueName.str(), aEncoding);
    current->addNewPrinter(aPrinterName, aUniqueName, pDest);
}

void CPDManager::printerRemoved(GDBusConnection*, const gchar*, const gchar*, const gchar*,
                                const gchar*, GVariant* parameters, gpointer user_data)
{
    // TODO: Remove every data linked to this particular printer.
    CPDManager* pManager = static_cast<CPDManager*>(user_data);
    char* id;
    char* backend_name;
    g_variant_get(parameters, "(ss)", &id, &backend_name);
    std::stringstream uniqueName;
    uniqueName << id << ", " << backend_name;
    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    OUString aUniqueName = OStringToOUString(uniqueName.str(), aEncoding);
    std::unordered_map<OUString, CPDPrinter*>::iterator it
        = pManager->m_aCPDDestMap.find(aUniqueName);
    if (it == pManager->m_aCPDDestMap.end())
    {
        SAL_WARN("vcl.unx.print""CPD trying to remove non-existent printer from list");
        return;
    }
    pManager->m_aCPDDestMap.erase(it);
    std::unordered_map<OUString, Printer>::iterator printersIt
        = pManager->m_aPrinters.find(aUniqueName);
    if (printersIt == pManager->m_aPrinters.end())
    {
        SAL_WARN("vcl.unx.print""CPD trying to remove non-existent printer from m_aPrinters");
        return;
    }
    pManager->m_aPrinters.erase(printersIt);
}

GDBusProxy* CPDManager::getProxy(const std::string& target)
{
    std::unordered_map<std::string, GDBusProxy*>::const_iterator it = m_pBackends.find(target);
    if (it == m_pBackends.end())
    {
        return nullptr;
    }
    return it->second;
}

void CPDManager::addBackend(std::pair<std::string, GDBusProxy*> pair) { m_pBackends.insert(pair); }

void CPDManager::addTempBackend(const std::pair<std::string, gchar*>& pair)
{
    m_tBackends.push_back(pair);
}

std::vector<std::pair<std::string, gchar*>> const& CPDManager::getTempBackends() const
{
    return m_tBackends;
}

void CPDManager::addNewPrinter(const OUString& aPrinterName, const OUString& aUniqueName,
                               CPDPrinter* pDest)
{
    m_aCPDDestMap[aUniqueName] = pDest;
    bool bSetToGlobalDefaults = m_aPrinters.find(aUniqueName) == m_aPrinters.end();
    Printer aPrinter = m_aPrinters[aUniqueName];
    if (bSetToGlobalDefaults)
        aPrinter.m_aInfo = m_aGlobalDefaults;
    aPrinter.m_aInfo.m_aPrinterName = aPrinterName;

    // TODO: I don't know how this should work when we have multiple
    // sources with multiple possible defaults for each
    // if( pDest->is_default )
    //     m_aDefaultPrinter = aPrinterName;

    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    aPrinter.m_aInfo.m_aComment = OStringToOUString(pDest->info, aEncoding);
    aPrinter.m_aInfo.m_aLocation = OStringToOUString(pDest->location, aEncoding);
    // note: the parser that goes with the PrinterInfo
    // is created implicitly by the JobData::operator=()
    // when it detects the NULL ptr m_pParser.
    // if we wanted to fill in the parser here this
    // would mean we'd have to send a dbus message for each and
    // every printer - which would be really bad runtime
    // behaviour
    aPrinter.m_aInfo.m_pParser = nullptr;
    aPrinter.m_aInfo.m_aContext.setParser(nullptr);
    std::unordered_map<OUString, PPDContext>::const_iterator c_it
        = m_aDefaultContexts.find(aUniqueName);
    if (c_it != m_aDefaultContexts.end())
    {
        aPrinter.m_aInfo.m_pParser = c_it->second.getParser();
        aPrinter.m_aInfo.m_aContext = c_it->second;
    }
    aPrinter.m_aInfo.m_aDriverName = "CPD:" + aUniqueName;
    m_aPrinters[aUniqueName] = aPrinter;
}
#endif

/*
 *  CPDManager class
 */


CPDManager* CPDManager::tryLoadCPD()
{
    CPDManager* pManager = nullptr;
#if ENABLE_DBUS && ENABLE_GIO
    static const char* pEnv = getenv("SAL_DISABLE_CPD");

    if (!pEnv || !*pEnv)
    {
        // interface description XML files are needed in 'onNameAcquired()'
        if (!g_file_test(FRONTEND_INTERFACE, G_FILE_TEST_IS_REGULAR)
            || !g_file_test(BACKEND_INTERFACE, G_FILE_TEST_IS_REGULAR))
        {
            return nullptr;
        }

        GDir* dir;
        const gchar* filename;
        dir = g_dir_open(BACKEND_DIR, 0, nullptr);
        if (dir != nullptr)
        {
            while ((filename = g_dir_read_name(dir)))
            {
                if (pManager == nullptr)
                {
                    pManager = new CPDManager();
                }
                gchar* contents;
                std::stringstream filepath;
                filepath << BACKEND_DIR << '/' << filename;
                if (g_file_get_contents(filepath.str().c_str(), &contents, nullptr, nullptr))
                {
                    std::pair<std::string, gchar*> new_tbackend(filename, contents);
                    pManager->addTempBackend(new_tbackend);
                    g_free(contents);
                }
            }
            g_dir_close(dir);
        }
    }
#endif
    return pManager;
}

CPDManager::CPDManager()
    : PrinterInfoManager(PrinterInfoManager::Type::CPD)
{
#if ENABLE_DBUS && ENABLE_GIO
    // Get Destinations number and pointers
    GError* error = nullptr;
    m_pConnection = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error);
    g_assert_no_error(error);
#endif
}

CPDManager::~CPDManager()
{
#if ENABLE_DBUS && ENABLE_GIO
    g_dbus_connection_emit_signal(m_pConnection, nullptr, "/org/libreoffice/PrintDialog",
                                  "org.openprinting.PrintFrontend""StopListing", nullptr,
                                  nullptr);
    g_dbus_connection_flush_sync(m_pConnection, nullptr, nullptr);
    g_dbus_connection_close_sync(m_pConnection, nullptr, nullptr);
    for (auto const& backend : m_pBackends)
    {
        g_object_unref(backend.second);
    }
    for (auto const& backend : m_aCPDDestMap)
    {
        free(backend.second);
    }
#endif
}

const PPDParser* CPDManager::createCPDParser(const OUString& rPrinter)
{
    const PPDParser* pNewParser = nullptr;
#if ENABLE_DBUS && ENABLE_GIO
    OUString aPrinter;

    if (rPrinter.startsWith("CPD:"))
        aPrinter = rPrinter.copy(4);
    else
        aPrinter = rPrinter;

    std::unordered_map<OUString, CPDPrinter*>::iterator dest_it = m_aCPDDestMap.find(aPrinter);

    if (dest_it != m_aCPDDestMap.end())
    {
        CPDPrinter* pDest = dest_it->second;
        GVariant* ret = nullptr;
        GError* error = nullptr;
        ret = g_dbus_proxy_call_sync(pDest->backend, "GetAllOptions",
                                     g_variant_new("(s)", (pDest->id)), G_DBUS_CALL_FLAGS_NONE, -1,
                                     nullptr, &error);
        if (ret != nullptr && error == nullptr)
        {
            // TODO: These keys need to be redefined to preserve usage across libreoffice
            // InputSlot - media-col.media-source?
            // Font - not needed now as it is required only for ps and we are using pdf
            // Dial? - for FAX (need to look up PWG spec)

            int num_attribute;
            GVariantIter *iter_attr, *iter_supported_values;
            g_variant_get(ret, "(ia(ssia(s)))", &num_attribute, &iter_attr);
            rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
            PPDKey* pKey = nullptr;
            OUString aValueName;
            PPDValue* pValue;
            std::vector<PPDKey*> keys;
            std::unordered_map<OUString, OUString> aOptionDefaults;
            for (int i = 0; i < num_attribute; i++)
            {
                char *name, *default_value;
                int num_supported_values;
                g_variant_iter_loop(iter_attr, "(ssia(s))", &name, &default_value,
                                    &num_supported_values, &iter_supported_values);
                OUString aOptionName = OStringToOUString(name, aEncoding);
                OUString aDefaultValue = OStringToOUString(default_value, aEncoding);
                if (aOptionName == "sides")
                {
                    // Duplex key is used throughout for checking Duplex Support
                    aOptionName = u"Duplex"_ustr;
                }
                else if (aOptionName == "printer-resolution")
                {
                    // Resolution key is used in places
                    aOptionName = u"Resolution"_ustr;
                }
                else if (aOptionName == "media")
                {
                    // PageSize key is used in many places
                    aOptionName = u"PageSize"_ustr;
                }
                aOptionDefaults[aOptionName] = aDefaultValue;
                pKey = new PPDKey(aOptionName);

                // If number of values are 0, this is not settable via UI
                if (num_supported_values > 0 && aDefaultValue != "NA")
                    pKey->m_bUIOption = true;

                bool bDefaultFound = false;

                for (int j = 0; j < num_supported_values; j++)
                {
                    char* value;
                    g_variant_iter_loop(iter_supported_values, "(s)", &value);
                    aValueName = OStringToOUString(value, aEncoding);
                    if (aOptionName == "Duplex")
                    {
                        // Duplex key matches against very specific Values
                        if (aValueName == "one-sided")
                        {
                            aValueName = u"None"_ustr;
                        }
                        else if (aValueName == "two-sided-long-edge")
                        {
                            aValueName = u"DuplexNoTumble"_ustr;
                        }
                        else if (aValueName == "two-sided-short-edge")
                        {
                            aValueName = u"DuplexTumble"_ustr;
                        }
                    }

                    pValue = pKey->insertValue(aValueName, PPDValueType::Quoted);
                    if (!pValue)
                        continue;
                    pValue->m_aValue = aValueName;

                    if (aValueName.equals(aDefaultValue))
                    {
                        pKey->m_pDefaultValue = pValue;
                        bDefaultFound = true;
                    }
                }
                // This could be done to ensure default values also appear as options:
                if (!bDefaultFound && pKey->m_bUIOption)
                {
                    //     pValue = pKey->insertValue( aDefaultValue, PPDValueType::Quoted );
                    //     if( pValue )
                    //         pValue->m_aValue = aDefaultValue;
                }
                keys.emplace_back(pKey);
            }

            pKey = new PPDKey(u"ModelName"_ustr);
            aValueName = OStringToOUString("", aEncoding);
            pValue = pKey->insertValue(aValueName, PPDValueType::Quoted);
            if (pValue)
                pValue->m_aValue = aValueName;
            pKey->m_pDefaultValue = pValue;
            keys.emplace_back(pKey);

            pKey = new PPDKey(u"NickName"_ustr);
            aValueName = OStringToOUString(pDest->name, aEncoding);
            pValue = pKey->insertValue(aValueName, PPDValueType::Quoted);
            if (pValue)
                pValue->m_aValue = aValueName;
            pKey->m_pDefaultValue = pValue;
            keys.emplace_back(pKey);

            pNewParser = new PPDParser(aPrinter, keys);
            PrinterInfo& rInfo = m_aPrinters[aPrinter].m_aInfo;
            PPDContext& rContext = m_aDefaultContexts[aPrinter];
            rContext.setParser(pNewParser);
            setDefaultPaper(rContext);

            for (const auto & [ rKey, rDefValue ] : aOptionDefaults)
            {
                const PPDKey* key = pNewParser->getKey(rKey);
                if (key)
                {
                    const PPDValue* p1Value = key->getValue(rDefValue);
                    if (p1Value)
                    {
                        if (p1Value != key->getDefaultValue())
                        {
                            rContext.setValue(key, p1Value, true);
                            SAL_INFO("vcl.unx.print",
                                     "key " << key->getKey() << " is set to " << rDefValue);
                        }
                        else
                            SAL_INFO("vcl.unx.print",
                                     "key " << key->getKey() << " is defaulted to " << rDefValue);
                    }
                }
            }

            rInfo.m_pParser = pNewParser;
            rInfo.m_aContext = rContext;
            g_variant_unref(ret);
        }
        else
        {
            g_clear_error(&error);
            SAL_INFO("vcl.unx.print""CPD GetAllOptions failed, falling back to generic driver");
        }
    }
    else
        SAL_INFO("vcl.unx.print""no dest found for printer " << aPrinter);

    if (!pNewParser)
    {
        // get the default PPD
        pNewParser = PPDParser::getParser(u"SGENPRT"_ustr);
        SAL_WARN("vcl.unx.print""Parsing default SGENPRT PPD");

        PrinterInfo& rInfo = m_aPrinters[aPrinter].m_aInfo;

        rInfo.m_pParser = pNewParser;
        rInfo.m_aContext.setParser(pNewParser);
    }
#else
    (void)rPrinter;
#endif
    return pNewParser;
}

void CPDManager::initialize()
{
    // get normal printers, clear printer list
    PrinterInfoManager::initialize();
#if ENABLE_DBUS && ENABLE_GIO
    g_bus_own_name_on_connection(m_pConnection, "org.libreoffice.print-dialog",
                                 G_BUS_NAME_OWNER_FLAGS_NONE, onNameAcquired, onNameLost, this,
                                 nullptr);

    g_dbus_connection_signal_subscribe(m_pConnection, // DBus Connection
                                       nullptr, // Sender Name
                                       "org.openprinting.PrintBackend"// Sender Interface
                                       "PrinterAdded"// Signal Name
                                       nullptr, // Object Path
                                       nullptr, // arg0 behaviour
                                       G_DBUS_SIGNAL_FLAGS_NONE, // Signal Flags
                                       printerAdded, // Callback Function
                                       this, nullptr);
    g_dbus_connection_signal_subscribe(m_pConnection, // DBus Connection
                                       nullptr, // Sender Name
                                       "org.openprinting.PrintBackend"// Sender Interface
                                       "PrinterRemoved"// Signal Name
                                       nullptr, // Object Path
                                       nullptr, // arg0 behaviour
                                       G_DBUS_SIGNAL_FLAGS_NONE, // Signal Flags
                                       printerRemoved, // Callback Function
                                       this, nullptr);

    // remove everything that is not a CUPS printer and not
    // a special purpose printer (PDF, Fax)
    std::unordered_map<OUString, Printer>::iterator it = m_aPrinters.begin();
    while (it != m_aPrinters.end())
    {
        if (m_aCPDDestMap.contains(it->first))
        {
            ++it;
            continue;
        }

        if (!it->second.m_aInfo.m_aFeatures.isEmpty())
        {
            ++it;
            continue;
        }
        it = m_aPrinters.erase(it);
    }
#endif
}

void CPDManager::setupJobContextData(JobData& rData)
{
#if ENABLE_DBUS && ENABLE_GIO
    std::unordered_map<OUString, CPDPrinter*>::iterator dest_it
        = m_aCPDDestMap.find(rData.m_aPrinterName);

    if (dest_it == m_aCPDDestMap.end())
        return PrinterInfoManager::setupJobContextData(rData);

    std::unordered_map<OUString, Printer>::iterator p_it = m_aPrinters.find(rData.m_aPrinterName);
    if (p_it == m_aPrinters.end()) // huh ?
    {
        SAL_WARN("vcl.unx.print""CPD printer list in disorder, "
                                  "no dest for printer "
                                      << rData.m_aPrinterName);
        return;
    }

    if (p_it->second.m_aInfo.m_pParser == nullptr)
    {
        // in turn calls createCPDParser
        // which updates the printer info
        p_it->second.m_aInfo.m_pParser = PPDParser::getParser(p_it->second.m_aInfo.m_aDriverName);
    }
    if (p_it->second.m_aInfo.m_aContext.getParser() == nullptr)
    {
        OUString aPrinter;
        if (p_it->second.m_aInfo.m_aDriverName.startsWith("CPD:"))
            aPrinter = p_it->second.m_aInfo.m_aDriverName.copy(4);
        else
            aPrinter = p_it->second.m_aInfo.m_aDriverName;

        p_it->second.m_aInfo.m_aContext = m_aDefaultContexts[aPrinter];
    }

    rData.m_pParser = p_it->second.m_aInfo.m_pParser;
    rData.m_aContext = p_it->second.m_aInfo.m_aContext;
#else
    (void)rData;
#endif
}

FILE* CPDManager::startSpool(const OUString& rPrintername, bool bQuickCommand)
{
#if ENABLE_DBUS && ENABLE_GIO
    SAL_INFO("vcl.unx.print",
             "startSpool: " << rPrintername << " " << (bQuickCommand ? "true" : "false"));
    if (m_aCPDDestMap.find(rPrintername) == m_aCPDDestMap.end())
    {
        SAL_INFO("vcl.unx.print""defer to PrinterInfoManager::startSpool");
        return PrinterInfoManager::startSpool(rPrintername, bQuickCommand);
    }
    OUString aTmpURL, aTmpFile;
    osl_createTempFile(nullptr, nullptr, &aTmpURL.pData);
    osl_getSystemPathFromFileURL(aTmpURL.pData, &aTmpFile.pData);
    OString aSysFile = OUStringToOString(aTmpFile, osl_getThreadTextEncoding());
    FILE* fp = fopen(aSysFile.getStr(), "w");
    if (fp)
        m_aSpoolFiles[fp] = aSysFile;

    return fp;
#else
    (void)rPrintername;
    (void)bQuickCommand;
    return nullptr;
#endif
}

#if ENABLE_DBUS && ENABLE_GIO
void CPDManager::getOptionsFromDocumentSetup(const JobData& rJob, bool bBanner,
                                             const OString& rJobName, int& rNumOptions,
                                             GVariant** arr)
{
    GVariantBuilder* builder;
    builder = g_variant_builder_new(G_VARIANT_TYPE("a(ss)"));
    g_variant_builder_add(builder, "(ss)""job-name", rJobName.getStr());
    if (rJob.m_pParser == rJob.m_aContext.getParser() && rJob.m_pParser)
    {
        std::size_t i;
        std::size_t nKeys = rJob.m_aContext.countValuesModified();
        ::std::vector<const PPDKey*> aKeys(nKeys);
        for (i = 0; i < nKeys; i++)
            aKeys[i] = rJob.m_aContext.getModifiedKey(i);
        for (i = 0; i < nKeys; i++)
        {
            const PPDKey* pKey = aKeys[i];
            const PPDValue* pValue = rJob.m_aContext.getValue(pKey);
            OUString sPayLoad;
            if (pValue)
            {
                sPayLoad = pValue->m_bCustomOption ? pValue->m_aCustomOption : pValue->m_aOption;
            }
            if (!sPayLoad.isEmpty())
            {
                OString aKey = OUStringToOString(pKey->getKey(), RTL_TEXTENCODING_ASCII_US);
                OString aValue = OUStringToOString(sPayLoad, RTL_TEXTENCODING_ASCII_US);
                if (aKey.equals("Duplex"_ostr))
                {
                    aKey = "sides"_ostr;
                }
                else if (aKey.equals("Resolution"_ostr))
                {
                    aKey = "printer-resolution"_ostr;
                }
                else if (aKey.equals("PageSize"_ostr))
                {
                    aKey = "media"_ostr;
                }
                if (aKey.equals("sides"_ostr))
                {
                    if (aValue.equals("None"_ostr))
                    {
                        aValue = "one-sided"_ostr;
                    }
                    else if (aValue.equals("DuplexNoTumble"_ostr))
                    {
                        aValue = "two-sided-long-edge"_ostr;
                    }
                    else if (aValue.equals("DuplexTumble"_ostr))
                    {
                        aValue = "two-sided-short-edge"_ostr;
                    }
                }
                g_variant_builder_add(builder, "(ss)", aKey.getStr(), aValue.getStr());
            }
        }
    }
    if (rJob.m_nCopies > 1)
    {
        OString aVal(OString::number(rJob.m_nCopies));
        g_variant_builder_add(builder, "(ss)""copies", aVal.getStr());
        rNumOptions++;
        // TODO: something for collate
        // Maybe this is the equivalent ipp attribute:
        if (rJob.m_bCollate)
        {
            g_variant_builder_add(builder, "(ss)""multiple-document-handling",
                                  "separate-documents-collated-copies");
        }
        else
        {
            g_variant_builder_add(builder, "(ss)""multiple-document-handling",
                                  "separate-documents-uncollated-copies");
        }
        rNumOptions++;
    }
    if (!bBanner)
    {
        g_variant_builder_add(builder, "(ss)""job-sheets""none");
        rNumOptions++;
    }
    if (rJob.m_eOrientation == orientation::Portrait)
    {
        g_variant_builder_add(builder, "(ss)""orientation-requested""portrait");
        rNumOptions++;
    }
    else if (rJob.m_eOrientation == orientation::Landscape)
    {
        g_variant_builder_add(builder, "(ss)""orientation-requested""landscape");
        rNumOptions++;
    }
    (*arr) = g_variant_new("a(ss)", builder);
    g_variant_builder_unref(builder);
}
#endif

bool CPDManager::endSpool(const OUString& rPrintername, const OUString& rJobTitle, FILE* pFile,
                          const JobData& rDocumentJobData, bool bBanner, const OUString& rFaxNumber)
{
    bool success = false;
#if ENABLE_DBUS && ENABLE_GIO
    SAL_INFO("vcl.unx.print""endSpool: " << rPrintername << "," << rJobTitle
                                           << " copy count = " << rDocumentJobData.m_nCopies);
    std::unordered_map<OUString, CPDPrinter*>::iterator dest_it = m_aCPDDestMap.find(rPrintername);
    if (dest_it == m_aCPDDestMap.end())
    {
        SAL_INFO("vcl.unx.print""defer to PrinterInfoManager::endSpool");
        return PrinterInfoManager::endSpool(rPrintername, rJobTitle, pFile, rDocumentJobData,
                                            bBanner, rFaxNumber);
    }

    std::unordered_map<FILE*, OString, FPtrHash>::const_iterator it = m_aSpoolFiles.find(pFile);
    if (it != m_aSpoolFiles.end())
    {
        fclose(pFile);
        rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
        OString sJobName(OUStringToOString(rJobTitle, aEnc));
        if (!rFaxNumber.isEmpty())
        {
            sJobName = OUStringToOString(rFaxNumber, aEnc);
        }
        OString aSysFile = it->second;
        CPDPrinter* pDest = dest_it->second;
        GVariant* ret;
        gint job_id;
        int nNumOptions = 0;
        GVariant* pArr = nullptr;
        getOptionsFromDocumentSetup(rDocumentJobData, bBanner, sJobName, nNumOptions, &pArr);
        ret = g_dbus_proxy_call_sync(
            pDest->backend, "printFile",
            g_variant_new("(ssi@a(ss))", (pDest->id), aSysFile.getStr(), nNumOptions, pArr),
            G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr);
        g_variant_get(ret, "(i)", &job_id);
        if (job_id != -1)
        {
            success = true;
        }
        g_variant_unref(ret);
        unlink(it->second.getStr());
        m_aSpoolFiles.erase(it);
    }
#else
    (void)rPrintername;
    (void)rJobTitle;
    (void)pFile;
    (void)rDocumentJobData;
    (void)bBanner;
    (void)rFaxNumber;
#endif
    return success;
}

bool CPDManager::checkPrintersChanged(bool)
{
#if ENABLE_DBUS && ENABLE_GIO
    bool bChanged = m_aPrintersChanged;
    m_aPrintersChanged = false;
    g_dbus_connection_emit_signal(m_pConnection, nullptr, "/org/libreoffice/PrintDialog",
                                  "org.openprinting.PrintFrontend""RefreshBackend", nullptr,
                                  nullptr);
    return bChanged;
#else
    return false;
#endif
}

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

Messung V0.5
C=92 H=91 G=91

¤ Dauer der Verarbeitung: 0.21 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge