/***************************************************************************
                          klprfax.cpp  -  description
                             -------------------
    begin                : Thu May 24 23:17:55 'Europe/Amsterdam' 2001
    copyright            : (C) 2001 by Hans Dijkema
    email                : hdijkema@hum.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "klprfax.h"
#include "klprfax_widget.h"

#include <kmessagebox.h>
#include <kaboutapplication.h>

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

#include <fcntl.h>
#include <unistd.h>

#include <klocale.h>

Klprfax::Klprfax(KApplication *_app,KConfigBase *cnf,QCString faxF,QWidget *parent, const char *name) : QWidget(parent, name)
{
AddressBook::ErrorCode err;
AddressBook   *bk;
int            n,i;
QString        name,fax0,fax1,fax2,fax3;
QString        nil="";

   app=_app;

   fatal=false;
   findEFax();

   // Dialog

   dlg=new QGrid(5,QGrid::Vertical,this);
   dlg->setMargin(10);
   dlg->setSpacing(10);

   // Fax numbers

   names=new klprfax_table(1,2,dlg);
   names->setMinimumSize(200,100);
   names->setMaximumSize(1024,120);
   names->setSelectionMode(QTable::NoSelection);
   {QHeader *h=names->horizontalHeader();
      h->setLabel(0,i18n("Name"));
      h->setLabel(1,i18n("Fax No."));
   }

   // Search all entries with fax numbers

   kab=new KabAPI;
   err=kab->init();
   bk=kab->addressbook();
   n=bk->noOfEntries();

   int rows=-1,col0=0,col1=0;
   for(i=0;i<n;i++) {KabKey k;
                     AddressBook::Entry e;
     err=bk->getKey(i,k);
     err=bk->getEntry(k,e);
     if (NameFax(e,name,fax0,fax1,fax2,fax3)) {klprfax_widget *tmp;

	rows+=1;if (rows>=names->numRows()) { names->setNumRows(rows+1); }

	tmp=new klprfax_widget(rows,0,names);
	tmp->add(name);
	tmp->commit();
	tmp->adjustSize();
	if (tmp->width()>col0) { col0=tmp->widget()->width()+5; }

        tmp=new klprfax_widget(rows,1,names);
        tmp->add(fax0);tmp->add(fax1);tmp->add(fax2);tmp->add(fax3);
	tmp->commit();
	tmp->adjustSize();
	if (tmp->widget()->width()>col1) { col1=tmp->widget()->width()+5; }

        names->adjustRow(rows);
     }
   }
   names->setColumnWidth(0,col0);
   names->setColumnWidth(1,col1);
   names->adjustSize();

   // Headers

   edits=new QGrid(2,dlg);
   edits->setSpacing(10);
   edits->setMargin(10);
   edits->setFrameStyle(QFrame::Box|QFrame::Raised);

   lfrom=new QLabel(edits);
   lfrom->setText(i18n("your header :"));
   from=new QLineEdit(edits);
   from->setMinimumWidth(200);

   lfromFax=new QLabel(edits);
   lfromFax->setText(i18n("your fax :"));
   fromFax=new QLineEdit(edits);

   conf=cnf;
   conf->setGroup("klprfax");
   {QString ft,fft;
     ft=conf->readEntry("from",nil);
     fft=conf->readEntry("fromFax",nil);
     from->setText(ft);
     fromFax->setText(fft);
   }

   lprefix=new QLabel(edits);
   lprefix->setText(i18n("Dial prefix :"));
   prefix=new QLineEdit(edits);
   prefix->setText(conf->readEntry("dialprefix",nil));

   // Progress bar

   progr=new QGrid(2,dlg);
   progr->setSpacing(10);

   doing=new QLabel(progr);
   doing->setText(i18n("doing nothing"));
   progress=new QProgressBar(progr);
   progress->setTotalSteps(4);
   progress->reset();

   // Buttons

   buttons=new QGrid(5,dlg);
   buttons->setSpacing(10);

   about=new QPushButton(buttons);about->setText(i18n("&About"));
   configure=new QPushButton(buttons);configure->setText(i18n("&Save config"));
   noFax=new QPushButton(buttons);noFax->setText(i18n("&Done"));
   goFax=new QPushButton(buttons);goFax->setText(i18n("&Fax document"));
   gogoFax=new QPushButton(buttons);gogoFax->setText(i18n("&Fax with prefix"));

   connect(about,SIGNAL(clicked()),SLOT(doAbout()) );
   connect(configure, SIGNAL(clicked()), SLOT(setConfig()) );
   connect(noFax, SIGNAL(clicked()), SLOT(noFaxing()) );
   connect(goFax, SIGNAL(clicked()), SLOT(goFaxing()) );
   connect(gogoFax, SIGNAL(clicked()), SLOT(gogoFaxing()) );

   // Log list

   log = new QListBox(dlg);
   log->setMinimumHeight(80);
   log->setMaximumHeight(80);

   // adjust the dialog size

   dlg->adjustSize();
   //adjustSize();
   setFixedSize(dlg->width(),dlg->height());

   // Read the fax to fax.

   {QString cwd;
    char line[4096];
      getcwd(line,4096);
      cwd.sprintf("%s",line);
      faxFile=faxF;faxFile=cwd+"/"+faxFile;
      {FILE *f=fopen(faxFile.latin1(),"rb");
          if (f==NULL) { faxFile=faxF; }
          f=fopen(faxFile.latin1(),"rb");
          if (f==NULL) {
            KMessageBox::error(this,i18n("Can't open file to fax"));
            fatal=true;
          }
      }
   }

   // Set the Done button behaviour to default

   canCancel=false;

   // Set the kprocess behaviour

   connect(&efax_helper,SIGNAL(receivedStdout(KProcess *,char *,int )),SLOT(efaxOutput(KProcess *,char *,int )));
   connect(&efax_helper,SIGNAL(receivedStderr(KProcess *,char *,int )),SLOT(efaxOutput(KProcess *,char *,int )));
   connect(&efax_helper,SIGNAL(processExited(KProcess *)),SLOT(efaxExited(KProcess *)));
}

Klprfax::~Klprfax()
{}

/** No descriptions */
bool Klprfax::NameFax(AddressBook::Entry & e,QString & name, QString & fax0,QString & fax1, QString & fax2, QString & fax3)
{
bool isFax=false,ok;
unsigned int n,i;
QString nil="";
AddressBook::Telephone faxEnum=AddressBook::Fax; // 3;  // AddressBook::Telephone::Fax
int fn=0;
QString fax;

   fax0=QString::null;
   fax1=QString::null;
   fax2=QString::null;
   fax3=QString::null;

   n=e.telephone.count();
   for(i=0;i<n;i+=2) {QString type;
                                 int _type;
      type=e.telephone[i];
      _type=type.toInt(&ok,10);
      if (ok) {
        if ((_type+1)==faxEnum) {
          fax=e.telephone[i+1].stripWhiteSpace();
          if (fax!="") {
            isFax=true;
            switch (fn++) {
              case 0 : fax0=fax;
              break;
              case 1 : fax1=fax;
              break;
              case 2 : fax2=fax;
              break;
              case 3 : fax3=fax;
              break;
            }

          }
        }
      }
   }

   if (isFax) {
     name=e.fn.stripWhiteSpace();
     if (name=="") {QString fn,mn,ln;
       fn=e.firstname.stripWhiteSpace();
       mn=e.middlename.stripWhiteSpace();
       ln=e.lastname.stripWhiteSpace();
       if (mn=="") { name=fn+" "+ln; }
       else { name=fn+" "+mn+" "+ln; }
     }
   }

return isFax;
}
/** No descriptions */
void Klprfax::noFaxing()
{
   if (canCancel) {
     doLog(i18n("Cancelling efax..."));
     if (!efax_helper.kill(SIGTERM)) {
       doLog(i18n("Cancelling persistent efax..."));
       efax_helper.kill(SIGKILL);
     }
   }
   else {
     close();
   }
}

void Klprfax::setConfig(void)
{
   conf->setGroup("klprfax");
   conf->writeEntry("from",from->text());
   conf->writeEntry("fromFax",fromFax->text());
   conf->writeEntry("dialprefix",prefix->text().stripWhiteSpace());
}

void Klprfax::gogoFaxing()
{
  dialPrefix=true;
  Fax();
}


/** No descriptions */
void Klprfax::goFaxing()
{
  dialPrefix=false;
  Fax();
}

void Klprfax::Fax()
{
klprfax_widget *it;
QString tel,name;
int     forkResult;
QString device;

  {FILE *dev=fopen("/etc/klprfax","rb");
   char line[1024];
     if (dev==NULL) {
        KMessageBox::error(this,i18n("No modem device configured, run klprfax as root"));
        return;
     }
     fgets(line,1024,dev);
     line[strlen(line)-1]='\0';
     device=line;
     fclose(dev);
  }

  if (names->currentRow()!=-1) {
    it=(klprfax_widget *) names->cellWidget(names->currentRow(),1);
  }
  else { it=0;
    KMessageBox::error(this,i18n("Select a fax number"));
    return;
  }
  tel=it->text();

  it=(klprfax_widget *) names->cellWidget(names->currentRow(),0);
  name=it->text();

  if (dialPrefix) {
    tel=prefix->text().stripWhiteSpace()+tel;   // add the prefix
  }

  // Now start the faxing!!!

  {QString cmd,filetofax,logfile="log";
   int     k;

     script.sprintf("/tmp/fax.%d",getpid());
     dir.sprintf("/tmp/faxd.%d",getpid());

     doing->setText(i18n("preparing fax command..."));
     progress->setProgress(1);

     FILE *fin=fopen(efax.latin1(),"rb");
     FILE *fout=fopen(script.latin1(),"wb");
     char line[4096];

     while(fgets(line,4096,fin)!=NULL) {
        if (strncmp(line,"NAME=",5)==0) {
          fprintf(fout,"NAME=\"%s\"\n",from->text().latin1());
        }
        else if (strncmp(line,"FROM=",5)==0) {
          fprintf(fout,"FROM=\"%s\"\n",fromFax->text().latin1());
        }
        else if (strncmp(line,"FAILRETRIES=",12)==0 || strncmp(line,"BUSYRETRIES=",12)==0) {
          // skip line
        }
        else if (strncmp(line,"DEV=",4)==0) {
          fprintf(fout,"DEV=\"%s\"\n",device.latin1());
        }
        else if (strncmp(line,"FAX=",4)==0) {
          fprintf(fout,"FAX=" KDE_BINDIR "/fax\n");
        }
        else if (strncmp(line,"EFAX=",4)==0) {
          fprintf(fout,"EFAX=" KDE_BINDIR "/efax\n");
        }
        else if (strncmp(line,"EFIX=",4)==0) {
          fprintf(fout,"EFIX=" KDE_BINDIR "/efix\n");
        }
        else {
          fputs(line,fout);
        }
     }

     fclose(fin);fclose(fout);

     doing->setText(i18n("copying input file..."));
     progress->setProgress(2);

     mkdir(dir.latin1(),S_IRWXU);
     if (chdir(dir.latin1())==-1) {QString msg;
        msg=i18n("Can't change directory to :")+dir;
        KMessageBox::error(this,msg);
        return;
     }

     {FILE *fin=fopen(faxFile.latin1(),"rb"),
           *fout=fopen("faxfile","wb");
           int fh=fileno(fin);
           char buf[8192];
           int bytes;
           while((bytes=read(fh,buf,8192))!=0) {
              fwrite(buf,bytes,1,fout);
              app->processEvents(50);
           }
           fclose(fin);
           fclose(fout);
           filetofax="faxfile";
     }

     doing->setText(i18n("efax is running..."));
     progress->setProgress(3);

     enableAll(false);
     log->clear();
     efax_helper.clearArguments();
     efax_diagnostic="";

     {QString n=i18n("name="),f=i18n("fax no.=");
        n=n+name+"  "+f+tel;
        doLog(n);
     }

     chmod(script.latin1(),S_IXUSR|S_IRUSR|S_IWUSR);

     efax_helper << script;
     {QString t="\""+tel+"\"",
              f="\""+filetofax+"\"";
       efax_helper << "send" << t << f;
     }
     efax_helper.setRunPrivileged(true);

     if (!efax_helper.start(KProcess::NotifyOnExit,KProcess::AllOutput)) {
       KMessageBox::error(this,i18n("Can't start efax process"));
       enableAll();
     }
  }
}

/** No descriptions */
void Klprfax::findEFax()
{
char *path[]={KDE_BINDIR"/fax",NULL};
int     i;
FILE    *f=NULL;

   for(i=0;(f=fopen(path[i],"rb"))==NULL && path[i]!=NULL;i++);
   if (f==NULL) {
     KMessageBox::error(this,"Can't find 'efax' on this system,\n"
                             "The klprfax package didn't compile right\n"
                       );
     fatal=true;
   }
   efax=path[i];
   fclose(f);
}


void Klprfax::doAbout()
{
  KAboutApplication(this).exec();
}


void Klprfax::efaxOutput(KProcess *proc,char *buf, int  len)
{
int i;
  for(i=0;i<len;i++) {
    if (buf[i]=='\n') {
      doLog(efax_diagnostic);
      efax_diagnostic="";
    }
    else {
      efax_diagnostic+=buf[i];
    }
  }
}

void Klprfax::efaxExited(KProcess *p)
{
QString cmd,txt;
int     k;
bool    err=false;

  if (!p->normalExit()) {
    txt=i18n("efax has been canceled");
    doing->setText("CANCELED");
    progress->setProgress(4);
    err=true;
  }
  else {
    k=p->exitStatus();
    if (k==0) {
      doing->setText("fax successfully sent");
      progress->setProgress(4);
    }
    else {
          switch (k) {
             case 1 : txt=i18n("number busy or modem already in use");
             break;
             case 2 : txt=i18n("Is your modem connected? Did you SUID root efax?");
             break;
             case 3 : txt=i18n("modem error, maybe no fax at the other side?");
             break;
             case 4 : txt=i18n("no response from modem");
             break;
             case 5 : txt=i18n("efax has been canceled");
             break;
             default: txt=i18n("I can't figure out what happened");
          }
          doing->setText(i18n("NO SUCCESS"));
          progress->setProgress(4);
          err=true;
    }
  }

  if (err) {
    txt+=i18n("\nlog can be found at '")+dir+"'";
    txt+=i18n("\nYou can watch it before closing this box");
    KMessageBox::error(this,txt);
  }

  cmd.sprintf("rm -f *");
  system(cmd.latin1());
  chdir("..");
  rmdir(dir.latin1());
  unlink(script.latin1());

  enableAll();
}


void Klprfax::enableAll(bool yes)
{
     goFax->setEnabled(yes);
     if (yes) { noFax->setText(i18n("&Done")); }
     else { noFax->setText(i18n("&Cancel")); }
     canCancel=!yes;
     gogoFax->setEnabled(yes);
     about->setEnabled(yes);
     configure->setEnabled(yes);
}


void Klprfax::doLog(QString s)
{
  log->insertItem(s);
  log->setCurrentItem(log->count()-1);
}
