summaryrefslogtreecommitdiffstats
path: root/kppp/connect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kppp/connect.cpp')
-rw-r--r--kppp/connect.cpp1535
1 files changed, 1535 insertions, 0 deletions
diff --git a/kppp/connect.cpp b/kppp/connect.cpp
new file mode 100644
index 00000000..1203f4ba
--- /dev/null
+++ b/kppp/connect.cpp
@@ -0,0 +1,1535 @@
+/*
+ * kPPP: A pppd front end for the KDE project
+ *
+ *
+ * Copyright (C) 1997 Bernd Johannes Wuebben
+ * Copyright (C) 1998-2001 Harri Porten <[email protected]>
+ *
+ * based on EzPPP:
+ * Copyright (C) 1997 Jay Painter
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <qlayout.h>
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <assert.h>
+
+#ifdef _XPG4_2
+#define __xnet_connect connect
+#endif
+
+#include <errno.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef __linux__
+#include "runtests.h"
+#endif
+
+#include "auth.h"
+#include "connect.h"
+#include "docking.h"
+#include "main.h"
+#include "modem.h"
+#include "kpppconfig.h"
+#include "pppdata.h"
+#include "pppstats.h"
+#include "requester.h"
+#include "utils.h"
+
+extern KPPPWidget *p_kppp;
+
+QString old_hostname;
+bool modified_hostname;
+
+
+ConnectWidget::ConnectWidget(QWidget *parent, const char *name, PPPStats *st)
+ : QWidget(parent, name),
+ // initialize some important variables
+ myreadbuffer(""),
+ main_timer_ID(0),
+ vmain(0),
+ substate(-1),
+ scriptindex(0),
+ loopnest(0),
+ loopend(false),
+ semaphore(false),
+ expecting(false),
+ readbuffer(""),
+ scanvar(""),
+ scanning(false),
+ pausing(false),
+ termwindow(0),
+ dialnumber(0),
+ stats(st)
+{
+ modified_hostname = false;
+
+ QVBoxLayout *tl = new QVBoxLayout(this, 8, 10);
+ QString tit = i18n("Connecting to: ");
+ setCaption(tit);
+
+ QHBoxLayout *l0 = new QHBoxLayout(10);
+ tl->addLayout(l0);
+ l0->addSpacing(10);
+ messg = new QLabel(this, "messg");
+ messg->setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ messg->setAlignment(AlignCenter);
+ messg->setText(i18n("Unable to create modem lock file."));
+ messg->setMinimumHeight(messg->sizeHint().height() + 5);
+ int messw = (messg->sizeHint().width() * 12) / 10;
+ messw = QMAX(messw,280);
+ messg->setMinimumWidth(messw);
+ messg->setText(i18n("Looking for modem..."));
+ l0->addWidget(messg);
+ l0->addSpacing(10);
+
+ QHBoxLayout *l1 = new QHBoxLayout(10);
+ tl->addLayout(l1);
+ l1->addStretch(1);
+
+ debug = new QPushButton(i18n("&Log"), this);
+ debug->setToggleButton(true);
+ connect(debug, SIGNAL(clicked()), SIGNAL(toggleDebugWindow()));
+
+ cancel = new KPushButton(KStdGuiItem::cancel(), this);
+ cancel->setFocus();
+ connect(cancel, SIGNAL(clicked()), SLOT(cancelbutton()));
+
+ int maxw = QMAX(cancel->sizeHint().width(),
+ debug->sizeHint().width());
+ maxw = QMAX(maxw,65);
+ debug->setFixedWidth(maxw);
+ cancel->setFixedWidth(maxw);
+ l1->addWidget(debug);
+ l1->addWidget(cancel);
+ l1->addSpacing(10);
+
+ setFixedSize(sizeHint());
+
+ pausetimer = new QTimer(this);
+ connect(pausetimer, SIGNAL(timeout()), SLOT(pause()));
+
+ kapp->processEvents();
+
+ timeout_timer = new QTimer(this);
+ connect(timeout_timer, SIGNAL(timeout()), SLOT(script_timed_out()));
+
+ inittimer = new QTimer(this);
+ connect(inittimer, SIGNAL(timeout()), SLOT(init()));
+
+ if_timeout_timer = new QTimer(this);
+ connect(if_timeout_timer, SIGNAL(timeout()), SLOT(if_waiting_timed_out()));
+
+ connect(this,SIGNAL(if_waiting_signal()),this,SLOT(if_waiting_slot()));
+
+ prompt = new PWEntry( this, "pw" );
+ if_timer = new QTimer(this);
+ connect(if_timer,SIGNAL(timeout()), SLOT(if_waiting_slot()));
+}
+
+
+ConnectWidget::~ConnectWidget() {
+}
+
+
+void ConnectWidget::disableButtons()
+{
+ debug->setEnabled(false);
+ cancel->setEnabled(false);
+}
+
+void ConnectWidget::enableButtons()
+{
+ debug->setEnabled(true);
+ cancel->setEnabled(true);
+}
+
+void ConnectWidget::preinit() {
+ // this is all just to keep the GUI nice and snappy ....
+ // you have to see to believe ...
+ messg->setText(i18n("Looking for modem..."));
+ inittimer->start(100);
+}
+
+void ConnectWidget::init() {
+ gpppdata.setpppdError(0);
+ inittimer->stop();
+ vmain = 0;
+ substate = -1;
+ expecting = false;
+ pausing = false;
+ scriptindex = 0;
+ myreadbuffer = "";
+ scanning = false;
+ scanvar = "";
+ firstrunID = true;
+ firstrunPW = true;
+ stats->totalbytes = 0;
+ dialnumber = 0;
+
+ p_kppp->con_speed = "";
+
+ p_kppp->setQuitOnDisconnect (p_kppp->quitOnDisconnect() || gpppdata.quit_on_disconnect());
+
+ comlist = &gpppdata.scriptType();
+ arglist = &gpppdata.script();
+
+ QString tit = i18n("Connecting to: %1").arg(gpppdata.accname());
+ setCaption(tit);
+
+ kapp->processEvents();
+
+ // signal other applications that we are about to get connected
+ kapp->dcopClient()->emitDCOPSignal("KpppIface", "aboutToConnect()", QByteArray());
+
+ // run the "before-connect" command
+ if (!gpppdata.command_before_connect().isEmpty()) {
+ messg->setText(i18n("Running pre-startup command..."));
+ emit debugMessage(i18n("Running pre-startup command..."));
+
+ kapp->processEvents();
+ QApplication::flushX();
+ pid_t id = execute_command(gpppdata.command_before_connect());
+ int i, status;
+
+ do {
+ kapp->processEvents();
+ i = waitpid(id, &status, WNOHANG);
+ usleep(100000);
+ } while (i == 0 && errno == 0);
+ }
+
+ int lock = Modem::modem->lockdevice();
+
+ if (lock == 1) {
+ messg->setText(i18n("Modem device is locked."));
+ vmain = 20; // wait until cancel is pressed
+ return;
+ }
+
+ if (lock == -1) {
+ messg->setText(i18n("Unable to create modem lock file."));
+ vmain = 20; // wait until cancel is pressed
+ return;
+ }
+
+ if(Modem::modem->opentty()) {
+ messg->setText(Modem::modem->modemMessage());
+ kapp->processEvents();
+ if(Modem::modem->hangup()) {
+
+ kapp->processEvents();
+
+ semaphore = false;
+
+ Modem::modem->stop();
+ Modem::modem->notify(this, SLOT(readChar(unsigned char)));
+
+ // if we are stuck anywhere we will time out
+ timeout_timer->start(gpppdata.modemTimeout()*1000);
+
+ // this timer will run the script etc.
+ main_timer_ID = startTimer(10);
+
+ return;
+ }
+ }
+
+ // initialization failed
+ messg->setText(Modem::modem->modemMessage());
+ vmain = 20; // wait until cancel is pressed
+ Modem::modem->unlockdevice();
+}
+
+
+void ConnectWidget::timerEvent(QTimerEvent *) {
+ if (semaphore || pausing)
+ return;
+
+ if(vmain == 0) {
+#ifdef DEBUG_WO_DIALING
+ vmain = 10;
+ return;
+#endif
+
+ assert(PPPData::NumInitStrings > 0);
+ // first init string ?
+ if(substate == -1) {
+ messg->setText(i18n("Initializing modem..."));
+ emit debugMessage(i18n("Initializing modem..."));
+ substate = 0;
+ }
+
+ QString initStr = gpppdata.modemInitStr(substate);
+ if (!initStr.isEmpty()) {
+ // send a carriage return and then wait a bit so that the modem will
+ // let us issue commands.
+ if(gpppdata.modemPreInitDelay() > 0) {
+ usleep(gpppdata.modemPreInitDelay() * 5000);
+ writeline("");
+ usleep(gpppdata.modemPreInitDelay() * 5000);
+ }
+ setExpect(gpppdata.modemInitResp());
+ writeline(initStr);
+ usleep(gpppdata.modemInitDelay() * 10000); // 0.01 - 3.0 sec
+ }
+
+ substate++;
+
+ /*
+ * FIXME after 3.0: Make it possible to disable ATS11 since it
+ * seems to be incompatible with some ISDN adapters (e.g. DataBox
+ * Speed Dragon). Even better would be to detect this when doing
+ * a "Modem Query"
+ */
+ if (MODEM_TONEDURATION != gpppdata.modemToneDuration())
+ vmain = 5;
+ else
+ vmain = 3;
+
+ return;
+ }
+
+ if (vmain == 5) {
+ if(!expecting) {
+ QString sToneDuration = "ATS11=" + QString::number(gpppdata.modemToneDuration());
+ QString msg = i18n("Setting ") + sToneDuration;
+ messg->setText(msg);
+ emit debugMessage(msg);
+ setExpect(gpppdata.modemInitResp());
+ writeline(sToneDuration);
+ }
+ vmain = 3;
+ return;
+ }
+
+ if(vmain == 3) {
+ if(!expecting) {
+ // done with all init strings ?
+ if(substate < PPPData::NumInitStrings) {
+ vmain = 0;
+ return;
+ }
+ substate = -1;
+ // skip setting the volume if command is empty
+ if(gpppdata.volumeInitString().isEmpty()) {
+ vmain = 4;
+ return;
+ }
+ messg->setText(i18n("Setting speaker volume..."));
+ emit debugMessage(i18n("Setting speaker volume..."));
+
+ setExpect(gpppdata.modemInitResp());
+ QString vol("AT");
+ vol += gpppdata.volumeInitString();
+ writeline(vol);
+ usleep(gpppdata.modemInitDelay() * 10000); // 0.01 - 3.0 sec
+ vmain = 4;
+ return;
+ }
+ }
+
+ if(vmain == 4) {
+ if(!expecting) {
+ if(!gpppdata.waitForDialTone() || gpppdata.waitCallback()) {
+ QString msg = i18n("Turning off dial tone waiting...");
+ messg->setText(msg);
+ emit debugMessage(msg);
+ setExpect(gpppdata.modemInitResp());
+ writeline(gpppdata.modemNoDialToneDetectionStr());
+ }
+ vmain = 1;
+ return;
+ }
+ }
+
+ // dial the number and wait to connect
+ if(vmain == 1) {
+ if(!expecting) {
+
+ timeout_timer->stop();
+ timeout_timer->start(gpppdata.modemTimeout()*1000);
+
+ if(gpppdata.waitCallback()) {
+ QString msg = i18n("Waiting for callback...");
+ messg->setText(msg);
+ emit debugMessage(msg);
+ setExpect(gpppdata.modemRingResp());
+ vmain = 102;
+ return;
+ }
+
+ QStringList &plist = gpppdata.phonenumbers();
+ QString bmarg= gpppdata.dialPrefix();
+ bmarg += *plist.at(dialnumber);
+ QString bm = i18n("Dialing %1").arg(bmarg);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ QString pn = gpppdata.modemDialStr();
+ pn += gpppdata.dialPrefix();
+ pn += *plist.at(dialnumber);
+ if(++dialnumber >= plist.count())
+ dialnumber = 0;
+ writeline(pn);
+
+ setExpect(gpppdata.modemConnectResp());
+ vmain = 100;
+ return;
+ }
+ }
+
+ // wait for connect, but redial if BUSY or wait for user cancel
+ // if NO CARRIER or NO DIALTONE
+ if(vmain == 100) {
+ if(!expecting) {
+ myreadbuffer = gpppdata.modemConnectResp();
+ setExpect("\n");
+ vmain = 101;
+ return;
+ }
+
+ if(readbuffer.contains(gpppdata.modemBusyResp())) {
+ timeout_timer->stop();
+ timeout_timer->start(gpppdata.modemTimeout()*1000);
+
+ messg->setText(i18n("Line busy. Hanging up..."));
+ emit debugPutChar('\n');
+ Modem::modem->hangup();
+
+ if(gpppdata.busyWait() > 0) {
+ QString bm = i18n("Line busy. Waiting: %1 seconds").arg(gpppdata.busyWait());
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ pausing = true;
+
+ pausetimer->start(gpppdata.busyWait()*1000, true);
+ timeout_timer->stop();
+ }
+
+ Modem::modem->setDataMode(false);
+ vmain = 0;
+ substate = -1;
+ gpppdata.setWaitCallback(false);
+ return;
+ }
+
+ if(readbuffer.contains(gpppdata.modemNoDialtoneResp())) {
+ timeout_timer->stop();
+
+ messg->setText(i18n("No Dial Tone"));
+ vmain = 20;
+ Modem::modem->unlockdevice();
+ gpppdata.setWaitCallback(false);
+ return;
+ }
+
+ if(readbuffer.contains(gpppdata.modemNoCarrierResp())) {
+ if (gpppdata.get_redial_on_nocarrier()) {
+ timeout_timer->stop();
+ timeout_timer->start(gpppdata.modemTimeout()*1000);
+
+ if(gpppdata.busyWait() > 0) {
+ QString bm = i18n("No carrier. Waiting: %1 seconds").arg(gpppdata.busyWait());
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ pausing = true;
+
+ pausetimer->start(gpppdata.busyWait()*1000, true);
+ timeout_timer->stop();
+ }
+
+ Modem::modem->setDataMode(false);
+ vmain = 0;
+ substate = -1;
+ return;
+ } else {
+ timeout_timer->stop();
+
+ messg->setText(i18n("No Carrier"));
+ vmain = 20;
+ Modem::modem->unlockdevice();
+ gpppdata.setWaitCallback(false);
+ }
+ return;
+ }
+
+ if(readbuffer.contains(gpppdata.modemDLPResp())) {
+ timeout_timer->stop();
+
+ messg->setText(i18n("Digital Line Protection Detected."));
+ vmain = 20;
+ Modem::modem->unlockdevice();
+ KMessageBox::error(this,
+ i18n("A Digital Line Protection (DLP) error response "
+ "has been detected.\n"
+ "Please disconnect the phone line.\n\n"
+ "Do NOT connect this modem to a digital phone "
+ "line or the modem could get permanently "
+ "damaged"));
+ gpppdata.setWaitCallback(false);
+ return;
+ }
+
+
+ }
+
+ // wait for newline after CONNECT response (so we get the speed)
+ if(vmain == 101) {
+ if(!expecting) {
+ Modem::modem->setDataMode(true); // modem will no longer respond to AT commands
+
+ emit startAccounting();
+ p_kppp->con_win->startClock();
+
+ vmain = 2;
+ scriptTimeout=gpppdata.modemTimeout()*1000;
+ return;
+ }
+ }
+
+ // send answer on callback phase
+ if(vmain == 102) {
+ if(!expecting) {
+ writeline(gpppdata.modemAnswerStr());
+ setExpect(gpppdata.modemConnectResp());
+ vmain = 100;
+ return;
+ }
+ }
+
+ // execute the script
+ if(vmain == 2) {
+ if(!expecting && !pausing && !scanning) {
+
+ timeout_timer->stop();
+ timeout_timer->start(scriptTimeout);
+
+ if((unsigned) scriptindex < comlist->count()) {
+ scriptCommand = *(comlist->at(scriptindex));
+ scriptArgument = *(arglist->at(scriptindex));
+ } else {
+ kdDebug(5002) << "End of script" << endl;
+ vmain = 10;
+ return;
+ }
+
+ if (scriptCommand == "Scan") {
+ QString bm = i18n("Scanning %1").arg(scriptArgument);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ setScan(scriptArgument);
+ scriptindex++;
+ return;
+ }
+
+ if (scriptCommand == "Save") {
+ QString bm = i18n("Saving %1").arg(scriptArgument);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ if (scriptArgument.lower() == "password") {
+ gpppdata.setPassword(scanvar);
+ p_kppp->setPW_Edit(scanvar);
+ if(gpppdata.storePassword())
+ gpppdata.setStoredPassword(scanvar);
+ firstrunPW = true;
+ }
+
+ scriptindex++;
+ return;
+ }
+
+
+ if (scriptCommand == "Send" || scriptCommand == "SendNoEcho") {
+ QString bm = i18n("Sending %1");
+
+ // replace %USERNAME% and %PASSWORD%
+ QString arg = scriptArgument;
+ QRegExp re1("%USERNAME%");
+ QRegExp re2("%PASSWORD%");
+ arg = arg.replace(re1, gpppdata.storedUsername());
+ arg = arg.replace(re2, gpppdata.storedPassword());
+
+ if (scriptCommand == "Send")
+ bm = bm.arg(scriptArgument);
+ else {
+ for(uint i = 0; i < scriptArgument.length(); i++)
+ bm = bm.arg("*");
+ }
+
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ writeline(scriptArgument);
+ scriptindex++;
+ return;
+ }
+
+ if (scriptCommand == "Expect") {
+ QString bm = i18n("Expecting %1").arg(scriptArgument);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ // The incrementing of the scriptindex MUST be before the
+ // call to setExpect otherwise the expect will miss a string that is
+ // already in the buffer.
+ scriptindex++;
+ setExpect(scriptArgument);
+ return;
+ }
+
+
+ if (scriptCommand == "Pause") {
+ QString bm = i18n("Pause %1 seconds").arg(scriptArgument);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ pausing = true;
+
+ pausetimer->start(scriptArgument.toInt()*1000, true);
+ timeout_timer->stop();
+
+ scriptindex++;
+ return;
+ }
+
+ if (scriptCommand == "Timeout") {
+
+ timeout_timer->stop();
+
+ QString bm = i18n("Timeout %1 seconds").arg(scriptArgument);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ scriptTimeout=scriptArgument.toInt()*1000;
+ timeout_timer->start(scriptTimeout);
+
+ scriptindex++;
+ return;
+ }
+
+ if (scriptCommand == "Hangup") {
+ messg->setText(i18n("Hangup"));
+ emit debugMessage(i18n("Hangup"));
+
+ writeline(gpppdata.modemHangupStr());
+ setExpect(gpppdata.modemHangupResp());
+
+ scriptindex++;
+ return;
+ }
+
+ if (scriptCommand == "Answer") {
+
+ timeout_timer->stop();
+
+ messg->setText(i18n("Answer"));
+ emit debugMessage(i18n("Answer"));
+
+ setExpect(gpppdata.modemRingResp());
+ vmain = 150;
+ return;
+ }
+
+ if (scriptCommand == "ID") {
+ QString bm = i18n("ID %1").arg(scriptArgument);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ QString idstring = gpppdata.storedUsername();
+
+ if(!idstring.isEmpty() && firstrunID) {
+ // the user entered an Id on the main kppp dialog
+ writeline(idstring);
+ firstrunID = false;
+ scriptindex++;
+ }
+ else {
+ // the user didn't enter and Id on the main kppp dialog
+ // let's query for an ID
+ /* if not around yet, then post window... */
+ if (prompt->Consumed()) {
+ if (!(prompt->isVisible())) {
+ prompt->setPrompt(scriptArgument);
+ prompt->setEchoModeNormal();
+ prompt->show();
+ }
+ } else {
+ /* if prompt withdrawn ... then, */
+ if(!(prompt->isVisible())) {
+ writeline(prompt->text());
+ prompt->setConsumed();
+ scriptindex++;
+ return;
+ }
+ /* replace timeout value */
+ }
+ }
+ }
+
+ if (scriptCommand == "Password") {
+ QString bm = i18n("Password %1").arg(scriptArgument);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ QString pwstring = gpppdata.password();
+
+ if(!pwstring.isEmpty() && firstrunPW) {
+ // the user entered a password on the main kppp dialog
+ writeline(pwstring);
+ firstrunPW = false;
+ scriptindex++;
+ }
+ else {
+ // the user didn't enter a password on the main kppp dialog
+ // let's query for a password
+ /* if not around yet, then post window... */
+ if (prompt->Consumed()) {
+ if (!(prompt->isVisible())) {
+ prompt->setPrompt(scriptArgument);
+ prompt->setEchoModePassword();
+ prompt->show();
+ }
+ } else {
+ /* if prompt withdrawn ... then, */
+ if(!(prompt->isVisible())) {
+ p_kppp->setPW_Edit(prompt->text());
+ writeline(prompt->text());
+ prompt->setConsumed();
+ scriptindex++;
+ return;
+ }
+ /* replace timeout value */
+ }
+ }
+ }
+
+ if (scriptCommand == "Prompt") {
+ QString bm = i18n("Prompting %1");
+
+ // if the scriptindex (aka the prompt text) includes a ## marker
+ // this marker should get substituted with the contents of our stored
+ // variable (from the subsequent scan).
+
+ QString ts = scriptArgument;
+ int vstart = ts.find( "##" );
+ if( vstart != -1 ) {
+ ts.remove( vstart, 2 );
+ ts.insert( vstart, scanvar );
+ }
+
+ bm = bm.arg(ts);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ /* if not around yet, then post window... */
+ if (prompt->Consumed()) {
+ if (!(prompt->isVisible())) {
+ prompt->setPrompt( ts );
+ prompt->setEchoModeNormal();
+ prompt->show();
+ }
+ } else {
+ /* if prompt withdrawn ... then, */
+ if (!(prompt->isVisible())) {
+ writeline(prompt->text());
+ prompt->setConsumed();
+ scriptindex++;
+ return;
+ }
+ /* replace timeout value */
+ }
+ }
+
+ if (scriptCommand == "PWPrompt") {
+ QString bm = i18n("PW Prompt %1").arg(scriptArgument);
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ /* if not around yet, then post window... */
+ if (prompt->Consumed()) {
+ if (!(prompt->isVisible())) {
+ prompt->setPrompt(scriptArgument);
+ prompt->setEchoModePassword();
+ prompt->show();
+ }
+ } else {
+ /* if prompt withdrawn ... then, */
+ if (!(prompt->isVisible())) {
+ writeline(prompt->text());
+ prompt->setConsumed();
+ scriptindex++;
+ return;
+ }
+ /* replace timeout value */
+ }
+ }
+
+ if (scriptCommand == "LoopStart") {
+
+ QString bm = i18n("Loop Start %1").arg(scriptArgument);
+
+ // The incrementing of the scriptindex MUST be before the
+ // call to setExpect otherwise the expect will miss a string that is
+ // already in the buffer.
+ scriptindex++;
+
+ if ( loopnest > (MAXLOOPNEST-2) ) {
+ bm += i18n("ERROR: Nested too deep, ignored.");
+ vmain=20;
+ cancelbutton();
+ KMessageBox::error(0, i18n("Loops nested too deeply."));
+ } else {
+ setExpect(scriptArgument);
+ loopstartindex[loopnest] = scriptindex;
+ loopstr[loopnest] = scriptArgument;
+ loopend = false;
+ loopnest++;
+ }
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ }
+
+ if (scriptCommand == "LoopEnd") {
+ QString bm = i18n("Loop End %1").arg(scriptArgument);
+ if ( loopnest <= 0 ) {
+ bm = i18n("LoopEnd without matching Start. Line: %1").arg(bm);
+ vmain=20;
+ cancelbutton();
+ KMessageBox::error(0, bm);
+ return;
+ } else {
+ // NB! The incrementing of the scriptindex MUST be before the
+ // call to setExpect otherwise the expect will miss a string
+ // that is already in the buffer.
+ scriptindex++;
+ setExpect(scriptArgument);
+ loopnest--;
+ loopend = true;
+ }
+ messg->setText(bm);
+ emit debugMessage(bm);
+
+ }
+ }
+ }
+
+ // this is a subroutine for the "Answer" script option
+
+ if(vmain == 150) {
+ if(!expecting) {
+ writeline(gpppdata.modemAnswerStr());
+ setExpect(gpppdata.modemAnswerResp());
+
+ vmain = 2;
+ scriptindex++;
+ return;
+ }
+ }
+
+ if(vmain == 30) {
+ if (termwindow->isVisible())
+ return;
+ if (termwindow->pressedContinue())
+ vmain = 10;
+ else
+ cancelbutton();
+ }
+
+ if(vmain == 10) {
+ if(!expecting) {
+
+ int result;
+
+ timeout_timer->stop();
+ if_timeout_timer->stop(); // better be sure.
+
+ // stop reading of data
+ Modem::modem->stop();
+
+ if(gpppdata.authMethod() == AUTH_TERMINAL) {
+ if (termwindow) {
+ delete termwindow;
+ termwindow = 0L;
+ show();
+ } else {
+ termwindow = new LoginTerm(0L, 0L);
+ hide();
+ termwindow->show();
+ vmain = 30;
+ return;
+ }
+ }
+
+ // Close the tty. This prevents the QTimer::singleShot() in
+ // Modem::readtty() from re-enabling the socket notifier.
+ // The port is still held open by the helper process.
+ Modem::modem->closetty();
+
+ killTimer( main_timer_ID );
+
+ if_timeout_timer->start(gpppdata.pppdTimeout()*1000);
+ kdDebug(5002) << "started if timeout timer with " << gpppdata.pppdTimeout()*1000 << endl;
+
+ // find out PPP interface and notify the stats module
+ stats->setUnit(pppInterfaceNumber());
+
+ kapp->flushX();
+ semaphore = true;
+ result = execppp();
+
+ emit debugMessage(i18n("Starting pppd..."));
+ kdDebug(5002) << "execppp() returned with return-code " << result << endl;
+
+ if(result) {
+ if(!gpppdata.autoDNS())
+ adddns();
+
+ // O.K we are done here, let's change over to the if_waiting loop
+ // where we wait for the ppp if (interface) to come up.
+
+ emit if_waiting_signal();
+ } else {
+
+ // starting pppd wasn't successful. Error messages were
+ // handled by execppp();
+ if_timeout_timer->stop();
+
+ hide();
+ messg->setText("");
+ p_kppp->quit_b->setFocus();
+ p_kppp->show();
+ kapp->processEvents();
+ Modem::modem->hangup();
+ emit stopAccounting();
+ p_kppp->con_win->stopClock();
+ Modem::modem->closetty();
+ Modem::modem->unlockdevice();
+
+ }
+
+ return;
+ }
+ }
+
+ // this is a "wait until cancel" entry
+
+ if(vmain == 20) {
+ gpppdata.setWaitCallback(false);
+ }
+}
+
+
+void ConnectWidget::set_con_speed_string() {
+ // Here we are trying to determine the speed at which we are connected.
+ // Usually the modem responds after connect with something like
+ // CONNECT 115200, so all we need to do is find the number after CONNECT
+ // or whatever the modemConnectResp() is.
+ p_kppp->con_speed = Modem::modem->parseModemSpeed(myreadbuffer);
+}
+
+
+
+void ConnectWidget::readChar(unsigned char c) {
+ if(semaphore)
+ return;
+
+ readbuffer += c;
+ myreadbuffer += c;
+
+ // While in scanning mode store each char to the scan buffer
+ // for use in the prompt command
+ if( scanning )
+ scanbuffer += c;
+
+ // add to debug window
+ emit debugPutChar(c);
+
+ checkBuffers();
+}
+
+
+void ConnectWidget::checkBuffers() {
+ // Let's check if we are finished with scanning:
+ // The scanstring have to be in the buffer and the latest character
+ // was a carriage return or an linefeed (depending on modem setup)
+ if( scanning && scanbuffer.contains(scanstr) &&
+ ( scanbuffer.right(1) == "\n" || scanbuffer.right(1) == "\r") ) {
+ scanning = false;
+
+ int vstart = scanbuffer.find( scanstr ) + scanstr.length();
+ scanvar = scanbuffer.mid( vstart, scanbuffer.length() - vstart);
+ scanvar = scanvar.stripWhiteSpace();
+
+ // Show the Variabel content in the debug window
+ QString sv = i18n("Scan Var: %1").arg(scanvar);
+ emit debugMessage(sv);
+ }
+
+ if(expecting) {
+ if(readbuffer.contains(expectstr)) {
+ expecting = false;
+ // keep everything after the expected string
+ readbuffer.remove(0, readbuffer.find(expectstr) + expectstr.length());
+
+ QString ts = i18n("Found: %1").arg(expectstr);
+ emit debugMessage(ts);
+
+ if (loopend) {
+ loopend=false;
+ }
+ }
+
+ if (loopend && readbuffer.contains(loopstr[loopnest])) {
+ expecting = false;
+ readbuffer = "";
+ QString ts = i18n("Looping: %1").arg(loopstr[loopnest]);
+ emit debugMessage(ts);
+ scriptindex = loopstartindex[loopnest];
+ loopend = false;
+ loopnest++;
+ }
+ // notify event loop if expected string was found
+ if(!expecting)
+ timerEvent((QTimerEvent *) 0);
+ }
+}
+
+
+
+void ConnectWidget::pause() {
+ pausing = false;
+ pausetimer->stop();
+}
+
+
+void ConnectWidget::cancelbutton() {
+ gpppdata.setWaitCallback(false);
+ Modem::modem->stop();
+ killTimer(main_timer_ID);
+ timeout_timer->stop();
+ if_timer->stop();
+ if_timeout_timer->stop();
+
+ if (termwindow) {
+ delete termwindow;
+ termwindow = 0L;
+ show();
+ }
+
+ messg->setText(i18n("One moment please..."));
+
+ // just to be sure
+ Requester::rq->removeSecret(AUTH_PAP);
+ Requester::rq->removeSecret(AUTH_CHAP);
+ removedns();
+
+ kapp->processEvents();
+
+ Requester::rq->killPPPDaemon();
+ Modem::modem->hangup();
+
+ hide();
+ messg->setText("");
+ p_kppp->quit_b->setFocus();
+ p_kppp->show();
+ emit stopAccounting(); // just to be sure
+ p_kppp->con_win->stopClock();
+ Modem::modem->closetty();
+ Modem::modem->unlockdevice();
+
+ //abort prompt window...
+ if (prompt->isVisible()) {
+ prompt->hide();
+ }
+ prompt->setConsumed();
+
+ if(p_kppp->quitOnDisconnect())
+ kapp->exit(0);
+}
+
+
+void ConnectWidget::script_timed_out() {
+ if(vmain == 20) { // we are in the 'wait for the user to cancel' state
+ timeout_timer->stop();
+ emit stopAccounting();
+ p_kppp->con_win->stopClock();
+ return;
+ }
+
+ if (prompt->isVisible())
+ prompt->hide();
+
+ prompt->setConsumed();
+ messg->setText(i18n("Script timed out."));
+ Modem::modem->hangup();
+ emit stopAccounting();
+ p_kppp->con_win->stopClock();
+
+ vmain = 0; // let's try again.
+ substate = -1;
+}
+
+
+void ConnectWidget::setScan(const QString &n) {
+ scanning = true;
+ scanstr = n;
+ scanbuffer = "";
+
+ QString ts = i18n("Scanning: %1").arg(n);
+ emit debugMessage(ts);
+}
+
+
+void ConnectWidget::setExpect(const QString &n) {
+ expecting = true;
+ expectstr = n;
+
+ QString ts = i18n("Expecting: %1").arg(n);
+ ts.replace(QRegExp("\n"), "<LF>");
+ emit debugMessage(ts);
+
+ // check if the expected string is in the read buffer already.
+ checkBuffers();
+}
+
+
+void ConnectWidget::if_waiting_timed_out() {
+ if_timer->stop();
+ if_timeout_timer->stop();
+ kdDebug(5002) << "if_waiting_timed_out()" << endl;
+
+ gpppdata.setpppdError(E_IF_TIMEOUT);
+
+ // let's kill the stuck pppd
+ Requester::rq->killPPPDaemon();
+
+ emit stopAccounting();
+ p_kppp->con_win->stopClock();
+
+
+ // killing ppp will generate a SIGCHLD which will be caught in pppdie()
+ // in main.cpp what happens next will depend on the boolean
+ // reconnect_on_disconnect which is set in ConnectWidget::init();
+}
+
+void ConnectWidget::pppdDied()
+{
+ if_timer->stop();
+ if_timeout_timer->stop();
+}
+
+void ConnectWidget::if_waiting_slot() {
+ messg->setText(i18n("Logging on to network..."));
+
+ if(!stats->ifIsUp()) {
+
+ if(gpppdata.pppdError() != 0) {
+ // we are here if pppd died immediately after starting it.
+ pppdDied();
+ // error message handled in main.cpp: sigPPPDDied()
+ return;
+ }
+
+ if_timer->start(100, TRUE); // single shot
+ return;
+ }
+
+ // O.K the ppp interface is up and running
+ // give it a few time to come up completly (0.2 seconds)
+ if_timeout_timer->stop();
+ if_timer->stop();
+ usleep(200000);
+
+ if(gpppdata.autoDNS())
+ addpeerdns();
+
+ // Close the debugging window. If we are connected, we
+ // are not really interested in debug output
+ emit closeDebugWindow();
+ p_kppp->statdlg->take_stats(); // start taking ppp statistics
+ auto_hostname();
+
+ // signal other applications that we are connected now
+ kapp->dcopClient()->emitDCOPSignal("KpppIface", "connected()", QByteArray());
+
+ if(!gpppdata.command_on_connect().isEmpty()) {
+ messg->setText(i18n("Running startup command..."));
+
+ // make sure that we don't get any async errors
+ kapp->flushX();
+ execute_command(gpppdata.command_on_connect());
+ messg->setText(i18n("Done"));
+ }
+
+ // remove the authentication file
+ Requester::rq->removeSecret(AUTH_PAP);
+ Requester::rq->removeSecret(AUTH_CHAP);
+
+ emit debugMessage(i18n("Done"));
+ set_con_speed_string();
+
+ p_kppp->con_win->setConnectionSpeed(p_kppp->con_speed);
+ hide();
+ messg->setText("");
+
+ // prepare the con_win so as to have the right size for
+ // accounting / non-accounting mode
+ if(p_kppp->acct != 0)
+ p_kppp->con_win->accounting(p_kppp->acct->running());
+ else
+ p_kppp->con_win->accounting(false);
+
+ if (gpppdata.get_dock_into_panel()) {
+ DockWidget::dock_widget->show();
+ DockWidget::dock_widget->take_stats();
+ hide();
+ }
+ else {
+ p_kppp->con_win->show();
+
+ if(gpppdata.get_iconify_on_connect()) {
+ p_kppp->con_win->showMinimized();
+ }
+ }
+
+ Modem::modem->closetty();
+}
+
+
+bool ConnectWidget::execppp() {
+ QString command;
+
+ command = "pppd";
+
+ // as of version 2.3.6 pppd falls back to the real user rights when
+ // opening a device given in a command line. To avoid permission conflicts
+ // we'll simply leave this argument away. pppd will then use the default tty
+ // which is the serial port we connected stdin/stdout to in opener.cpp.
+ // command += " ";
+ // command += gpppdata.modemDevice();
+
+ command += " " + gpppdata.speed();
+
+ command += " -detach";
+
+ if(gpppdata.ipaddr() != "0.0.0.0" ||
+ gpppdata.gateway() != "0.0.0.0") {
+ if(gpppdata.ipaddr() != "0.0.0.0") {
+ command += " ";
+ command += gpppdata.ipaddr();
+ command += ":";
+ }
+ else {
+ command += " ";
+ command += ":";
+ }
+
+ if(gpppdata.gateway() != "0.0.0.0")
+ command += gpppdata.gateway();
+ }
+
+ if(gpppdata.subnetmask() != "0.0.0.0")
+ command += " netmask " + gpppdata.subnetmask();
+
+ // the english/i18n mix below is ugly but we want to keep working
+ // after someone changed the code to use i18n'ed config values
+ QString flowCtrl = gpppdata.flowcontrol();
+ if(flowCtrl != "None" && flowCtrl != i18n("None")) {
+ if(flowCtrl == "CRTSCTS" || flowCtrl == "Hardware [CRTSCTS]" ||
+ flowCtrl == i18n("Hardware [CRTSCTS]"))
+ command += " crtscts";
+ else
+ command += " xonxoff";
+ }
+
+ if(gpppdata.defaultroute())
+ command += " defaultroute";
+
+ if(gpppdata.autoDNS())
+ command += " usepeerdns";
+
+ QStringList &arglist = gpppdata.pppdArgument();
+ for ( QStringList::Iterator it = arglist.begin();
+ it != arglist.end();
+ ++it )
+ {
+ command += " " + *it;
+ }
+
+ // Callback settings
+ if(gpppdata.callbackType() && !gpppdata.waitCallback()) {
+ if(!gpppdata.pppdVersionMin(2, 4, 2)) {
+ command += " +callback";
+ if(gpppdata.callbackType() == CBTYPE_USER)
+ command += " callback " + gpppdata.callbackPhone();
+ } else {
+ command += " callback ";
+ command += gpppdata.callbackType() == CBTYPE_ADMIN ?
+ QString("0") : gpppdata.callbackPhone();
+ }
+ } else
+ gpppdata.setWaitCallback(false);
+
+ // PAP settings
+ if(gpppdata.authMethod() == AUTH_PAP) {
+ command += " -chap user ";
+ command = command + "\"" + gpppdata.storedUsername() + "\"";
+ }
+
+ // CHAP settings
+ if(gpppdata.authMethod() == AUTH_CHAP) {
+ command += " -pap user ";
+ command = command + "\"" + gpppdata.storedUsername() + "\"";
+ }
+
+ // PAP/CHAP settings
+ if(gpppdata.authMethod() == AUTH_PAPCHAP) {
+ command += " user ";
+ command = command + "\"" + gpppdata.storedUsername() + "\"";
+ }
+
+ // check for debug
+ if(gpppdata.getPPPDebug())
+ command += " debug";
+
+ if (command.length() > MAX_CMDLEN) {
+ KMessageBox::error(this, i18n(
+ "pppd command + command-line arguments exceed "
+ "2024 characters in length."
+ ));
+
+ return false; // nonsensically long command which would bust my buffer buf.
+ }
+
+ kapp->flushX();
+
+ return Requester::rq->execPPPDaemon(command);
+}
+
+
+void ConnectWidget::closeEvent( QCloseEvent *e ) {
+ e->ignore();
+ emit cancelbutton();
+}
+
+
+void ConnectWidget::setMsg(const QString &msg) {
+ messg->setText(msg);
+}
+
+void ConnectWidget::writeline(const QString &s) {
+ Modem::modem->writeLine(s.local8Bit());
+}
+
+// Set the hostname and domain from DNS Server
+void auto_hostname() {
+ struct in_addr local_ip;
+ struct hostent *hostname_entry;
+ QString new_hostname;
+ int dot;
+ char tmp_str[100]; // buffer overflow safe
+
+ gethostname(tmp_str, sizeof(tmp_str));
+ tmp_str[sizeof(tmp_str)-1]=0; // panic
+ old_hostname=tmp_str; // copy to QString
+
+ if (!p_kppp->stats->local_ip_address.isEmpty() && gpppdata.autoname()) {
+ local_ip.s_addr=inet_addr(p_kppp->stats->local_ip_address.ascii());
+ hostname_entry=gethostbyaddr((const char *)&local_ip,sizeof(in_addr),AF_INET);
+
+ if (hostname_entry != 0L) {
+ new_hostname=hostname_entry->h_name;
+ dot=new_hostname.find('.');
+ new_hostname=new_hostname.remove(dot,new_hostname.length()-dot);
+ Requester::rq->setHostname(new_hostname);
+ modified_hostname = TRUE;
+
+ new_hostname=hostname_entry->h_name;
+ new_hostname.remove(0,dot+1);
+
+ add_domain(new_hostname);
+ }
+ }
+
+}
+
+// Replace the DNS domain entry in the /etc/resolv.conf file and
+// disable the nameserver entries if option is enabled
+void add_domain(const QString &domain) {
+
+ int fd;
+ char c;
+ QString resolv[MAX_RESOLVCONF_LINES];
+
+ if (domain.isEmpty())
+ return;
+
+ if((fd = Requester::rq->openResolv(O_RDONLY)) >= 0) {
+
+ int i=0;
+ while((read(fd, &c, 1) == 1) && (i < MAX_RESOLVCONF_LINES)) {
+ if(c == '\n') {
+ i++;
+ }
+ else {
+ resolv[i] += c;
+ }
+ }
+ close(fd);
+ if ((c != '\n') && (i < MAX_RESOLVCONF_LINES)) i++;
+
+ if((fd = Requester::rq->openResolv(O_WRONLY|O_TRUNC)) >= 0) {
+ QCString tmp = "domain " + domain.local8Bit() +
+ " \t\t#kppp temp entry\n";
+ write(fd, tmp.data(), tmp.length());
+
+ for(int j=0; j < i; j++) {
+ if((resolv[j].contains("domain") ||
+ ( resolv[j].contains("nameserver")
+ && !resolv[j].contains("#kppp temp entry")
+ && gpppdata.exDNSDisabled()))
+ && !resolv[j].contains("#entry disabled by kppp")) {
+ QCString tmp = "# " + resolv[j].local8Bit() +
+ " \t#entry disabled by kppp\n";
+ write(fd, tmp, tmp.length());
+ }
+ else {
+ QCString tmp = resolv[j].local8Bit() + "\n";
+ write(fd, tmp, tmp.length());
+ }
+ }
+ }
+ close(fd);
+ }
+}
+
+
+// adds the DNS entries in the /etc/resolv.conf file
+void adddns()
+{
+ int fd;
+
+ if ((fd = Requester::rq->openResolv(O_WRONLY|O_APPEND)) >= 0) {
+ QStringList &dnslist = gpppdata.dns();
+ for ( QStringList::Iterator it = dnslist.begin();
+ it != dnslist.end();
+ ++it )
+ {
+ QCString dns = "nameserver " + (*it).local8Bit() +
+ " \t#kppp temp entry\n";
+ write(fd, dns.data(), dns.length());
+ }
+ close(fd);
+ }
+ add_domain(gpppdata.domain());
+}
+
+void addpeerdns() {
+ int fd, fd2;
+
+ if((fd = Requester::rq->openResolv(O_WRONLY|O_APPEND)) >= 0) {
+ if((fd2 = open("/etc/ppp/resolv.conf", O_RDONLY)) >= 0) {
+ char c;
+ int i = 0;
+ while(i++ < 100 && read(fd2, &c, 1) == 1) {
+ if(c == '\n')
+ write(fd, "\t#kppp temp entry\n", 18);
+ else
+ write(fd, &c, 1);
+ }
+ close(fd2);
+ } else
+ fprintf(stderr, "failed to read from /etc/ppp/resolv.conf\n");
+ close(fd);
+ }
+ add_domain(gpppdata.domain());
+}
+
+// remove the dns entries from the /etc/resolv.conf file
+void removedns() {
+
+ int fd;
+ char c;
+ QString resolv[MAX_RESOLVCONF_LINES];
+
+ if((fd = Requester::rq->openResolv(O_RDONLY)) >= 0) {
+
+ int i=0;
+ while(read(fd, &c, 1) == 1 && i < MAX_RESOLVCONF_LINES) {
+ if(c == '\n') {
+ i++;
+ }
+ else {
+ resolv[i] += c;
+ }
+ }
+ close(fd);
+
+ if((fd = Requester::rq->openResolv(O_WRONLY|O_TRUNC)) >= 0) {
+ for(int j=0; j < i; j++) {
+ if(resolv[j].contains("#kppp temp entry")) continue;
+ if(resolv[j].contains("#entry disabled by kppp")) {
+ QCString tmp = resolv[j].local8Bit();
+ write(fd, tmp.data()+2, tmp.length() - 27);
+ write(fd, "\n", 1);
+ }
+ else {
+ QCString tmp = resolv[j].local8Bit() + "\n";
+ write(fd, tmp, tmp.length());
+ }
+ }
+ }
+ close(fd);
+
+ }
+
+ if ( modified_hostname ) {
+ Requester::rq->setHostname(old_hostname);
+ modified_hostname = FALSE;
+ }
+
+}
+
+#include "connect.moc"