kdeprintd.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 "kdeprintd.h"
00021 #include "kprintprocess.h"
00022 
00023 #include <qfile.h>
00024 #include <klocale.h>
00025 #include <knotifyclient.h>
00026 #include <kmessagebox.h>
00027 #include <kdebug.h>
00028 #include <dcopclient.h>
00029 #include <kio/passdlg.h>
00030 #include <kio/authinfo.h>
00031 #include <qlabel.h>
00032 #include <kpushbutton.h>
00033 #include <kiconloader.h>
00034 #include <kstandarddirs.h>
00035 #include <kwin.h>
00036 #include <kapplication.h>
00037 #include <qlayout.h>
00038 #include <qtimer.h>
00039 #include <qregexp.h>
00040 
00041 #include <unistd.h>
00042 
00043 extern "C"
00044 {
00045     KDE_EXPORT KDEDModule *create_kdeprintd(const QCString& name)
00046     {
00047         return new KDEPrintd(name);
00048     }
00049 }
00050 
00051 class StatusWindow : public QWidget
00052 {
00053 public:
00054     StatusWindow(int pid = -1);
00055     void setMessage(const QString&);
00056     int pid() const { return m_pid; }
00057 
00058 private:
00059     QLabel      *m_label;
00060     QPushButton *m_button;
00061     int     m_pid;
00062     QLabel      *m_icon;
00063 };
00064 
00065 StatusWindow::StatusWindow(int pid)
00066 : QWidget(NULL, "StatusWindow", WType_TopLevel|WStyle_DialogBorder|WStyle_StaysOnTop|WDestructiveClose), m_pid(pid)
00067 {
00068     m_label = new QLabel(this);
00069     m_label->setAlignment(AlignCenter);
00070     m_button = new KPushButton(KStdGuiItem::close(), this);
00071     m_icon = new QLabel(this);
00072     m_icon->setPixmap(DesktopIcon("fileprint"));
00073     m_icon->setAlignment(AlignCenter);
00074     KWin::setIcons(winId(), *(m_icon->pixmap()), SmallIcon("fileprint"));
00075     QGridLayout *l0 = new QGridLayout(this, 2, 3, 10, 10);
00076     l0->setRowStretch(0, 1);
00077     l0->setColStretch(1, 1);
00078     l0->addMultiCellWidget(m_label, 0, 0, 1, 2);
00079     l0->addWidget(m_button, 1, 2);
00080     l0->addMultiCellWidget(m_icon, 0, 1, 0, 0);
00081     connect(m_button, SIGNAL(clicked()), SLOT(hide()));
00082     resize(200, 50);
00083 }
00084 
00085 void StatusWindow::setMessage(const QString& msg)
00086 {
00087     //QSize oldSz = size();
00088     m_label->setText(msg);
00089     //QSize sz = m_label->sizeHint();
00090     //sz += QSize(layout()->margin()*2, layout()->margin()*2+layout()->spacing()+m_button->sizeHint().height());
00091     // dialog will never be smaller
00092     //sz = sz.expandedTo(oldSz);
00093     //resize(sz);
00094     //setFixedSize(sz);
00095     //layout()->activate();
00096 }
00097 
00098 //*****************************************************************************************************
00099 
00100 KDEPrintd::KDEPrintd(const QCString& obj)
00101 : KDEDModule(obj)
00102 {
00103     m_processpool.setAutoDelete(true);
00104     m_windows.setAutoDelete(false);
00105     m_requestsPending.setAutoDelete( true );
00106 }
00107 
00108 KDEPrintd::~KDEPrintd()
00109 {
00110 }
00111 
00112 int KDEPrintd::print(const QString& cmd, const QStringList& files, bool remflag)
00113 {
00114     KPrintProcess *proc = new KPrintProcess;
00115     QString command(cmd);
00116     QRegExp re( "\\$out\\{([^}]*)\\}" );
00117 
00118     connect(proc,SIGNAL(printTerminated(KPrintProcess*)),SLOT(slotPrintTerminated(KPrintProcess*)));
00119     connect(proc,SIGNAL(printError(KPrintProcess*,const QString&)),SLOT(slotPrintError(KPrintProcess*,const QString&)));
00120     proc->setCommand( command );
00121     if ( re.search( command ) != -1 )
00122     {
00123         KURL url( re.cap( 1 ) );
00124         if ( !url.isLocalFile() )
00125         {
00126             QString tmpFilename = locateLocal( "tmp", "kdeprint_" + kapp->randomString( 8 ) );
00127             command.replace( re, KProcess::quote( tmpFilename ) );
00128             proc->setOutput( re.cap( 1 ) );
00129             proc->setTempOutput( tmpFilename );
00130         }
00131         else
00132             command.replace( re, KProcess::quote( re.cap( 1 ) ) );
00133     }
00134 
00135     if ( checkFiles( command, files ) )
00136     {
00137         *proc << command;
00138         if ( remflag )
00139             proc->setTempFiles( files );
00140         if ( proc->print() )
00141         {
00142             m_processpool.append( proc );
00143             return ( int )proc->pid();
00144         }
00145     }
00146 
00147     delete proc;
00148     return -1;
00149 }
00150 
00151 void KDEPrintd::slotPrintTerminated( KPrintProcess *proc )
00152 {
00153     m_processpool.removeRef( proc );
00154 }
00155 
00156 void KDEPrintd::slotPrintError( KPrintProcess *proc, const QString& msg )
00157 {
00158     KNotifyClient::event("printerror",i18n("<p><nobr>A print error occurred. Error message received from system:</nobr></p><br>%1").arg(msg));
00159     m_processpool.removeRef( proc );
00160 }
00161 
00162 QString KDEPrintd::openPassDlg(const QString& user)
00163 {
00164     QString user_(user), pass_, result;
00165     if (KIO::PasswordDialog::getNameAndPassword(user_, pass_, NULL) == KDialog::Accepted)
00166         result.append(user_).append(":").append(pass_);
00167     return result;
00168 }
00169 
00170 bool KDEPrintd::checkFiles(QString& cmd, const QStringList& files)
00171 {
00172     for (QStringList::ConstIterator it=files.begin(); it!=files.end(); ++it)
00173         if (::access(QFile::encodeName(*it).data(), R_OK) != 0)
00174         {
00175             if (KMessageBox::warningContinueCancel(0,
00176                 i18n("Some of the files to print are not readable by the KDE "
00177                      "print daemon. This may happen if you are trying to print "
00178                      "as a different user to the one currently logged in. To continue "
00179                      "printing, you need to provide root's password."),
00180                 QString::null,
00181                 i18n("Provide root's Password"),
00182                 "provideRootsPassword") == KMessageBox::Continue)
00183             {
00184                 cmd = ("kdesu -c " + KProcess::quote(cmd));
00185                 break;
00186             }
00187             else
00188                 return false;
00189         }
00190     return true;
00191 }
00192 
00193 void KDEPrintd::statusMessage(const QString& msg, int pid, const QString& appName)
00194 {
00195     StatusWindow    *w = m_windows.find(pid);
00196     if (!w && !msg.isEmpty())
00197     {
00198         w = new StatusWindow(pid);
00199         if (appName.isEmpty())
00200             w->setCaption(i18n("Printing Status - %1").arg("(pid="+QString::number(pid)+")"));
00201         else
00202             w->setCaption(i18n("Printing Status - %1").arg(appName));
00203         connect(w, SIGNAL(destroyed()), SLOT(slotClosed()));
00204         w->show();
00205         m_windows.insert(pid, w);
00206     }
00207     if (w)
00208     {
00209         if (!msg.isEmpty())
00210             w->setMessage(msg);
00211         else
00212             w->close();
00213     }
00214 }
00215 
00216 void KDEPrintd::slotClosed()
00217 {
00218     const StatusWindow  *w = static_cast<const StatusWindow*>(sender());
00219     if (w)
00220     {
00221         m_windows.remove(w->pid());
00222     }
00223 }
00224 
00225 //******************************************************************************************
00226 
00227 class KDEPrintd::Request
00228 {
00229 public:
00230     DCOPClientTransaction *transaction;
00231     QString user;
00232     QString uri;
00233     int seqNbr;
00234 };
00235 
00236 QString KDEPrintd::requestPassword( const QString& user, const QString& host, int port, int seqNbr )
00237 {
00238     Request *req = new Request;
00239     req->user = user;
00240     req->uri = "print://" + user + "@" + host + ":" + QString::number(port);
00241     req->seqNbr = seqNbr;
00242     req->transaction = callingDcopClient()->beginTransaction();
00243     m_requestsPending.append( req );
00244     if ( m_requestsPending.count() == 1 )
00245         QTimer::singleShot( 0, this, SLOT( processRequest() ) );
00246     return "::";
00247 }
00248 
00249 void KDEPrintd::processRequest()
00250 {
00251     if ( m_requestsPending.count() == 0 )
00252         return;
00253 
00254     Request *req = m_requestsPending.first();
00255     KIO::AuthInfo info;
00256     QByteArray params, reply;
00257     QCString replyType;
00258     QString authString( "::" );
00259 
00260     info.username = req->user;
00261     info.keepPassword = true;
00262     info.url = req->uri;
00263     info.comment = i18n( "Printing system" );
00264 
00265     QDataStream input( params, IO_WriteOnly );
00266     input << info << i18n( "Authentication failed (user name=%1)" ).arg( info.username ) << 0L << (long int) req->seqNbr;
00267     if ( callingDcopClient()->call( "kded", "kpasswdserver", "queryAuthInfo(KIO::AuthInfo,QString,long int,long int)",
00268                 params, replyType, reply ) )
00269     {
00270         if ( replyType == "KIO::AuthInfo" )
00271         {
00272             QDataStream output( reply, IO_ReadOnly );
00273             KIO::AuthInfo result;
00274             int seqNbr;
00275             output >> result >> seqNbr;
00276 
00277             if ( result.isModified() )
00278                 authString = result.username + ":" + result.password + ":" + QString::number( seqNbr );
00279         }
00280         else
00281             kdWarning( 500 ) << "DCOP returned type error, expected KIO::AuthInfo, received " << replyType << endl;
00282     }
00283     else
00284         kdWarning( 500 ) << "Cannot communicate with kded_kpasswdserver" << endl;
00285 
00286     QByteArray outputData;
00287     QDataStream output( outputData, IO_WriteOnly );
00288     output << authString;
00289     replyType = "QString";
00290     callingDcopClient()->endTransaction( req->transaction, replyType, outputData );
00291 
00292     m_requestsPending.remove( ( unsigned int )0 );
00293     if ( m_requestsPending.count() > 0 )
00294         QTimer::singleShot( 0, this, SLOT( processRequest() ) );
00295 }
00296 
00297 void KDEPrintd::initPassword( const QString& user, const QString& passwd, const QString& host, int port )
00298 {
00299     QByteArray params, reply;
00300     QCString replyType;
00301     KIO::AuthInfo info;
00302 
00303     info.username = user;
00304     info.password = passwd;
00305     info.url = "print://" + user + "@" + host + ":" + QString::number(port);
00306 
00307     QDataStream input( params, IO_WriteOnly );
00308     input << info << ( long int )0;
00309 
00310     if ( !callingDcopClient()->call( "kded", "kpasswdserver", "addAuthInfo(KIO::AuthInfo,long int)",
00311             params, replyType, reply ) )
00312         kdWarning( 500 ) << "Unable to initialize password, cannot communicate with kded_kpasswdserver" << endl;
00313 }
00314 
00315 #include "kdeprintd.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys