00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "cupsaddsmb2.h"
00021 #include "cupsinfos.h"
00022 #include "sidepixmap.h"
00023
00024 #include <QtCore/QTimer>
00025 #include <QtGui/QProgressBar>
00026 #include <QtGui/QLabel>
00027 #include <QtGui/QLayout>
00028 #include <klineedit.h>
00029 #include <klocale.h>
00030 #include <kmessagebox.h>
00031 #include <QtGui/QMessageBox>
00032 #include <QtCore/QFile>
00033 #include <kdebug.h>
00034 #include <kseparator.h>
00035 #include <kpushbutton.h>
00036 #include <kstandardguiitem.h>
00037
00038 #include <cups/cups.h>
00039 #include <ctype.h>
00040
00041 CupsAddSmb::CupsAddSmb(QWidget *parent, const char *name)
00042 : KDialog(parent)
00043 {
00044 setObjectName(name);
00045 m_state = None;
00046 m_status = false;
00047 m_actionindex = 0;
00048 m_proc.setOutputChannelMode(KProcess::MergedChannels);
00049 connect(&m_proc, SIGNAL(readyReadStandardOutput()), SLOT(slotReceived()));
00050 connect(&m_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
00051 SLOT(slotProcessExited(int, QProcess::ExitStatus)));
00052
00053 m_side = new SidePixmap(this);
00054 m_doit = new QPushButton(i18n("&Export"), this);
00055 m_cancel = new KPushButton(KStandardGuiItem::cancel(), this);
00056 connect(m_cancel, SIGNAL(clicked()), SLOT(reject()));
00057 connect(m_doit, SIGNAL(clicked()), SLOT(slotActionClicked()));
00058 m_bar = new QProgressBar(this);
00059 m_text = new QLabel(this);
00060 m_text->setOpenExternalLinks(true);
00061 m_text->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
00062 QLabel *m_title = new QLabel(i18n("Export Printer Driver to Windows Clients"), this);
00063 setCaption(m_title->text());
00064 QFont f(m_title->font());
00065 f.setBold(true);
00066 m_title->setFont(f);
00067 KSeparator *m_sep = new KSeparator(Qt::Horizontal, this);
00068 m_textinfo = new QLabel(this);
00069 m_logined = new KLineEdit(this);
00070 m_passwded = new KLineEdit(this);
00071 m_passwded->setPasswordMode(true);
00072 m_servered = new KLineEdit(this);
00073 QLabel *m_loginlab = new QLabel(i18n("&Username:"), this);
00074 QLabel *m_serverlab = new QLabel(i18n("&Samba server:"), this);
00075 QLabel *m_passwdlab = new QLabel(i18n("&Password:"), this);
00076 m_loginlab->setBuddy(m_logined);
00077 m_serverlab->setBuddy(m_servered);
00078 m_passwdlab->setBuddy(m_passwded);
00079
00080 QString txt = i18n("<p><b>Samba server</b></p>"
00081 "Adobe Windows PostScript driver files plus the CUPS printer PPD will be "
00082 "exported to the <tt>[print$]</tt> special share of the Samba server (to change "
00083 "the source CUPS server, use the <nobr><i>Configure Manager -> CUPS server</i></nobr> first). "
00084 "The <tt>[print$]</tt> share must exist on the Samba side prior to clicking the "
00085 "<b>Export</b> button below.");
00086 m_serverlab->setWhatsThis(txt);
00087 m_servered->setWhatsThis(txt);
00088
00089 txt = i18n("<p><b>Samba username</b></p>"
00090 "User needs to have write access to the <tt>[print$]</tt> share on the Samba server. "
00091 "<tt>[print$]</tt> holds printer drivers prepared for download to Windows clients. "
00092 "This dialog does not work for Samba servers configured with <tt>security = share</tt> "
00093 "(but works fine with <tt>security = user</tt>).");
00094 m_loginlab->setWhatsThis(txt);
00095 m_logined->setWhatsThis(txt);
00096
00097 txt = i18n("<p><b>Samba password</b></p>"
00098 "The Samba setting <tt>encrypt passwords = yes</tt> "
00099 "(default) requires prior use of <tt>smbpasswd -a [username]</tt> command, "
00100 "to create an encrypted Samba password and have Samba recognize it.");
00101 m_passwdlab->setWhatsThis(txt);
00102 m_passwded->setWhatsThis(txt);
00103
00104 QHBoxLayout *l0 = new QHBoxLayout(this);
00105 l0->setMargin(10);
00106 l0->setSpacing(10);
00107 QVBoxLayout *l1 = new QVBoxLayout();
00108 l1->setMargin(0);
00109 l1->setSpacing(10);
00110 l0->addWidget(m_side);
00111 l0->addLayout(l1);
00112 l1->addWidget(m_title);
00113 l1->addWidget(m_sep);
00114 l1->addWidget(m_text);
00115 QGridLayout *l3 = new QGridLayout();
00116 l3->setMargin(0);
00117 l3->setSpacing(10);
00118 l1->addLayout(l3);
00119 l3->addWidget(m_loginlab, 1, 0);
00120 l3->addWidget(m_passwdlab, 2, 0);
00121 l3->addWidget(m_serverlab, 0, 0);
00122 l3->addWidget(m_logined, 1, 1);
00123 l3->addWidget(m_passwded, 2, 1);
00124 l3->addWidget(m_servered, 0, 1);
00125 l3->setColumnStretch(1, 1);
00126 l1->addSpacing(10);
00127 l1->addWidget(m_bar);
00128 l1->addWidget(m_textinfo);
00129 l1->addSpacing(30);
00130 QHBoxLayout *l2 = new QHBoxLayout();
00131 l2->setMargin(0);
00132 l2->setSpacing(10);
00133 l1->addLayout(l2);
00134 l2->addStretch(1);
00135 l2->addWidget(m_doit);
00136 l2->addWidget(m_cancel);
00137
00138 m_logined->setText(CupsInfos::self()->login());
00139 m_passwded->setText(CupsInfos::self()->password());
00140 m_servered->setText(cupsServer());
00141
00142 setMinimumHeight(400);
00143 }
00144
00145 CupsAddSmb::~CupsAddSmb()
00146 {
00147 }
00148
00149 void CupsAddSmb::slotActionClicked()
00150 {
00151 if (m_state == None)
00152 doExport();
00153 else if (m_proc.state() != QProcess::NotRunning)
00154 m_proc.kill();
00155 }
00156
00157 void CupsAddSmb::slotReceived()
00158 {
00159 QString line;
00160 bool partial(false);
00161 static bool incomplete(false);
00162
00163 kDebug(500) << "slotReceived()";
00164 while (1) {
00165
00166 line = QLatin1String("");
00167 partial = true;
00168 char c;
00169 while (m_proc.getChar(&c)) {
00170 if (c == '\n') {
00171 partial = false;
00172 break;
00173 } else {
00174 QChar qc(c);
00175 if (qc.isPrint())
00176 line += qc;
00177 }
00178 }
00179
00180 if (line.isEmpty()) {
00181 kDebug(500) << "NOTHING TO READ";
00182 return;
00183 }
00184
00185 kDebug(500) << "ANSWER = " << line << " (END = " << line.length() << ")";
00186 if (!partial) {
00187 if (incomplete && m_buffer.count() > 0)
00188 m_buffer[m_buffer.size()-1].append(line);
00189 else
00190 m_buffer << line;
00191 incomplete = false;
00192 kDebug(500) << "COMPLETE LINE READ (" << m_buffer.count() << ")";
00193 } else {
00194 if (line.startsWith("smb:") || line.startsWith("rpcclient $")) {
00195 kDebug(500) << "END OF ACTION";
00196 checkActionStatus();
00197 if (m_status)
00198 nextAction();
00199 else {
00200
00201 kDebug(500) << "EXITING PROGRAM...";
00202 m_proc.write("quit\n", 5);
00203 kDebug(500) << "SENT";
00204 }
00205 return;
00206 } else {
00207 if (incomplete && m_buffer.count() > 0)
00208 m_buffer[m_buffer.size()-1].append(line);
00209 else
00210 m_buffer << line;
00211 incomplete = true;
00212 kDebug(500) << "INCOMPLETE LINE READ (" << m_buffer.count() << ")";
00213 }
00214 }
00215 }
00216 }
00217
00218 void CupsAddSmb::checkActionStatus()
00219 {
00220 m_status = false;
00221
00222
00223 switch (m_state) {
00224 case None:
00225 case Start:
00226 m_status = true;
00227 break;
00228 case Copy:
00229 m_status = (m_buffer.count() == 0);
00230 break;
00231 case MkDir:
00232 m_status = (m_buffer.count() == 1 || m_buffer[1].indexOf("ERRfilexists") != -1);
00233 break;
00234 case AddDriver:
00235 case AddPrinter:
00236 m_status = (m_buffer.count() == 1 || !m_buffer[1].startsWith("result"));
00237 break;
00238 }
00239 kDebug(500) << "ACTION STATUS = " << m_status;
00240 }
00241
00242 void CupsAddSmb::nextAction()
00243 {
00244 if (m_actionindex < (int)(m_actions.count()))
00245 QTimer::singleShot(1, this, SLOT(doNextAction()));
00246 }
00247
00248 void CupsAddSmb::doNextAction()
00249 {
00250 m_buffer.clear();
00251 m_state = None;
00252 if (m_proc.state() == QProcess::Running) {
00253 QByteArray s = m_actions[m_actionindex++].toLatin1();
00254 m_bar->setValue(m_bar->value() + 1);
00255 kDebug(500) << "NEXT ACTION = " << s;
00256 if (s == "quit") {
00257
00258 } else if (s == "mkdir") {
00259 m_state = MkDir;
00260
00261 m_textinfo->setText(i18n("Creating folder %1", m_actions[m_actionindex]));
00262 s.append(" ").append(m_actions[m_actionindex].toLatin1());
00263 m_actionindex++;
00264 } else if (s == "put") {
00265 m_state = Copy;
00266
00267 m_textinfo->setText(i18n("Uploading %1", m_actions[m_actionindex+1]));
00268 s.append(" ").append(QFile::encodeName(m_actions[m_actionindex]).data()).append(" ").append(m_actions[m_actionindex+1].toLatin1());
00269 m_actionindex += 2;
00270 } else if (s == "adddriver") {
00271 m_state = AddDriver;
00272
00273 m_textinfo->setText(i18n("Installing driver for %1", m_actions[m_actionindex]));
00274 s.append(" \"").append(m_actions[m_actionindex].toLatin1()).append("\" \"").append(m_actions[m_actionindex+1].toLatin1()).append("\"");
00275 m_actionindex += 2;
00276 } else if (s == "addprinter" || s == "setdriver") {
00277 m_state = AddPrinter;
00278
00279 m_textinfo->setText(i18n("Installing printer %1", m_actions[m_actionindex]));
00280 QByteArray dest = m_actions[m_actionindex].toLocal8Bit();
00281 if (s == "addprinter")
00282 s.append(" ").append(dest).append(" ").append(dest).append(" \"").append(dest).append("\" \"\"");
00283 else
00284 s.append(" ").append(dest).append(" ").append(dest);
00285 m_actionindex++;
00286 } else {
00287 kDebug(500) << "ACTION = unknown action";
00288 m_proc.kill();
00289 return;
00290 }
00291
00292 kDebug(500) << "ACTION = " << s;
00293 s.append("\n");
00294 m_proc.write(s);
00295 }
00296 }
00297
00298 void CupsAddSmb::slotProcessExited(int, QProcess::ExitStatus exitStatus)
00299 {
00300 kDebug(500) << "PROCESS EXITED (" << m_state << ")";
00301 if (exitStatus == QProcess::NormalExit && m_state != Start && m_status) {
00302
00303 if (m_procname == "smbclient") {
00304 doInstall();
00305 return;
00306 } else {
00307 m_doit->setEnabled(false);
00308 m_cancel->setEnabled(true);
00309 m_cancel->setText(i18n("&Close"));
00310 m_cancel->setDefault(true);
00311 m_cancel->setFocus();
00312 m_logined->setEnabled(true);
00313 m_servered->setEnabled(true);
00314 m_passwded->setEnabled(true);
00315 m_text->setText(i18n("Driver successfully exported."));
00316 m_bar->reset();
00317 m_textinfo->setText(QString());
00318 return;
00319 }
00320 }
00321
00322 if (exitStatus == QProcess::NormalExit) {
00323 showError(
00324 i18n("Operation failed. Possible reasons are: permission denied "
00325 "or invalid Samba configuration (see <a href=\"man:/cupsaddsmb\">"
00326 "cupsaddsmb</a> manual page for detailed information, you need "
00327 "<a href=\"http://www.cups.org\">CUPS</a> version 1.1.11 or higher). "
00328 "You may want to try again with another login/password."));
00329
00330 } else {
00331 showError(i18n("Operation aborted (process killed)."));
00332 }
00333 }
00334
00335 void CupsAddSmb::showError(const QString& msg)
00336 {
00337 m_text->setText(i18n("<h3>Operation failed.</h3><p>%1</p>", msg));
00338 m_cancel->setEnabled(true);
00339 m_logined->setEnabled(true);
00340 m_servered->setEnabled(true);
00341 m_passwded->setEnabled(true);
00342 m_doit->setText(i18n("&Export"));
00343 m_state = None;
00344 }
00345
00346 bool CupsAddSmb::exportDest(const QString &dest, const QString& datadir)
00347 {
00348 CupsAddSmb dlg;
00349 dlg.m_dest = dest;
00350 dlg.m_datadir = datadir;
00351 dlg.m_text->setText(
00352 i18n("You are about to prepare the <b>%1</b> driver to be "
00353 "shared out to Windows clients through Samba. This operation "
00354 "requires the <a href=\"http://www.adobe.com/products/printerdrivers/main.html\">Adobe PostScript Driver</a>, a recent version of "
00355 "Samba 2.2.x and a running SMB service on the target server. "
00356 "Click <b>Export</b> to start the operation. Read the <a href=\"man:/cupsaddsmb\">cupsaddsmb</a> "
00357 "manual page in Konqueror or type <tt>man cupsaddsmb</tt> in a "
00358 "console window to learn more about this functionality." , dest));
00359 dlg.exec();
00360 return dlg.m_status;
00361 }
00362
00363 bool CupsAddSmb::doExport()
00364 {
00365 m_status = false;
00366 m_state = None;
00367
00368 if (!QFile::exists(m_datadir + "/drivers/ADOBEPS5.DLL") ||
00369 !QFile::exists(m_datadir + "/drivers/ADOBEPS4.DRV")) {
00370 showError(
00371 i18n("Some driver files are missing. You can get them on "
00372 "<a href=\"http://www.adobe.com\">Adobe</a> web site. "
00373 "See <a href=\"man:/cupsaddsmb\">cupsaddsmb</a> manual "
00374 "page for more details (you need <a href=\"http://www.cups.org\">CUPS</a> "
00375 "version 1.1.11 or higher)."));
00376 return false;
00377 }
00378
00379 m_bar->setRange(0, 18);
00380 m_bar->setValue(0);
00381
00382 m_textinfo->setText(i18n("Preparing to upload driver to host %1", m_servered->text()));
00383 m_cancel->setEnabled(false);
00384 m_logined->setEnabled(false);
00385 m_servered->setEnabled(false);
00386 m_passwded->setEnabled(false);
00387 m_doit->setText(i18n("&Abort"));
00388
00389 const char *ppdfile;
00390
00391 if ((ppdfile = cupsGetPPD(m_dest.toLocal8Bit())) == NULL) {
00392 showError(i18n("The driver for printer <b>%1</b> could not be found.", m_dest));
00393 return false;
00394 }
00395
00396 m_actions.clear();
00397 m_actions << "mkdir" << "W32X86";
00398 m_actions << "put" << ppdfile << "W32X86/" + m_dest + ".PPD";
00399 m_actions << "put" << m_datadir + "/drivers/ADOBEPS5.DLL" << "W32X86/ADOBEPS5.DLL";
00400 m_actions << "put" << m_datadir + "/drivers/ADOBEPSU.DLL" << "W32X86/ADOBEPSU.DLL";
00401 m_actions << "put" << m_datadir + "/drivers/ADOBEPSU.HLP" << "W32X86/ADOBEPSU.HLP";
00402 m_actions << "mkdir" << "WIN40";
00403 m_actions << "put" << ppdfile << "WIN40/" + m_dest + ".PPD";
00404 m_actions << "put" << m_datadir + "/drivers/ADFONTS.MFM" << "WIN40/ADFONTS.MFM";
00405 m_actions << "put" << m_datadir + "/drivers/ADOBEPS4.DRV" << "WIN40/ADOBEPS4.DRV";
00406 m_actions << "put" << m_datadir + "/drivers/ADOBEPS4.HLP" << "WIN40/ADOBEPS4.HLP";
00407 m_actions << "put" << m_datadir + "/drivers/DEFPRTR2.PPD" << "WIN40/DEFPRTR2.PPD";
00408 m_actions << "put" << m_datadir + "/drivers/ICONLIB.DLL" << "WIN40/ICONLIB.DLL";
00409 m_actions << "put" << m_datadir + "/drivers/PSMON.DLL" << "WIN40/PSMON.DLL";
00410 m_actions << "quit";
00411
00412 m_proc.clearProgram();
00413 m_procname = "smbclient";
00414 m_proc << m_procname << QLatin1String("//") + m_servered->text() + "/print$";
00415 return startProcess();
00416 }
00417
00418 bool CupsAddSmb::doInstall()
00419 {
00420 m_status = false;
00421 m_state = None;
00422
00423 m_actions.clear();
00424 m_actions << "adddriver" << "Windows NT x86" << m_dest + ":ADOBEPS5.DLL:" + m_dest + ".PPD:ADOBEPSU.DLL:ADOBEPSU.HLP:NULL:RAW:NULL";
00425
00426
00427 m_actions << "adddriver" << "Windows 4.0" << m_dest + ":ADOBEPS4.DRV:" + m_dest + ".PPD:NULL:ADOBEPS4.HLP:PSMON.DLL:RAW:ADFONTS.MFM,DEFPRTR2.PPD,ICONLIB.DLL";
00428
00429 m_actions << "setdriver" << m_dest;
00430 m_actions << "quit";
00431
00432
00433 m_textinfo->setText(i18n("Preparing to install driver on host %1", m_servered->text()));
00434
00435 m_proc.clearProgram();
00436 m_procname = "rpcclient";
00437 m_proc << m_procname << m_servered->text();
00438 return startProcess();
00439 }
00440
00441 bool CupsAddSmb::startProcess()
00442 {
00443 m_proc << "-d" << "0" << "-N" << "-U";
00444 if (m_passwded->text().isEmpty())
00445 m_proc << m_logined->text();
00446 else
00447 m_proc << m_logined->text() + '%' + m_passwded->text();
00448 m_state = Start;
00449 m_actionindex = 0;
00450 m_buffer.clear();
00451 kDebug(500) << "PROCESS STARTED = " << m_procname;
00452 m_proc.start();
00453 return m_proc.waitForStarted(5000);
00454 }
00455
00456 #include "cupsaddsmb2.moc"