kmcupsjobmanager.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., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 
00020 #include "kmcupsjobmanager.h"
00021 #include "kmcupsmanager.h"
00022 #include "kmjob.h"
00023 #include "cupsinfos.h"
00024 #include "ipprequest.h"
00025 #include "pluginaction.h"
00026 #include "kprinter.h"
00027 #include "kprinterpropertydialog.h"
00028 #include "kmuimanager.h"
00029 #include "kmfactory.h"
00030 #include "kpdriverpage.h"
00031 #include "kpschedulepage.h"
00032 #include "kpcopiespage.h"
00033 #include "kptagspage.h"
00034 
00035 #include <klocale.h>
00036 #include <kdebug.h>
00037 #include <kurl.h>
00038 
00039 KMCupsJobManager::KMCupsJobManager(QObject *parent, const char *name, const QStringList & /*args*/)
00040 : KMJobManager(parent,name)
00041 {
00042 }
00043 
00044 KMCupsJobManager::~KMCupsJobManager()
00045 {
00046 }
00047 
00048 int KMCupsJobManager::actions()
00049 {
00050     return KMJob::All;
00051 }
00052 
00053 bool KMCupsJobManager::sendCommandSystemJob(const QPtrList<KMJob>& jobs, int action, const QString& argstr)
00054 {
00055     IppRequest  req;
00056     QString     uri;
00057     bool        value(true);
00058 
00059     QPtrListIterator<KMJob> it(jobs);
00060     for (;it.current() && value;++it)
00061     {
00062         // hypothesis: job operation are always done on local jobs. The only operation
00063         // allowed on remote jobs is listing (done elsewhere).
00064 
00065         req.addURI(IPP_TAG_OPERATION,"job-uri",it.current()->uri());
00066         req.addName(IPP_TAG_OPERATION,"requesting-user-name",CupsInfos::self()->login());
00067         /*
00068         QString jobHost;
00069         if (!it.current()->uri().isEmpty())
00070         {
00071             KURL    url(it.current()->uri());
00072             req.setHost(url.host());
00073             req.setPort(url.port());
00074             jobHost = url.host();
00075         }
00076         */
00077 
00078         switch (action)
00079         {
00080             case KMJob::Remove:
00081                 req.setOperation(IPP_CANCEL_JOB);
00082                 break;
00083             case KMJob::Hold:
00084                 req.setOperation(IPP_HOLD_JOB);
00085                 break;
00086             case KMJob::Resume:
00087                 req.setOperation(IPP_RELEASE_JOB);
00088                 break;
00089             case KMJob::Restart:
00090                 req.setOperation(IPP_RESTART_JOB);
00091                 break;
00092             case KMJob::Move:
00093                 if (argstr.isEmpty()) return false;
00094                 req.setOperation(CUPS_MOVE_JOB);
00095                 uri =
00096                     QString::fromLatin1("ipp://%1/printers/%2").arg(CupsInfos::self()->hostaddr(),
00097                         argstr);
00098                 req.addURI(IPP_TAG_OPERATION, "job-printer-uri", uri);
00099                 break;
00100             default:
00101                 return false;
00102         }
00103 
00104         if (!(value = req.doRequest("/jobs/")))
00105             KMManager::self()->setErrorMsg(req.statusMessage());
00106     }
00107 
00108     return value;
00109 }
00110 
00111 bool KMCupsJobManager::listJobs(const QString& prname, KMJobManager::JobType type, int limit)
00112 {
00113     IppRequest  req;
00114     QStringList keys;
00115     CupsInfos   *infos = CupsInfos::self();
00116 
00117     // wanted attributes
00118     keys.append("job-id");
00119     keys.append("job-uri");
00120     keys.append("job-name");
00121     keys.append("job-state");
00122     keys.append("job-printer-uri");
00123     keys.append("job-k-octets");
00124     keys.append("job-originating-user-name");
00125     keys.append("job-k-octets-completed");
00126     keys.append("job-media-sheets");
00127     keys.append("job-media-sheets-completed");
00128     keys.append("job-priority");
00129     keys.append("job-billing");
00130 
00131     req.setOperation(IPP_GET_JOBS);
00132 
00133     // add printer-uri
00134     KMPrinter *mp = KMManager::self()->findPrinter(prname);
00135     if (!mp)
00136         return false;
00137 
00138     if (!mp->uri().isEmpty())
00139     {
00140         req.addURI(IPP_TAG_OPERATION, "printer-uri", mp->uri().prettyURL());
00141         /*
00142         req.setHost(mp->uri().host());
00143         req.setPort(mp->uri().port());
00144         */
00145     }
00146     else
00147         req.addURI(IPP_TAG_OPERATION, "printer-uri", QString("ipp://%1/%2/%3").arg(infos->hostaddr(),
00148                             (mp&&mp->isClass())?"classes":"printers", prname));
00149 
00150     // other attributes
00151     req.addKeyword(IPP_TAG_OPERATION, "requested-attributes", keys);
00152     if (type == KMJobManager::CompletedJobs)
00153         req.addKeyword(IPP_TAG_OPERATION,"which-jobs",QString::fromLatin1("completed"));
00154     if (limit > 0)
00155         req.addInteger(IPP_TAG_OPERATION,"limit",limit);
00156 
00157     // send request
00158     if (req.doRequest("/"))
00159         parseListAnswer(req, mp);
00160     else
00161         return false;
00162 
00163     return true;
00164 }
00165 
00166 void KMCupsJobManager::parseListAnswer(IppRequest& req, KMPrinter *pr)
00167 {
00168     ipp_attribute_t *attr = req.first();
00169     KMJob       *job = new KMJob();
00170     QString     uri;
00171     while (attr)
00172     {
00173         QString name(attr->name);
00174         if (name == "job-id") job->setId(attr->values[0].integer);
00175         else if (name == "job-uri") job->setUri(QString::fromLocal8Bit(attr->values[0].string.text));
00176         else if (name == "job-name") job->setName(QString::fromLocal8Bit(attr->values[0].string.text));
00177         else if (name == "job-state")
00178         {
00179             switch (attr->values[0].integer)
00180             {
00181                 case IPP_JOB_PENDING:
00182                     job->setState(KMJob::Queued);
00183                     break;
00184                 case IPP_JOB_HELD:
00185                     job->setState(KMJob::Held);
00186                     break;
00187                 case IPP_JOB_PROCESSING:
00188                     job->setState(KMJob::Printing);
00189                     break;
00190                 case IPP_JOB_STOPPED:
00191                     job->setState(KMJob::Error);
00192                     break;
00193                 case IPP_JOB_CANCELLED:
00194                     job->setState(KMJob::Cancelled);
00195                     break;
00196                 case IPP_JOB_ABORTED:
00197                     job->setState(KMJob::Aborted);
00198                     break;
00199                 case IPP_JOB_COMPLETED:
00200                     job->setState(KMJob::Completed);
00201                     break;
00202                 default:
00203                     job->setState(KMJob::Unknown);
00204                     break;
00205             }
00206         }
00207         else if (name == "job-k-octets") job->setSize(attr->values[0].integer);
00208         else if (name == "job-originating-user-name") job->setOwner(QString::fromLocal8Bit(attr->values[0].string.text));
00209         else if (name == "job-k-octets-completed") job->setProcessedSize(attr->values[0].integer);
00210         else if (name == "job-media-sheets") job->setPages(attr->values[0].integer);
00211         else if (name == "job-media-sheets-completed") job->setProcessedPages(attr->values[0].integer);
00212         else if (name == "job-printer-uri" && !pr->isRemote())
00213         {
00214             QString str(attr->values[0].string.text);
00215             int p = str.findRev('/');
00216             if (p != -1)
00217                 job->setPrinter(str.mid(p+1));
00218         }
00219         else if (name == "job-priority")
00220         {
00221             job->setAttribute(0, QString::fromLatin1("%1").arg(attr->values[0].integer, 3));
00222         }
00223         else if (name == "job-billing")
00224         {
00225             job->setAttributeCount(2);
00226             job->setAttribute(1, QString::fromLocal8Bit(attr->values[0].string.text));
00227         }
00228 
00229         if (name.isEmpty() || attr == req.last())
00230         {
00231             if (job->printer().isEmpty())
00232                 job->setPrinter(pr->printerName());
00233             job->setRemote(pr->isRemote());
00234             addJob(job);    // don't use job after this call !!!
00235             job = new KMJob();
00236         }
00237 
00238         attr = attr->next;
00239     }
00240     delete job;
00241 }
00242 
00243 bool KMCupsJobManager::doPluginAction(int ID, const QPtrList<KMJob>& jobs)
00244 {
00245     switch (ID)
00246     {
00247         case 0:
00248             if (jobs.count() == 1)
00249                 return jobIppReport(jobs.getFirst());
00250             break;
00251         case 1:
00252             return changePriority(jobs, true);
00253         case 2:
00254             return changePriority(jobs, false);
00255         case 3:
00256             return editJobAttributes(jobs.getFirst());
00257     }
00258     return false;
00259 }
00260 
00261 bool KMCupsJobManager::jobIppReport(KMJob *j)
00262 {
00263     IppRequest  req;
00264 
00265     req.setOperation(IPP_GET_JOB_ATTRIBUTES);
00266     req.addURI(IPP_TAG_OPERATION, "job-uri", j->uri());
00267     bool    result(true);
00268     /*
00269     if (!j->uri().isEmpty())
00270     {
00271         KURL    url(j->uri());
00272         req.setHost(url.host());
00273         req.setPort(url.port());
00274     }
00275     */
00276     if ((result=req.doRequest("/")))
00277         static_cast<KMCupsManager*>(KMManager::self())->ippReport(req, IPP_TAG_JOB, i18n("Job Report"));
00278     else
00279         KMManager::self()->setErrorMsg(i18n("Unable to retrieve job information: ")+req.statusMessage());
00280     return result;
00281 }
00282 
00283 QValueList<KAction*> KMCupsJobManager::createPluginActions(KActionCollection *coll)
00284 {
00285     QValueList<KAction*>    list;
00286     KAction *act(0);
00287 
00288     list <<  (act = new PluginAction(0, i18n("&Job IPP Report"), "kdeprint_report", 0, coll, "plugin_ipp"));
00289     act->setGroup("plugin");
00290     list << (act = new PluginAction(1, i18n("&Increase Priority"), "up", 0, coll, "plugin_prioup"));
00291     act->setGroup("plugin");
00292     list << (act = new PluginAction(2, i18n("&Decrease Priority"), "down", 0, coll, "plugin_priodown"));
00293     act->setGroup("plugin");
00294     list << (act = new PluginAction(3, i18n("&Edit Attributes..."), "edit", 0, coll, "plugin_editjob"));
00295     act->setGroup("plugin");
00296 
00297     return list;
00298 }
00299 
00300 void KMCupsJobManager::validatePluginActions(KActionCollection *coll, const QPtrList<KMJob>& joblist)
00301 {
00302     QPtrListIterator<KMJob> it(joblist);
00303     bool    flag(true);
00304     for (; it.current(); ++it)
00305     {
00306         flag = (flag && it.current()->type() == KMJob::System
00307                 && (it.current()->state() == KMJob::Queued || it.current()->state() == KMJob::Held)
00308             /*&& !it.current()->isRemote()*/);
00309     }
00310     flag = (flag && joblist.count() > 0);
00311     KAction *a;
00312     if ( ( a = coll->action( "plugin_ipp" ) ) )
00313         a->setEnabled( joblist.count() == 1 );
00314     if ( ( a = coll->action( "plugin_prioup" ) ) )
00315         a->setEnabled( flag );
00316     if ( ( a = coll->action( "plugin_priodown" ) ) )
00317         a->setEnabled( flag );
00318     if ( ( a = coll->action( "plugin_editjob" ) ) )
00319         a->setEnabled( flag && ( joblist.count() == 1 ) );
00320 }
00321 
00322 bool KMCupsJobManager::changePriority(const QPtrList<KMJob>& jobs, bool up)
00323 {
00324     QPtrListIterator<KMJob> it(jobs);
00325     bool    result(true);
00326     for (; it.current() && result; ++it)
00327     {
00328         int value = it.current()->attribute(0).toInt();
00329         if (up) value = QMIN(value+10, 100);
00330         else value = QMAX(value-10, 1);
00331 
00332         IppRequest  req;
00333         /*
00334         if (!it.current()->uri().isEmpty())
00335         {
00336             KURL    url(it.current()->uri());
00337             req.setHost(url.host());
00338             req.setPort(url.port());
00339         }
00340         */
00341         req.setOperation(IPP_SET_JOB_ATTRIBUTES);
00342         req.addURI(IPP_TAG_OPERATION, "job-uri", it.current()->uri());
00343         req.addName(IPP_TAG_OPERATION, "requesting-user-name", CupsInfos::self()->login());
00344         req.addInteger(IPP_TAG_JOB, "job-priority", value);
00345 
00346         if (!(result = req.doRequest("/jobs/")))
00347             KMManager::self()->setErrorMsg(i18n("Unable to change job priority: ")+req.statusMessage());
00348     }
00349     return result;
00350 }
00351 
00352 static QString processRange(const QString& range)
00353 {
00354     QStringList l = QStringList::split(',', range, false);
00355     QString s;
00356     for (QStringList::ConstIterator it=l.begin(); it!=l.end(); ++it)
00357     {
00358         s.append(*it);
00359         if ((*it).find('-') == -1)
00360             s.append("-").append(*it);
00361         s.append(",");
00362     }
00363     if (!s.isEmpty())
00364         s.truncate(s.length()-1);
00365     return s;
00366 }
00367 
00368 bool KMCupsJobManager::editJobAttributes(KMJob *j)
00369 {
00370     IppRequest  req;
00371 
00372     req.setOperation(IPP_GET_JOB_ATTRIBUTES);
00373     req.addURI(IPP_TAG_OPERATION, "job-uri", j->uri());
00374     /*
00375     if (!j->uri().isEmpty())
00376     {
00377         KURL    url(j->uri());
00378         req.setHost(url.host());
00379         req.setPort(url.port());
00380     }
00381     */
00382     if (!req.doRequest("/"))
00383     {
00384         KMManager::self()->setErrorMsg(i18n("Unable to retrieve job information: ")+req.statusMessage());
00385         return false;
00386     }
00387 
00388     QMap<QString,QString>   opts = req.toMap(IPP_TAG_JOB);
00389     // translate the "Copies" option to non-CUPS syntax
00390     if (opts.contains("copies"))
00391         opts["kde-copies"] = opts["copies"];
00392     if (opts.contains("page-set"))
00393         opts["kde-pageset"] = (opts["page-set"] == "even" ? "2" : (opts["page-set"] == "odd" ? "1" : "0"));
00394     if (opts.contains("OutputOrder"))
00395         opts["kde-pageorder"] = opts["OutputOrder"];
00396     if (opts.contains("multiple-document-handling"))
00397         opts["kde-collate"] = (opts["multiple-document-handling"] == "separate-documents-collated-copies" ? "Collate" : "Uncollate");
00398     if (opts.contains("page-ranges"))
00399         opts["kde-range"] = opts["page-ranges"];
00400 
00401     // find printer and construct dialog
00402     KMPrinter   *prt = KMManager::self()->findPrinter(j->printer());
00403     if (!prt)
00404     {
00405         KMManager::self()->setErrorMsg(i18n("Unable to find printer %1.").arg(j->printer()));
00406         return false;
00407     }
00408     KMManager::self()->completePrinterShort(prt);
00409     KPrinter::ApplicationType oldAppType = KPrinter::applicationType();
00410     KPrinter::setApplicationType(KPrinter::StandAlone);
00411     KPrinterPropertyDialog  dlg(prt);
00412     dlg.setDriver(KMManager::self()->loadPrinterDriver(prt));
00413     KMFactory::self()->uiManager()->setupPrinterPropertyDialog(&dlg);
00414     KPrinter::setApplicationType( oldAppType );
00415     if (dlg.driver())
00416         dlg.addPage(new KPDriverPage(prt, dlg.driver(), &dlg));
00417     dlg.addPage(new KPCopiesPage(0, &dlg));
00418     dlg.addPage(new KPSchedulePage(&dlg));
00419     dlg.addPage(new KPTagsPage(true, &dlg));
00420     dlg.setOptions(opts);
00421     dlg.enableSaveButton(false);
00422     dlg.setCaption(i18n("Attributes of Job %1@%2 (%3)").arg(j->id()).arg(j->printer()).arg(j->name()));
00423     if (dlg.exec())
00424     {
00425         opts.clear();
00426         // include default values to override non-default values
00427         dlg.getOptions(opts, true);
00428         // translate the "Copies" options from non-CUPS syntax
00429         opts["copies"] = opts["kde-copies"];
00430         opts["OutputOrder"] = opts["kde-pageorder"];
00431         opts["multiple-document-handling"] = (opts["kde-collate"] == "Collate" ? "separate-documents-collated-copies" : "separate-documents-uncollated-copies");
00432         opts["page-set"] = (opts["kde-pageset"] == "1" ? "odd" : (opts["kde-pageset"] == "2" ? "even" : "all"));
00433         // it seems CUPS is buggy. Disable page-ranges modification, otherwise nothing gets printed
00434         opts["page-ranges"] = processRange(opts["kde-range"]);
00435 
00436         req.init();
00437         req.setOperation(IPP_SET_JOB_ATTRIBUTES);
00438         req.addURI(IPP_TAG_OPERATION, "job-uri", j->uri());
00439         req.addName(IPP_TAG_OPERATION, "requesting-user-name", CupsInfos::self()->login());
00440         req.setMap(opts);
00441         //req.dump(1);
00442         if (!req.doRequest("/jobs/"))
00443         {
00444             KMManager::self()->setErrorMsg(i18n("Unable to set job attributes: ")+req.statusMessage());
00445             return false;
00446         }
00447     }
00448 
00449     return true;
00450 }
00451 
00452 #include "kmcupsjobmanager.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys