00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#include "matichandler.h"
00021
#include "printcapentry.h"
00022
#include "kmprinter.h"
00023
#include "matichelper.h"
00024
#include "driver.h"
00025
#include "kpipeprocess.h"
00026
#include "kmmanager.h"
00027
#include "kprinter.h"
00028
#include "lprsettings.h"
00029
#include "util.h"
00030
#include "foomatic2loader.h"
00031
00032
#include <klocale.h>
00033
#include <kstandarddirs.h>
00034
#include <kapplication.h>
00035
#include <kdebug.h>
00036
#include <kprocess.h>
00037
#include <qfile.h>
00038
#include <qtextstream.h>
00039
#include <qregexp.h>
00040
00041
#include <stdlib.h>
00042
#include <sys/wait.h>
00043
00044 MaticHandler::MaticHandler(KMManager *mgr)
00045 : LprHandler(
"foomatic", mgr)
00046 {
00047
QString PATH = getenv(
"PATH");
00048 PATH.append(
":/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
00049 m_exematicpath = KStandardDirs::findExe(
"lpdomatic", PATH);
00050 m_ncpath = KStandardDirs::findExe(
"nc");
00051 m_smbpath = KStandardDirs::findExe(
"smbclient");
00052 m_rlprpath = KStandardDirs::findExe(
"rlpr");
00053 }
00054
00055
bool MaticHandler::validate(PrintcapEntry *entry)
00056 {
00057
if (entry)
00058
return (entry->field(
"if").right(9) ==
"lpdomatic");
00059
return false;
00060 }
00061
00062 KMPrinter* MaticHandler::createPrinter(PrintcapEntry *entry)
00063 {
00064
if (entry && validate(entry))
00065 {
00066 KMPrinter *prt =
new KMPrinter;
00067 prt->setName(entry->name);
00068 prt->setPrinterName(entry->name);
00069 prt->setType(KMPrinter::Printer);
00070
00071
00072
return prt;
00073 }
00074
return NULL;
00075 }
00076
00077
bool MaticHandler::completePrinter(KMPrinter *prt, PrintcapEntry *entry,
bool shortmode)
00078 {
00079
QString val = entry->field(
"lp");
00080
if (val ==
"/dev/null" || val.isEmpty())
00081 {
00082 prt->setLocation(i18n(
"Network printer"));
00083 }
00084
else
00085 {
00086 prt->setLocation(i18n(
"Local printer on %1").arg(val));
00087 KURL url(val);
00088
if (val.find(
"usb") != -1)
00089 url.setProtocol(
"usb");
00090
else
00091 url.setProtocol(
"parallel");
00092 prt->setDevice(url.url());
00093 }
00094 prt->setDescription(entry->aliases.join(
", "));
00095
00096
if (!shortmode)
00097 {
00098 Foomatic2Loader loader;
00099
if ( loader.readFromFile( maticFile( entry ) ) )
00100 {
00101
QString postpipe = loader.data()[
"POSTPIPE" ].toString();
00102
if (!postpipe.isEmpty())
00103 {
00104 KURL url ( parsePostpipe(postpipe) );
00105
if (!url.isEmpty())
00106 {
00107
QString ds = QString::fromLatin1(
"%1 (%2)").arg(prt->location()).arg(url.protocol());
00108 prt->setDevice(url.url());
00109 prt->setLocation(ds);
00110 }
00111 }
00112
00113
QMap<QString,QVariant> m = loader.data()[
"VAR" ].toMap();
00114
if ( !m.isEmpty() )
00115 {
00116 prt->setManufacturer(m[
"make"].toString());
00117 prt->setModel(m[
"model"].toString());
00118 prt->setDriverInfo(QString::fromLatin1(
"%1 %2 (%3)").arg(prt->manufacturer()).arg(prt->model()).arg(m[
"driver"].toString()));
00119 }
00120 }
00121 }
00122
00123
return true;
00124 }
00125
00126
QString MaticHandler::parsePostpipe(
const QString& s)
00127 {
00128
QString url;
00129
int p = s.findRev(
'|');
00130
QStringList args = QStringList::split(
" ", s.right(s.length()-p-1));
00131
00132
if (args.count() != 0)
00133 {
00134
00135
if (args[0].right(3) ==
"/nc")
00136 {
00137 url =
"socket://" + args[ 1 ];
00138
if ( args.count() > 2 )
00139 url +=
":" + args[ 2 ];
00140
else
00141 url +=
":9100";
00142 }
00143
00144
else if (args[0].right(10) ==
"/smbclient")
00145 {
00146
QStringList host_components = QStringList::split(
QRegExp(
"/|\\\\\""), args[1],
false);
00147
QString workgrp, user, pass;
00148
for (uint i=2; i<args.count(); i++)
00149 {
00150
if (args[i] ==
"-U")
00151 user = args[++i];
00152
else if (args[i] ==
"-W")
00153 workgrp = args[++i];
00154
else if (args[i][0] !=
'-' && i == 2)
00155 pass = args[i];
00156 }
00157 url = buildSmbURI( workgrp, host_components[ 0 ], host_components[ 1 ], user, pass );
00158 }
00159
00160
else if (args[0].right(5) ==
"/rlpr")
00161 {
00162 uint i=1;
00163
while (i < args.count())
00164 {
00165
if (args[i].left(2) !=
"-P")
00166 i++;
00167
else
00168 {
00169
QString host = (args[i].length() == 2 ? args[i+1] : args[i].right(args[i].length()-2));
00170
int p = host.find(
"\\@");
00171
if (p != -1)
00172 {
00173 url =
"lpd://" + host.right(host.length()-p-2) +
"/" + host.left(p);
00174 }
00175
break;
00176 }
00177 }
00178 }
00179 }
00180
00181
return url;
00182 }
00183
00184
QString MaticHandler::createPostpipe(
const QString& _url)
00185 {
00186 KURL url( _url );
00187
QString prot = url.protocol();
00188
QString str;
00189
if (prot ==
"socket")
00190 {
00191 str += (
"| " + m_ncpath);
00192 str += (
" " + url.host());
00193
if (url.port() != 0)
00194 str += (
" " + QString::number(url.port()));
00195 }
00196
else if (prot ==
"lpd")
00197 {
00198 str += (
"| " + m_rlprpath +
" -q -h");
00199
QString h = url.host(), p = url.path().mid(1);
00200 str += (
" -P " + p +
"\\@" + h);
00201 }
00202
else if (prot ==
"smb")
00203 {
00204
QString work, server, printer, user, passwd;
00205
if ( splitSmbURI( _url, work, server, printer, user, passwd ) )
00206 {
00207 str += (
"| (\\n echo \\\"print -\\\"\\n cat \\n) | " + m_smbpath);
00208 str += (
" \\\"//" + server +
"/" + printer +
"\\\"");
00209
if (!passwd.isEmpty())
00210 str += (
" " + passwd);
00211
if (!user.isEmpty())
00212 str += (
" -U " + user);
00213
if (!work.isEmpty())
00214 str += (
" -W " + work);
00215 str +=
" -N -P";
00216 }
00217 }
00218
return str;
00219 }
00220
00221 DrMain* MaticHandler::loadDriver(KMPrinter*, PrintcapEntry *entry,
bool)
00222 {
00223
00224
00225
00226
QString origfilename = maticFile(entry);
00227
QString filename = locateLocal(
"tmp",
"foomatic_" + kapp->randomString(8));
00228 ::system(QFile::encodeName(
"cp " + KProcess::quote(origfilename) +
" " + KProcess::quote(filename)));
00229 DrMain *driver = Foomatic2Loader::loadDriver(filename);
00230
if (driver)
00231 {
00232 driver->set(
"template", filename);
00233 driver->set(
"temporary",
"true");
00234
return driver;
00235 }
00236
else
00237
return NULL;
00238 }
00239
00240 DrMain* MaticHandler::loadDbDriver(
const QString& path)
00241 {
00242
QStringList comps = QStringList::split(
'/', path,
false);
00243
if (comps.count() < 3 || comps[0] !=
"foomatic")
00244 {
00245 manager()->setErrorMsg(i18n(
"Internal error."));
00246
return NULL;
00247 }
00248
00249
QString tmpFile = locateLocal(
"tmp",
"foomatic_" + kapp->randomString(8));
00250
QString PATH = getenv(
"PATH") + QString::fromLatin1(
":/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
00251
QString exe = KStandardDirs::findExe(
"foomatic-datafile", PATH);
00252
if (exe.isEmpty())
00253 {
00254 manager()->setErrorMsg(i18n(
"Unable to find the executable foomatic-datafile "
00255
"in your PATH. Check that Foomatic is correctly installed."));
00256
return NULL;
00257 }
00258
00259 KPipeProcess in;
00260
QFile out(tmpFile);
00261
QString cmd = KProcess::quote(exe);
00262 cmd +=
" -t lpd -d ";
00263 cmd += KProcess::quote(comps[2]);
00264 cmd +=
" -p ";
00265 cmd += KProcess::quote(comps[1]);
00266
if (in.open(cmd) && out.open(IO_WriteOnly))
00267 {
00268
QTextStream tin(&in), tout(&out);
00269
QString line;
00270
while (!tin.atEnd())
00271 {
00272 line = tin.readLine();
00273 tout << line << endl;
00274 }
00275 in.close();
00276 out.close();
00277
00278 DrMain *driver = Foomatic2Loader::loadDriver(tmpFile);
00279
if (driver)
00280 {
00281 driver->set(
"template", tmpFile);
00282 driver->set(
"temporary", tmpFile);
00283
return driver;
00284 }
00285 }
00286 manager()->setErrorMsg(i18n(
"Unable to create the Foomatic driver [%1,%2]. "
00287
"Either that driver does not exist, or you don't have "
00288
"the required permissions to perform that operation.").arg(comps[1]).arg(comps[2]));
00289
return NULL;
00290 }
00291
00292
bool MaticHandler::savePrinterDriver(KMPrinter *prt, PrintcapEntry *entry, DrMain *driver,
bool*)
00293 {
00294
QFile tmpFile(locateLocal(
"tmp",
"foomatic_" + kapp->randomString(8)));
00295
QFile inFile(driver->get(
"template"));
00296
QString outFile = maticFile(entry);
00297
bool result(
false);
00298
QString postpipe = createPostpipe(prt->device());
00299
00300
if (inFile.open(IO_ReadOnly) && tmpFile.open(IO_WriteOnly))
00301 {
00302
QTextStream tin(&inFile), tout(&tmpFile);
00303
QString line, optname;
00304
int p(-1), q(-1);
00305
if (!postpipe.isEmpty())
00306 tout <<
"$postpipe = \"" << postpipe <<
"\";" << endl;
00307
while (!tin.atEnd())
00308 {
00309 line = tin.readLine();
00310
if (line.stripWhiteSpace().startsWith(
"$postpipe"))
00311
continue;
00312
else if ((p = line.find(
"'name'")) != -1)
00313 {
00314 p = line.find(
'\'', p+6)+1;
00315 q = line.find(
'\'', p);
00316 optname = line.mid(p, q-p);
00317 }
00318
else if ((p = line.find(
"'default'")) != -1)
00319 {
00320 DrBase *opt = driver->findOption(optname);
00321
if (opt)
00322 {
00323 tout << line.left(p+9) <<
" => '" << opt->valueText() <<
"'," << endl;
00324
continue;
00325 }
00326 }
00327 tout << line << endl;
00328 }
00329 inFile.close();
00330 tmpFile.close();
00331
00332
QString cmd =
"mv " + KProcess::quote(tmpFile.name()) +
" " + KProcess::quote(outFile);
00333
int status = ::system(QFile::encodeName(cmd).data());
00334 QFile::remove(tmpFile.name());
00335 result = (status != -1 && WEXITSTATUS(status) == 0);
00336 }
00337
00338
if (!result)
00339 manager()->setErrorMsg(i18n(
"You probably don't have the required permissions "
00340
"to perform that operation."));
00341 QFile::remove(tmpFile.name());
00342
if (!result || entry->field(
"ppdfile").isEmpty())
00343
return result;
00344
else
00345
return savePpdFile(driver, entry->field(
"ppdfile"));
00346 }
00347
00348
bool MaticHandler::savePpdFile(DrMain *driver,
const QString& filename)
00349 {
00350
QString mdriver(driver->get(
"matic_driver")), mprinter(driver->get(
"matic_printer"));
00351
if (mdriver.isEmpty() || mprinter.isEmpty())
00352
return true;
00353
00354
QString PATH = getenv(
"PATH") + QString::fromLatin1(
":/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
00355
QString exe = KStandardDirs::findExe(
"foomatic-datafile", PATH);
00356
if (exe.isEmpty())
00357 {
00358 manager()->setErrorMsg(i18n(
"Unable to find the executable foomatic-datafile "
00359
"in your PATH. Check that Foomatic is correctly installed."));
00360
return false;
00361 }
00362
00363 KPipeProcess in;
00364
QFile out(filename);
00365
if (in.open(exe +
" -t cups -d " + mdriver +
" -p " + mprinter) && out.open(IO_WriteOnly))
00366 {
00367
QTextStream tin(&in), tout(&out);
00368
QString line, optname;
00369
QRegExp re(
"^\\*Default(\\w+):"), foo(
"'name'\\s+=>\\s+'(\\w+)'"), foo2(
"'\\w+'\\s*,\\s*$");
00370
while (!tin.atEnd())
00371 {
00372 line = tin.readLine();
00373
if (line.startsWith(
"*% COMDATA #"))
00374 {
00375
if (line.find(
"'default'") != -1)
00376 {
00377 DrBase *opt = (optname.isEmpty() ? NULL : driver->findOption(optname));
00378
if (opt)
00379 {
00380 line.replace(foo2,
"'"+opt->valueText()+
"',");
00381 }
00382 }
00383
else if (foo.search(line) != -1)
00384 optname = foo.cap(1);
00385 }
00386
else if (re.search(line) != -1)
00387 {
00388 DrBase *opt = driver->findOption(re.cap(1));
00389
if (opt)
00390 {
00391
QString val = opt->valueText();
00392
if (opt->type() == DrBase::Boolean)
00393 val = (val ==
"1" ?
"True" :
"False");
00394 tout <<
"*Default" << opt->name() <<
": " << val << endl;
00395
continue;
00396 }
00397 }
00398 tout << line << endl;
00399 }
00400 in.close();
00401 out.close();
00402
00403
return true;
00404 }
00405 manager()->setErrorMsg(i18n(
"Unable to create the Foomatic driver [%1,%2]. "
00406
"Either that driver does not exist, or you don't have "
00407
"the required permissions to perform that operation.").arg(mdriver).arg(mprinter));
00408
00409
return false;
00410 }
00411
00412 PrintcapEntry* MaticHandler::createEntry(KMPrinter *prt)
00413 {
00414 KURL url( prt->device() );
00415
QString prot = url.protocol();
00416
if ((prot !=
"lpd" || m_rlprpath.isEmpty()) &&
00417 (prot !=
"socket" || m_ncpath.isEmpty()) &&
00418 (prot !=
"smb" || m_smbpath.isEmpty()) &&
00419 prot !=
"parallel")
00420 {
00421 manager()->setErrorMsg(i18n(
"Unsupported backend: %1.").arg(prot));
00422
return NULL;
00423 }
00424
if (m_exematicpath.isEmpty())
00425 {
00426 manager()->setErrorMsg(i18n(
"Unable to find executable lpdomatic. "
00427
"Check that Foomatic is correctly installed "
00428
"and that lpdomatic is installed in a standard "
00429
"location."));
00430
return NULL;
00431 }
00432 PrintcapEntry *entry =
new PrintcapEntry;
00433 entry->addField(
"lf", Field::String,
"/var/log/lp-errs");
00434 entry->addField(
"lp", Field::String, (prot !=
"parallel" ?
"/dev/null" : url.path()));
00435 entry->addField(
"if", Field::String, m_exematicpath);
00436
if (LprSettings::self()->mode() == LprSettings::LPRng)
00437 {
00438 entry->addField(
"filter_options", Field::String,
" --lprng $Z /etc/foomatic/lpd/"+prt->printerName()+
".lom");
00439 entry->addField(
"force_localhost", Field::Boolean);
00440 entry->addField(
"ppdfile", Field::String,
"/etc/foomatic/"+prt->printerName()+
".ppd");
00441 }
00442
else
00443 entry->addField(
"af", Field::String,
"/etc/foomatic/lpd/"+prt->printerName()+
".lom");
00444
if (!prt->description().isEmpty())
00445 entry->aliases << prt->description();
00446
return entry;
00447 }
00448
00449
bool MaticHandler::removePrinter(KMPrinter *prt, PrintcapEntry *entry)
00450 {
00451
00452
QString af = entry->field(
"af");
00453
if (af.isEmpty())
00454
return true;
00455
if (!QFile::remove(af))
00456 {
00457 manager()->setErrorMsg(i18n(
"Unable to remove driver file %1.").arg(af));
00458
return false;
00459 }
00460
return true;
00461 }
00462
00463
QString MaticHandler::printOptions(
KPrinter *printer)
00464 {
00465
QMap<QString,QString> opts = printer->
options();
00466
QString str;
00467
for (
QMap<QString,QString>::Iterator it=opts.begin(); it!=opts.end(); ++it)
00468 {
00469
if (it.key().startsWith(
"kde-") || it.key().startsWith(
"_kde-") || it.key().startsWith(
"app-" ))
00470
continue;
00471 str += (
" " + it.key() +
"=" + (*it));
00472 }
00473
if (!str.isEmpty())
00474 str.prepend(
"-J '").append(
"'");
00475
return str;
00476 }
00477
00478
QString MaticHandler::driverDirInternal()
00479 {
00480
return locateDir(
"foomatic/db/source",
"/usr/share:/usr/local/share:/opt/share");
00481 }