From 273857932d4d4af9bf78bfca92f2986163e5f4f6 Mon Sep 17 00:00:00 2001 From: tille Date: Thu, 22 May 2003 15:08:21 +0000 Subject: finds the modem of my laptop now, thanks to the kppp team --- (limited to 'noncore/settings/networksettings/ppp/modem.cpp') diff --git a/noncore/settings/networksettings/ppp/modem.cpp b/noncore/settings/networksettings/ppp/modem.cpp new file mode 100644 index 0000000..e9e3f06 --- a/dev/null +++ b/noncore/settings/networksettings/ppp/modem.cpp @@ -0,0 +1,671 @@ +/* + * kPPP: A pppd Front End for the KDE project + * + * $Id$ + * + * Copyright (C) 1997 Bernd Johannes Wuebben + * wuebben@math.cornell.edu + * + * This file was added by Harri Porten + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "modem.h" +#include "pppdata.h" +//#include "requester.h" +//#include +#define i18n QObject::tr +#define qError qDebug +//#include +//#include + +#define MY_ASSERT(x) if (!(x)) { \ + qFatal( "ASSERT: \"%s\" in %s (%d)\n",#x,__FILE__,__LINE__); \ + exit(1); } + + +static sigjmp_buf jmp_buffer; + +Modem *Modem::modem = 0; + +Modem::Modem() : + modemfd(-1), + sn(0L), + data_mode(false), + modem_is_locked(false) +{ + lockfile[0] = '\0'; + device = "/dev/modem"; + assert(modem==0); + modem = this; +} + + +Modem::~Modem() { + modem = 0; +} + + +speed_t Modem::modemspeed() { + // convert the string modem speed int the gpppdata object to a t_speed type + // to set the modem. The constants here should all be ifdef'd because + // other systems may not have them + int i = gpppdata.speed().toInt()/100; + + switch(i) { + case 24: + return B2400; + break; + case 96: + return B9600; + break; + case 192: + return B19200; + break; + case 384: + return B38400; + break; +#ifdef B57600 + case 576: + return B57600; + break; +#endif + +#ifdef B115200 + case 1152: + return B115200; + break; +#endif + +#ifdef B230400 + case 2304: + return B230400; + break; +#endif + +#ifdef B460800 + case 4608: + return B460800; + break; +#endif + + default: + return B38400; + break; + } +} + +bool Modem::opentty() { + // int flags; + +//begin if((modemfd = Requester::rq->openModem(gpppdata.modemDevice()))<0) { + close(modemfd); +// device = "/dev/modem";//deviceByIndex(request.modem.deviceNum); + if ((modemfd = open(device, O_RDWR|O_NDELAY|O_NOCTTY)) == -1) { + qDebug("error opening modem device !"); + errmsg = i18n("Unable to open modem."); + return false; + } +//bend if((modemfd = Requester::rq->openModem(gpppdata.modemDevice()))<0) { +//} + +#if 0 + if(gpppdata.UseCDLine()) { + if(ioctl(modemfd, TIOCMGET, &flags) == -1) { + errmsg = i18n("Unable to detect state of CD line."); + ::close(modemfd); + modemfd = -1; + return false; + } + if ((flags&TIOCM_CD) == 0) { + errmsg = i18n("The modem is not ready."); + ::close(modemfd); + modemfd = -1; + return false; + } + } +#endif + + tcdrain (modemfd); + tcflush (modemfd, TCIOFLUSH); + + if(tcgetattr(modemfd, &tty) < 0){ + // this helps in some cases + tcsendbreak(modemfd, 0); + sleep(1); + if(tcgetattr(modemfd, &tty) < 0){ + errmsg = i18n("The modem is busy."); + ::close(modemfd); + modemfd = -1; + return false; + } + } + + memset(&initial_tty,'\0',sizeof(initial_tty)); + + initial_tty = tty; + + tty.c_cc[VMIN] = 0; // nonblocking + tty.c_cc[VTIME] = 0; + tty.c_oflag = 0; + tty.c_lflag = 0; + + tty.c_cflag &= ~(CSIZE | CSTOPB | PARENB); + tty.c_cflag |= CS8 | CREAD; + tty.c_cflag |= CLOCAL; // ignore modem status lines + tty.c_iflag = IGNBRK | IGNPAR /* | ISTRIP */ ; + tty.c_lflag &= ~ICANON; // non-canonical mode + tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHOKE); + + + if(gpppdata.flowcontrol() != "None") { + if(gpppdata.flowcontrol() == "CRTSCTS") { + tty.c_cflag |= CRTSCTS; + } + else { + tty.c_iflag |= IXON | IXOFF; + tty.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */ + tty.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */ + } + } + else { + tty.c_cflag &= ~CRTSCTS; + tty.c_iflag &= ~(IXON | IXOFF); + } + + cfsetospeed(&tty, modemspeed()); + cfsetispeed(&tty, modemspeed()); + + tcdrain(modemfd); + + if(tcsetattr(modemfd, TCSANOW, &tty) < 0){ + errmsg = i18n("The modem is busy."); + ::close(modemfd); + modemfd=-1; + return false; + } + + errmsg = i18n("Modem Ready."); + return true; +} + + +bool Modem::closetty() { + if(modemfd >=0 ) { + stop(); + /* discard data not read or transmitted */ + tcflush(modemfd, TCIOFLUSH); + + if(tcsetattr(modemfd, TCSANOW, &initial_tty) < 0){ + errmsg = i18n("Can't restore tty settings: tcsetattr()\n"); + ::close(modemfd); + modemfd = -1; + return false; + } + ::close(modemfd); + modemfd = -1; + } + + return true; +} + + +void Modem::readtty(int) { + char buffer[200]; + unsigned char c; + int len; + + // read data in chunks of up to 200 bytes + if((len = ::read(modemfd, buffer, 200)) > 0) { + // split buffer into single characters for further processing + for(int i = 0; i < len; i++) { + c = buffer[i] & 0x7F; + emit charWaiting(c); + } + } +} + + +void Modem::notify(const QObject *receiver, const char *member) { + connect(this, SIGNAL(charWaiting(unsigned char)), receiver, member); + startNotifier(); +} + + +void Modem::stop() { + disconnect(SIGNAL(charWaiting(unsigned char))); + stopNotifier(); +} + + +void Modem::startNotifier() { + if(modemfd >= 0) { + if(sn == 0) { + sn = new QSocketNotifier(modemfd, QSocketNotifier::Read, this); + connect(sn, SIGNAL(activated(int)), SLOT(readtty(int))); + qDebug("QSocketNotifier started!"); + } else { + qDebug("QSocketNotifier re-enabled!"); + sn->setEnabled(true); + } + } +} + + +void Modem::stopNotifier() { + if(sn != 0) { + sn->setEnabled(false); + disconnect(sn); + delete sn; + sn = 0; + qDebug( "QSocketNotifier stopped!" ); + } +} + + +void Modem::flush() { + char c; + while(read(modemfd, &c, 1) == 1); +} + + +bool Modem::writeChar(unsigned char c) { + int s; + do { + s = write(modemfd, &c, 1); + if (s < 0) { + qError( "write() in Modem::writeChar failed" ); + return false; + } + } while(s == 0); + + return true; +} + + +bool Modem::writeLine(const char *buf) { + int len = strlen(buf); + char *b = new char[len+2]; + memcpy(b, buf, len); + // different modems seem to need different line terminations + QString term = gpppdata.enter(); + if(term == "LF") + b[len++]='\n'; + else if(term == "CR") + b[len++]='\r'; + else if(term == "CR/LF") { + b[len++]='\r'; + b[len++]='\n'; + } + int l = len; + while(l) { + int wr = write(modemfd, &b[len-l], l); + if(wr < 0) { + // TODO do something meaningful with the error code (or ignore it + qError( "write() in Modem::writeLine failed" ); + delete[] b; + return false; + } + l -= wr; + } + delete[] b; + return true; +} + + +bool Modem::hangup() { + // this should really get the modem to hang up and go into command mode + // If anyone sees a fault in the following please let me know, since + // this is probably the most imporant snippet of code in the whole of + // kppp. If people complain about kppp being stuck, this piece of code + // is most likely the reason. + struct termios temptty; + + if(modemfd >= 0) { + + // is this Escape & HangupStr stuff really necessary ? (Harri) + + if (data_mode) escape_to_command_mode(); + + // Then hangup command + writeLine(gpppdata.modemHangupStr().local8Bit()); + + usleep(gpppdata.modemInitDelay() * 10000); // 0.01 - 3.0 sec + +#ifndef DEBUG_WO_DIALING + if (sigsetjmp(jmp_buffer, 1) == 0) { + // set alarm in case tcsendbreak() hangs + signal(SIGALRM, alarm_handler); + alarm(2); + + tcsendbreak(modemfd, 0); + + alarm(0); + signal(SIGALRM, SIG_IGN); + } else { + // we reach this point if the alarm handler got called + closetty(); + close(modemfd); + modemfd = -1; + errmsg = i18n("The modem does not respond."); + return false; + } + +#ifndef __svr4__ // drops DTR but doesn't set it afterwards again. not good for init. + tcgetattr(modemfd, &temptty); + cfsetospeed(&temptty, B0); + cfsetispeed(&temptty, B0); + tcsetattr(modemfd, TCSAFLUSH, &temptty); +#else + int modemstat; + ioctl(modemfd, TIOCMGET, &modemstat); + modemstat &= ~TIOCM_DTR; + ioctl(modemfd, TIOCMSET, &modemstat); + ioctl(modemfd, TIOCMGET, &modemstat); + modemstat |= TIOCM_DTR; + ioctl(modemfd, TIOCMSET, &modemstat); +#endif + + usleep(gpppdata.modemInitDelay() * 10000); // 0.01 - 3.0 secs + + cfsetospeed(&temptty, modemspeed()); + cfsetispeed(&temptty, modemspeed()); + tcsetattr(modemfd, TCSAFLUSH, &temptty); +#endif + return true; + } else + return false; +} + + +void Modem::escape_to_command_mode() { + // Send Properly bracketed escape code to put the modem back into command state. + // A modem will accept AT commands only when it is in command state. + // When a modem sends the host the CONNECT string, that signals + // that the modem is now in the connect state (no long accepts AT commands.) + // Need to send properly timed escape sequence to put modem in command state. + // Escape codes and guard times are controlled by S2 and S12 values. + // + tcflush(modemfd, TCIOFLUSH); + + // +3 because quiet time must be greater than guard time. + usleep((gpppdata.modemEscapeGuardTime()+3)*20000); + QCString tmp = gpppdata.modemEscapeStr().local8Bit(); + write(modemfd, tmp.data(), tmp.length()); + tcflush(modemfd, TCIOFLUSH); + usleep((gpppdata.modemEscapeGuardTime()+3)*20000); + + data_mode = false; +} + + +const QString Modem::modemMessage() { + return errmsg; +} + + +QString Modem::parseModemSpeed(const QString &s) { + // this is a small (and bad) parser for modem speeds + int rx = -1; + int tx = -1; + int i; + QString result; + + qDebug( "Modem reported result string: %s", s.latin1()); + + const int RXMAX = 7; + const int TXMAX = 2; + QRegExp rrx[RXMAX] = { + QRegExp("[0-9]+[:/ ]RX", false), + QRegExp("[0-9]+RX", false), + QRegExp("[/: -][0-9]+[/: ]", false), + QRegExp("[/: -][0-9]+$", false), + QRegExp("CARRIER [^0-9]*[0-9]+", false), + QRegExp("CONNECT [^0-9]*[0-9]+", false), + QRegExp("[0-9]+") // panic mode + }; + + QRegExp trx[TXMAX] = { + QRegExp("[0-9]+[:/ ]TX", false), + QRegExp("[0-9]+TX", false) + }; + + for(i = 0; i < RXMAX; i++) { + int len, idx, result; + if((idx = rrx[i].match(s,0,&len)) > -1) { +// if((idx = rrx[i].search(s)) > -1) { + // len = rrx[i].matchedLength(); + + // + // rrx[i] has been matched, idx contains the start of the match + // and len contains how long the match is. Extract the match. + // + QString sub = s.mid(idx, len); + + // + // Now extract the digits only from the match, which will + // then be converted to an int. + // + if ((idx = rrx[RXMAX-1].match( sub,0,&len )) > -1) { +// if ((idx = rrx[RXMAX-1].search( sub )) > -1) { +// len = rrx[RXMAX-1].matchedLength(); + sub = sub.mid(idx, len); + result = sub.toInt(); + if(result > 0) { + rx = result; + break; + } + } + } + } + + for(i = 0; i < TXMAX; i++) { + int len, idx, result; + if((idx = trx[i].match(s,0,&len)) > -1) { +// if((idx = trx[i].search(s)) > -1) { +// len = trx[i].matchedLength(); + + // + // trx[i] has been matched, idx contains the start of the match + // and len contains how long the match is. Extract the match. + // + QString sub = s.mid(idx, len); + + // + // Now extract the digits only from the match, which will then + // be converted to an int. + // + if((idx = rrx[RXMAX-1].match(sub,0,&len)) > -1) { +// if((idx = rrx[RXMAX-1].search(sub)) > -1) { +// len = rrx[RXMAX-1].matchedLength(); + sub = sub.mid(idx, len); + result = sub.toInt(); + if(result > 0) { + tx = result; + break; + } + } + } + } + + if(rx == -1 && tx == -1) + result = i18n("Unknown speed"); + else if(tx == -1) + result.setNum(rx); + else if(rx == -1) // should not happen + result.setNum(tx); + else + result.sprintf("%d/%d", rx, tx); + + qDebug( "The parsed result is: %s", result.latin1()); + + return result; +} + + +// Lock modem device. Returns 0 on success 1 if the modem is locked and -1 if +// a lock file can't be created ( permission problem ) +int Modem::lockdevice() { + int fd; + char newlock[80]=""; // safe + + if(!gpppdata.modemLockFile()) { + qDebug("The user doesn't want a lockfile."); + return 0; + } + + if (modem_is_locked) + return 1; + + QString lockfile = LOCK_DIR"/LCK.."; + lockfile += gpppdata.modemDevice().mid(5); // append everything after /dev/ + + if(access(QFile::encodeName(lockfile), F_OK) == 0) { +// if ((fd = Requester::rq-> +if ((fd = openLockfile(QFile::encodeName(lockfile), O_RDONLY)) >= 0) { + // Mario: it's not necessary to read more than lets say 32 bytes. If + // file has more than 32 bytes, skip the rest + char oldlock[33]; // safe + int sz = read(fd, &oldlock, 32); + close (fd); + if (sz <= 0) + return 1; + oldlock[sz] = '\0'; + + qDebug( "Device is locked by: %s", oldlock); + + int oldpid; + int match = sscanf(oldlock, "%d", &oldpid); + + // found a pid in lockfile ? + if (match < 1 || oldpid <= 0) + return 1; + + // check if process exists + if (kill((pid_t)oldpid, 0) == 0 || errno != ESRCH) + return 1; + + qDebug( "lockfile is stale" ); + } + } + + fd = openLockfile(gpppdata.modemDevice(),O_WRONLY|O_TRUNC|O_CREAT); + if(fd >= 0) { + sprintf(newlock,"%010d\n", getpid()); + qDebug("Locking Device: %s", newlock); + + write(fd, newlock, strlen(newlock)); + close(fd); + modem_is_locked=true; + + return 0; + } + + return -1; + +} + + +// UnLock modem device +void Modem::unlockdevice() { + if (modem_is_locked) { + qDebug( "UnLocking Modem Device" ); + close(modemfd); + modemfd = -1; + unlink(lockfile); + lockfile[0] = '\0'; + modem_is_locked=false; + } +} + +int Modem::openLockfile( QString lockfile, int flags) +{ + int fd; + int mode; + flags = O_RDONLY; + if(flags == O_WRONLY|O_TRUNC|O_CREAT) + mode = 0644; + else + mode = 0; + + lockfile = LOCK_DIR; + lockfile += "/LCK.."; + lockfile += device.right( device.length() - device.findRev("/") -1 ); + qDebug("lockfile >%s<",lockfile.latin1()); + // TODO: + // struct stat st; + // if(stat(lockfile.data(), &st) == -1) { + // if(errno == EBADF) + // return -1; + // } else { + // // make sure that this is a regular file + // if(!S_ISREG(st.st_mode)) + // return -1; + // } + if ((fd = open(lockfile, flags, mode)) == -1) { + qDebug("error opening lockfile!"); + lockfile = QString::null; + fd = open(DEVNULL, O_RDONLY); + } else + fchown(fd, 0, 0); + return fd; +} + + + +void alarm_handler(int) { + // fprintf(stderr, "alarm_handler(): Received SIGALRM\n"); + + // jump + siglongjmp(jmp_buffer, 1); +} + + + +const char* pppdPath() { + // wasting a few bytes + static char buffer[sizeof(PPPDSEARCHPATH)+sizeof(PPPDNAME)]; + static char *pppdPath = 0L; + char *p; + + if(pppdPath == 0L) { + const char *c = PPPDSEARCHPATH; + while(*c != '\0') { + while(*c == ':') + c++; + p = buffer; + while(*c != '\0' && *c != ':') + *p++ = *c++; + *p = '\0'; + strcat(p, "/"); + strcat(p, PPPDNAME); + if(access(buffer, F_OK) == 0) + return (pppdPath = buffer); + } + } + + return pppdPath; +} -- cgit v0.9.0.2