00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
00088 m_label->setText(msg);
00089
00090
00091
00092
00093
00094
00095
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"