You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/kdeprint/cups/kmcupsmanager.cpp

1175 lines
33 KiB

/*
* This file is part of the KDE libraries
* Copyright (c) 2001 Michael Goffioul <kdeprint@swing.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
**/
#include <config.h>
#include "kmcupsmanager.h"
#include "kmprinter.h"
#include "ipprequest.h"
#include "cupsinfos.h"
#include "driver.h"
#include "kmfactory.h"
#include "kmdbentry.h"
#include "cupsaddsmb2.h"
#include "ippreportdlg.h"
#include "kpipeprocess.h"
#include "util.h"
#include "foomatic2loader.h"
#include "ppdloader.h"
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqregexp.h>
#include <tqtimer.h>
#include <tqsocket.h>
#include <tqdatetime.h>
#include <kdebug.h>
#include <kapplication.h>
#include <klocale.h>
#include <kconfig.h>
#include <kstandarddirs.h>
#include <ksocketbase.h>
#include <klibloader.h>
#include <kmessagebox.h>
#include <kaction.h>
#include <kdialogbase.h>
#include <kextendedsocket.h>
#include <kprocess.h>
#include <kbufferedsocket.h>
#include <kfilterdev.h>
#include <cups/cups.h>
#include <cups/ppd.h>
#include <math.h>
#define ppdi18n(s) i18n(TQString::fromLocal8Bit(s).utf8())
static void extractMaticData(TQString& buf, const TQString& filename);
static TQString printerURI(KMPrinter *p, bool useExistingURI);
static TQString downloadDriver(KMPrinter *p);
static int trials = 5;
//*****************************************************************************************************
KMCupsManager::KMCupsManager(TQObject *parent, const char *name, const TQStringList & /*args*/)
: KMManager(parent,name)
{
// be sure to create the CupsInfos object -> password
// management is handled correctly.
CupsInfos::self();
m_cupsdconf = 0;
m_currentprinter = 0;
m_socket = 0;
setHasManagement(true);
setPrinterOperationMask(KMManager::PrinterAll);
setServerOperationMask(KMManager::ServerAll);
// change LANG variable so that CUPS is always using
// english language: translation may only come from the PPD
// itself, or from KDE.
setenv("LANG", "en_US.UTF-8", 1);
}
KMCupsManager::~KMCupsManager()
{
delete m_socket;
}
TQString KMCupsManager::driverDbCreationProgram()
{
return TQString(__KDE_BINDIR).append(TQString::fromLatin1("/make_driver_db_cups"));
}
TQString KMCupsManager::driverDirectory()
{
TQString d = cupsInstallDir();
if (d.isEmpty()) {
#ifdef __OpenBSD__
d = "/usr/local";
#else
d = "/usr";
#endif
}
d.append("/share/cups/model");
// raw foomatic support
#ifdef __OpenBSD__
d.append(":/usr/local/share/foomatic/db/source");
#else
d.append(":/usr/share/foomatic/db/source");
// compressed foomatic support
d.append(":/usr/lib/cups/driver/foomatic-db-compressed-ppds");
#endif
return d;
}
TQString KMCupsManager::cupsInstallDir()
{
KConfig *conf= KMFactory::self()->printConfig();
conf->setGroup("CUPS");
TQString dir = conf->readPathEntry("InstallDir");
return dir;
}
void KMCupsManager::reportIppError(IppRequest *req)
{
setErrorMsg(req->statusMessage());
}
bool KMCupsManager::createPrinter(KMPrinter *p)
{
bool isclass = p->isClass(false), result(false);
IppRequest req;
TQString uri;
uri = printerURI(p,false);
req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
// needed to avoid problems when changing printer name
p->setUri(KURL(uri));
if (isclass)
{
req.setOperation(CUPS_ADD_CLASS);
TQStringList members = p->members(), uris;
TQString s;
s = TQString::fromLocal8Bit("ipp://%1/printers/").arg(CupsInfos::self()->hostaddr());
for (TQStringList::ConstIterator it=members.begin(); it!=members.end(); ++it)
uris.append(s+(*it));
req.addURI(IPP_TAG_PRINTER,"member-uris",uris);
}
else
{
req.setOperation(CUPS_ADD_PRINTER);
// only set the device-uri if needed, otherwise you may loose authentification
// data (login/password in URI's like smb or ipp).
KMPrinter *otherP = findPrinter(p->printerName());
if (!otherP || otherP->device() != p->device())
{
/**
* As now the device is a TQString instead of KURL, special encoding
* required for SMB is not needed anymore. Use a unique mechanism
* for all backends.
*/
req.addURI(IPP_TAG_PRINTER,"device-uri",p->device());
}
if (!p->option("kde-banners").isEmpty())
{
TQStringList bans = TQStringList::split(',',p->option("kde-banners"),false);
while (bans.count() < 2)
bans.append("none");
req.addName(IPP_TAG_PRINTER,"job-sheets-default",bans);
}
req.addInteger(IPP_TAG_PRINTER,"job-quota-period",p->option("job-quota-period").toInt());
req.addInteger(IPP_TAG_PRINTER,"job-k-limit",p->option("job-k-limit").toInt());
req.addInteger(IPP_TAG_PRINTER,"job-page-limit",p->option("job-page-limit").toInt());
if (!p->option("requesting-user-name-denied").isEmpty())
req.addName(IPP_TAG_PRINTER,"requesting-user-name-denied",TQStringList::split(",",p->option("requesting-user-name-denied"),false));
else if (!p->option("requesting-user-name-allowed").isEmpty())
req.addName(IPP_TAG_PRINTER,"requesting-user-name-allowed",TQStringList::split(",",p->option("requesting-user-name-allowed"),false));
else
req.addName(IPP_TAG_PRINTER,"requesting-user-name-allowed",TQString::fromLatin1("all"));
}
req.addText(IPP_TAG_PRINTER,"printer-info",p->description());
req.addText(IPP_TAG_PRINTER,"printer-location",p->location());
if (req.doRequest("/admin/"))
{
result = true;
if (p->driver())
result = savePrinterDriver(p,p->driver());
if (result)
upPrinter(p, true);
}
else reportIppError(&req);
return result;
}
bool KMCupsManager::removePrinter(KMPrinter *p)
{
bool result = setPrinterState(p,CUPS_DELETE_PRINTER);
return result;
}
bool KMCupsManager::enablePrinter(KMPrinter *p, bool state)
{
return setPrinterState(p, (state ? CUPS_ACCEPT_JOBS : CUPS_REJECT_JOBS));
}
bool KMCupsManager::startPrinter(KMPrinter *p, bool state)
{
return setPrinterState(p, (state ? IPP_RESUME_PRINTER : IPP_PAUSE_PRINTER));
}
bool KMCupsManager::setDefaultPrinter(KMPrinter *p)
{
return setPrinterState(p,CUPS_SET_DEFAULT);
}
bool KMCupsManager::setPrinterState(KMPrinter *p, int state)
{
IppRequest req;
TQString uri;
req.setOperation(state);
uri = printerURI(p, true);
req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
if (req.doRequest("/admin/"))
return true;
reportIppError(&req);
return false;
}
bool KMCupsManager::completePrinter(KMPrinter *p)
{
if (completePrinterShort(p))
{
// driver informations
TQString ppdname = downloadDriver(p);
ppd_file_t *ppd = (ppdname.isEmpty() ? NULL : ppdOpenFile(ppdname.local8Bit()));
if (ppd)
{
KMDBEntry entry;
// use the validation mechanism of KMDBEntry to
// fill possible missing entries like manufacturer
// or model.
entry.manufacturer = ppd->manufacturer;
entry.model = ppd->shortnickname;
entry.modelname = ppd->modelname;
// do not check the driver regarding the manager
entry.validate(false);
// update the KMPrinter object
p->setManufacturer(entry.manufacturer);
p->setModel(entry.model);
p->setDriverInfo(TQString::fromLocal8Bit(ppd->nickname));
ppdClose(ppd);
}
if (!ppdname.isEmpty())
TQFile::remove(ppdname);
return true;
}
return false;
}
bool KMCupsManager::completePrinterShort(KMPrinter *p)
{
IppRequest req;
TQStringList keys;
TQString uri;
req.setOperation(IPP_GET_PRINTER_ATTRIBUTES);
uri = printerURI(p, true);
req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
/*
// change host and port for remote stuffs
if (!p->uri().isEmpty())
{
// THIS IS AN UGLY HACK!! FIXME
// This attempts a "pre-connection" to see if the host is
// actually reachable. It times out after 2 seconds at most,
// preventing application freezes.
m_hostSuccess = false;
m_lookupDone = false;
// Give 2 seconds to connect to the printer, or abort
KExtendedSocket *kes = new KExtendedSocket(p->uri().host(),
p->uri().port());
connect(kes, TQT_SIGNAL(connectionSuccess()), this, TQT_SLOT(hostPingSlot()));
connect(kes, TQT_SIGNAL(connectionFailed(int)), this, TQT_SLOT(hostPingFailedSlot()));
if (kes->startAsyncConnect() != 0) {
delete kes;
m_hostSuccess = false;
} else {
TQDateTime tm = TQDateTime::currentDateTime().addSecs(2);
while (!m_lookupDone && (TQDateTime::currentDateTime() < tm))
tqApp->processEvents();
kes->cancelAsyncConnect();
delete kes;
if (!m_lookupDone)
m_hostSuccess = false;
}
if (m_hostSuccess == true) {
req.setHost(p->uri().host());
req.setPort(p->uri().port());
}
}
*/
// disable location as it has been transferred to listing (for filtering)
//keys.append("printer-location");
keys.append("printer-info");
keys.append("printer-make-and-model");
keys.append("job-sheets-default");
keys.append("job-sheets-supported");
keys.append("job-quota-period");
keys.append("job-k-limit");
keys.append("job-page-limit");
keys.append("requesting-user-name-allowed");
keys.append("requesting-user-name-denied");
if (p->isClass(true))
{
keys.append("member-uris");
keys.append("member-names");
}
else
keys.append("device-uri");
req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys);
if (req.doRequest("/printers/"))
{
TQString value;
if (req.text("printer-info",value)) p->setDescription(value);
// disabled location
//if (req.text("printer-location",value)) p->setLocation(value);
if (req.text("printer-make-and-model",value)) p->setDriverInfo(value);
if (req.uri("device-uri",value))
{
/**
* No specific treatment required as the device is
* a normal TQString instead of a KURL
*/
p->setDevice( value );
}
TQStringList values;
/* if (req.uri("member-uris",values))
{
TQStringList members;
for (TQStringList::ConstIterator it=values.begin(); it!=values.end(); ++it)
{
int p = (*it).findRev('/');
if (p != -1)
members.append((*it).right((*it).length()-p-1));
}
p->setMembers(members);
}*/
if (req.name("member-names",values))
p->setMembers(values);
// banners
req.name("job-sheets-default",values);
while (values.count() < 2) values.append("none");
p->setOption("kde-banners",values.join(TQString::fromLatin1(",")));
if (req.name("job-sheets-supported",values)) p->setOption("kde-banners-supported",values.join(TQString::fromLatin1(",")));
// quotas
int ival;
if (req.integer("job-quota-period",ival)) p->setOption("job-quota-period",TQString::number(ival));
if (req.integer("job-k-limit",ival)) p->setOption("job-k-limit",TQString::number(ival));
if (req.integer("job-page-limit",ival)) p->setOption("job-page-limit",TQString::number(ival));
// access permissions (allow and deny are mutually exclusives)
if (req.name("requesting-user-name-allowed",values) && values.count() > 0)
{
p->removeOption("requesting-user-name-denied");
p->setOption("requesting-user-name-allowed",values.join(","));
}
if (req.name("requesting-user-name-denied",values) && values.count() > 0)
{
p->removeOption("requesting-user-name-allowed");
p->setOption("requesting-user-name-denied",values.join(","));
}
return true;
}
reportIppError(&req);
return false;
}
bool KMCupsManager::testPrinter(KMPrinter *p)
{
return KMManager::testPrinter(p);
/*
TQString testpage = testPage();
if (testpage.isEmpty())
{
setErrorMsg(i18n("Unable to locate test page."));
return false;
}
IppRequest req;
TQString uri;
req.setOperation(IPP_PRINT_JOB);
uri = printerURI(p);
req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
req.addMime(IPP_TAG_OPERATION,"document-format","application/postscript");
if (!CupsInfos::self()->login().isEmpty()) req.addName(IPP_TAG_OPERATION,"requesting-user-name",CupsInfos::self()->login());
req.addName(IPP_TAG_OPERATION,"job-name",TQString::fromLatin1("KDE Print Test"));
if (req.doFileRequest("/printers/",testpage))
return true;
reportIppError(&req);
return false;
*/
}
void KMCupsManager::listPrinters()
{
loadServerPrinters();
}
void KMCupsManager::loadServerPrinters()
{
IppRequest req;
TQStringList keys;
// get printers
req.setOperation(CUPS_GET_PRINTERS);
keys.append("printer-name");
keys.append("printer-type");
keys.append("printer-state");
// location needed for filtering
keys.append("printer-location");
keys.append("printer-uri-supported");
keys.append("printer-is-accepting-jobs");
req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys);
// filtering by username (hides printers user doesn't have allowance to use)
req.addName(IPP_TAG_OPERATION, "requesting-user-name", TQString(cupsUser()));
if (req.doRequest("/printers/"))
{
processRequest(&req);
// get classes
req.init();
req.setOperation(CUPS_GET_CLASSES);
req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys);
if (req.doRequest("/classes/"))
{
processRequest(&req);
// load default
req.init();
req.setOperation(CUPS_GET_DEFAULT);
req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",TQString::fromLatin1("printer-name"));
if (req.doRequest("/printers/"))
{
TQString s = TQString::null;
req.name("printer-name",s);
setHardDefault(findPrinter(s));
}
// This request may fails for example if no printer is defined. Just
// discard the error message. Indeed as we successfully got printers
// and classes, the most probable reason why this request may fail is
// because of no printer defined. The best would be to actually check
// there's no printer (TODO).
return;
}
}
// something went wrong if we get there, report the error
reportIppError(&req);
}
void KMCupsManager::processRequest(IppRequest* req)
{
ipp_attribute_t *attr = req->first();
ipp_attribute_t *nextAttr;
KMPrinter *printer = new KMPrinter();
while (attr)
{
#ifdef HAVE_CUPS_1_6
TQString attrname(ippGetName(attr));
if (attrname == "printer-name")
{
TQString value = TQString::fromLocal8Bit(ippGetString(attr, 0, NULL));
printer->setName(value);
printer->setPrinterName(value);
}
else if (attrname == "printer-type")
{
int value = ippGetInteger(attr, 0);
printer->setType(0);
printer->addType(((value & CUPS_PRINTER_CLASS) || (value & CUPS_PRINTER_IMPLICIT) ? KMPrinter::Class : KMPrinter::Printer));
if ((value & CUPS_PRINTER_REMOTE)) printer->addType(KMPrinter::Remote);
if ((value & CUPS_PRINTER_IMPLICIT)) printer->addType(KMPrinter::Implicit);
// convert printer-type attribute
printer->setPrinterCap( ( value & CUPS_PRINTER_OPTIONS ) >> 2 );
}
else if (attrname == "printer-state")
{
switch (ippGetInteger(attr, 0))
{
case IPP_PRINTER_IDLE: printer->setState(KMPrinter::Idle); break;
case IPP_PRINTER_PROCESSING: printer->setState(KMPrinter::Processing); break;
case IPP_PRINTER_STOPPED: printer->setState(KMPrinter::Stopped); break;
}
}
else if (attrname == "printer-uri-supported")
{
printer->setUri(KURL(ippGetString(attr, 0, NULL)));
}
else if (attrname == "printer-location")
{
printer->setLocation(TQString::fromLocal8Bit(ippGetString(attr, 0, NULL)));
}
else if (attrname == "printer-is-accepting-jobs")
{
printer->setAcceptJobs(ippGetBoolean(attr, 0));
}
nextAttr = ippNextAttribute(req->request());
if (attrname.isEmpty() || (!nextAttr))
{
addPrinter(printer);
printer = new KMPrinter();
}
attr = nextAttr;
#else // HAVE_CUPS_1_6
TQString attrname(attr->name);
if (attrname == "printer-name")
{
TQString value = TQString::fromLocal8Bit(attr->values[0].string.text);
printer->setName(value);
printer->setPrinterName(value);
}
else if (attrname == "printer-type")
{
int value = attr->values[0].integer;
printer->setType(0);
printer->addType(((value & CUPS_PRINTER_CLASS) || (value & CUPS_PRINTER_IMPLICIT) ? KMPrinter::Class : KMPrinter::Printer));
if ((value & CUPS_PRINTER_REMOTE)) printer->addType(KMPrinter::Remote);
if ((value & CUPS_PRINTER_IMPLICIT)) printer->addType(KMPrinter::Implicit);
// convert printer-type attribute
printer->setPrinterCap( ( value & CUPS_PRINTER_OPTIONS ) >> 2 );
}
else if (attrname == "printer-state")
{
switch (attr->values[0].integer)
{
case IPP_PRINTER_IDLE: printer->setState(KMPrinter::Idle); break;
case IPP_PRINTER_PROCESSING: printer->setState(KMPrinter::Processing); break;
case IPP_PRINTER_STOPPED: printer->setState(KMPrinter::Stopped); break;
}
}
else if (attrname == "printer-uri-supported")
{
printer->setUri(KURL(attr->values[0].string.text));
}
else if (attrname == "printer-location")
{
printer->setLocation(TQString::fromLocal8Bit(attr->values[0].string.text));
}
else if (attrname == "printer-is-accepting-jobs")
{
printer->setAcceptJobs(attr->values[0].boolean);
}
if (attrname.isEmpty() || attr == req->last())
{
addPrinter(printer);
printer = new KMPrinter();
}
attr = attr->next;
#endif // HAVE_CUPS_1_6
}
delete printer;
}
DrMain* KMCupsManager::loadPrinterDriver(KMPrinter *p, bool)
{
if (!p)
return NULL;
if (p->isClass(true))
{
KMPrinter *first_class_member = NULL;
/* find the first printer in the class */
first_class_member = findPrinter(p->members().first());
if (first_class_member == NULL)
{
/* we didn't find a printer in the class */
return NULL;
}
else
{
p = first_class_member;
}
}
TQString fname = downloadDriver(p);
DrMain *driver(0);
if (!fname.isEmpty())
{
driver = loadDriverFile(fname);
if (driver)
driver->set("temporary",fname);
}
return driver;
}
DrMain* KMCupsManager::loadFileDriver(const TQString& filename)
{
if (filename.startsWith("ppd:"))
return loadDriverFile(filename.mid(4));
else if (filename.startsWith("compressed-ppd:"))
return loadDriverFile(filename);
else if (filename.startsWith("foomatic/"))
return loadMaticDriver(filename);
else
return loadDriverFile(filename);
}
DrMain* KMCupsManager::loadMaticDriver(const TQString& drname)
{
TQStringList comps = TQStringList::split('/', drname, false);
TQString tmpFile = locateLocal("tmp", "foomatic_" + kapp->randomString(8));
#ifdef __OpenBSD__
TQString PATH = getenv("PATH") + TQString::fromLatin1(":/usr/local/bin:/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
#else
TQString PATH = getenv("PATH") + TQString::fromLatin1(":/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
#endif
TQString exe = KStandardDirs::findExe("foomatic-datafile", PATH);
if (exe.isEmpty())
{
setErrorMsg(i18n("Unable to find the executable foomatic-datafile "
"in your PATH. Check that Foomatic is correctly installed."));
return NULL;
}
KPipeProcess in;
TQFile out(tmpFile);
TQString cmd = KProcess::quote(exe);
cmd += " -t cups -d ";
cmd += KProcess::quote(comps[2]);
cmd += " -p ";
cmd += KProcess::quote(comps[1]);
if (in.open(cmd) && out.open(IO_WriteOnly))
{
TQTextStream tin(&in), tout(&out);
TQString line;
while (!tin.atEnd())
{
line = tin.readLine();
tout << line << endl;
}
in.close();
out.close();
DrMain *driver = loadDriverFile(tmpFile);
if (driver)
{
driver->set("template", tmpFile);
driver->set("temporary", tmpFile);
return driver;
}
}
setErrorMsg(i18n("Unable to create the Foomatic driver [%1,%2]. "
"Either that driver does not exist, or you don't have "
"the required permissions to perform that operation.").arg(comps[1]).arg(comps[2]));
TQFile::remove(tmpFile);
return NULL;
}
DrMain* KMCupsManager::loadDriverFile(const TQString& fname)
{
if ((fname.startsWith("compressed-ppd:")) || TQFile::exists(fname))
{
TQString msg; /* possible error message */
DrMain *driver = PPDLoader::loadDriver( fname, &msg );
if ( driver )
{
driver->set( "template", fname );
// FIXME: should fix option in group "install"
}
else
setErrorMsg( msg );
return driver;
}
return NULL;
}
void KMCupsManager::saveDriverFile(DrMain *driver, const TQString& filename)
{
kdDebug( 500 ) << "Saving PPD file with template=" << driver->get( "template" ) << endl;
TQString templateFile = driver->get( "template" );
if (templateFile.startsWith("compressed-ppd:")) {
templateFile = driver->get( "temporary-cppd" );
}
TQIODevice *in = KFilterDev::deviceForFile( templateFile );
TQFile out(filename);
if (in && in->open(IO_ReadOnly) && out.open(IO_WriteOnly))
{
TQTextStream tin(in), tout(&out);
TQString line, keyword;
bool isnumeric(false);
DrBase *opt(0);
while (!tin.eof())
{
line = tin.readLine();
if (line.startsWith("*% COMDATA #"))
{
int p(-1), q(-1);
if ((p=line.find("'name'")) != -1)
{
p = line.find('\'',p+6)+1;
q = line.find('\'',p);
keyword = line.mid(p,q-p);
opt = driver->findOption(keyword);
if (opt && (opt->type() == DrBase::Integer || opt->type() == DrBase::Float))
isnumeric = true;
else
isnumeric = false;
}
/*else if ((p=line.find("'type'")) != -1)
{
p = line.find('\'',p+6)+1;
if (line.find("float",p) != -1 || line.find("int",p) != -1)
isnumeric = true;
else
isnumeric = false;
}*/
else if ((p=line.find("'default'")) != -1 && !keyword.isEmpty() && opt && isnumeric)
{
TQString prefix = line.left(p+9);
tout << prefix << " => '" << opt->valueText() << '\'';
if (line.find(',',p) != -1)
tout << ',';
tout << endl;
continue;
}
tout << line << endl;
}
else if (line.startsWith("*Default"))
{
int p = line.find(':',8);
keyword = line.mid(8,p-8);
DrBase *bopt = 0;
if ( keyword == "PageRegion" || keyword == "ImageableArea" || keyword == "PaperDimension" )
bopt = driver->findOption( TQString::fromLatin1( "PageSize" ) );
else
bopt = driver->findOption( keyword );
if (bopt)
switch (bopt->type())
{
case DrBase::List:
case DrBase::Boolean:
{
DrListOption *opt = static_cast<DrListOption*>(bopt);
if (opt && opt->currentChoice())
tout << "*Default" << keyword << ": " << opt->currentChoice()->name() << endl;
else
tout << line << endl;
}
break;
case DrBase::Integer:
{
DrIntegerOption *opt = static_cast<DrIntegerOption*>(bopt);
tout << "*Default" << keyword << ": " << opt->fixedVal() << endl;
}
break;
case DrBase::Float:
{
DrFloatOption *opt = static_cast<DrFloatOption*>(bopt);
tout << "*Default" << keyword << ": " << opt->fixedVal() << endl;
}
break;
default:
tout << line << endl;
break;
}
else
tout << line << endl;
}
else
tout << line << endl;
}
}
delete in;
}
bool KMCupsManager::savePrinterDriver(KMPrinter *p, DrMain *d)
{
TQString tmpfilename = locateLocal("tmp","print_") + kapp->randomString(8);
// first save the driver in a temporary file
saveDriverFile(d,tmpfilename);
// then send a request
IppRequest req;
TQString uri;
bool result(false);
req.setOperation(CUPS_ADD_PRINTER);
uri = printerURI(p, true);
req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
result = req.doFileRequest("/admin/",tmpfilename);
// remove temporary file
TQFile::remove(tmpfilename);
if (!result)
reportIppError(&req);
return result;
}
void* KMCupsManager::loadCupsdConfFunction(const char *name)
{
if (!m_cupsdconf)
{
m_cupsdconf = KLibLoader::self()->library("cupsdconf");
if (!m_cupsdconf)
{
setErrorMsg(i18n("Library cupsdconf not found. Check your installation."));
return NULL;
}
}
void* func = m_cupsdconf->symbol(name);
if (!func)
setErrorMsg(i18n("Symbol %1 not found in cupsdconf library.").arg(name));
return func;
}
void KMCupsManager::unloadCupsdConf()
{
if (m_cupsdconf)
{
KLibLoader::self()->unloadLibrary("libcupsdconf");
m_cupsdconf = 0;
}
}
bool KMCupsManager::restartServer()
{
TQString msg;
bool (*f1)(TQString&) = (bool(*)(TQString&))loadCupsdConfFunction("restartServer");
bool result(false);
if (f1)
{
result = f1(msg);
if (!result) setErrorMsg(msg);
}
unloadCupsdConf();
return result;
}
bool KMCupsManager::configureServer(TQWidget *parent)
{
TQString msg;
bool (*f2)(TQWidget*, TQString&) = (bool(*)(TQWidget*, TQString&))loadCupsdConfFunction("configureServer");
bool result(false);
if (f2)
{
result = f2(parent, msg);
if ( !result )
setErrorMsg( msg );
}
unloadCupsdConf();
return result;
}
TQStringList KMCupsManager::detectLocalPrinters()
{
TQStringList list;
IppRequest req;
ipp_attribute_t *nextAttr;
req.setOperation(CUPS_GET_DEVICES);
if (req.doRequest("/"))
{
TQString desc, uri, printer, cl;
ipp_attribute_t *attr = req.first();
while (attr)
{
#ifdef HAVE_CUPS_1_6
TQString attrname(ippGetName(attr));
if (attrname == "device-info") desc = ippGetString(attr, 0, NULL);
else if (attrname == "device-make-and-model") printer = ippGetString(attr, 0, NULL);
else if (attrname == "device-uri") uri = ippGetString(attr, 0, NULL);
else if ( attrname == "device-class" ) cl = ippGetString(attr, 0, NULL);
nextAttr = ippNextAttribute(req.request());
if (attrname.isEmpty() || (!nextAttr))
{
if (!uri.isEmpty())
{
if (printer == "Unknown") printer = TQString::null;
list << cl << uri << desc << printer;
}
uri = desc = printer = cl = TQString::null;
}
attr = nextAttr;
#else // HAVE_CUPS_1_6
TQString attrname(attr->name);
if (attrname == "device-info") desc = attr->values[0].string.text;
else if (attrname == "device-make-and-model") printer = attr->values[0].string.text;
else if (attrname == "device-uri") uri = attr->values[0].string.text;
else if ( attrname == "device-class" ) cl = attr->values[ 0 ].string.text;
if (attrname.isEmpty() || attr == req.last())
{
if (!uri.isEmpty())
{
if (printer == "Unknown") printer = TQString::null;
list << cl << uri << desc << printer;
}
uri = desc = printer = cl = TQString::null;
}
attr = attr->next;
#endif // HAVE_CUPS_1_6
}
}
return list;
}
void KMCupsManager::createPluginActions(KActionCollection *coll)
{
KAction *act = new KAction(i18n("&Export Driver..."), "kdeprint_uploadsmb", 0, this, TQT_SLOT(exportDriver()), coll, "plugin_export_driver");
act->setGroup("plugin");
act = new KAction(i18n("&Printer IPP Report"), "kdeprint_report", 0, this, TQT_SLOT(printerIppReport()), coll, "plugin_printer_ipp_report");
act->setGroup("plugin");
}
void KMCupsManager::validatePluginActions(KActionCollection *coll, KMPrinter *pr)
{
// save selected printer for future use in slots
m_currentprinter = pr;
coll->action("plugin_export_driver")->setEnabled(pr && pr->isLocal() && !pr->isClass(true) && !pr->isSpecial());
coll->action("plugin_printer_ipp_report")->setEnabled(pr && !pr->isSpecial());
}
void KMCupsManager::exportDriver()
{
if (m_currentprinter && m_currentprinter->isLocal() &&
!m_currentprinter->isClass(true) && !m_currentprinter->isSpecial())
{
TQString path = cupsInstallDir();
if (path.isEmpty()) {
#ifdef __OpenBSD__
path = "/usr/local/share/cups";
#else
path = "/usr/share/cups";
#endif
} else {
path += "/share/cups";
}
CupsAddSmb::exportDest(m_currentprinter->printerName(), path);
}
}
void KMCupsManager::printerIppReport()
{
if (m_currentprinter && !m_currentprinter->isSpecial())
{
IppRequest req;
TQString uri;
req.setOperation(IPP_GET_PRINTER_ATTRIBUTES);
uri = printerURI(m_currentprinter, true);
req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
/*
if (!m_currentprinter->uri().isEmpty())
{
req.setHost(m_currentprinter->uri().host());
req.setPort(m_currentprinter->uri().port());
}
*/
req.dump(2);
if (req.doRequest("/printers/"))
{
ippReport(req, IPP_TAG_PRINTER, i18n("IPP Report for %1").arg(m_currentprinter->printerName()));
}
else
{
KMessageBox::error(0, "<p>"+i18n("Unable to retrieve printer information. Error received:")+"</p>"+req.statusMessage());
}
}
}
void KMCupsManager::ippReport(IppRequest& req, int group, const TQString& caption)
{
IppReportDlg::report(&req, group, caption);
}
TQString KMCupsManager::stateInformation()
{
return TQString("%1: %2")
.arg(i18n("Server"))
.arg(CupsInfos::self()->host()[0] != '/' ?
TQString(TQString("%1:%2").arg(CupsInfos::self()->host()).arg(CupsInfos::self()->port()))
: CupsInfos::self()->host());
}
void KMCupsManager::checkUpdatePossibleInternal()
{
kdDebug(500) << "Checking for update possible" << endl;
delete m_socket;
m_socket = new KNetwork::KBufferedSocket;
m_socket->setTimeout( 1500 );
connect( m_socket, TQT_SIGNAL( connected(const KResolverEntry&) ),
TQT_SLOT( slotConnectionSuccess() ) );
connect( m_socket, TQT_SIGNAL( gotError( int ) ), TQT_SLOT( slotConnectionFailed( int ) ) );
trials = 5;
TQTimer::singleShot( 1, this, TQT_SLOT( slotAsyncConnect() ) );
}
void KMCupsManager::slotConnectionSuccess()
{
kdDebug(500) << "Connection success, trying to send a request..." << endl;
m_socket->close();
IppRequest req;
req.setOperation( CUPS_GET_PRINTERS );
req.addKeyword( IPP_TAG_OPERATION, "requested-attributes", TQString::fromLatin1( "printer-name" ) );
if ( req.doRequest( "/printers/" ) )
setUpdatePossible( true );
else
{
kdDebug(500) << "Unable to get printer list" << endl;
if ( trials > 0 )
{
trials--;
TQTimer::singleShot( 1000, this, TQT_SLOT( slotAsyncConnect() ) );
}
else
{
setErrorMsg( i18n( "Connection to CUPS server failed. Check that the CUPS server is correctly installed and running. "
"Error: %1." ).arg( i18n( "the IPP request failed for an unknown reason" ) ) );
setUpdatePossible( false );
}
}
}
void KMCupsManager::slotAsyncConnect()
{
kdDebug(500) << "Starting async connect to " << CupsInfos::self()->hostaddr() << endl;
//m_socket->startAsyncConnect();
if (CupsInfos::self()->host().startsWith("/"))
m_socket->connect( TQString(), CupsInfos::self()->host());
else
m_socket->connectToHost( CupsInfos::self()->host(), CupsInfos::self()->port() );
}
void KMCupsManager::slotConnectionFailed( int errcode )
{
kdDebug(500) << "Connection failed trials=" << trials << endl;
if ( trials > 0 )
{
//m_socket->setTimeout( ++to );
//m_socket->cancelAsyncConnect();
trials--;
m_socket->close();
TQTimer::singleShot( 1000, this, TQT_SLOT( slotAsyncConnect() ) );
return;
}
TQString einfo;
switch (errcode) {
case KNetwork::KSocketBase::ConnectionRefused:
case KNetwork::KSocketBase::ConnectionTimedOut:
einfo = i18n("connection refused") + TQString(" (%1)").arg(errcode);
break;
case KNetwork::KSocketBase::LookupFailure:
einfo = i18n("host not found") + TQString(" (%1)").arg(errcode);
break;
case KNetwork::KSocketBase::WouldBlock:
default:
einfo = i18n("read failed (%1)").arg(errcode);
break;
}
setErrorMsg( i18n( "Connection to CUPS server failed. Check that the CUPS server is correctly installed and running. "
"Error: %2: %1." ).arg( einfo, CupsInfos::self()->host()));
setUpdatePossible( false );
}
void KMCupsManager::hostPingSlot() {
m_hostSuccess = true;
m_lookupDone = true;
}
void KMCupsManager::hostPingFailedSlot() {
m_hostSuccess = false;
m_lookupDone = true;
}
//*****************************************************************************************************
static void extractMaticData(TQString& buf, const TQString& filename)
{
TQFile f(filename);
if (f.exists() && f.open(IO_ReadOnly))
{
TQTextStream t(&f);
TQString line;
while (!t.eof())
{
line = t.readLine();
if (line.startsWith("*% COMDATA #"))
buf.append(line.right(line.length()-12)).append('\n');
}
}
}
static TQString printerURI(KMPrinter *p, bool use)
{
TQString uri;
if (use && !p->uri().isEmpty())
uri = p->uri().prettyURL();
else
uri = TQString("ipp://%1/%3/%2").arg(CupsInfos::self()->hostaddr()).arg(p->printerName()).arg((p->isClass(false) ? "classes" : "printers"));
return uri;
}
static TQString downloadDriver(KMPrinter *p)
{
TQString driverfile, prname = p->printerName();
bool changed(false);
/*
if (!p->uri().isEmpty())
{
// try to load the driver from the host:port
// specified in its URI. Doing so may also change
// the printer name to use. Note that for remote
// printer, this operation is read-only, no counterpart
// for saving operation.
cupsSetServer(p->uri().host().local8Bit());
ippSetPort(p->uri().port());
// strip any "@..." from the printer name
prname = prname.replace(TQRegExp("@.*"), "");
changed = true;
}
*/
// download driver
driverfile = cupsGetPPD(prname.local8Bit());
// restore host:port (if they have changed)
if (changed)
{
cupsSetServer(CupsInfos::self()->host().local8Bit());
ippSetPort(CupsInfos::self()->port());
}
return driverfile;
}
#include "kmcupsmanager.moc"