SVN_SILENT made messages (.desktop file)
[kdeadmin.git] / kpackage / kpPty.cpp
blobd01e8f29f7eb0580e39f98236de2b5a1710389a1
1 /*
2 ** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
3 **
4 */
6 /*
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>
30 //Added by qt3to4:
31 #include <QtCore/QTextCodec>
33 #include <k3processcontroller.h>
34 #include <kpty.h>
35 #include <kdebug.h>
36 #include <kpassworddialog.h>
37 #include <kapplication.h>
39 #include <kpPty.h>
40 #include <kpackage.h>
41 #include <kpTerm.h>
42 #include <kpSettings.h>
43 #include <kpackageSettings.h>
44 #include <utils.h>
46 #define SHPROMPT "# "
47 const int TIMEOUT = -33;
48 const int PASSWORD = -2000;
49 const int PROMPT = -1000;
51 //////////////////////////////////////////////////////////////////////////////
53 kpKProcIO::kpKProcIO ( QTextCodec *_codec)
54 : K3ProcIO(_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,
85 SLOT(readLines()));
86 connect(pty, SIGNAL(processExited(K3Process *)), this,
87 SLOT(done()));
88 pty->pty()->setWinSize(0,80);
89 tm = new QTimer(this);
90 connect(tm, SIGNAL(timeout()), this, SLOT(slotTimeout()));
92 eventLoop = false;
93 inSession = false;
94 pUnterm = false;
95 loginSession = false;
97 codec = QTextCodec::codecForLocale();
101 kpPty::~kpPty()
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";
125 } else {
126 (*pty) << hostName;
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
140 pUnterm = false;
141 kDebug() << "kpPty::startSession\n";
142 if (!inSession && needSession(needRoot)) {
143 // Assume !needRoot actions are simple executables
144 kDebug() << "kpPty::startSession TRUE\n";
145 loginSession = true;
146 int ret;
147 QString s = "echo START=$?\n";
149 FULL_RESTART:
150 interact = false;
151 retList.clear();
152 pty->resetAll();
154 QString passMsg;
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");
158 startSsh();
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");
161 startSu();
162 } else if (kpkg->conf->privCommand == Settings::EnumPrivCommand::sudo) {
163 passMsg = i18n("The action you requested needs root privileges. Please enter your password.\n");
164 startSudo();
165 } else {
166 kDebug() << "privCommand Invalid\n";
168 pty->sstart(K3Process::NotifyOnExit);
170 RESTART:
171 tm->start(6*1000);
172 eventLoop = true;
173 kDebug() << "Loopst\n";
174 kapp->enter_loop();
175 kDebug() << "Loopfn Result=" << Result << "\n";
176 tm->stop();
177 if (Result == TIMEOUT) { // timeout
178 interact = true;
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";
185 if (ret) {
186 inSession = false;
187 } else {
188 inSession = true;
190 } else if (Result == PASSWORD) { // We got a password prompt
191 QString pass;
192 int res;
193 interact = true;
194 kDebug() << "H=" << hostName << " PT=" << passwordTried <<"\n";
196 if (passwords[hostName].count()!=0 && !passwordTried) {
197 pass = passwords[hostName];
198 res = 1;
199 } else {
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 );
207 res = dlg.exec();
208 pass = dlg.password();
209 // kDebug() << "Pass=" << pass << " Res=" << res << "\n";
210 if (res && dlg.keepPassword()) {
211 passwords[hostName] = pass;
212 } else if(res) {
213 passwords.remove(hostName);
216 pty->writeStdin(pass.append("\n"), false);
217 passwordTried = true;
218 if (res) {
219 retList.clear();
220 goto RESTART;
221 } else {
222 inSession = false;
224 } else if (Result == PROMPT) { // Got Prompt
225 inSession = true;
226 kDebug() << "kpPty::startSession TRUE\n";
227 } else { // process return code
228 pty->writeStdin(QByteArray("\04"), false); // SU doesn't listen to ^C
229 if (interact) {
230 goto FULL_RESTART;
231 } else {
232 QString errMsg = retList.join(" ");
233 KpMsgE(errMsg, true);
234 inSession = false;
237 } else {
238 kDebug() << "kpPty::startSession Not needed\n";
241 loginSession = false;
242 if (!inSession)
243 close();
245 return inSession;
248 void kpPty::breakUpCmd(const QString &cmd)
250 kDebug() << " kpPty::run CMD=\""<< cmd <<"\" pty = " << pty << "\n";
252 bool quote = false;
253 QString s;
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
260 s = *it;
261 if ((*it)[lastPt] == '\'') { // Also End of quoted string
262 s.replace("'","");
263 (*pty) << s;
264 quote = false;
265 } else {
266 s += ' ';
267 quote = true;
269 } else if ((*it)[lastPt] == '\'') { // End of quoted string
270 s += *it;
271 s.replace("'","");
272 (*pty) << s;
273 quote = false;
274 } else if (quote) {
275 s += *it;
276 s += ' ';
277 } else {
278 (*pty) << (*it);
283 void kpPty::listClear()
285 retList.clear();
288 QStringList kpPty::run(const QString &cmd, bool inLoop, bool needRoot, bool noReturn)
290 Result = 0;
292 pUnterm = false;
293 noRet = noReturn;
295 if (!inSession && !needSession(needRoot)) {
296 // Assume !needRoot actions are simple executables
297 pty->resetAll();
298 breakUpCmd(cmd);
299 pty->setEnvironment("TERM", "dumb");
300 if (!pty->sstart(K3Process::NotifyOnExit)) {
301 kDebug() << " kpPty::run execute=0\n";
302 return QStringList();
304 } else {
305 if (startSession(needRoot)) {
306 kDebug() << "CMDroot='"<< cmd <<"'\n";
307 QString s = cmd + ";echo RESULT=$?";
308 pty->writeStdin(s);
309 kDebug() << " kpPty::run session\n";
310 } else {
311 kDebug() << " kpPty::run other=0\n";
312 return QStringList();
315 retList.clear();
317 if (inLoop) {
318 eventLoop = true;
319 kapp->enter_loop();
320 kDebug() << "return Result=" << Result << " " << retList.count() << "\n";
321 return retList;
322 } else {
323 return QStringList();
327 void kpPty::close() {
328 // kDebug() << "kpPty::close\n";
330 pty->closeAll();
331 while(pty->isRunning()) {
332 K3ProcessController::instance()->waitForProcessExit(1);
334 inSession = false;
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()) {
352 int p;
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()) {
362 l = retList.begin();
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";
373 Result = ret;
375 if (eventLoop) {
376 eventLoop = false;
377 kapp->exit_loop();
381 void kpPty::readLines()
383 bool unterm = false;
385 QString stext;
386 while(pty->readln(stext, false, &unterm) >= 0)
388 // kDebug() << "[=" << pUnterm << "-" << unterm << "=" << stext.length() << "-" << stext << ">\n";
390 emit textIn(stext, !unterm);
392 if (pUnterm) {
393 QStringList::Iterator lst;
394 lst = retList.fromLast();
395 if (lst != retList.end())
397 stext = *lst + stext;
398 retList.erase(lst);
402 if (!unterm)
403 emit textLine(stext);
405 int i;
406 if (!unterm) {
407 while (stext.endsWith("\r")) {
408 stext.truncate(stext.length()-1);
411 i = stext.lastIndexOf('\r');
412 if (i > -1) {
413 stext = stext.mid(i+1);
417 pUnterm = unterm;
419 if (!noRet || unterm)
420 retList << stext;
422 // kDebug() << "++" << stext << "\n";
423 if (stext.right(2) == SHPROMPT) { // Shell prompt
424 emit textIn("\r \n", false);
425 finish(PROMPT);
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";
430 finish(PASSWORD);
434 pty->ackRead();
437 void kpPty::keyOut(QString s)
439 pty->writeStdin(s, false);
442 void kpPty::done()
444 int ret = pty->exitStatus();
445 QString stext;
447 finish(ret);
450 void kpPty::slotTimeout()
452 kDebug() << "Timeout..............\n";
453 finish(TIMEOUT);
455 #include "kpPty.moc"