1
2/*
3 This file is part of KHelpCenter.
4
5 Copyright (c) 2005 Cornelius Schumacher <schumacher@kde.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20*/
21
22#include "searchhandler.h"
23
24#include "searchengine.h"
25#include "prefs.h"
26#include "docentry.h"
27
28#include <KDesktopFile>
29#include <KProcess>
30#include <KDebug>
31#include <KMessageBox>
32#include <KLocale>
33#include <KStandardDirs>
34#include <KShell>
35
36#include <stdlib.h>
37
38using namespace KHC;
39
40SearchJob::SearchJob(DocEntry *entry) : mEntry( entry ), mProcess( 0 ), mKioJob( 0 )
41{
42}
43
44bool SearchJob::startLocal(const QString &cmdString)
45{
46 mProcess = new KProcess;
47 *mProcess << KShell::splitArgs(cmdString);
48
49 connect( mProcess, SIGNAL( finished(int, QProcess::ExitStatus) ),
50 this, SLOT( searchExited(int, QProcess::ExitStatus) ) );
51
52 mProcess->setOutputChannelMode(KProcess::SeparateChannels);
53 mProcess->start();
54 if (!mProcess->waitForStarted()) {
55 QString txt = i18n("Error executing search command '%1'.", cmdString );
56 emit searchError( this, mEntry, txt );
57 return false;
58 }
59 return true;
60}
61
62bool SearchJob::startRemote(const QString &urlString)
63{
64 KIO::TransferJob *job = KIO::get( KUrl( urlString ) );
65 connect( job, SIGNAL( result( KJob * ) ),
66 this, SLOT( slotJobResult( KJob * ) ) );
67 connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
68 this, SLOT( slotJobData( KIO::Job *, const QByteArray & ) ) );
69
70 mKioJob = job;
71 return true;
72}
73
74SearchJob::~SearchJob()
75{
76 delete mProcess;
77 delete mKioJob;
78}
79
80void SearchJob::searchExited( int exitCode, QProcess::ExitStatus exitStatus )
81{
82 if ( exitStatus == QProcess::NormalExit && exitCode == 0 ) {
83 mResult = mProcess->readAllStandardOutput();
84 emit searchFinished( this, mEntry, mResult );
85 } else {
86 mError = mProcess->readAllStandardError();
87 QString error = QLatin1String("<em>") + mCmd + QLatin1String("</em>\n") + mError;
88 emit searchError( this, mEntry, error );
89 }
90}
91
92void SearchJob::slotJobResult( KJob *job )
93{
94 QString result;
95 //DocEntry *entry = 0;
96
97 if ( job->error() ) {
98 emit searchError( this, mEntry, i18n("Error: %1", job->errorString() ) );
99 } else {
100 emit searchFinished( this, mEntry, mResult );
101 }
102}
103
104void SearchJob::slotJobData( KIO::Job *job, const QByteArray &data )
105{
106 Q_UNUSED(job);
107 mResult += data.data();
108}
109
110
111SearchHandler::SearchHandler( const KConfigGroup &cg )
112{
113 mLang = KGlobal::locale()->language().left( 2 );
114 mDocumentTypes = cg.readEntry( "DocumentTypes" , QStringList() );
115}
116
117SearchHandler::~SearchHandler()
118{
119}
120
121SearchHandler *SearchHandler::initFromFile( const QString &filename )
122{
123 KDesktopFile file( filename );
124 KConfigGroup dg = file.desktopGroup();
125
126 SearchHandler *handler = 0;
127
128 const QString type = dg.readEntry( "Type" );
129 if ( false ) {
130 } else {
131 handler = new ExternalProcessSearchHandler( dg );
132 }
133
134 return handler;
135}
136
137QStringList SearchHandler::documentTypes() const
138{
139 return mDocumentTypes;
140}
141
142
143ExternalProcessSearchHandler::ExternalProcessSearchHandler( const KConfigGroup &cg )
144 : SearchHandler( cg )
145{
146 mSearchCommand = cg.readEntry( "SearchCommand" );
147 mSearchUrl = cg.readEntry( "SearchUrl" );
148 mIndexCommand = cg.readEntry( "IndexCommand" );
149 mTryExec = cg.readEntry( "TryExec" );
150 mSearchBinary = cg.readEntry( "SearchBinary" );
151 const QStringList searchBinaryPaths = cg.readEntry( "SearchBinaryPaths", QStringList() );
152 mSearchBinary = KStandardDirs::findExe(mSearchBinary, searchBinaryPaths.join(":"));
153}
154
155QString ExternalProcessSearchHandler::indexCommand( const QString &identifier )
156{
157 QString cmd = mIndexCommand;
158 cmd.replace( "%i", identifier );
159 cmd.replace( "%d", Prefs::indexDirectory() );
160 cmd.replace( "%l", mLang );
161 return cmd;
162}
163
164bool ExternalProcessSearchHandler::checkPaths(QString* error) const
165{
166 if ( !mSearchCommand.isEmpty() && !checkBinary( mSearchCommand ) ) {
167 *error = i18n("'%1' not found, check your installation", mSearchCommand);
168 return false;
169 }
170
171 if ( !mIndexCommand.isEmpty() && !checkBinary( mIndexCommand ) ) {
172 *error = i18n("'%1' not found, check your installation", mIndexCommand);
173 return false;
174 }
175
176 if ( !mTryExec.isEmpty() && !checkBinary( mTryExec ) ) {
177 *error = i18n("'%1' not found, install the package containing it", mTryExec);
178 return false;
179 }
180
181 return true;
182}
183
184bool ExternalProcessSearchHandler::checkBinary( const QString &cmd ) const
185{
186 QString binary;
187
188 int pos = cmd.indexOf( ' ' );
189 if ( pos < 0 ) binary = cmd;
190 else binary = cmd.left( pos );
191
192 return !KStandardDirs::findExe( binary ).isEmpty();
193}
194
195void ExternalProcessSearchHandler::search( DocEntry *entry, const QStringList &words,
196 int maxResults,
197 SearchEngine::Operation operation )
198{
199 kDebug() << entry->identifier();
200
201 if ( !mSearchCommand.isEmpty() ) {
202 QString cmdString = SearchEngine::substituteSearchQuery( mSearchCommand,
203 entry->identifier(), words, maxResults, operation, mLang, mSearchBinary );
204
205 kDebug() << "CMD:" << cmdString;
206
207 SearchJob *searchJob = new SearchJob(entry);
208 connect(searchJob, SIGNAL(searchFinished( SearchJob *, DocEntry *, const QString & )),
209 this, SLOT(slotSearchFinished( SearchJob *, DocEntry *, const QString & )));
210 connect(searchJob, SIGNAL(searchError( SearchJob *, DocEntry *, const QString & )),
211 this, SLOT(slotSearchError( SearchJob *, DocEntry *, const QString & )));
212 searchJob->startLocal(cmdString);
213
214 } else if ( !mSearchUrl.isEmpty() ) {
215 QString urlString = SearchEngine::substituteSearchQuery( mSearchUrl,
216 entry->identifier(), words, maxResults, operation, mLang, mSearchBinary );
217
218 kDebug() << "URL:" << urlString;
219
220 SearchJob *searchJob = new SearchJob(entry);
221 connect(searchJob, SIGNAL(searchFinished( SearchJob *, DocEntry *, const QString & )),
222 this, SLOT(slotSearchFinished( SearchJob *, DocEntry *, const QString & )));
223 connect(searchJob, SIGNAL(searchError( SearchJob *, DocEntry *, const QString & )),
224 this, SLOT(slotSearchError( SearchJob *, DocEntry *, const QString & )));
225 searchJob->startRemote(urlString);
226
227 } else {
228 QString txt = i18n("No search command or URL specified.");
229 emit searchFinished( this, entry, txt );
230 }
231}
232
233void ExternalProcessSearchHandler::slotSearchFinished( SearchJob *job, DocEntry *entry, const QString &result )
234{
235 emit searchFinished( this, entry, result);
236 job->deleteLater();
237}
238
239void ExternalProcessSearchHandler::slotSearchError( SearchJob *job, DocEntry *entry, const QString &error )
240{
241 emit searchError(this, entry, error);
242 job->deleteLater();
243}
244
245#include "searchhandler.moc"
246