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