#include <qdir.h>                       /* ...to work against the qfiledlg.h problem... */

#include <kapp.h>
#include <kbutton.h>
#include <klocale.h>
#include <kmsgbox.h>
#include <kprocess.h>
#include <ktopwidget.h>
#include <kwm.h>

#include <qbttngrp.h>
#include <qchkbox.h>
#include <qcombo.h>			
#include <qevent.h>			
#include <qframe.h>			
#include <qpushbt.h>			
#include <qfont.h>			
#include <qgrpbox.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qlistbox.h>
#include <qmsgbox.h>
#include <qpixmap.h>
#include <qpopmenu.h>
#include <qradiobt.h>
#include <qstring.h>
#include <qtabdlg.h>
#include <qtimer.h>
#include <qtooltip.h>

#include <sys/types.h>
#include <stdio.h>
#include <string.h>

#include "logo.h"
#include "mytypes.h"
#include "kISDNdata.h"
#include "accdlg.h"
#include "prefdlg.h"
#include "adapter.h"
#include "display.h"
#include "connection.h"
#include "kISDN.h"


/* Audioserver */
#include <iostream.h>
#include <stdlib.h>

extern "C"
{
#include <mediatool.h>
}

#include "kaudio.h"


#include "LEDs/LED_yellow_off.xpm"
#include "LEDs/LED_green_off.xpm"
#include "LEDs/LED_red_off.xpm"
#include "LEDs/LED_yellow_on.xpm"
#include "LEDs/LED_green_on.xpm"
#include "LEDs/LED_red_on.xpm"

#define KISDNVERSION "0.3.1"

enum {YELLOW, GREEN, RED};
enum {OFF, ON, BLINK};
enum {CONNECT, DISCONNECT};

KApplication *kISDN;


MyLabel::MyLabel(uint xpos, uint ypos, const char *label, QWidget *parent, const char *name):QLabel(parent, name)
{
  setText(label);
  move(xpos, ypos);
  setFont(QFont("Helvetica", 12));
}


LED::LED(ushort Color, uint xpos, uint ypos, QWidget *parent, const char *name):QLabel(parent, name)
{
  state  = OFF;
  switch (color = Color)
  {
    case YELLOW : pixmap = QPixmap(LED_yellow_off_xpm);
    	 	  break;
    case GREEN  : pixmap = QPixmap(LED_green_off_xpm);
    		  break;
    case RED    : pixmap = QPixmap(LED_red_off_xpm);
    		  break;
    default     : fprintf(stderr, "Bad color value for LED.\n");
  }   
  setPixmap(pixmap);
  resize(16, 16);
  move(xpos, ypos);
}


void LED::set(void)
{
  if (state != ON)
  {
    state = ON;
    switch (color)
    {
      case YELLOW : setPixmap(pixmap = QPixmap(LED_yellow_on_xpm));
    	 	    break;
      case GREEN  : setPixmap(pixmap = QPixmap(LED_green_on_xpm));
    		    break;
      case RED    : setPixmap(pixmap = QPixmap(LED_red_on_xpm));
    		    break;
      default     : fprintf(stderr, "LED::set has bad color.\n");
    }
  }
}


void LED::clear(void)
{
  if (state != OFF)
  {
    state = OFF;
    switch (color)
    {
      case YELLOW : setPixmap(pixmap = QPixmap(LED_yellow_off_xpm));
    	 	    break;
      case GREEN  : setPixmap(pixmap = QPixmap(LED_green_off_xpm));
    		    break;
      case RED    : setPixmap(pixmap = QPixmap(LED_red_off_xpm));
    		    break;
      default     : fprintf(stderr, "LED::set has bad color.\n");
    }
  }
}


/* This may be obsolete... */

PasswordDialog::PasswordDialog(QWidget *parent, const char *name):QDialog(parent, name, true)
{
  PasswordLabel = new QLabel(klocale->translate("Enter root password:"), this);
  Password      = new QLineEdit(this);
  Ok            = new QPushButton(klocale->translate("Ok"), this);
  Cancel        = new QPushButton(klocale->translate("Cancel"), this);
  
  setMinimumSize(300, 110);
  setMaximumSize(300, 110);
  setCaption(klocale->translate("Password required"));
  PasswordLabel->setGeometry(20, 20, 120, 24);
  Password->setGeometry(150, 20, 140, 24);
  Password->setEchoMode( QLineEdit::Password );
  Ok->setGeometry(120, 70, 80, 32);
  Ok->setDefault(true);
  Cancel->setGeometry(210, 70, 80, 32);
  connect(Ok, SIGNAL(clicked()), SLOT(accept()));
  connect(Cancel, SIGNAL(clicked()), SLOT(reject()));
}


DockedWin::DockedWin(const char *name) : QLabel(name)
{
  myDisplay = new MyDisplay(this);
 
  showToolTip();
  menu = new QPopupMenu();
  CHECK_PTR(menu);
  
  subMenu = new QPopupMenu();
  CHECK_PTR(subMenu);

  menu->insertItem(klocale->translate("kISDN Configuration"));
  menu->insertSeparator();
  menu->insertItem(klocale->translate("Connect..."), subMenu);  
  menu->insertItem(klocale->translate("Disconnect"));
  menu->insertSeparator();
  menu->insertItem(klocale->translate("Quit"));
  connect(myDisplay, SIGNAL(rightClick()), SLOT(slotPopupMenu()));
}


void DockedWin::showToolTip(QString onlineTime)
{
  if (ISDNmon->isOnline()) QToolTip::add( this, klocale->translate(onlineTime.data()));
}


void DockedWin::showToolTip()
{
  if (!ISDNmon->isOnline()) QToolTip::add( this, klocale->translate("kISDN 0.3.0 - Offline") );
}


void DockedWin::launchConfig()
{
  kISDN->setMainWidget(ISDNmon);
  ISDNmon->show();
}


void DockedWin::slotPopupMenu()
{
  /* we need to create the subMenu everytime, because the providers may  */
  /* have changed. Maybe we could notify subMenu which items changed...? */
  subMenu->clear();

  AccData *provider;

  provider = ISDNData.FirstAccount;
  if (provider != (AccData *) 0L)
  {
    while (provider != (AccData *) 0L)
    {
      subMenu->insertItem(provider->providername);
      provider = provider->next;
    }
  }
  else	// no accounts configured
  {
    subMenu->insertItem(klocale->translate("None configured"));
    subMenu->setItemEnabled(0, false);
    menu->setItemEnabled(3, false);
  }
  
  boolean online = ISDNmon->isOnline();
  menu->setItemEnabled( 2, !online );
  menu->setItemEnabled( 3, online );

  /* qt-bug: first determine the real size of the menu with a trick */
  /* (thanks to Matthias Ettrich for this hint :)		    */
  
  menu->move(-1000,-1000);
  menu->show();
  menu->hide();
  
  // now do the corrent positioning:
  QRect g = KWM::geometry(Docked->winId());
  if (g.x() > QApplication::desktop()->width()/2 &&
     g.y() + menu->height() > QApplication::desktop()->height())
     menu->popup(QPoint( g.x(), g.y() - menu->height()));
  else menu->popup(QPoint( g.x() + g.width(), g.y() + g.height()));
}


Monitor::Monitor(QWidget *parent, const char *name): QDialog(parent, name, true)
{
  ushort   i;
  boolean  dummy[2];
  
  modloaded  = false;
  modchanged = false;

  for (i = 0; i < 2; i++) Connect[i] = (Connection *) 0L;
    
  setMinimumSize(404, 150);
  setMaximumSize(404, 150);

  Label = new MyLabel(18, 28, "A", this);
  Label = new MyLabel(18, 58, "B", this);
  Label = new MyLabel(34, 5, klocale->translate("Dial"), this);
  Label = new MyLabel(64, 5, klocale->translate("Con"), this);
  Label = new MyLabel(99, 5, klocale->translate("Tx"), this);
  Label = new MyLabel(124, 5, klocale->translate("Rx"), this);
  Label = new MyLabel(150, 5, klocale->translate("Connect to"), this);

  for (i = 0; i < 2; i++)
  {
    Dial[i]  = new LED(YELLOW, 38, 36+i*30, this);
    On[i]    = new LED(GREEN, 68, 36+i*30, this);
    Tx[i]    = new LED(RED, 98, 36+i*30, this);
    Rx[i]    = new LED(RED, 123, 36+i*30, this);
    
    Clock[i]       = 0;
    Received[i]    = 0;
    Transmitted[i] = 0;
    Device[i]      = i;
    
    PushConnect[i] = new QPushButton(klocale->translate("Connect"), this);
    PushConnect[i]->setGeometry(300, 32+i*30, 90, 24);

    ServerCombo[i] = new QComboBox(false, this);
    ServerCombo[i]->setGeometry(150, 32+i*30, 140, 24);    
    writeCombo(i);
    ServerCombo[i]->setCurrentItem(ISDNData.AccIndex[i]);
  }
  connect(ServerCombo[0], SIGNAL(activated(int)), SLOT(slotProviderAChanged(int)));
  connect(ServerCombo[1], SIGNAL(activated(int)), SLOT(slotProviderBChanged(int)));
  
  PushConnect[0]->setFocus();
  
  EtchedLine = new QFrame(this);
  EtchedLine->setFrameStyle(0x34);
  EtchedLine->setLineWidth(2);
  EtchedLine->setGeometry(8, 98, 388, 2);
  
  PushSetup = new QPushButton(klocale->translate("Setup"), this);
  PushSetup->setGeometry(14, 110, 80, 32);
  
  PushHelp = new QPushButton(klocale->translate("Help"), this);
  PushHelp->setGeometry(100, 110, 80, 32);
  PushHelp->setEnabled(true);

  PushDock = new QPushButton(klocale->translate("Hide"), this);
  PushDock->setGeometry(226, 110, 70, 32);
  setEnableHide( ISDNData.Dock() );
 
  PushQuit = new QPushButton(klocale->translate("Quit"), this);
  PushQuit->setGeometry(310, 110, 80, 32);

  PrefDlg = new LogoTabDialog( (QWidget *) 0, (const char *) 0);
  PrefDlg->setCaption(klocale->translate("kISDN Preferences"));
  PrefDlg->setCancelButton();
  PrefDlg->resize( 365, 406 );
  PrefDlg->setFixedSize( 365, 406 );
    
  Account  = new AccountWidget(PrefDlg);
  General  = new GeneralWidget(PrefDlg);
  Commands = new CommandWidget(PrefDlg);
  Driver   = new DriverWidget(PrefDlg);
  Logging  = new LoggingWidget(PrefDlg);
  About    = new AboutWidget(PrefDlg);
  
  PrefDlg->addTab(Account, klocale->translate("Accounts"));
  PrefDlg->addTab(General, klocale->translate("General"));
  PrefDlg->addTab(Commands, klocale->translate("Paths"));
  PrefDlg->addTab(Driver, klocale->translate("Driver"));
  PrefDlg->addTab(Logging, klocale->translate("Log"));
  PrefDlg->addTab(About, klocale->translate("About"));
      
  setCaption("kISDN "KISDNVERSION);
    
  connect(PushConnect[0], SIGNAL(clicked()), this, SLOT(slotTakeActionA()));
  connect(PushConnect[1], SIGNAL(clicked()), this, SLOT(slotTakeActionB()));
  connect(PushHelp, SIGNAL(clicked()), SLOT( slotInvokeHelp()));
  connect(PushSetup, SIGNAL(clicked()), this, SLOT(slotSetPreferences()));
  connect(PushQuit, SIGNAL(clicked()), this, SLOT(slotQuit()));
  connect(Docked->menu, SIGNAL(activated(int)), SLOT(slotDockMainMenu(int)));
  connect(Docked->subMenu, SIGNAL(activated(int)), SLOT(slotCallProvider(int)));

  checkTraffic(dummy, dummy);  
  Pulse = new QTimer(this);
  connect(Pulse, SIGNAL(timeout()), this, SLOT(slotCheckStatus()));
  Pulse->start(125, true);
}


Monitor::~Monitor(void)
{
  if (modloaded) removeModule();
}


void Monitor::writeCombo(ushort i)
{
  AccData *account;
  
  ServerCombo[i]->clear();
    
  account = ISDNData.FirstAccount;
  if (account == (AccData *) 0L) 
  {
    ServerCombo[i]->insertItem(klocale->translate("None configured"));
	ServerCombo[i]->setEnabled(false);
    PushConnect[i]->setEnabled(false);	// where does this segfault come from?
  }
  else
  {
    PushConnect[i]->setEnabled(true);
	ServerCombo[i]->setEnabled(true);
	while (account != (AccData *) 0L)
    {
      ServerCombo[i]->insertItem(account->providername);
      account = account->next;
    }
  }
}


void Monitor::setEnableHide(bool hide)
{
  PushDock->setEnabled(hide);
  if (hide) connect(PushDock, SIGNAL(clicked()), SLOT( slotMinimize()));
  else disconnect(PushDock, SIGNAL(clicked()), this, SLOT( slotMinimize()));
}


bool Monitor::demandPassword(void)
{
  bool correct;
  
  PasswordDialog *dialog = new PasswordDialog(); 
  correct = dialog->exec();			        /* This can't be taken seriously for now... */
  delete dialog;
  return (correct);
}


void Monitor::messageBadPassword(void)
{
  QMessageBox::warning(this, "ISP change failed","Incorrect root password,\n"    				   
		             "ISP is NOT changed.\n\n", "OK", 0);				   
}


void Monitor::slotProviderAChanged(int i)		/* May these 2 be superflous with a smarter */ {							/* SIGNAL/SLOT connection ?		    */
  providerChanged(0, i);				
}


void Monitor::slotProviderBChanged(int i)
{
  providerChanged(1, i);
}


bool Monitor::providerChanged(ushort channel, int i)
{
  char  buffer[8];
  bool  success;
  uint  actacc = ISDNData.AccIndex[channel];
  
//  if ((i != 0) && ((uint) i != actacc))
  if ((uint) i != actacc)
  {
    if (true)					// former: (demandPassword()), may be obsolete...			
    {
      locateAccount(i);					
      
      if (success = writeScripts())		        
      {							
        ISDNData.AccIndex[channel] = i;
        KConfig  *kc = kapp->getConfig();
        kc->setGroup("Configuration");
        sprintf(buffer, "ISP%i", channel);		
        kc->writeEntry(buffer, i);			
        kc->sync();
		ServerCombo[channel]->setCurrentItem(i);
      }
      if (!success) ServerCombo[channel]->setCurrentItem(actacc);
      return (success);
    }
    else
    {
      messageBadPassword();
      printf("Password was wrong.\n"); 
      ServerCombo[channel]->setCurrentItem(actacc);
      return (false);
    }
  }
  return (true);
}


void Monitor::slotTakeActionA(void)
{
  if (On[0]->LEDstate() == ON) hangUp(0);
  else dialUp(0);
}


void Monitor::slotTakeActionB(void)
{
  if (On[1]->LEDstate() == ON) hangUp(1);
  else dialUp(1);
}


void Monitor::slotCallProvider(int isp)
{
  if (providerChanged(0, isp)) dialUp(0);
}


void Monitor::slotDockMainMenu(int choice)
{
  if (choice == 0) Docked->launchConfig();
  // choice = 1: Separator
  // choice = 2: SubMenu Connect
  if (choice == 3) hangUp(0);
  // choice = 4: Separator
  if (choice == 5) ISDNmon->slotQuit();
}


void Monitor::playSound( ushort sound )
{
  KAudio KAServer;
  
  if (ISDNData.Audio())
  {
    switch (sound)
    {
      case CONNECT     : KAServer.play(ISDNData.General->wavonlinepath.data());
                         break;
      case DISCONNECT  : KAServer.play(ISDNData.General->wavofflinepath.data());
                         break;
      default          : fprintf(stderr, "Wrong Soundrequest.\n");
    }
  }
}


void Monitor::slotCheckStatus(void)			
{							
  boolean  Online[2], Dialing[2], Tra[2], Rec[2];
  ushort   channel;
  uint clock, seconds, minutes, hours;
  QString onlineTime;
  
  checkOnline(Online, Dialing);				
 
  for (channel = 0; channel < 2; channel++)
  {
    if (Online[channel]) 			
    {							
      if (Dial[channel]->LEDstate() == ON)      
      {
        Dial[channel]->clear();					
	    if (channel == 0) myDisplay->clearDial();
      }
      if (On[channel]->LEDstate() != ON)	// we're online!
      {
        On[channel]->set();						
	    if (channel == 0) myDisplay->setOnline();
        ISDNmon->playSound (CONNECT);
        debug("We're online");
		  
        PushConnect[channel]->setText(klocale->translate("Hangup"));    
	    PushConnect[channel]->setEnabled(true);
      }
      Clock[channel]++;
      if (!(Clock[channel]%8))
      {
        clock    = Clock[channel] >> 3;
        seconds  = clock % 60;
        clock   /= 60;
        minutes  = clock % 60;
        clock   /= 60;
        hours    = clock % 24;
        // days     = clock / 24;
        onlineTime.sprintf( klocale->translate("Online: %02i:%02i:%02i Hours"), hours, minutes, seconds);
        Docked->showToolTip( onlineTime );
        // Timer[channel]->setText(buffer);
      }     
    }
    else
    {
      if (Dialing[channel])
      {
        if (Dial[channel]->LEDstate() != ON)
        {
          PushConnect[channel]->setEnabled(false);
	      Dial[channel]->set();
	      if (channel == 0) myDisplay->setDial();
	    }
      }
      else
      {
	    if (On[channel]->LEDstate() == ON)	// we're offline again
	    {
          ISDNmon->playSound(DISCONNECT);
          debug("We're offline");
	  
	      On[channel]->clear();
          Clock[channel] = 0;
	      Docked->showToolTip();
	  
	      if (channel == 0) myDisplay->clearOnline();
          PushConnect[channel]->setText(klocale->translate("Connect"));
	    }
        if (Dial[channel]->LEDstate() == ON)
	    {
	      Dial[channel]->clear();
	      if (channel == 0) myDisplay->clearDial();
          PushConnect[channel]->setText(klocale->translate("Connect"));
        }
        if ( ISDNData.FirstAccount != 0L )
	      PushConnect[channel]->setEnabled(true);
      }
    }
  }
  
  checkTraffic(Tra, Rec);
  for (channel = 0; channel < 2; channel++)
  {
    if (Tra[channel] && !(Tx[channel]->LEDstate() == ON))
    {
      Tx[channel]->set();
      if (channel == 0) myDisplay->setTransmit();
    }
    if (!Tra[channel] && (Tx[channel]->LEDstate() == ON))
    {
      Tx[channel]->clear();
      if (channel == 0) myDisplay->clearTransmit();
    }
    if (Rec[channel] && !(Rx[channel]->LEDstate() == ON))
    {
      Rx[channel]->set();
      if (channel == 0) myDisplay->setReceive();
    }
    if (!Rec[channel] && (Rx[channel]->LEDstate() == ON))
    {
      Rx[channel]->clear();
      if (channel == 0) myDisplay->clearReceive();
    }
  } 
  Pulse->start(125, true);
}


void Monitor::slotQuit()
{
  int conn = ISDNmon->onlineChannels();

  if (conn != -1)       // we're still online
  {
    KMsgBox *hangupOnQuit = new KMsgBox;
    int i = hangupOnQuit->yesNoCancel( this, klocale->translate("Disconnect?"),  klocale->translate("Disconnect active line?"), 8, klocale->translate("Yes"), klocale->translate("No"), klocale->translate("Cancel") );
    if ( i == 1 )
    {
      if (conn == 2)
	  {
        ISDNmon->hangUp( 0 );
        ISDNmon->hangUp( 1 );
      }
      else ISDNmon->hangUp( (ushort) conn );
    }
    if ( i == 3 ) return;
  }
  kapp->quit();
}


void Monitor::checkOnline(boolean *Online, boolean *Dialing)
{
  FILE     *isdninfo;
  char     buffer[256];
  char	   token[32], phoneA[50], phoneB[50];
  boolean  online = false, dialing = false;
  int      packets[2];
  
  isdninfo = fopen("/dev/isdninfo", "r");
  if (isdninfo)
  {
    do
    {
      if (fgets(buffer, 254, isdninfo))
      {
        sscanf(buffer, "%s%i%i", token, &packets[0], &packets[1]);
        if (!online)
        {
	      online = !strcmp(token, "flags:"); 
          if (online)
          {
            Online[0] = (boolean)packets[0];
    	    Online[1] = (boolean)packets[1];
    	  }
    	}
        if (!dialing)
        {
	      dialing = !strcmp(token, "phone:");
          if (dialing)
          {
            sscanf(buffer, "%s%s%s", token, phoneA, phoneB);
            Dialing[0] = (boolean)strcmp(phoneA, "???");
	        Dialing[1] = (boolean)strcmp(phoneB, "???");
          }
        }
      }
    } while (!(online && dialing));
    fclose(isdninfo);
  }
  else 					// This is the case when the driver module has been
  {					// removed from the kernel (/dev/isdninfo missing).
    for (ushort i = 0; i < 2; i++) 	
    {
      Dialing[i] = false;		// We're offline and not dialing for certain, then.
      Online[i]  = false;
    }
  }   
}


void Monitor::checkTraffic(boolean *Tra, boolean *Rec)
{
  FILE	   *procnet;					// Still lacks Kernel 2.1.x support
  char	   buffer[256], token[100];
  uint     rec[2] ={0, 0}, tra[2] = {0, 0}, dummy;
  boolean  found[2] = {false, false};
  ushort   channel; 
  
  for (channel = 0; channel < 2; channel++)
  {
    Tra[channel] = false;
    Rec[channel] = false;
  } 
  procnet = fopen("/proc/net/dev", "r"); 
  if (procnet)
  {
    do
    {
      fgets(buffer, 254, procnet);
      sscanf(buffer, "%s", token);
      if (!strcmp(token, "ippp0:"))
      {
        found[0] = true;
        sscanf(buffer, "%s%i%i%i%i%i%i", token, &rec[0], &dummy, &dummy, &dummy, &dummy, &tra[0]);
      }
      if (!strcmp(token, "ippp1:"))
      {
        found[1] = true;
        sscanf(buffer, "%s%i%i%i%i%i%i", token, &rec[1], &dummy, &dummy, &dummy, &dummy, &tra[1]);
      }
    } while (!feof(procnet) && (!found[0] || !found[1] ));
    
    for (channel = 0; channel < 2; channel++)
    {
      if (found[channel])
      {     
        Rec[channel] = (rec[channel] > Received[channel]);
        Tra[channel] = (tra[channel] > Transmitted[channel]);
        Received[channel]    = rec[channel];
        Transmitted[channel] = tra[channel];
      }
    }  
    fclose(procnet);
  }
}


bool Monitor::isOnline()
{
  boolean Online[2], dummy[2];
  checkOnline( Online, dummy );
  
  return ( Online[0] || Online[1] );
}


/**
  * -1 = not connected
  *  0 = ippp0 connected
  *  1 = ippp1 connected
  *  2 = both ippp0 and ippp1 connected
  **/
int Monitor::onlineChannels()
{
  boolean Online[2], dummy[2];
  checkOnline( Online, dummy );

  if ( Online[0] && Online[1] ) return 2;
  else
  {
    if ( Online[0] ) return 0;
    else if ( Online[1] ) return 1;
    else return -1;
  }
}


void Monitor::slotMinimize()
{
  ISDNmon->hide();
  
  kISDN->setMainWidget(Docked);
  KWM::setDockWindow(Docked->winId());
  Docked->show();
}


//void Monitor::messageNoAccSelected(void)
//{
//  QMessageBox::warning(this, "No ISP Selected",
//    		             "You have to select an ISP\n"
//		             "prior to dialing.\n\n", "OK", 0);
//}


void Monitor::dialUp(ushort channel)
{
  GenData  *gen = ISDNData.General;
  
//  if (ISDNData.AccIndex[channel])
//  {
    PushConnect[channel]->setEnabled(false);

    locateAccount(ISDNData.AccIndex[channel]);
    
    if (gen->loadasmodule) 
    {
      if (modloaded)
      {
        if (modchanged) 
	    {
	      removeModule();	// CAUTION: This implies that the old and the new driver are the same
	      insertModule();	//          and only parameters have changed !
	    }
      }
      else insertModule();
    }
 
    if (Connect[channel] != (Connection *) 0L)
    {
      QMessageBox::warning(this, "Warning",
      "This connection seems to be\n"
      "up -- deleting.\n\n", "OK", 0);
      delete Connect[channel];
    }
    
    fprintf(stderr, "Configuring device and starting the ipppd.\n");
    Connect[channel] = new Connection();
    fprintf(stderr, "Dialing out...\n");
    Connect[channel]->dialOut();
//  }
//  else messageNoAccSelected();
}


void Monitor::hangUp(ushort channel)
{
  GenData  *gen = ISDNData.General;

  if  (Connect[channel] == (Connection *) 0L) QMessageBox::warning(this, "Warning",
                                                "This connection seems to be\n"
                                                "terminated -- can't delete.\n\n", "OK", 0);
  else 
  {
    Connect[channel]->hangUp();
    delete Connect[channel];
    Connect[channel] = (Connection *) 0L;                                             
  }
  if (gen->loadasmodule) removeModule();
}


void Monitor::messageBadSysValues(void)
{
  QString tmp;
  
  tmp  = klocale->translate("I/O Address must be within 0x0000\n");
  tmp += klocale->translate("and 0xFFFF, Interrupt must be a value\n");
  tmp += klocale->translate("between 0 and 15.\n");
  tmp += klocale->translate("Warning: Incorrect input can hang your\n");
  tmp += klocale->translate("system!\n\n");
  
  QMessageBox::warning(this, klocale->translate("Bad Value"), tmp, "Ok", 0);
}


void Monitor::messageCantOpenFile(const char *fname)
{
  char buffer[128];
  
  sprintf(buffer, "Can't open file\n%s !\n\n", fname);
  QMessageBox::warning(this, klocale->translate("I/O Error"), buffer, "OK", 0);
}


void Monitor::messageNoDNSSupplied(void)
{
  QString tmp;
  
  tmp  = klocale->translate("You forgot to specify a\n");
  tmp += klocale->translate("nameserver for this ISP\n\n");
  
  QMessageBox::warning(this, klocale->translate("Can't connect"), tmp, "Ok", 0);
}


void Monitor::slotSetPreferences(void)
{ 
  char buffer[4];
  
  ISDNData.Backup();
  bool okpressed = PrefDlg->exec();
   
  if (!okpressed)
  {
    ISDNData.Restore();
    General->refreshSettings();
    Commands->refreshSettings();
  } 
  else 
  {
    modchanged = true;				// We assume this since we can't determine, whether
    while (( !Driver->isValidIOAddr(0) || 	// the user actually changed module parameters or not...
             !Driver->isValidIOAddr(1) ||
             !Driver->isValidInterrupt() ||
	     !Driver->isValidMembase()
	  ) && okpressed && Driver->Modulechk->isChecked() )
    {
      messageBadSysValues();
      okpressed = PrefDlg->exec();
    }
     
    if (okpressed)
    {
      GenData *gen = ISDNData.General;
      
      writeCombo(0);
      writeCombo(1);
      Driver->setIOBase(0, (ISDNData.General)->iobase0);
      Driver->setIOBase(1, (ISDNData.General)->iobase1);
      sprintf(buffer, "%i", (ISDNData.General)->interrupt);
      Driver->setInterrupt(buffer);
      Driver->setMembase((ISDNData.General)->membase);
      
      gen->ctrlpath     = (Commands->ctrlpath)->text();
      gen->ipppdpath    = (Commands->ipppdpath)->text();
      gen->prefix       = (General->prefix)->text();
      gen->msn          = (General->msn)->text();
      gen->modprobepath = (Driver->Modprobe)->text();
      gen->iobase0      = (Driver->Ioaddr0)->text();
      gen->iobase1      = (Driver->Ioaddr1)->text();
      gen->interrupt    = atoi((Driver->Interrupt)->text());
      gen->membase      = (Driver->Membase)->text();
      gen->isdnlogpath  = (Logging->Isdnlog)->text();
      gen->isdnreppath  = (Logging->Isdnrep)->text();
      ISDNData.Save();  // ISDNdata.save(); 
      setEnableHide(ISDNData.Dock());
    }
  }
}


void Monitor::slotInvokeHelp()
{
  KApplication::getKApplication()->invokeHTMLHelp("kISDN/kISDN.html","");
}


void Monitor::locateAccount(int Account)
{
  AccData  *actual = ISDNData.FirstAccount;
  
//  uint dummy = Account--;
uint dummy = Account;
  
//  while (Account && (actual->next != (AccData *) 0L))
  while ((Account > 0) && actual->next != (AccData *) 0L)
  {
    actual = actual->next;
    Account--;
  }
  ISDNData.Current = actual;
  fprintf(stderr, "Located account #%i as ISP %s\n", dummy, actual->providername.data());
}


void Monitor::insertModule(void)
{
  char     buffer[128], mem[16] = "", io0[8] = "", io1[8] = "";
  GenData  *gen = ISDNData.General;
  ushort   adtype = gen->adapter;
  Adapter  adapter;
   
  if (adapter.NeedMem[adtype]) sprintf(mem, "mem=%s", gen->membase.data());
  
  if (adapter.NeedIO1[adtype])
  {
    if (!adapter.NeedIO2[adtype]) sprintf(io0, "io=%s", gen->iobase0.data());
    else 
    {
      sprintf(io0, "io0=%s", gen->iobase0.data());
      sprintf(io1, "io1=%s", gen->iobase1.data());
    }
  }
  
  sprintf(buffer,"%s %s %s %s %s irq=%i type=%i protocol=%i id=%s\n", 
      gen->modprobepath.data(),
	  (adapter.HLDriver[adtype]).data(),
	  mem,
	  io0,
	  io1,
	  gen->interrupt,
	  adapter.Type[adtype],
	  gen->protocol+1,
	  (adapter.Id[adtype]).data()
	  );

  fprintf(stderr, "Insert module...\n");
  system(buffer);
  modchanged = false;
  modloaded  = true;
}	  


void Monitor::removeModule(void)
{
  char     buffer[128];
  GenData  *gen = ISDNData.General;
  ushort   adtype = gen->adapter;
  Adapter  adapter;

  sprintf(buffer,"%s -r %s", gen->modprobepath.data(), (adapter.HLDriver[adtype]).data());
  
  fprintf(stderr, "Remove module...\n");
  system(buffer);
  modchanged = false;
  modloaded  = false;  
} 


bool Monitor::writeScripts(void)	
{
  FILE     *OutStream;
  AccData  *acc = ISDNData.Current;
  
  if (acc->UsePAP)
  {
    if ((OutStream = fopen(PAPFILE, "w")) != 0)
    {
      fprintf(stderr, "Writing %s...\n", PAPFILE);
      fprintf(OutStream, "%s * %s\n", acc->username.data(), acc->password.data());
      fclose(OutStream);
    }
    else 
    {
      messageCantOpenFile(PAPFILE);
      return (false);
    }
  }
  else
  {
    if (acc->UseCHAP)
    {
      if ((OutStream = fopen(CHAPFILE, "w")) != 0)
      {
        fprintf(stderr, "Writing %s...\n", CHAPFILE);
        fprintf(OutStream, "%s * %s\n", acc->username.data(), acc->password.data());
        fclose(OutStream);
      }
      else 
      {
        messageCantOpenFile(CHAPFILE);
        return (false);
      }
    }
    else
    {
      fprintf(stderr, "kISDN Fatal Error: UsePAP and UseCHAP are both set to false\n");
      return (false);
    }
  }

  if ((OutStream = fopen(DNSFILE, "w")) != 0)
  {
    fprintf(stderr, "Writing %s...\n", DNSFILE);
    fprintf(OutStream, "%s\n", acc->domain.data());
    
    DNSData *DNS = acc->FirstDNS;
    if (DNS != (DNSData *) 0L)
    {
      while (DNS != (DNSData *) 0L)
      {
        fprintf(OutStream, "nameserver %s\n", DNS->ipaddress.data());
	    DNS = DNS->next;
      }
      fclose(OutStream);
    }
    else
    {
      messageNoDNSSupplied();
      fclose(OutStream);
      return(false);
    }
  }
  else 
  {
    messageCantOpenFile(DNSFILE);
    return (false);
  }
  if ((OutStream = fopen(OPTFILE, "w")) != 0)
  {
    fprintf(stderr, "Writing %s...\n\n", OPTFILE);
    fprintf(OutStream, "name %s\n", acc->username.data());
    fclose(OutStream);
  }
  else 
  {
    messageCantOpenFile(OPTFILE);
    return (false);
  }
  return (true);
}
    

int main(int argc, char **argv)
{
  kISDN = new KApplication(argc, argv, "kISDN");

  ISDNData.Load();

  Docked = new DockedWin;	// do we really need Docked if we don't want to dock?
  CHECK_PTR(Docked);

  ISDNmon = new Monitor;	// we get a SEGV, when there is no "Docked"-pointer
  CHECK_PTR(ISDNmon);

  if ( ISDNData.Dock() )
  {  
    kISDN->setMainWidget(Docked);
    KWM::setDockWindow(Docked->winId());
    Docked->show();
  }
  else
  {
    kISDN->setMainWidget(ISDNmon);
    ISDNmon->show();
  }  
  return kISDN->exec();
}

#include "kISDN.moc"
#include "prefdlg.moc"
#include "accdlg.moc"
#include "display.moc"
