kdeprint Library API Documentation

cupsaddsmb2.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., 59 Temple Place - Suite 330,
00017  *  Boston, MA 02111-1307, USA.
00018  **/
00019 
00020 #include "cupsaddsmb2.h"
00021 #include "cupsinfos.h"
00022 #include "sidepixmap.h"
00023 
00024 #include <qtimer.h>
00025 #include <qprogressbar.h>
00026 #include <qlabel.h>
00027 #include <qpushbutton.h>
00028 #include <qlayout.h>
00029 #include <qlineedit.h>
00030 #include <klocale.h>
00031 #include <kmessagebox.h>
00032 #include <qmessagebox.h>
00033 #include <qfile.h>
00034 #include <kio/passdlg.h>
00035 #include <kdebug.h>
00036 #include <kseparator.h>
00037 #include <kactivelabel.h>
00038 #include <qwhatsthis.h>
00039 
00040 #include <cups/cups.h>
00041 #include <ctype.h>
00042 
00043 CupsAddSmb::CupsAddSmb(QWidget *parent, const char *name)
00044 : KDialog(parent, name)
00045 {
00046     m_state = None;
00047     m_status = false;
00048     m_actionindex = 0;
00049     connect(&m_proc, SIGNAL(receivedStdout(KProcess*,char*,int)), SLOT(slotReceived(KProcess*,char*,int)));
00050     connect(&m_proc, SIGNAL(receivedStderr(KProcess*,char*,int)), SLOT(slotReceived(KProcess*,char*,int)));
00051     connect(&m_proc, SIGNAL(processExited(KProcess*)), SLOT(slotProcessExited(KProcess*)));
00052 
00053     m_side = new SidePixmap(this);
00054     m_doit = new QPushButton(i18n("&Export"), this);
00055     m_cancel = new QPushButton(i18n("&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 KActiveLabel(this);
00060     QLabel  *m_title = new QLabel(i18n("Export printer driver to Windows clients"), this);
00061     setCaption(m_title->text());
00062     QFont   f(m_title->font());
00063     f.setBold(true);
00064     m_title->setFont(f);
00065     KSeparator  *m_sep = new KSeparator(Qt::Horizontal, this);
00066     m_textinfo = new QLabel( this );
00067     m_logined = new QLineEdit( this );
00068     m_passwded = new QLineEdit( this );
00069     m_passwded->setEchoMode( QLineEdit::Password );
00070     m_servered = new QLineEdit( this );
00071     QLabel *m_loginlab = new QLabel( i18n( "&Username:" ), this );
00072     QLabel *m_serverlab = new QLabel( i18n( "&Samba server:" ), this );
00073     QLabel *m_passwdlab = new QLabel( i18n( "&Password:" ), this );
00074     m_loginlab->setBuddy( m_logined );
00075     m_serverlab->setBuddy( m_servered );
00076     m_passwdlab->setBuddy( m_passwded );
00077 
00078     QString txt = i18n( "<p><b>Samba server</b></p>"
00079                         "Adobe Windows PostScript driver files plus the CUPS printer PPD will be "
00080                         "exported to the <tt>[print$]</tt> special share of the Samba server (to change "
00081                         "the source CUPS server, use the <nobr><i>Configure Manager -> CUPS server</i></nobr> first). "
00082                         "The <tt>[print$]</tt> share must exist on the Samba side prior to clicking the "
00083                         "<b>Export</b> button below." );
00084     QWhatsThis::add( m_serverlab, txt );
00085     QWhatsThis::add( m_servered, txt );
00086 
00087     txt = i18n( "<p><b>Samba username</b></p>"
00088                 "User needs to have write access to the <tt>[print$]</tt> share on the Samba server. "
00089                 "<tt>[print$]</tt> holds printer drivers prepared for download to Windows clients. "
00090                 "This dialog does not work for Samba servers configured with <tt>security = share</tt> "
00091                 "(but works fine with <tt>security = user</tt>)." );
00092     QWhatsThis::add( m_loginlab, txt );
00093     QWhatsThis::add( m_logined, txt );
00094 
00095     txt = i18n( "<p><b>Samba password</b></p>"
00096                 "The Samba setting <tt>encrypt passwords = yes</tt> "
00097                 "(default) requires prior use of <tt>smbpasswd -a [username]</tt> command, "
00098                 "to create an encrypted Samba password and have Samba recognize it." );
00099     QWhatsThis::add( m_passwdlab, txt );
00100     QWhatsThis::add( m_passwded, txt );
00101 
00102     QHBoxLayout *l0 = new QHBoxLayout(this, 10, 10);
00103     QVBoxLayout *l1 = new QVBoxLayout(0, 0, 10);
00104     l0->addWidget(m_side);
00105     l0->addLayout(l1);
00106     l1->addWidget(m_title);
00107     l1->addWidget(m_sep);
00108     l1->addWidget(m_text);
00109     QGridLayout *l3 = new QGridLayout( 0, 3, 2, 0, 10 );
00110     l1->addLayout( l3 );
00111     l3->addWidget( m_loginlab, 1, 0 );
00112     l3->addWidget( m_passwdlab, 2, 0 );
00113     l3->addWidget( m_serverlab, 0, 0 );
00114     l3->addWidget( m_logined, 1, 1 );
00115     l3->addWidget( m_passwded, 2, 1 );
00116     l3->addWidget( m_servered, 0, 1 );
00117     l3->setColStretch( 1, 1 );
00118     l1->addSpacing( 10 );
00119     l1->addWidget(m_bar);
00120     l1->addWidget( m_textinfo );
00121     l1->addSpacing(30);
00122     QHBoxLayout *l2 = new QHBoxLayout(0, 0, 10);
00123     l1->addLayout(l2);
00124     l2->addStretch(1);
00125     l2->addWidget(m_doit);
00126     l2->addWidget(m_cancel);
00127 
00128     m_logined->setText( CupsInfos::self()->login() );
00129     m_passwded->setText( CupsInfos::self()->password() );
00130     m_servered->setText( cupsServer() );
00131 
00132     setMinimumHeight(400);
00133 }
00134 
00135 CupsAddSmb::~CupsAddSmb()
00136 {
00137 }
00138 
00139 void CupsAddSmb::slotActionClicked()
00140 {
00141     if (m_state == None)
00142         doExport();
00143     else if (m_proc.isRunning())
00144         m_proc.kill();
00145 }
00146 
00147 void CupsAddSmb::slotReceived(KProcess*, char *buf, int buflen)
00148 {
00149     QString line;
00150     int     index(0);
00151     bool    partial(false);
00152     static bool incomplete(false);
00153 
00154     kdDebug(500) << "slotReceived()" << endl;
00155     while (1)
00156     {
00157         // read a line
00158         line = QString::fromLatin1("");
00159         partial = true;
00160         while (index < buflen)
00161         {
00162             QChar   c(buf[index++]);
00163             if (c == '\n')
00164             {
00165                 partial = false;
00166                 break;
00167             }
00168             else if (c.isPrint())
00169                 line += c;
00170         }
00171 
00172         if (line.isEmpty())
00173         {
00174             kdDebug(500) << "NOTHING TO READ" << endl;
00175             return;
00176         }
00177 
00178         kdDebug(500) << "ANSWER = " << line << " (END = " << line.length() << ")" << endl;
00179         if (!partial)
00180         {
00181             if (incomplete && m_buffer.count() > 0)
00182                 m_buffer[m_buffer.size()-1].append(line);
00183             else
00184                 m_buffer << line;
00185             incomplete = false;
00186             kdDebug(500) << "COMPLETE LINE READ (" << m_buffer.count() << ")" << endl;
00187         }
00188         else
00189         {
00190             if (line.startsWith("smb:") || line.startsWith("rpcclient $"))
00191             {
00192                 kdDebug(500) << "END OF ACTION" << endl;
00193                 checkActionStatus();
00194                 if (m_status)
00195                     nextAction();
00196                 else
00197                 {
00198                     // quit program
00199                     kdDebug(500) << "EXITING PROGRAM..." << endl;
00200                     m_proc.writeStdin("quit\n", 5);
00201                     kdDebug(500) << "SENT" << endl;
00202                 }
00203                 return;
00204             }
00205             else
00206             {
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                 kdDebug(500) << "INCOMPLETE LINE READ (" << m_buffer.count() << ")" << endl;
00213             }
00214         }
00215     }
00216 }
00217 
00218 void CupsAddSmb::checkActionStatus()
00219 {
00220     m_status = false;
00221     // when checking the status, we need to take into account the
00222     // echo of the command in the output buffer.
00223     switch (m_state)
00224     {
00225         case None:
00226         case Start:
00227             m_status = true;
00228             break;
00229         case Copy:
00230             m_status = (m_buffer.count() == 0);
00231             break;
00232         case MkDir:
00233             m_status = (m_buffer.count() == 1 || m_buffer[1].find("ERRfilexists") != -1);
00234             break;
00235         case AddDriver:
00236         case AddPrinter:
00237             m_status = (m_buffer.count() == 1 || !m_buffer[1].startsWith("result"));
00238             break;
00239     }
00240     kdDebug(500) << "ACTION STATUS = " << m_status << endl;
00241 }
00242 
00243 void CupsAddSmb::nextAction()
00244 {
00245     if (m_actionindex < (int)(m_actions.count()))
00246         QTimer::singleShot(1, this, SLOT(doNextAction()));
00247 }
00248 
00249 void CupsAddSmb::doNextAction()
00250 {
00251     m_buffer.clear();
00252     m_state = None;
00253     if (m_proc.isRunning())
00254     {
00255         QCString    s = m_actions[m_actionindex++].latin1();
00256         m_bar->setProgress(m_bar->progress()+1);
00257         kdDebug(500) << "NEXT ACTION = " << s << endl;
00258         if (s == "quit")
00259         {
00260             // do nothing
00261         }
00262         else if (s == "mkdir")
00263         {
00264             m_state = MkDir;
00265             //m_text->setText(i18n("Creating directory %1").arg(m_actions[m_actionindex]));
00266             m_textinfo->setText(i18n("Creating folder %1").arg(m_actions[m_actionindex]));
00267             s.append(" ").append(m_actions[m_actionindex].latin1());
00268             m_actionindex++;
00269         }
00270         else if (s == "put")
00271         {
00272             m_state = Copy;
00273             //m_text->setText(i18n("Uploading %1").arg(m_actions[m_actionindex+1]));
00274             m_textinfo->setText(i18n("Uploading %1").arg(m_actions[m_actionindex+1]));
00275             s.append(" ").append(QFile::encodeName(m_actions[m_actionindex]).data()).append(" ").append(m_actions[m_actionindex+1].latin1());
00276             m_actionindex += 2;
00277         }
00278         else if (s == "adddriver")
00279         {
00280             m_state = AddDriver;
00281             //m_text->setText(i18n("Installing driver for %1").arg(m_actions[m_actionindex]));
00282             m_textinfo->setText(i18n("Installing driver for %1").arg(m_actions[m_actionindex]));
00283             s.append(" \"").append(m_actions[m_actionindex].latin1()).append("\" \"").append(m_actions[m_actionindex+1].latin1()).append("\"");
00284             m_actionindex += 2;
00285         }
00286         else if (s == "addprinter" || s == "setdriver")
00287         {
00288             m_state = AddPrinter;
00289             //m_text->setText(i18n("Installing printer %1").arg(m_actions[m_actionindex]));
00290             m_textinfo->setText(i18n("Installing printer %1").arg(m_actions[m_actionindex]));
00291             QCString    dest = m_actions[m_actionindex].local8Bit();
00292             if (s == "addprinter")
00293                 s.append(" ").append(dest).append(" ").append(dest).append(" \"").append(dest).append("\" \"\"");
00294             else
00295                 s.append(" ").append(dest).append(" ").append(dest);
00296             m_actionindex++;
00297         }
00298         else
00299         {
00300             kdDebug(500) << "ACTION = unknown action" << endl;
00301             m_proc.kill();
00302             return;
00303         }
00304         // send action
00305         kdDebug(500) << "ACTION = " << s << endl;
00306         s.append("\n");
00307         m_proc.writeStdin(s.data(), s.length());
00308     }
00309 }
00310 
00311 void CupsAddSmb::slotProcessExited(KProcess*)
00312 {
00313     kdDebug(500) << "PROCESS EXITED (" << m_state << ")" << endl;
00314     if (m_proc.normalExit() && m_state != Start && m_status)
00315     {
00316         // last process went OK. If it was smbclient, then switch to rpcclient
00317         if (qstrncmp(m_proc.args().first(), "smbclient", 9) == 0)
00318         {
00319             doInstall();
00320             return;
00321         }
00322         else
00323         {
00324             m_doit->setEnabled(false);
00325             m_cancel->setEnabled(true);
00326             m_cancel->setText(i18n("&Close"));
00327             m_cancel->setDefault(true);
00328             m_cancel->setFocus();
00329             m_logined->setEnabled( true );
00330             m_servered->setEnabled( true );
00331             m_passwded->setEnabled( true );
00332             m_text->setText(i18n("Driver successfully exported."));
00333             m_bar->reset();
00334             m_textinfo->setText( QString::null );
00335             return;
00336         }
00337     }
00338 
00339     if (m_proc.normalExit())
00340     {
00341         showError(
00342                 i18n("Operation failed. Possible reasons are: permission denied "
00343                      "or invalid Samba configuration (see <a href=\"man:/cupsaddsmb\">"
00344                      "cupsaddsmb</a> manual page for detailed information, you need "
00345                      "<a href=\"http://www.cups.org\">CUPS</a> version 1.1.11 or higher). "
00346                      "You may want to try again with another login/password."));
00347 
00348     }
00349     else
00350     {
00351         showError(i18n("Operation aborted (process killed)."));
00352     }
00353 }
00354 
00355 void CupsAddSmb::showError(const QString& msg)
00356 {
00357     m_text->setText(i18n("<h3>Operation failed!</h3><p>%1</p>").arg(msg));
00358     m_cancel->setEnabled(true);
00359     m_logined->setEnabled( true );
00360     m_servered->setEnabled( true );
00361     m_passwded->setEnabled( true );
00362     m_doit->setText(i18n("&Export"));
00363     m_state = None;
00364 }
00365 
00366 bool CupsAddSmb::exportDest(const QString &dest, const QString& datadir)
00367 {
00368     CupsAddSmb  dlg;
00369     dlg.m_dest = dest;
00370     dlg.m_datadir = datadir;
00371     dlg.m_text->setText(
00372             i18n( "You are about to prepare the <b>%1</b> driver to be "
00373                   "shared out to Windows clients through Samba. This operation "
00374                   "requires the <a href=\"http://www.adobe.com/products/printerdrivers/main.html\">Adobe PostScript Driver</a>, a recent version of "
00375                   "Samba 2.2.x and a running SMB service on the target server. "
00376                   "Click <b>Export</b> to start the operation. Read the <a href=\"man:/cupsaddsmb\">cupsaddsmb</a> "
00377                   "manual page in Konqueror or type <tt>man cupsaddsmb</tt> in a "
00378                   "console window to learn more about this functionality." ).arg( dest ) );
00379     dlg.exec();
00380     return dlg.m_status;
00381 }
00382 
00383 bool CupsAddSmb::doExport()
00384 {
00385     m_status = false;
00386     m_state = None;
00387 
00388     if (!QFile::exists(m_datadir+"/drivers/ADOBEPS5.DLL") ||
00389         !QFile::exists(m_datadir+"/drivers/ADOBEPS4.DRV"))
00390     {
00391         showError(
00392             i18n("Some driver files are missing. You can get them on "
00393                  "<a href=\"http://www.adobe.com\">Adobe</a> web site. "
00394                  "See <a href=\"man:/cupsaddsmb\">cupsaddsmb</a> manual "
00395                  "page for more details (you need <a href=\"http://www.cups.org\">CUPS</a> "
00396                  "version 1.1.11 or higher)."));
00397         return false;
00398     }
00399 
00400     m_bar->setTotalSteps(18);
00401     m_bar->setProgress(0);
00402     //m_text->setText(i18n("<p>Preparing to upload driver to host <b>%1</b>").arg(m_servered->text()));
00403     m_textinfo->setText(i18n("Preparing to upload driver to host %1").arg(m_servered->text()));
00404     m_cancel->setEnabled(false);
00405     m_logined->setEnabled( false );
00406     m_servered->setEnabled( false );
00407     m_passwded->setEnabled( false );
00408     m_doit->setText(i18n("&Abort"));
00409 
00410     const char  *ppdfile;
00411 
00412     if ((ppdfile = cupsGetPPD(m_dest.local8Bit())) == NULL)
00413     {
00414         showError(i18n("The driver for printer <b>%1</b> could not be found.").arg(m_dest));
00415         return false;
00416     }
00417 
00418     m_actions.clear();
00419     m_actions << "mkdir" << "W32X86";
00420     m_actions << "put" << ppdfile << "W32X86/"+m_dest+".PPD";
00421     m_actions << "put" << m_datadir+"/drivers/ADOBEPS5.DLL" << "W32X86/ADOBEPS5.DLL";
00422     m_actions << "put" << m_datadir+"/drivers/ADOBEPSU.DLL" << "W32X86/ADOBEPSU.DLL";
00423     m_actions << "put" << m_datadir+"/drivers/ADOBEPSU.HLP" << "W32X86/ADOBEPSU.HLP";
00424     m_actions << "mkdir" << "WIN40";
00425     m_actions << "put" << ppdfile << "WIN40/"+m_dest+".PPD";
00426     m_actions << "put" << m_datadir+"/drivers/ADFONTS.MFM" << "WIN40/ADFONTS.MFM";
00427     m_actions << "put" << m_datadir+"/drivers/ADOBEPS4.DRV" << "WIN40/ADOBEPS4.DRV";
00428     m_actions << "put" << m_datadir+"/drivers/ADOBEPS4.HLP" << "WIN40/ADOBEPS4.HLP";
00429     m_actions << "put" << m_datadir+"/drivers/DEFPRTR2.PPD" << "WIN40/DEFPRTR2.PPD";
00430     m_actions << "put" << m_datadir+"/drivers/ICONLIB.DLL" << "WIN40/ICONLIB.DLL";
00431     m_actions << "put" << m_datadir+"/drivers/PSMON.DLL" << "WIN40/PSMON.DLL";
00432     m_actions << "quit";
00433 
00434     m_proc.clearArguments();
00435     m_proc << "smbclient" << QString::fromLatin1("//")+m_servered->text()+"/print$";
00436     return startProcess();
00437 }
00438 
00439 bool CupsAddSmb::doInstall()
00440 {
00441     m_status = false;
00442     m_state = None;
00443 
00444     m_actions.clear();
00445     m_actions << "adddriver" << "Windows NT x86" << m_dest+":ADOBEPS5.DLL:"+m_dest+".PPD:ADOBEPSU.DLL:ADOBEPSU.HLP:NULL:RAW:NULL";
00446     // seems to be wrong with newer versions of Samba
00447     //m_actions << "addprinter" << m_dest;
00448     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";
00449     // seems to be ok with newer versions of Samba
00450     m_actions << "setdriver" << m_dest;
00451     m_actions << "quit";
00452 
00453     //m_text->setText(i18n("Preparing to install driver on host <b>%1</b>").arg(m_servered->text()));
00454     m_textinfo->setText(i18n("Preparing to install driver on host %1").arg(m_servered->text()));
00455 
00456     m_proc.clearArguments();
00457     m_proc << "rpcclient" << m_servered->text();
00458     return startProcess();
00459 }
00460 
00461 bool CupsAddSmb::startProcess()
00462 {
00463     m_proc << "-d" << "0" << "-N" << "-U";
00464     if (m_passwded->text().isEmpty())
00465         m_proc << m_logined->text();
00466     else
00467         m_proc << m_logined->text()+"%"+m_passwded->text();
00468     m_state = Start;
00469     m_actionindex = 0;
00470     m_buffer.clear();
00471     kdDebug(500) << "PROCESS STARTED = " << m_proc.args()[0] << endl;
00472     return m_proc.start(KProcess::NotifyOnExit, KProcess::All);
00473 }
00474 
00475 #include "cupsaddsmb2.moc"
KDE Logo
This file is part of the documentation for kdeprint Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Mar 3 19:24:20 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003