You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kdeprint/kprinter/printwrapper.cpp

404 lines
10 KiB

/*
* This file is part of the KDE libraries
* Copyright (c) 2001 Michael Goffioul <kdeprint@swing.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library 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 library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
**/
#include "printwrapper.h"
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <qstring.h>
#include <qstringlist.h>
#include <stdlib.h>
#include <kmessagebox.h>
#include <qfile.h>
#include <qtimer.h>
#include <qregexp.h>
#include <qsocketnotifier.h>
#include <kapplication.h>
#include <kcmdlineargs.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kio/netaccess.h>
#include <kurl.h>
#include <kdebug.h>
#include <ktempfile.h>
#include <kprinter.h>
#include <kdeprint/kmmanager.h>
#include <kdeprint/kmprinter.h>
#include <kdeprint/kprintdialog.h>
void signal_handler(int);
QString tempFile;
bool fromStdin = false;
char job_output = 0; // 0: dialog, 1: console, 2: none
char readchar = '\0';
bool dataread = false;
bool docopy = false;
void showmsgdialog(const QString& msg, int type = 0)
{
switch (type)
{
case 0: KMessageBox::information(NULL,msg,i18n("Print Information")); break;
case 1: KMessageBox::sorry(NULL,msg,i18n("Print Warning")); break;
case 2: KMessageBox::error(NULL,msg,i18n("Print Error")); break;
}
}
void showmsgconsole(const QString& msg, int type = 0)
{
QString errmsg = QString::fromLatin1("%1 : ").arg((type == 0 ? i18n("Print info") : (type == 1 ? i18n("Print warning") : i18n("Print error"))));
kdDebug() << errmsg << msg << endl;
}
void showmsg(const QString& msg, int type = 0)
{
switch (job_output) {
case 0: showmsgdialog(msg,type); break;
case 1: showmsgconsole(msg,type); break;
default: break;
}
}
void errormsg(const QString& msg)
{
showmsg(msg,2);
exit(1);
}
void signal_handler(int s)
{
QFile::remove(tempFile);
exit(s);
}
QString copyfile( const QString& filename )
{
kdDebug( 500 ) << "Copying file " << filename << endl;
QString result;
QFile f( filename );
if ( f.open( IO_ReadOnly ) )
{
KTempFile temp;
temp.setAutoDelete( false );
QFile *tf = temp.file();
if ( tf )
{
char buffer[ 0xFFFF ];
int b = 0;
while ( ( b = f.readBlock( buffer, 0xFFFF ) ) > 0 )
{
if ( tf->writeBlock( buffer, b ) != b )
break;
}
tf->close();
if ( b > 0 )
temp.setAutoDelete( true );
else
{
kdDebug( 500 ) << "File copied to " << temp.name() << endl;
result = temp.name();
}
}
else
temp.setAutoDelete( true );
f.close();
}
return result;
}
//******************************************************************************************************
PrintWrapper::PrintWrapper()
: QWidget(), force_stdin(false), check_stdin(true)
{
}
void PrintWrapper::slotPrint()
{
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action;
#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
// read variables from command line
QString printer = args->getOption("d");
QString title = args->getOption("t");
int ncopies = QString(args->getOption("n")).toInt();
QString job_mode = args->getOption("j");
QString system = args->getOption("system");
QCStringList optlist = args->getOptionList("o");
QMap<QString,QString> opts;
KURL::List files;
QStringList filestoprint;
force_stdin = args->isSet("stdin");
docopy = args->isSet( "c" );
bool nodialog = !(args->isSet("dialog"));
if( isatty( 0 ))
{
kdDebug( 500 ) << "stdin is a terminal, disabling it" << endl;
check_stdin = false;
}
// parse options
for (QCStringList::ConstIterator it=optlist.begin(); it!=optlist.end(); ++it)
{
QStringList l = QStringList::split('=',QString(*it),false);
if (l.count() >= 1) opts[l[0]] = (l.count() == 2 ? l[1] : QString::null);
}
// read file list
for (int i=0; i<args->count(); i++)
files.append(args->url(i));
// some clean-up
args->clear();
// set default values if necessary
if (job_mode == "console") job_output = 1;
else if (job_mode == "none") job_output = 2;
else job_output = 0;
// some checking
if ( files.count() > 0)
{
check_stdin = false;
if( force_stdin )
{
showmsg(i18n("A file has been specified on the command line. Printing from STDIN will be disabled."), 1);
force_stdin = false;
}
}
if (nodialog && files.count() == 0 &&!force_stdin && !check_stdin )
{
errormsg(i18n("When using '--nodialog', you must at least specify one file to print or use the '--stdin' flag."));
}
if( check_stdin )
{ // check if there's any input on stdin
fd_set in;
struct timeval tm;
tm.tv_sec = 0;
tm.tv_usec = 0;
FD_ZERO( &in );
FD_SET( 0, &in );
if( select( 1, &in, NULL, NULL, &tm ) )
{ // we have data on stdin
if ( read( 0, &readchar, 1 ) > 0 )
{
force_stdin = true;
check_stdin = false;
dataread = true;
kdDebug( 500 ) << "input detected on stdin" << endl;
}
else
{
force_stdin = check_stdin = false;
kdDebug( 500 ) << "stdin closed and empty" << endl;
}
}
else
kdDebug( 500 ) << "no input on stdin at startup" << endl;
}
// force_stdin ? or also check_stdin ?
KPrinter::ApplicationType dialog_mode = (force_stdin || nodialog ? KPrinter::StandAlone : KPrinter::StandAlonePersistent);
KPrinter::setApplicationType(dialog_mode);
if (!force_stdin)
KPrinter::addStandardPage(KPrinter::FilesPage);
KPrinter kprinter;
if (nodialog)
{
KMPrinter *prt(0);
KMManager *mgr = KMManager::self();
mgr->printerList(false);
if (!printer.isEmpty())
prt = mgr->findPrinter(printer);
else
prt = mgr->defaultPrinter();
if (prt == 0)
errormsg(i18n("The specified printer or the default printer could not be found."));
else if (!prt->autoConfigure(&kprinter))
errormsg(i18n("Operation aborted."));
}
else if (!printer.isEmpty())
kprinter.setSearchName(printer);
kprinter.setDocName(title);
kprinter.initOptions(opts);
kprinter.setOption("kde-filelist", files.toStringList().join("@@"));
kdDebug( 500 ) << kprinter.option( "kde-filelist" ) << endl;
if (ncopies > 0)
kprinter.setNumCopies(ncopies);
if (nodialog)
slotPrintRequested(&kprinter);
else
{
dlg = KPrintDialog::printerDialog(&kprinter, 0);
if (dlg)
{
connect(dlg, SIGNAL(printRequested(KPrinter*)), SLOT(slotPrintRequested(KPrinter*)));
if( check_stdin )
{
notif = new QSocketNotifier( 0, QSocketNotifier::Read, this );
connect( notif, SIGNAL( activated( int )), this, SLOT( slotGotStdin()));
kdDebug( 500 ) << "waiting for input on stdin" << endl;
}
dlg->exec();
delete dlg;
}
else
errormsg(i18n("Unable to construct the print dialog."));
}
QTimer::singleShot(10,kapp,SLOT(quit()));
}
void hack( KPrintDialog* dlg );
void PrintWrapper::slotGotStdin()
{
delete notif;
if ( read( 0, &readchar, 1 ) > 0 )
{
force_stdin = true;
check_stdin = false;
dataread = true;
dlg->enableDialogPage( 0, false );
kdDebug( 500 ) << "got delayed input on stdin" << endl;
}
}
void PrintWrapper::slotPrintRequested(KPrinter *kprinter)
{
// re-initialize docName
kprinter->setDocName(QString::null);
// download files if needed
QStringList files = QStringList::split("@@", kprinter->option("kde-filelist"), false), filestoprint;
for (QStringList::ConstIterator it=files.begin(); it!=files.end(); ++it)
{
QString tmpFile;
KURL url = KURL::fromPathOrURL(*it);
kdDebug( 500 ) << url.url() << endl;
if (KIO::NetAccess::download(url, tmpFile, this))
{
filestoprint << tmpFile;
kprinter->setDocName(url.fileName());
}
}
if (filestoprint.count() > 1)
kprinter->setDocName(i18n("Multiple files (%1)").arg(filestoprint.count()));
else if (kprinter->docName().isEmpty())
kprinter->setDocName(force_stdin ? "<STDIN>" : "KPrinter");
if (filestoprint.count() == 0)
{
// At this point force_stdin should be true
if (!force_stdin)
errormsg(i18n("Nothing to print."));
// print from stdin
# if defined(HAVE_SIGSET)
sigset(SIGHUP, signal_handler);
sigset(SIGINT, signal_handler);
sigset(SIGTERM, signal_handler);
# elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
action.sa_handler = signal_handler;
sigaction(SIGHUP, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
# else
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
# endif
tempFile = locateLocal("tmp","kprinter_")+QString::number(getpid());
filestoprint.append(tempFile);
fromStdin = true;
FILE *fout = fopen(QFile::encodeName(filestoprint[0]),"w");
if (!fout) errormsg(i18n("Unable to open temporary file."));
char buffer[8192];
int s;
// check for previously read data
if ( dataread )
fwrite( &readchar, 1, 1, fout );
// read stdin and write to temporary file
while ((s=fread(buffer,1,sizeof(buffer),stdin)) > 0)
fwrite(buffer,1,s,fout);
s = ftell(fout);
fclose(fout);
if (s <= 0)
{
showmsg(i18n("Stdin is empty, no job sent."), 2);
QFile::remove(filestoprint[0]);
return;
}
}
else if ( docopy )
{
for ( QStringList::Iterator it=filestoprint.begin(); it!=filestoprint.end(); ++it )
{
QString tmp = copyfile( *it );
if ( tmp.isEmpty() )
{
errormsg( i18n( "Unable to copy file %1." ).arg( *it ) );
return;
}
*it = tmp;
}
fromStdin = true;
}
else
fromStdin = false;
// print all files. Remove it after if printing from
// stdin. "kprinter" shouldn't remove temp file itself,
// otherwise the temp file might get removed before the
// print process finishes.
bool ok = kprinter->printFiles(filestoprint, fromStdin);
if (!ok)
showmsg(i18n("Error while printing files"), 2);
// Do not show this dialog anymore. Code sould be removed definitively
// if nobody complains.
/*else
{
QString msg = i18n("<nobr>File(s) sent to printer <b>%1</b>.</nobr>").arg(kprinter->printerName());
showmsg(msg,0);
}*/
}
#include "printwrapper.moc"