summaryrefslogtreecommitdiffstats
path: root/kdeprint/cups/kmcupsjobmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdeprint/cups/kmcupsjobmanager.cpp')
-rw-r--r--kdeprint/cups/kmcupsjobmanager.cpp452
1 files changed, 452 insertions, 0 deletions
diff --git a/kdeprint/cups/kmcupsjobmanager.cpp b/kdeprint/cups/kmcupsjobmanager.cpp
new file mode 100644
index 000000000..73f6005d9
--- /dev/null
+++ b/kdeprint/cups/kmcupsjobmanager.cpp
@@ -0,0 +1,452 @@
+/*
+ * 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 "kmcupsjobmanager.h"
+#include "kmcupsmanager.h"
+#include "kmjob.h"
+#include "cupsinfos.h"
+#include "ipprequest.h"
+#include "pluginaction.h"
+#include "kprinter.h"
+#include "kprinterpropertydialog.h"
+#include "kmuimanager.h"
+#include "kmfactory.h"
+#include "kpdriverpage.h"
+#include "kpschedulepage.h"
+#include "kpcopiespage.h"
+#include "kptagspage.h"
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kurl.h>
+
+KMCupsJobManager::KMCupsJobManager(QObject *parent, const char *name, const QStringList & /*args*/)
+: KMJobManager(parent,name)
+{
+}
+
+KMCupsJobManager::~KMCupsJobManager()
+{
+}
+
+int KMCupsJobManager::actions()
+{
+ return KMJob::All;
+}
+
+bool KMCupsJobManager::sendCommandSystemJob(const QPtrList<KMJob>& jobs, int action, const QString& argstr)
+{
+ IppRequest req;
+ QString uri;
+ bool value(true);
+
+ QPtrListIterator<KMJob> it(jobs);
+ for (;it.current() && value;++it)
+ {
+ // hypothesis: job operation are always done on local jobs. The only operation
+ // allowed on remote jobs is listing (done elsewhere).
+
+ req.addURI(IPP_TAG_OPERATION,"job-uri",it.current()->uri());
+ req.addName(IPP_TAG_OPERATION,"requesting-user-name",CupsInfos::self()->login());
+ /*
+ QString jobHost;
+ if (!it.current()->uri().isEmpty())
+ {
+ KURL url(it.current()->uri());
+ req.setHost(url.host());
+ req.setPort(url.port());
+ jobHost = url.host();
+ }
+ */
+
+ switch (action)
+ {
+ case KMJob::Remove:
+ req.setOperation(IPP_CANCEL_JOB);
+ break;
+ case KMJob::Hold:
+ req.setOperation(IPP_HOLD_JOB);
+ break;
+ case KMJob::Resume:
+ req.setOperation(IPP_RELEASE_JOB);
+ break;
+ case KMJob::Restart:
+ req.setOperation(IPP_RESTART_JOB);
+ break;
+ case KMJob::Move:
+ if (argstr.isEmpty()) return false;
+ req.setOperation(CUPS_MOVE_JOB);
+ uri =
+ QString::fromLatin1("ipp://%1/printers/%2").arg(CupsInfos::self()->hostaddr(),
+ argstr);
+ req.addURI(IPP_TAG_OPERATION, "job-printer-uri", uri);
+ break;
+ default:
+ return false;
+ }
+
+ if (!(value = req.doRequest("/jobs/")))
+ KMManager::self()->setErrorMsg(req.statusMessage());
+ }
+
+ return value;
+}
+
+bool KMCupsJobManager::listJobs(const QString& prname, KMJobManager::JobType type, int limit)
+{
+ IppRequest req;
+ QStringList keys;
+ CupsInfos *infos = CupsInfos::self();
+
+ // wanted attributes
+ keys.append("job-id");
+ keys.append("job-uri");
+ keys.append("job-name");
+ keys.append("job-state");
+ keys.append("job-printer-uri");
+ keys.append("job-k-octets");
+ keys.append("job-originating-user-name");
+ keys.append("job-k-octets-completed");
+ keys.append("job-media-sheets");
+ keys.append("job-media-sheets-completed");
+ keys.append("job-priority");
+ keys.append("job-billing");
+
+ req.setOperation(IPP_GET_JOBS);
+
+ // add printer-uri
+ KMPrinter *mp = KMManager::self()->findPrinter(prname);
+ if (!mp)
+ return false;
+
+ if (!mp->uri().isEmpty())
+ {
+ req.addURI(IPP_TAG_OPERATION, "printer-uri", mp->uri().prettyURL());
+ /*
+ req.setHost(mp->uri().host());
+ req.setPort(mp->uri().port());
+ */
+ }
+ else
+ req.addURI(IPP_TAG_OPERATION, "printer-uri", QString("ipp://%1/%2/%3").arg(infos->hostaddr(),
+ (mp&&mp->isClass())?"classes":"printers", prname));
+
+ // other attributes
+ req.addKeyword(IPP_TAG_OPERATION, "requested-attributes", keys);
+ if (type == KMJobManager::CompletedJobs)
+ req.addKeyword(IPP_TAG_OPERATION,"which-jobs",QString::fromLatin1("completed"));
+ if (limit > 0)
+ req.addInteger(IPP_TAG_OPERATION,"limit",limit);
+
+ // send request
+ if (req.doRequest("/"))
+ parseListAnswer(req, mp);
+ else
+ return false;
+
+ return true;
+}
+
+void KMCupsJobManager::parseListAnswer(IppRequest& req, KMPrinter *pr)
+{
+ ipp_attribute_t *attr = req.first();
+ KMJob *job = new KMJob();
+ QString uri;
+ while (attr)
+ {
+ QString name(attr->name);
+ if (name == "job-id") job->setId(attr->values[0].integer);
+ else if (name == "job-uri") job->setUri(QString::fromLocal8Bit(attr->values[0].string.text));
+ else if (name == "job-name") job->setName(QString::fromLocal8Bit(attr->values[0].string.text));
+ else if (name == "job-state")
+ {
+ switch (attr->values[0].integer)
+ {
+ case IPP_JOB_PENDING:
+ job->setState(KMJob::Queued);
+ break;
+ case IPP_JOB_HELD:
+ job->setState(KMJob::Held);
+ break;
+ case IPP_JOB_PROCESSING:
+ job->setState(KMJob::Printing);
+ break;
+ case IPP_JOB_STOPPED:
+ job->setState(KMJob::Error);
+ break;
+ case IPP_JOB_CANCELLED:
+ job->setState(KMJob::Cancelled);
+ break;
+ case IPP_JOB_ABORTED:
+ job->setState(KMJob::Aborted);
+ break;
+ case IPP_JOB_COMPLETED:
+ job->setState(KMJob::Completed);
+ break;
+ default:
+ job->setState(KMJob::Unknown);
+ break;
+ }
+ }
+ else if (name == "job-k-octets") job->setSize(attr->values[0].integer);
+ else if (name == "job-originating-user-name") job->setOwner(QString::fromLocal8Bit(attr->values[0].string.text));
+ else if (name == "job-k-octets-completed") job->setProcessedSize(attr->values[0].integer);
+ else if (name == "job-media-sheets") job->setPages(attr->values[0].integer);
+ else if (name == "job-media-sheets-completed") job->setProcessedPages(attr->values[0].integer);
+ else if (name == "job-printer-uri" && !pr->isRemote())
+ {
+ QString str(attr->values[0].string.text);
+ int p = str.findRev('/');
+ if (p != -1)
+ job->setPrinter(str.mid(p+1));
+ }
+ else if (name == "job-priority")
+ {
+ job->setAttribute(0, QString::fromLatin1("%1").arg(attr->values[0].integer, 3));
+ }
+ else if (name == "job-billing")
+ {
+ job->setAttributeCount(2);
+ job->setAttribute(1, QString::fromLocal8Bit(attr->values[0].string.text));
+ }
+
+ if (name.isEmpty() || attr == req.last())
+ {
+ if (job->printer().isEmpty())
+ job->setPrinter(pr->printerName());
+ job->setRemote(pr->isRemote());
+ addJob(job); // don't use job after this call !!!
+ job = new KMJob();
+ }
+
+ attr = attr->next;
+ }
+ delete job;
+}
+
+bool KMCupsJobManager::doPluginAction(int ID, const QPtrList<KMJob>& jobs)
+{
+ switch (ID)
+ {
+ case 0:
+ if (jobs.count() == 1)
+ return jobIppReport(jobs.getFirst());
+ break;
+ case 1:
+ return changePriority(jobs, true);
+ case 2:
+ return changePriority(jobs, false);
+ case 3:
+ return editJobAttributes(jobs.getFirst());
+ }
+ return false;
+}
+
+bool KMCupsJobManager::jobIppReport(KMJob *j)
+{
+ IppRequest req;
+
+ req.setOperation(IPP_GET_JOB_ATTRIBUTES);
+ req.addURI(IPP_TAG_OPERATION, "job-uri", j->uri());
+ bool result(true);
+ /*
+ if (!j->uri().isEmpty())
+ {
+ KURL url(j->uri());
+ req.setHost(url.host());
+ req.setPort(url.port());
+ }
+ */
+ if ((result=req.doRequest("/")))
+ static_cast<KMCupsManager*>(KMManager::self())->ippReport(req, IPP_TAG_JOB, i18n("Job Report"));
+ else
+ KMManager::self()->setErrorMsg(i18n("Unable to retrieve job information: ")+req.statusMessage());
+ return result;
+}
+
+QValueList<KAction*> KMCupsJobManager::createPluginActions(KActionCollection *coll)
+{
+ QValueList<KAction*> list;
+ KAction *act(0);
+
+ list << (act = new PluginAction(0, i18n("&Job IPP Report"), "kdeprint_report", 0, coll, "plugin_ipp"));
+ act->setGroup("plugin");
+ list << (act = new PluginAction(1, i18n("&Increase Priority"), "up", 0, coll, "plugin_prioup"));
+ act->setGroup("plugin");
+ list << (act = new PluginAction(2, i18n("&Decrease Priority"), "down", 0, coll, "plugin_priodown"));
+ act->setGroup("plugin");
+ list << (act = new PluginAction(3, i18n("&Edit Attributes..."), "edit", 0, coll, "plugin_editjob"));
+ act->setGroup("plugin");
+
+ return list;
+}
+
+void KMCupsJobManager::validatePluginActions(KActionCollection *coll, const QPtrList<KMJob>& joblist)
+{
+ QPtrListIterator<KMJob> it(joblist);
+ bool flag(true);
+ for (; it.current(); ++it)
+ {
+ flag = (flag && it.current()->type() == KMJob::System
+ && (it.current()->state() == KMJob::Queued || it.current()->state() == KMJob::Held)
+ /*&& !it.current()->isRemote()*/);
+ }
+ flag = (flag && joblist.count() > 0);
+ KAction *a;
+ if ( ( a = coll->action( "plugin_ipp" ) ) )
+ a->setEnabled( joblist.count() == 1 );
+ if ( ( a = coll->action( "plugin_prioup" ) ) )
+ a->setEnabled( flag );
+ if ( ( a = coll->action( "plugin_priodown" ) ) )
+ a->setEnabled( flag );
+ if ( ( a = coll->action( "plugin_editjob" ) ) )
+ a->setEnabled( flag && ( joblist.count() == 1 ) );
+}
+
+bool KMCupsJobManager::changePriority(const QPtrList<KMJob>& jobs, bool up)
+{
+ QPtrListIterator<KMJob> it(jobs);
+ bool result(true);
+ for (; it.current() && result; ++it)
+ {
+ int value = it.current()->attribute(0).toInt();
+ if (up) value = QMIN(value+10, 100);
+ else value = QMAX(value-10, 1);
+
+ IppRequest req;
+ /*
+ if (!it.current()->uri().isEmpty())
+ {
+ KURL url(it.current()->uri());
+ req.setHost(url.host());
+ req.setPort(url.port());
+ }
+ */
+ req.setOperation(IPP_SET_JOB_ATTRIBUTES);
+ req.addURI(IPP_TAG_OPERATION, "job-uri", it.current()->uri());
+ req.addName(IPP_TAG_OPERATION, "requesting-user-name", CupsInfos::self()->login());
+ req.addInteger(IPP_TAG_JOB, "job-priority", value);
+
+ if (!(result = req.doRequest("/jobs/")))
+ KMManager::self()->setErrorMsg(i18n("Unable to change job priority: ")+req.statusMessage());
+ }
+ return result;
+}
+
+static QString processRange(const QString& range)
+{
+ QStringList l = QStringList::split(',', range, false);
+ QString s;
+ for (QStringList::ConstIterator it=l.begin(); it!=l.end(); ++it)
+ {
+ s.append(*it);
+ if ((*it).find('-') == -1)
+ s.append("-").append(*it);
+ s.append(",");
+ }
+ if (!s.isEmpty())
+ s.truncate(s.length()-1);
+ return s;
+}
+
+bool KMCupsJobManager::editJobAttributes(KMJob *j)
+{
+ IppRequest req;
+
+ req.setOperation(IPP_GET_JOB_ATTRIBUTES);
+ req.addURI(IPP_TAG_OPERATION, "job-uri", j->uri());
+ /*
+ if (!j->uri().isEmpty())
+ {
+ KURL url(j->uri());
+ req.setHost(url.host());
+ req.setPort(url.port());
+ }
+ */
+ if (!req.doRequest("/"))
+ {
+ KMManager::self()->setErrorMsg(i18n("Unable to retrieve job information: ")+req.statusMessage());
+ return false;
+ }
+
+ QMap<QString,QString> opts = req.toMap(IPP_TAG_JOB);
+ // translate the "Copies" option to non-CUPS syntax
+ if (opts.contains("copies"))
+ opts["kde-copies"] = opts["copies"];
+ if (opts.contains("page-set"))
+ opts["kde-pageset"] = (opts["page-set"] == "even" ? "2" : (opts["page-set"] == "odd" ? "1" : "0"));
+ if (opts.contains("OutputOrder"))
+ opts["kde-pageorder"] = opts["OutputOrder"];
+ if (opts.contains("multiple-document-handling"))
+ opts["kde-collate"] = (opts["multiple-document-handling"] == "separate-documents-collated-copies" ? "Collate" : "Uncollate");
+ if (opts.contains("page-ranges"))
+ opts["kde-range"] = opts["page-ranges"];
+
+ // find printer and construct dialog
+ KMPrinter *prt = KMManager::self()->findPrinter(j->printer());
+ if (!prt)
+ {
+ KMManager::self()->setErrorMsg(i18n("Unable to find printer %1.").arg(j->printer()));
+ return false;
+ }
+ KMManager::self()->completePrinterShort(prt);
+ KPrinter::ApplicationType oldAppType = KPrinter::applicationType();
+ KPrinter::setApplicationType(KPrinter::StandAlone);
+ KPrinterPropertyDialog dlg(prt);
+ dlg.setDriver(KMManager::self()->loadPrinterDriver(prt));
+ KMFactory::self()->uiManager()->setupPrinterPropertyDialog(&dlg);
+ KPrinter::setApplicationType( oldAppType );
+ if (dlg.driver())
+ dlg.addPage(new KPDriverPage(prt, dlg.driver(), &dlg));
+ dlg.addPage(new KPCopiesPage(0, &dlg));
+ dlg.addPage(new KPSchedulePage(&dlg));
+ dlg.addPage(new KPTagsPage(true, &dlg));
+ dlg.setOptions(opts);
+ dlg.enableSaveButton(false);
+ dlg.setCaption(i18n("Attributes of Job %1@%2 (%3)").arg(j->id()).arg(j->printer()).arg(j->name()));
+ if (dlg.exec())
+ {
+ opts.clear();
+ // include default values to override non-default values
+ dlg.getOptions(opts, true);
+ // translate the "Copies" options from non-CUPS syntax
+ opts["copies"] = opts["kde-copies"];
+ opts["OutputOrder"] = opts["kde-pageorder"];
+ opts["multiple-document-handling"] = (opts["kde-collate"] == "Collate" ? "separate-documents-collated-copies" : "separate-documents-uncollated-copies");
+ opts["page-set"] = (opts["kde-pageset"] == "1" ? "odd" : (opts["kde-pageset"] == "2" ? "even" : "all"));
+ // it seems CUPS is buggy. Disable page-ranges modification, otherwise nothing gets printed
+ opts["page-ranges"] = processRange(opts["kde-range"]);
+
+ req.init();
+ req.setOperation(IPP_SET_JOB_ATTRIBUTES);
+ req.addURI(IPP_TAG_OPERATION, "job-uri", j->uri());
+ req.addName(IPP_TAG_OPERATION, "requesting-user-name", CupsInfos::self()->login());
+ req.setMap(opts);
+ //req.dump(1);
+ if (!req.doRequest("/jobs/"))
+ {
+ KMManager::self()->setErrorMsg(i18n("Unable to set job attributes: ")+req.statusMessage());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#include "kmcupsjobmanager.moc"