kdeprint Library API Documentation

matichandler.cpp

00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (c) 2001 Michael Goffioul <kdeprint@swing.be>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License version 2 as published by the Free Software Foundation.
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  *  Boston, MA 02111-1307, USA.
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         //if (entry->field("lp") == "/dev/null" || entry->field("lp").isEmpty())
00071         //  prt->addType(KMPrinter::Remote);
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         // socket printer
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         // smb printer
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         // remote printer
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("\\@");
                    if (p != -1)
                    {
                        url = "lpd://" + host.right(host.length()-p-2) + "/" + host.left(p);
00171                     }
00172                     break;
00173                 }
00174             }
00175         }
00176     }
00177 
00178     return url;
00179 }
00180 
00181 QString MaticHandler::createPostpipe(const QString& _url)
00182 {
00183     KURL url( _url );
00184     QString prot = url.protocol();
00185     QString str;
00186     if (prot == "socket")
00187     {
00188         str += ("| " + m_ncpath);
00189         str += (" " + url.host());
00190         if (url.port() != 0)
00191             str += (" " + QString::number(url.port()));
00192     }
00193     else if (prot == "lpd")
00194     {
00195         str += ("| " + m_rlprpath + " -q -h");
00196         QString h = url.host(), p = url.path().mid(1);
00197         str += (" -P " + p + "\\@" + h);
    }
    else if (prot == "smb")
00198     {
00199         QString work, server, printer, user, passwd;
00200         if ( splitSmbURI( _url, work, server, printer, user, passwd ) )
00201         {
00202             str += ("| (\\n echo \\\"print -\\\"\\n cat \\n) | " + m_smbpath);
00203             str += (" \\\"//" + server + "/" + printer + "\\\"");
00204             if (!passwd.isEmpty())
00205                 str += (" " + passwd);
00206             if (!user.isEmpty())
00207                 str += (" -U " + user);
00208             if (!work.isEmpty())
00209                 str += (" -W " + work);
00210             str += " -N -P";
00211         }
00212     }
00213     return str;
00214 }
00215 
00216 DrMain* MaticHandler::loadDriver(KMPrinter*, PrintcapEntry *entry, bool)
00217 {
00218     // we need to use a copy of the driver, as the driver
00219     // is not self-contained. If the printer is removed (when
00220     // changing printer name), the template would be also removed
00221     QString origfilename = maticFile(entry);
00222     QString filename = locateLocal("tmp", "foomatic_" + kapp->randomString(8));
00223     ::system(QFile::encodeName("cp " + KProcess::quote(origfilename) + " " + KProcess::quote(filename)));
00224     DrMain  *driver = Foomatic2Loader::loadDriver(filename);
00225     if (driver)
00226     {
00227         driver->set("template", filename);
00228         driver->set("temporary", "true");
00229         return driver;
00230     }
00231     else
00232         return NULL;
00233 }
00234 
00235 DrMain* MaticHandler::loadDbDriver(const QString& path)
00236 {
00237     QStringList comps = QStringList::split('/', path, false);
00238     if (comps.count() < 3 || comps[0] != "foomatic")
00239     {
00240         manager()->setErrorMsg(i18n("Internal error."));
00241         return NULL;
00242     }
00243 
00244     QString tmpFile = locateLocal("tmp", "foomatic_" + kapp->randomString(8));
00245     QString PATH = getenv("PATH") + QString::fromLatin1(":/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
00246     QString exe = KStandardDirs::findExe("foomatic-datafile", PATH);
00247     if (exe.isEmpty())
00248     {
00249         manager()->setErrorMsg(i18n("Unable to find the executable foomatic-datafile "
00250                                     "in your PATH. Check that Foomatic is correctly installed."));
00251         return NULL;
00252     }
00253 
00254     KPipeProcess    in;
00255     QFile       out(tmpFile);
00256     QString cmd = KProcess::quote(exe);
00257     cmd += " -t lpd -d ";
00258     cmd += KProcess::quote(comps[2]);
00259     cmd += " -p ";
00260     cmd += KProcess::quote(comps[1]);
00261     if (in.open(cmd) && out.open(IO_WriteOnly))
00262     {
00263         QTextStream tin(&in), tout(&out);
00264         QString line;
00265         while (!tin.atEnd())
00266         {
00267             line = tin.readLine();
00268             tout << line << endl;
00269         }
00270         in.close();
00271         out.close();
00272 
00273         DrMain  *driver = Foomatic2Loader::loadDriver(tmpFile);
00274         if (driver)
00275         {
00276             driver->set("template", tmpFile);
00277             driver->set("temporary", tmpFile);
00278             return driver;
00279         }
00280     }
00281     manager()->setErrorMsg(i18n("Unable to create the Foomatic driver [%1,%2]. "
00282                                 "Either that driver does not exist, or you don't have "
00283                                 "the required permissions to perform that operation.").arg(comps[1]).arg(comps[2]));
00284     return NULL;
00285 }
00286 
00287 bool MaticHandler::savePrinterDriver(KMPrinter *prt, PrintcapEntry *entry, DrMain *driver, bool*)
00288 {
00289     QFile   tmpFile(locateLocal("tmp", "foomatic_" + kapp->randomString(8)));
00290     QFile   inFile(driver->get("template"));
00291     QString outFile = maticFile(entry);
00292     bool    result(false);
00293     QString postpipe = createPostpipe(prt->device());
00294 
00295     if (inFile.open(IO_ReadOnly) && tmpFile.open(IO_WriteOnly))
00296     {
00297         QTextStream tin(&inFile), tout(&tmpFile);
00298         QString line, optname;
00299         int p(-1), q(-1);
00300         if (!postpipe.isEmpty())
00301             tout << "$postpipe = \"" << postpipe << "\";" << endl;
00302         while (!tin.atEnd())
00303         {
00304             line = tin.readLine();
00305             if (line.stripWhiteSpace().startsWith("$postpipe"))
00306                 continue;
00307             else if ((p = line.find("'name'")) != -1)
00308             {
00309                 p = line.find('\'', p+6)+1;
00310                 q = line.find('\'', p);
00311                 optname = line.mid(p, q-p);
00312             }
00313             else if ((p = line.find("'default'")) != -1)
00314             {
00315                 DrBase  *opt = driver->findOption(optname);
00316                 if (opt)
00317                 {
00318                     tout << line.left(p+9) << " => '" << opt->valueText() << "'," << endl;
00319                     continue;
00320                 }
00321             }
00322             tout << line << endl;
00323         }
00324         inFile.close();
00325         tmpFile.close();
00326 
00327         QString cmd = "mv " + KProcess::quote(tmpFile.name()) + " " + KProcess::quote(outFile);
00328         int status = ::system(QFile::encodeName(cmd).data());
00329         QFile::remove(tmpFile.name());
00330         result = (status != -1 && WEXITSTATUS(status) == 0);
00331     }
00332 
00333     if (!result)
00334         manager()->setErrorMsg(i18n("You probably don't have the required permissions "
00335                                     "to perform that operation."));
00336     QFile::remove(tmpFile.name());
00337     if (!result || entry->field("ppdfile").isEmpty())
00338         return result;
00339     else
00340         return savePpdFile(driver, entry->field("ppdfile"));
00341 }
00342 
00343 bool MaticHandler::savePpdFile(DrMain *driver, const QString& filename)
00344 {
00345     QString mdriver(driver->get("matic_driver")), mprinter(driver->get("matic_printer"));
00346     if (mdriver.isEmpty() || mprinter.isEmpty())
00347         return true;
00348 
00349     QString PATH = getenv("PATH") + QString::fromLatin1(":/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
00350     QString exe = KStandardDirs::findExe("foomatic-datafile", PATH);
00351     if (exe.isEmpty())
00352     {
00353         manager()->setErrorMsg(i18n("Unable to find the executable foomatic-datafile "
00354                                     "in your PATH. Check that Foomatic is correctly installed."));
00355         return false;
00356     }
00357 
00358     KPipeProcess    in;
00359     QFile       out(filename);
00360     if (in.open(exe + " -t cups -d " + mdriver + " -p " + mprinter) && out.open(IO_WriteOnly))
00361     {
00362         QTextStream tin(&in), tout(&out);
00363         QString line, optname;
00364         QRegExp re("^\\*Default(\\w+):"), foo("'name'\\s+=>\\s+'(\\w+)'"), foo2("'\\w+'\\s*,\\s*$");
00365         while (!tin.atEnd())
00366         {
00367             line = tin.readLine();
00368             if (line.startsWith("*% COMDATA #"))
00369             {
00370                 if (line.find("'default'") != -1)
00371                 {
00372                     DrBase  *opt = (optname.isEmpty() ? NULL : driver->findOption(optname));
00373                     if (opt)
00374                     {
00375                         line.replace(foo2, "'"+opt->valueText()+"',");
00376                     }
00377                 }
00378                 else if (foo.search(line) != -1)
00379                     optname = foo.cap(1);
00380             }
00381             else if (re.search(line) != -1)
00382             {
00383                 DrBase  *opt = driver->findOption(re.cap(1));
00384                 if (opt)
00385                 {
00386                     QString val = opt->valueText();
00387                     if (opt->type() == DrBase::Boolean)
00388                         val = (val == "1" ? "True" : "False");
00389                     tout << "*Default" << opt->name() << ": " << val << endl;
00390                     continue;
00391                 }
00392             }
00393             tout << line << endl;
00394         }
00395         in.close();
00396         out.close();
00397 
00398         return true;
00399     }
00400     manager()->setErrorMsg(i18n("Unable to create the Foomatic driver [%1,%2]. "
00401                                 "Either that driver does not exist, or you don't have "
00402                                 "the required permissions to perform that operation.").arg(mdriver).arg(mprinter));
00403     
00404     return false;
00405 }
00406 
00407 PrintcapEntry* MaticHandler::createEntry(KMPrinter *prt)
00408 {
00409     KURL url( prt->device() );
00410     QString prot = url.protocol();
00411     if ((prot != "lpd" || m_rlprpath.isEmpty()) &&
00412         (prot != "socket" || m_ncpath.isEmpty()) &&
00413         (prot != "smb" || m_smbpath.isEmpty()) &&
00414          prot != "parallel")
00415     {
00416         manager()->setErrorMsg(i18n("Unsupported backend: %1.").arg(prot));
00417         return NULL;
00418     }
00419     if (m_exematicpath.isEmpty())
00420     {
00421         manager()->setErrorMsg(i18n("Unable to find executable lpdomatic. "
00422                                     "Check that Foomatic is correctly installed "
00423                                     "and that lpdomatic is installed in a standard "
00424                                     "location."));
00425         return NULL;
00426     }
00427     PrintcapEntry   *entry = new PrintcapEntry;
00428     entry->addField("lf", Field::String, "/var/log/lp-errs");
00429     entry->addField("lp", Field::String, (prot != "parallel" ? "/dev/null" : url.path()));
00430     entry->addField("if", Field::String, m_exematicpath);
00431     if (LprSettings::self()->mode() == LprSettings::LPRng)
00432     {
00433         entry->addField("filter_options", Field::String, " --lprng $Z /etc/foomatic/lpd/"+prt->printerName()+".lom");
00434         entry->addField("force_localhost", Field::Boolean);
00435         entry->addField("ppdfile", Field::String, "/etc/foomatic/"+prt->printerName()+".ppd");
00436     }
00437     else
00438         entry->addField("af", Field::String, "/etc/foomatic/lpd/"+prt->printerName()+".lom");
00439     if (!prt->description().isEmpty())
00440         entry->aliases << prt->description();
00441     return entry;
00442 }
00443 
00444 bool MaticHandler::removePrinter(KMPrinter *prt, PrintcapEntry *entry)
00445 {
00446     // remove Foomatic driver
00447     QString af = entry->field("af");
00448     if (af.isEmpty())
00449         return true;
00450     if (!QFile::remove(af))
00451     {
00452         manager()->setErrorMsg(i18n("Unable to remove driver file %1.").arg(af));
00453         return false;
00454     }
00455     return true;
00456 }
00457 
00458 QString MaticHandler::printOptions(KPrinter *printer)
00459 {
00460     QMap<QString,QString>   opts = printer->options();
00461     QString str;
00462     for (QMap<QString,QString>::Iterator it=opts.begin(); it!=opts.end(); ++it)
00463     {
00464         if (it.key().startsWith("kde-") || it.key().startsWith("_kde-") || it.key().startsWith( "app-" ))
00465             continue;
00466         str += (" " + it.key() + "=" + (*it));
00467     }
00468     if (!str.isEmpty())
00469         str.prepend("-J '").append("'");
00470     return str;
00471 }
00472 
00473 QString MaticHandler::driverDirInternal()
00474 {
00475     return locateDir("foomatic/db/source", "/usr/share:/usr/local/share:/opt/share");
00476 }
00477 
KDE Logo
This file is part of the documentation for kdeprint Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 5 07:17:51 2004 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003