2 ** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program in a file called COPYING; if not, write to
19 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 ** MA 02110-1301, USA.
24 ** Bug reports and questions can be sent to kde-devel@kde.org
28 #include <QtCore/QTimer>
29 #include <QtCore/QRegExp>
31 #include <QtCore/QTextCodec>
33 #include <k3processcontroller.h>
36 #include <kpassworddialog.h>
37 #include <kapplication.h>
42 #include <kpSettings.h>
43 #include <kpackageSettings.h>
47 const int TIMEOUT
= -33;
48 const int PASSWORD
= -2000;
49 const int PROMPT
= -1000;
51 //////////////////////////////////////////////////////////////////////////////
53 kpKProcIO::kpKProcIO ( QTextCodec
*_codec
)
58 kpKProcIO::~kpKProcIO()
62 bool kpKProcIO::sstart (RunMode runmode
)
65 connect (this, SIGNAL (receivedStdout (K3Process
*, char *, int)),
66 this, SLOT (received (K3Process
*, char *, int)));
69 connect (this, SIGNAL (wroteStdin(K3Process
*)),
70 this, SLOT (sent (K3Process
*)));
72 return K3Process::start (runmode
,( K3Process::Communication
) ( K3Process::Stdin
| K3Process::Stdout
));
75 //////////////////////////////////////////////////////////////////////////////
77 kpPty::kpPty() : QObject()
79 QTextCodec
*codec
= QTextCodec::codecForName("UTF-8");
80 pty
= new kpKProcIO(codec
);
81 pty
->setUsePty(K3Process::All
, false);
84 connect(pty
, SIGNAL(readReady(K3ProcIO
*)), this,
86 connect(pty
, SIGNAL(processExited(K3Process
*)), this,
88 pty
->pty()->setWinSize(0,80);
89 tm
= new QTimer(this);
90 connect(tm
, SIGNAL(timeout()), this, SLOT(slotTimeout()));
97 codec
= QTextCodec::codecForLocale();
105 void kpPty::startSu()
107 kDebug() << "startSu()\n";
108 pty
->setEnvironment("PS1", SHPROMPT
);
109 (*pty
) << "su" << "-s" << "/bin/sh";
112 void kpPty::startSudo()
114 kDebug() << "startSudo()\n";
115 pty
->setEnvironment("PS1", SHPROMPT
);
116 (*pty
) << "sudo" << "-p" << "Password: " << "/bin/sh";
119 void kpPty::startSsh()
121 kDebug() << "startSsh()\n";
122 (*pty
) << "/usr/bin/ssh" << "-t" << "-l" << "root";
123 if (hostName
.isEmpty()) {
124 (*pty
) << "-o" << "StrictHostKeyChecking=no" << "localhost";
128 (*pty
) << "env PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin PS1='" SHPROMPT
"' sh";
131 bool kpPty::needSession(bool needRoot
)
133 return (!hostName
.isEmpty() || needRoot
);
136 bool kpPty::startSession(bool needRoot
)
138 bool interact
= false; // Have interacted with user, prevents loops
139 bool passwordTried
= false; // Have tried the current save password, so need to put up dialog
141 kDebug() << "kpPty::startSession\n";
142 if (!inSession
&& needSession(needRoot
)) {
143 // Assume !needRoot actions are simple executables
144 kDebug() << "kpPty::startSession TRUE\n";
147 QString s
= "echo START=$?\n";
155 kDebug() << "privCmd=" << kpkg
->conf
->privCommand
<< " " << Settings::EnumPrivCommand::sudo
<< " " << Settings::EnumPrivCommand::su
<< "\n";
156 if (kpkg
->conf
->privCommand
== Settings::EnumPrivCommand::ssh
|| !hostName
.isEmpty()) {
157 passMsg
= i18n("The action you requested uses ssh. Please enter the password or pass phrase.\n");
159 } else if (kpkg
->conf
->privCommand
== Settings::EnumPrivCommand::su
) {
160 passMsg
= i18n("The action you requested needs root privileges. Please enter root's password.\n");
162 } else if (kpkg
->conf
->privCommand
== Settings::EnumPrivCommand::sudo
) {
163 passMsg
= i18n("The action you requested needs root privileges. Please enter your password.\n");
166 kDebug() << "privCommand Invalid\n";
168 pty
->sstart(K3Process::NotifyOnExit
);
173 kDebug() << "Loopst\n";
175 kDebug() << "Loopfn Result=" << Result
<< "\n";
177 if (Result
== TIMEOUT
) { // timeout
179 // kDebug() << "Line=" << retList.last() << "\n";
180 kpstart
->addText(retList
);
181 kpstart
->run("", i18n("Login Problem: Please login manually"));
183 ret
= kpstart
->exec();
184 kDebug() << "Sret=" << ret
<< "\n";
190 } else if (Result
== PASSWORD
) { // We got a password prompt
194 kDebug() << "H=" << hostName
<< " PT=" << passwordTried
<<"\n";
196 if (passwords
[hostName
].count()!=0 && !passwordTried
) {
197 pass
= passwords
[hostName
];
200 kDebug() << "Passwd=" << retList
.last() << "\n";
201 QString msg
= passMsg
;
202 if (kpkg
->conf
->privCommand
== Settings::EnumPrivCommand::ssh
|| !hostName
.isEmpty()) {
203 msg
+= retList
.last();
205 KPasswordDialog
dlg(0 , KPasswordDialog::ShowKeepPassword
);
206 dlg
.setPrompt( msg
);
208 pass
= dlg
.password();
209 // kDebug() << "Pass=" << pass << " Res=" << res << "\n";
210 if (res
&& dlg
.keepPassword()) {
211 passwords
[hostName
] = pass
;
213 passwords
.remove(hostName
);
216 pty
->writeStdin(pass
.append("\n"), false);
217 passwordTried
= true;
224 } else if (Result
== PROMPT
) { // Got Prompt
226 kDebug() << "kpPty::startSession TRUE\n";
227 } else { // process return code
228 pty
->writeStdin(QByteArray("\04"), false); // SU doesn't listen to ^C
232 QString errMsg
= retList
.join(" ");
233 KpMsgE(errMsg
, true);
238 kDebug() << "kpPty::startSession Not needed\n";
241 loginSession
= false;
248 void kpPty::breakUpCmd(const QString
&cmd
)
250 kDebug() << " kpPty::run CMD=\""<< cmd
<<"\" pty = " << pty
<< "\n";
254 QStringList cl
= cmd
.split(" ", QString::SkipEmptyParts
);
256 for ( QStringList::Iterator it
= cl
.begin(); it
!= cl
.end(); ++it
) {
257 // kDebug() << "S=" << *it << "\n";
258 int lastPt
= (*it
).length() - 1;
259 if ((*it
)[0] == '\'') { // Start of quoted string
261 if ((*it
)[lastPt
] == '\'') { // Also End of quoted string
269 } else if ((*it
)[lastPt
] == '\'') { // End of quoted string
283 void kpPty::listClear()
288 QStringList
kpPty::run(const QString
&cmd
, bool inLoop
, bool needRoot
, bool noReturn
)
295 if (!inSession
&& !needSession(needRoot
)) {
296 // Assume !needRoot actions are simple executables
299 pty
->setEnvironment("TERM", "dumb");
300 if (!pty
->sstart(K3Process::NotifyOnExit
)) {
301 kDebug() << " kpPty::run execute=0\n";
302 return QStringList();
305 if (startSession(needRoot
)) {
306 kDebug() << "CMDroot='"<< cmd
<<"'\n";
307 QString s
= cmd
+ ";echo RESULT=$?";
309 kDebug() << " kpPty::run session\n";
311 kDebug() << " kpPty::run other=0\n";
312 return QStringList();
320 kDebug() << "return Result=" << Result
<< " " << retList
.count() << "\n";
323 return QStringList();
327 void kpPty::close() {
328 // kDebug() << "kpPty::close\n";
331 while(pty
->isRunning()) {
332 K3ProcessController::instance()->waitForProcessExit(1);
337 void kpPty::finish(int ret
)
339 // kDebug() << "kpPty::finish " << ret << " " << retList.count() << "\n";
341 QStringList::Iterator l
;
343 if (ret
== PROMPT
) { // Called program executed in session
344 if (!retList
.empty()) {
345 l
= retList
.fromLast();
346 if ((*l
).right(2) == SHPROMPT
) {
347 retList
.erase(l
); // Remove prompt
351 if (!retList
.empty()) {
353 l
= retList
.fromLast();
354 // kDebug() << "kpPty::finish RESULT=" << *l << "\n";
355 if ((p
= (*l
).indexOf("RESULT=")) >= 0) {
356 ret
= (*l
).mid(p
+7).toInt(0,10);
357 retList
.erase(l
); // Remove return code
361 if (!retList
.empty()) {
363 if ( l
!= retList
.end()) {
364 if ((*l
).indexOf("RESULT=") >= 0) {
365 retList
.erase(l
); // Remove command at start
370 emit
result(retList
,ret
);
372 // kDebug() << "Result=" << Result << " ret=" << ret <<"\n";
381 void kpPty::readLines()
386 while(pty
->readln(stext
, false, &unterm
) >= 0)
388 // kDebug() << "[=" << pUnterm << "-" << unterm << "=" << stext.length() << "-" << stext << ">\n";
390 emit
textIn(stext
, !unterm
);
393 QStringList::Iterator lst
;
394 lst
= retList
.fromLast();
395 if (lst
!= retList
.end())
397 stext
= *lst
+ stext
;
403 emit
textLine(stext
);
407 while (stext
.endsWith("\r")) {
408 stext
.truncate(stext
.length()-1);
411 i
= stext
.lastIndexOf('\r');
413 stext
= stext
.mid(i
+1);
419 if (!noRet
|| unterm
)
422 // kDebug() << "++" << stext << "\n";
423 if (stext
.right(2) == SHPROMPT
) { // Shell prompt
424 emit
textIn("\r \n", false);
426 } else if (loginSession
) {
427 QRegExp
rx( "^[^:]+:[\\s]*$"); // Password prompt
428 if (rx
.indexIn(retList
.last()) >= 0) {
429 kDebug() << loginSession
<< " " <<retList
.last()<< " Match password p\n";
437 void kpPty::keyOut(QString s
)
439 pty
->writeStdin(s
, false);
444 int ret
= pty
->exitStatus();
450 void kpPty::slotTimeout()
452 kDebug() << "Timeout..............\n";