/* * This file is part of the KDE libraries * Copyright (c) 2001 Michael Goffioul * * 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 "kio_print.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PRINT_DEBUG kdDebug(7019) << "kio_print: " extern "C" { int KDE_EXPORT kdemain(int argc, char **argv); } void addAtom(KIO::UDSEntry& entry, unsigned int ID, long l, const TQString& s = TQString()) { KIO::UDSAtom atom; atom.m_uds = ID; atom.m_long = l; atom.m_str = s; entry.append(atom); } static void createDirEntry(KIO::UDSEntry& entry, const TQString& name, const TQString& url, const TQString& mime) { entry.clear(); addAtom(entry, KIO::UDS_NAME, 0, name); addAtom(entry, KIO::UDS_FILE_TYPE, S_IFDIR); addAtom(entry, KIO::UDS_ACCESS, 0500); addAtom(entry, KIO::UDS_MIME_TYPE, 0, mime); addAtom(entry, KIO::UDS_URL, 0, url); PRINT_DEBUG << "creating dir entry url=" << url << " mimetype=" << mime << endl; addAtom(entry, KIO::UDS_SIZE, 0); //addAtom(entry, KIO::UDS_GUESSED_MIME_TYPE, 0, "application/octet-stream"); } static void createFileEntry(KIO::UDSEntry& entry, const TQString& name, const TQString& url, const TQString& mime) { entry.clear(); addAtom(entry, KIO::UDS_NAME, 0, name); addAtom(entry, KIO::UDS_FILE_TYPE, S_IFREG); addAtom(entry, KIO::UDS_URL, 0, url); addAtom(entry, KIO::UDS_ACCESS, 0400); addAtom(entry, KIO::UDS_MIME_TYPE, 0, mime); addAtom(entry, KIO::UDS_SIZE, 0); addAtom(entry, KIO::UDS_GUESSED_MIME_TYPE, 0, "application/octet-stream"); } TQString buildMenu(const TQStringList& items, const TQStringList& links, int active) { if (items.count() == 0 || items.count() != links.count()) return TQString(" "); TQString s; int index = 0; for (TQStringList::ConstIterator it1=items.begin(), it2=links.begin(); it1!=items.end() && it2!=links.end(); ++it1, ++it2, index++) { if (index == active) s.append("  ").append(*it1).append(" "); else s.append("  ").append(*it1).append(" "); if ((unsigned int)index < items.count()-1) s.append("|"); } return s; } TQString buildOptionRow(DrBase *opt, bool f) { TQString s("%1%1\n"); s = s.arg(f ? "contentwhite" : "contentyellow").arg(opt->get("text")).arg(opt->prettyText()); return s; } TQString buildGroupTable(DrGroup *grp, bool showHeader = true) { TQString s("%1\n"); if (showHeader) s = s.arg(grp->get("text")); else s = TQString(); TQPtrListIterator oit(grp->options()); bool f(false); for (; oit.current(); ++oit, f = !f) s.append(buildOptionRow(oit.current(), f)); TQPtrListIterator git(grp->groups()); for (; git.current(); ++git) s.append(buildGroupTable(git.current())); return s; } int kdemain(int argc, char **argv) { KInstance instance("kio_print"); PRINT_DEBUG << "starting ioslave" << endl; if (argc != 4) { fprintf(stderr, "Usage: kio_print protocol domain-socket1 domain-socket2\n"); exit(-1); } /* create fake KApplicatiom object, needed for job stuffs */ KAboutData about( "kio_print", "kio_print", "fake_version", "TDEPrint IO slave", KAboutData::License_GPL, "(c) 2003, Michael Goffioul" ); KCmdLineArgs::init( &about ); KApplication app; KIO_Print slave(argv[2], argv[3]); slave.dispatchLoop(); PRINT_DEBUG << "done" << endl; return 0; } KIO_Print::KIO_Print(const TQCString& pool, const TQCString& app) : KIO::SlaveBase("print", pool, app) { } void KIO_Print::listDir(const KURL& url) { if ( url.protocol() == "printdb" ) { listDirDB( url ); return; } TQStringList path = TQStringList::split('/', url.path(), false); PRINT_DEBUG << "listing " << url.path() << endl; TQString group = path[0].lower(); if (path.count() == 0) listRoot(); else if (path.count() == 1 && group != "manager" && group != "jobs") { PRINT_DEBUG << "listing group " << path[0] << endl; int mask; TQString mimeType; KIO::UDSEntry entry; if (group == "printers") { mask = KMPrinter::Printer; mimeType = "print/printer"; } else if (group == "classes") { mask = KMPrinter::Class | KMPrinter::Implicit; mimeType = "print/class"; } else if (group == "specials") { mask = KMPrinter::Special; mimeType = "print/printer"; } else { error(KIO::ERR_DOES_NOT_EXIST, url.url()); return; } TQPtrListIterator it(*(KMManager::self()->printerList())); for (;it.current();++it) { if (!(it.current()->type() & mask) || !it.current()->instanceName().isEmpty()) { PRINT_DEBUG << "rejecting " << it.current()->name() << endl; continue; } //createFileEntry(entry, it.current()->name(), ("print:/"+path[0]+"/"+it.current()->name()), mimeType, "text/html", S_IFDIR); createDirEntry(entry, it.current()->name(), ("print:/"+group+"/"+KURL::encode_string_no_slash(it.current()->name())), mimeType); PRINT_DEBUG << "accepting " << it.current()->name() << endl; listEntry(entry, false); } listEntry(KIO::UDSEntry(), true); finished(); } else { //error(KIO::ERR_UNSUPPORTED_ACTION, i18n("Unsupported path %1").arg(url.path())); // better do nothing listEntry(KIO::UDSEntry(), true); totalSize(0); finished(); } } void KIO_Print::listRoot() { PRINT_DEBUG << "listing root entry" << endl; KIO::UDSEntry entry; // Classes entry createDirEntry(entry, i18n("Classes"), "print:/classes", "print/folder"); listEntry(entry, false); // Printers entry createDirEntry(entry, i18n("Printers"), "print:/printers", "print/folder"); listEntry(entry, false); // Specials entry createDirEntry(entry, i18n("Specials"), "print:/specials", "print/folder"); listEntry(entry, false); // Management entry //createFileEntry(entry, i18n("Manager"), "print:/manager", "print/manager", TQString(), S_IFDIR); createDirEntry(entry, i18n("Manager"), "print:/manager", "print/manager"); listEntry(entry, false); // Jobs entry createDirEntry(entry, i18n("Jobs"), "print:/jobs", "print/jobs"); listEntry(entry, false); // finish totalSize(4); listEntry(entry, true); finished(); } void KIO_Print::listDirDB( const KURL& url ) { PRINT_DEBUG << "listDirDB: " << url << endl; TQStringList pathComps = TQStringList::split( '/', url.path(), false ); KURL remUrl; remUrl.setProtocol( "http" ); remUrl.setHost( url.host() ); remUrl.setPort( url.port() ); remUrl.setPath( "/list-data.cgi" ); switch ( pathComps.size() ) { case 0: /* list manufacturers */ remUrl.addQueryItem( "type", "makes" ); break; case 1: /* list printers for the given manufacturer */ remUrl.addQueryItem( "type", "printers" ); remUrl.addQueryItem( "make", pathComps[ 0 ] ); break; case 2: /* list drivers for given printer */ remUrl.addQueryItem( "type", "drivers" ); remUrl.addQueryItem( "printer", pathComps[ 1 ] ); break; default: error( KIO::ERR_UNSUPPORTED_ACTION, "Not implemented" ); return; } remUrl.addQueryItem( "format", "xml" ); if ( getDBFile( remUrl ) ) { TQDomDocument doc; if ( doc.setContent( &m_httpBuffer, false ) ) { TQDomNodeList l; KIO::UDSEntry entry; switch ( pathComps.size() ) { case 0: l = doc.documentElement().elementsByTagName( "make" ); for ( unsigned int i=0; ienter_loop(); m_httpBuffer.close(); /* return the result */ if ( m_httpError != 0 ) error( m_httpError, m_httpErrorTxt ); return ( m_httpError == 0 ); } void KIO_Print::getDB( const KURL& url ) { PRINT_DEBUG << "downloading PPD file for " << url.url() << endl; TQStringList pathComps = TQStringList::split( '/', url.path(), false ); if ( pathComps.size() != 3 ) error( KIO::ERR_MALFORMED_URL, url.url() ); else { KURL remUrl; remUrl.setProtocol( "http" ); remUrl.setHost( url.host() ); remUrl.setPath( "/ppd-o-matic.cgi" ); remUrl.addQueryItem( "driver", pathComps[ 2 ] ); remUrl.addQueryItem( "printer", pathComps[ 1 ] ); if ( getDBFile( remUrl ) ) { mimeType( "text/plain" ); data( m_httpBuffer.buffer() ); finished(); } /* * no "else" statement needed, the error has * already been emitted by the getDBFile function */ } } void KIO_Print::slotResult( KIO::Job *j ) { /* * store slave results for later user (job gets deleted * after this function). Store only if no other error * occured previously (when writing to the buffer). */ if ( m_httpError == 0 ) { m_httpError = j->error(); m_httpErrorTxt = j->errorText(); } kapp->exit_loop(); } void KIO_Print::slotData( KIO::Job *j, const TQByteArray& d ) { PRINT_DEBUG << "HTTP data received (size=" << d.size() << ")" << endl; if ( d.size() > 0 ) { int len = m_httpBuffer.writeBlock( d ); if ( len == -1 || len != ( int )d.size() ) { m_httpError = KIO::ERR_INTERNAL; m_httpErrorTxt = "Unable to write to the internal buffer."; j->kill( false ); } } } void KIO_Print::slotTotalSize( KIO::Job*, KIO::filesize_t sz ) { totalSize( sz ); } void KIO_Print::slotProcessedSize( KIO::Job*, KIO::filesize_t sz ) { processedSize( sz ); } void KIO_Print::get(const KURL& url) { if ( url.protocol() == "printdb" ) { getDB( url ); return; } TQStringList elems = TQStringList::split('/', url.encodedPathAndQuery(), false); TQString group(elems[0].lower()), printer(KURL::decode_string(elems[1])), path, query; KMPrinter *mprinter(0); if (group == "manager") { PRINT_DEBUG << "opening print management part" << endl; mimeType("print/manager"); finished(); return; } PRINT_DEBUG << "getting " << url.url() << endl; if (group.startsWith("jobs")) { int p = group.find('?'); if (p != -1) query = group.mid(p+1); if (!query.isEmpty() && query != "jobs" && query != "completed_jobs") { error(KIO::ERR_MALFORMED_URL, TQString()); return; } PRINT_DEBUG << "listing jobs for all printers" << endl; showJobs(0, query == "completed_jobs"); return; } int p = printer.find('?'); if (p != -1) { query = printer.mid(p+1); printer = printer.left(p); } PRINT_DEBUG << "opening " << url.url() << endl; PRINT_DEBUG << "extracted printer name = " << printer << endl; KMManager::self()->printerList(false); mprinter = KMManager::self()->findPrinter(printer); if (!mprinter) path = locateData(printer.isEmpty() ? group : printer); if (elems.count() > 2 || (path.isEmpty() && group != "printers" && group != "classes" && group != "specials") || (mprinter == 0 && path.isEmpty())) { error(KIO::ERR_DOES_NOT_EXIST, url.path()); return; } if (mprinter != 0) { if (!query.isEmpty() && query != "general") { if (query == "jobs") showJobs(mprinter, false); else if (query == "completed_jobs") showJobs(mprinter, true); else if (query == "driver") showDriver(mprinter); else error(KIO::ERR_MALFORMED_URL, KURL::decode_string(elems[1])); } else if (group == "printers" && mprinter->isPrinter()) showPrinterInfo(mprinter); else if (group == "classes" && mprinter->isClass(true)) showClassInfo(mprinter); else if (group == "specials" && mprinter->isSpecial()) showSpecialInfo(mprinter); else error(KIO::ERR_INTERNAL, i18n("Unable to determine object type for %1.").arg(printer)); } else if (!path.isEmpty()) showData(path); else error(KIO::ERR_INTERNAL, i18n("Unable to determine source type for %1.").arg(printer)); } void KIO_Print::showPrinterInfo(KMPrinter *printer) { if (!KMManager::self()->completePrinter(printer)) error(KIO::ERR_INTERNAL, i18n("Unable to retrieve printer information for %1.").arg(printer->name())); else { mimeType("text/html"); TQString content; if (!loadTemplate(TQString::fromLatin1("printer.template"), content)) { error(KIO::ERR_INTERNAL, i18n("Unable to load template %1").arg("printer.template")); return; } content = content .arg(i18n("Properties of %1").arg(printer->printerName())) .arg(i18n("Properties of %1").arg(printer->printerName())) .arg(buildMenu(TQStringList::split('|', i18n("General|Driver|Active jobs|Completed jobs"), false), TQStringList::split('|', "?general|?driver|?jobs|?completed_jobs", true), 0)) .arg(TQString()) .arg(printer->pixmap()) .arg(printer->name()) .arg(i18n("General Properties")) .arg(i18n("Type")).arg(printer->isRemote() ? i18n("Remote") : i18n("Local")) .arg(i18n("State")).arg(printer->stateString()) .arg(i18n("Location")).arg(printer->location()) .arg(i18n("Description")).arg(printer->description()) .arg(i18n("URI")).arg(printer->uri().prettyURL()) .arg(i18n("Interface (Backend)")).arg(printer->device()) .arg(i18n("Driver")) .arg(i18n("Manufacturer")).arg(printer->manufacturer()) .arg(i18n("Model")).arg(printer->model()) .arg(i18n("Driver Information")).arg(printer->driverInfo()); data(content.local8Bit()); finished(); } } void KIO_Print::showClassInfo(KMPrinter *printer) { if (!KMManager::self()->completePrinter(printer)) error(KIO::ERR_INTERNAL, i18n("Unable to retrieve class information for %1.").arg(printer->name())); else { mimeType("text/html"); TQString content; if (!loadTemplate(TQString::fromLatin1("class.template"), content)) { error(KIO::ERR_INTERNAL, i18n("Unable to load template %1").arg("class.template")); return; } TQString memberContent("
    \n"); TQStringList members(printer->members()); for (TQStringList::ConstIterator it=members.begin(); it!=members.end(); ++it) { memberContent.append(TQString::fromLatin1("
  • %2
  • \n").arg(*it).arg(*it)); } memberContent.append("
\n"); TQString typeContent = (printer->isImplicit() ? i18n("Implicit") : (printer->isRemote() ? i18n("Remote") : i18n("Local"))); content = content .arg(i18n("Properties of %1").arg(printer->printerName())) .arg(i18n("Properties of %1").arg(printer->printerName())) .arg(buildMenu(TQStringList::split('|', i18n("General|Active jobs|Completed jobs"), false), TQStringList::split('|', "?general|?jobs|?completed_jobs", true), 0)) .arg(TQString()) .arg(printer->pixmap()) .arg(printer->name()) .arg(i18n("General Properties")) .arg(i18n("Type")).arg(typeContent) .arg(i18n("State")).arg(printer->stateString()) .arg(i18n("Location")).arg(printer->location()) .arg(i18n("Description")).arg(printer->description()) .arg(i18n("URI")).arg(printer->uri().prettyURL()) .arg(i18n("Members")).arg(memberContent); data(content.local8Bit()); finished(); } } void KIO_Print::showSpecialInfo(KMPrinter *printer) { mimeType("text/html"); TQString content; if (!loadTemplate(TQString::fromLatin1("pseudo.template"), content)) { error(KIO::ERR_INTERNAL, i18n("Unable to load template %1").arg("pseudo.template")); return; } TQString reqContent("
    \n"); TQStringList requirements = TQStringList::split(",", printer->option("kde-special-require"), false); for (TQStringList::ConstIterator it=requirements.begin(); it!=requirements.end(); ++it) reqContent += ("
  • " + (*it) + "
  • \n"); reqContent.append("
\n"); content = content .arg(i18n("Properties of %1").arg(printer->printerName())) .arg(i18n("Properties of %1").arg(printer->printerName())) .arg(buildMenu(TQStringList::split('|', i18n("General"), false), TQStringList::split('|', "?general", true), 0)) .arg(TQString()) .arg(printer->pixmap()) .arg(printer->name()) .arg(i18n("General Properties")) .arg(i18n("Location")).arg(printer->location()) .arg(i18n("Description")).arg(printer->description()) .arg(i18n("Requirements")).arg(reqContent) .arg(i18n("Command Properties")) .arg(i18n("Command")).arg(""+printer->option("kde-special-command")+"") .arg(i18n("Use Output File")).arg(printer->option("kde-special-file") == "1" ? i18n("Yes") : i18n("No")) .arg(i18n("Default Extension")).arg(printer->option("kde-special-extension")); data(content.local8Bit()); finished(); } bool KIO_Print::loadTemplate(const TQString& filename, TQString& buffer) { TQFile f(locate("data", TQString::fromLatin1("tdeprint/template/")+filename)); if (f.exists() && f.open(IO_ReadOnly)) { TQTextStream t(&f); buffer = t.read(); return true; } else { buffer = TQString(); return false; } } void KIO_Print::showData(const TQString& pathname) { PRINT_DEBUG << "sending data: " << pathname << endl; TQFile f(pathname); if (f.exists() && f.open(IO_ReadOnly)) { TQByteArray arr(f.readAll()); mimeType(KMimeType::findByURL(KURL(pathname), 0, true, true)->name()); data(arr); finished(); } else { PRINT_DEBUG << "file not found" << endl; error(KIO::ERR_DOES_NOT_EXIST, pathname); } } /** * Locate a data in this order: * - $TDEDIR/share/apps/tdeprint/template/ * - as a desktop icon */ TQString KIO_Print::locateData(const TQString& item) { TQString path = locate("data", "tdeprint/template/"+item); if (path.isEmpty()) path = KGlobal::iconLoader()->iconPath(item, KIcon::Desktop, true); return path; } void KIO_Print::showJobs(KMPrinter *prt, bool completed) { mimeType("text/html"); // Add the printer to the current list in the job manager KMJobManager::JobType type = (completed ? KMJobManager::CompletedJobs : KMJobManager::ActiveJobs); KMJobManager *mgr = KMJobManager::self(); if (prt) mgr->addPrinter(prt->printerName(), type); else { TQPtrListIterator pit(*(KMManager::self()->printerList())); for (; pit.current(); ++pit) if (pit.current()->isVirtual() || pit.current()->isSpecial()) continue; else mgr->addPrinter(pit.current()->printerName(), type); } TQString content; if (!loadTemplate(TQString::fromLatin1("jobs.template"), content)) { error(KIO::ERR_INTERNAL, i18n("Unable to load template %1").arg("pseudo.template")); return; } if (prt) { content = content .arg(i18n("Jobs of %1").arg(prt->printerName())) .arg(i18n("Jobs of %1").arg(prt->printerName())) .arg(prt->isClass () ? buildMenu(TQStringList::split('|', i18n("General|Active jobs|Completed jobs"), false), TQStringList::split('|', "?general|?jobs|?completed_jobs", true), (completed ? 2 : 1)) : buildMenu(TQStringList::split('|', i18n("General|Driver|Active jobs|Completed jobs"), false), TQStringList::split('|', "?general|?driver|?jobs|?completed_jobs", true), (completed ? 3 : 2))) .arg(TQString()) .arg(prt->pixmap()) .arg(prt->printerName()); } else { content = content .arg(i18n("All jobs")) .arg(buildMenu(TQStringList::split('|', i18n("Active jobs|Completed jobs"), false), TQStringList::split('|', "?jobs|?completed_jobs", true), (completed ? 1 : 0))) .arg("fileprint") .arg(i18n("All jobs")); } content = content.arg(i18n("ID")).arg(i18n("Owner")).arg(i18n("Printer")).arg(i18n("Name")).arg(i18n("State")); TQString jobContent, cellContent("%1\n"); TQPtrListIterator it(mgr->jobList()); bool flag(true); for (; it.current(); ++it, flag = !flag) { jobContent.append("\n"); jobContent.append(cellContent.arg(it.current()->id())); jobContent.append(cellContent.arg(it.current()->owner())); jobContent.append(cellContent.arg(it.current()->printer())); jobContent.append(cellContent.arg(it.current()->name())); jobContent.append(cellContent.arg(it.current()->stateString())); jobContent.append("\n"); } content = content.arg(jobContent); // remove the current printer to the current list in the job manager if (prt) mgr->removePrinter(prt->printerName(), type); else { TQPtrListIterator pit(*(KMManager::self()->printerList())); for (; pit.current(); ++pit) if (pit.current()->isVirtual() || pit.current()->isSpecial()) continue; else mgr->removePrinter(pit.current()->printerName(), type); } data(content.local8Bit()); finished(); } void KIO_Print::showDriver(KMPrinter *prt) { mimeType("text/html"); TQString content; if (!loadTemplate(TQString::fromLatin1("driver.template"), content)) { error(KIO::ERR_INTERNAL, i18n("Unable to load template %1").arg("pseudo.template")); return; } DrMain *driver = KMManager::self()->loadPrinterDriver(prt, true); content = content .arg(i18n("Driver of %1").arg(prt->printerName())) .arg(i18n("Driver of %1").arg(prt->printerName())) .arg(buildMenu(TQStringList::split('|', i18n("General|Driver|Active jobs|Completed jobs"), false), TQStringList::split('|', "?general|?driver|?jobs|?completed_jobs", true), 1)) .arg(TQString()) .arg(prt->pixmap()) .arg(prt->printerName() + " (" + (driver ? driver->get("text") : i18n("No driver found")) + ")"); if (driver) content = content.arg(buildGroupTable(driver, false)); else content = content.arg(TQString()); data(content.local8Bit()); finished(); } #include "kio_print.moc"