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"