/***************************************************************************
    smb4kprint  -  The printing core class.
                             -------------------
    begin                : Tue Mar 30 2004
    copyright            : (C) 2004 by Alexander Reinholdt
    email                : dustpuppy@mail.berlios.de
 ***************************************************************************/

/***************************************************************************
 *   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.                                   *
 *                                                                         *
 *   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     *
 *   General Public License for more details.                              *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,   *
 *   MA  02110-1301 USA                                                    *
 ***************************************************************************/

// TQt includes
#include <tqtimer.h>
#include <tqfile.h>

// KDE includes
#include <kurl.h>
#include <tdefileitem.h>
#include <kdebug.h>

// system includes
#include <sys/types.h>
#include <pwd.h>

// application specific includes
#include "smb4kprint.h"
#include "smb4kdefs.h"
#include "smb4kerror.h"
#include "smb4tdeglobal.h"
#include "smb4kauthinfo.h"
#include "smb4kpasswordhandler.h"
#include "smb4kprintinfo.h"
#include "smb4ksettings.h"

using namespace Smb4TDEGlobal;



Smb4KPrint::Smb4KPrint( TQObject *parent, const char *name ) : TQObject( parent, name )
{
  m_proc = new TDEProcess( this, "PrintProcess" );
  m_proc->setUseShell( true );

  m_info = NULL;

  m_working = false;

  connect( m_proc, TQ_SIGNAL( receivedStdout( TDEProcess *, char *, int ) ),
           this,   TQ_SLOT( slotReceivedStdout( TDEProcess *, char *, int ) ) );

  connect( m_proc, TQ_SIGNAL( receivedStderr( TDEProcess *, char *, int ) ),
           this,   TQ_SLOT( slotReceivedStderr( TDEProcess *, char *, int ) ) );

  connect( m_proc, TQ_SIGNAL( processExited( TDEProcess * ) ),
           this,   TQ_SLOT( slotProcessExited( TDEProcess * ) ) );
}


Smb4KPrint::~Smb4KPrint()
{
  abort();
}


/****************************************************************************
   Aborts the current process.
****************************************************************************/

void Smb4KPrint::abort()
{
  if ( m_proc->isRunning() )
  {
    m_proc->kill();
  }
}


/****************************************************************************
   Start the printing.
****************************************************************************/

bool Smb4KPrint::print( Smb4KPrintInfo *info )
{
  // Do nothing if we receive a NULL pointer:
  if ( !info )
  {
    return false;
  }

  m_working = true;
  m_info = info;

  // Start processing the file:
  if ( TQFile::exists( m_info->path() ) )
  {
    // Determine the mimetype of the file:
    KURL url;
    url.setPath( m_info->path() );

    KFileItem file_item = KFileItem( KFileItem::Unknown, KFileItem::Unknown, url, false );

    if ( TQString::compare( file_item.mimetype(), "application/postscript" ) == 0 ||
         TQString::compare( file_item.mimetype(), "application/pdf" ) == 0 ||
         file_item.mimetype().startsWith( "image" ) )
    {
      setDeviceURI();
      printNormal();
    }
    else if ( TQString::compare( file_item.mimetype(), "application/x-dvi" ) == 0 &&
              !Smb4KSettings::dvips().isEmpty() )
    {
      setDeviceURI();
      printDVI();
    }
    else if ( (file_item.mimetype().startsWith( "text" ) ||
               file_item.mimetype().startsWith( "message" ) ||
               TQString::compare( file_item.mimetype(), "application/x-shellscript" ) == 0) &&
              !Smb4KSettings::enscript().isEmpty() )
    {
      setDeviceURI();
      printText();
    }
    else
    {
      Smb4KError::information( INFO_MIMETYPE_NOT_SUPPORTED, file_item.mimetype() );

      delete m_info;
      m_info = NULL;

      m_working = false;
      emit state( PRINT_STOP );
      return false;
    }
  }
  else
  {
    Smb4KError::error( ERROR_FILE_NOT_FOUND, m_info->path() );

    delete m_info;
    m_info = NULL;

    m_working = false;
    emit state( PRINT_STOP );
    return false;
  }

  return true;
}


/****************************************************************************
   Sets the device URI
****************************************************************************/

void Smb4KPrint::setDeviceURI()
{
  Smb4KAuthInfo *auth = passwordHandler()->readAuth( new Smb4KAuthInfo( m_info->workgroup(),
                                                     m_info->host(), m_info->printer() ) );

  TQString uri;

  // It seems that we must not quote the entries for the DEVICE_URI
  // environment variable. Printing will fail if you do it.

  if ( !m_info->workgroup().isEmpty() )
  {
    if ( !auth->user().isEmpty() )
    {
      uri = TQString( "smb://%1:%2@%3/%4/%5" ).arg( auth->user().data(), auth->password().data() ).arg( m_info->workgroup(), m_info->host(), m_info->printer() );
    }
    else
    {
      uri = TQString( "smb://%1/%2/%3" ).arg( m_info->workgroup(), m_info->host(), m_info->printer() );
    }
  }
  else
  {
    if ( !auth->user().isEmpty() )
    {
      uri = TQString( "smb://%1:%2@%3/%4" ).arg( auth->user().data(), auth->password().data() ).arg( m_info->host(), m_info->printer() );
    }
    else
    {
      uri = TQString( "smb://%1/%2" ).arg( m_info->host(), m_info->printer() );
    }
  }

  m_proc->setEnvironment( "DEVICE_URI", uri );

  delete auth;
}


/****************************************************************************
   Do normal printing.
****************************************************************************/

void Smb4KPrint::printNormal()
{
  TQString command;

  command.append( "smbspool 111 "+TQString( getpwuid( getuid() )->pw_name ) );
  command.append( " \"Smb4K print job\" "+TQString( "%1" ).arg( m_info->copies() ) );
  command.append( " \"\" "+TDEProcess::quote( m_info->path() ) );

  *m_proc << command;

  emit state( PRINT_START );

  m_proc->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput );
}


/****************************************************************************
   Print DVI files.
****************************************************************************/

void Smb4KPrint::printDVI()
{
  // The temporary file.
  TQString temp_file = tempDir()+"/smb4k_print.ps";

  TQString command;

  // First we need the conversion:
  command.append( "cd "+TDEProcess::quote( m_info->path().section( "/", 0, -2 ) )+" && " );
  command.append( "dvips -P pdf -o "+temp_file+" "+TDEProcess::quote( m_info->path().section( "/", -1, -1 ) )+" && " );

  // The actual print command:
  command.append( "smbspool 111 "+TQString( getpwuid( getuid() )->pw_name ) );
  command.append( " \"Smb4K print job\" "+TQString( "%1" ).arg( m_info->copies() ) );
  command.append( " \"\" "+TDEProcess::quote( temp_file )+" && " );

  // Clean up:
  command.append( "rm -f "+temp_file );

  *m_proc << command;

  emit state( PRINT_START );

  m_proc->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput );
}


/****************************************************************************
   Print text files.
****************************************************************************/

void Smb4KPrint::printText()
{
  // The temporary file.
  TQString temp_file = tempDir()+"/smb4k_print.ps";

  TQString command;

  // Conversion:
  command.append( "enscript --columns=1 --no-header --ps-level=2 " );
  command.append( "-o "+TDEProcess::quote( temp_file )+" " );
  command.append( TDEProcess::quote( m_info->path() )+ " && " );

  // The actual print command:
  command.append( "smbspool 111 "+TQString( getpwuid( getuid() )->pw_name ) );
  command.append( " \"Smb4K print job\" "+TQString( "%1" ).arg( m_info->copies() ) );
  command.append( " \"\" "+TDEProcess::quote( temp_file )+" && " );

  // Clean up:
  command.append( "rm -f "+temp_file );

  *m_proc << command;

  emit state( PRINT_START );

  m_proc->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput );
}


/////////////////////////////////////////////////////////////////////////////
// SLOT IMPLEMENTATIONS
/////////////////////////////////////////////////////////////////////////////

void Smb4KPrint::slotReceivedStdout( TDEProcess *, char *buf, int len )
{
  m_buffer.append( TQString::fromLocal8Bit( buf, len ) );
}


void Smb4KPrint::slotReceivedStderr( TDEProcess *, char *buf, int len )
{
  m_buffer.append( TQString::fromLocal8Bit( buf, len ) );

  if ( m_buffer.contains( "NT_STATUS" ) != 0 )
  {
    abort();
  }
}


void Smb4KPrint::slotProcessExited( TDEProcess * )
{
  bool retry = false;

  if ( m_buffer.contains( "NT_STATUS", true ) != 0 ||
       m_buffer.contains( "enscript", true ) != 0  ||
       m_buffer.contains( "dvips", true ) != 0 )
  {
    if ( m_buffer.contains( "NT_STATUS_ACCESS_DENIED" ) != 0 || m_buffer.contains( "NT_STATUS_LOGON_FAILURE" ) != 0 )
    {
      int state = Smb4KPasswordHandler::None;

      if ( m_buffer.contains( "NT_STATUS_ACCESS_DENIED" ) != 0 )
      {
        state = Smb4KPasswordHandler::AccessDenied;
      }
      else if (m_buffer.contains( "NT_STATUS_LOGON_FAILURE" ) != 0  )
      {
        state = Smb4KPasswordHandler::LogonFailure;
      }

      if ( passwordHandler()->askpass( m_info->workgroup(), m_info->host(), m_info->printer(), state ) )
      {
        retry = true;
        TQTimer::singleShot( 50, this, TQ_SLOT( slotRetry() ) );
      }
    }
    else
    {
      Smb4KError::error( ERROR_PRINTING, m_info->path(), m_buffer );

      // Clean up:
      TQFile::remove( TQString( "%1/smb4k_print.ps" ).arg( tempDir() ) );
    }
  }
  else
  {
    // Clean up:
    TQFile::remove( TQString( "%1/smb4k_print.ps" ).arg( tempDir() ) );
  }

  m_proc->clearArguments();

  if ( !retry )
  {
    delete m_info;
    m_info = NULL;
  }

  m_working = false;
  emit state( PRINT_STOP );
}


void Smb4KPrint::slotRetry()
{
  print( m_info );
}


#include "smb4kprint.moc"
