~ubuntu-branches/ubuntu/wily/kbibtex/wily

« back to all changes in this revision

Viewing changes to src/webquerygooglescholar.cpp

  • Committer: Package Import Robot
  • Author(s): Michael Hanke
  • Date: 2011-07-18 09:29:48 UTC
  • mfrom: (1.1.6) (2.1.5 sid)
  • Revision ID: package-import@ubuntu.com-20110718092948-ksxjmg7kdfamolmg
Tags: 0.3-1
* First upstream release for KDE4 (Closes: #634255). A number of search
  engines are still missing, in comparison to the 0.2 series.
* Bumped Standards-Version to 3.9.2, no changes necessary.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *   Copyright (C) 2004-2009 by Thomas Fischer                             *
3
 
 *   fischer@unix-ag.uni-kl.de                                             *
4
 
 *                                                                         *
5
 
 *   This program is free software; you can redistribute it and/or modify  *
6
 
 *   it under the terms of the GNU General Public License as published by  *
7
 
 *   the Free Software Foundation; either version 2 of the License, or     *
8
 
 *   (at your option) any later version.                                   *
9
 
 *                                                                         *
10
 
 *   This program is distributed in the hope that it will be useful,       *
11
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13
 
 *   GNU General Public License for more details.                          *
14
 
 *                                                                         *
15
 
 *   You should have received a copy of the GNU General Public License     *
16
 
 *   along with this program; if not, write to the                         *
17
 
 *   Free Software Foundation, Inc.,                                       *
18
 
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19
 
 ***************************************************************************/
20
 
#include <qfile.h>
21
 
#include <qapplication.h>
22
 
#include <qregexp.h>
23
 
#include <qtimer.h>
24
 
#include <qmap.h>
25
 
#include <qspinbox.h>
26
 
#include <kconfig.h>
27
 
 
28
 
#include <klineedit.h>
29
 
#include <klocale.h>
30
 
#include <kdebug.h>
31
 
#include <kmessagebox.h>
32
 
#include <kio/job.h>
33
 
 
34
 
#include <dcopref.h>
35
 
 
36
 
#include <settings.h>
37
 
#include "webquerygooglescholar.h"
38
 
 
39
 
namespace KBibTeX
40
 
{
41
 
    WebQueryGoogleScholarWidget::WebQueryGoogleScholarWidget( QWidget *parent, const char *name )
42
 
            : WebQueryWidget( parent, name )
43
 
    {
44
 
        init();
45
 
 
46
 
        Settings *settings = Settings::self();
47
 
        QString value = settings->getWebQueryDefault( "GoogleScholar" );
48
 
        value = value == QString::null ? "" : value;
49
 
        lineEditQuery->setText( value );
50
 
        slotTextChanged( value, true );
51
 
    }
52
 
 
53
 
    WebQueryGoogleScholar::WebQueryGoogleScholar( QWidget* parent )
54
 
            : WebQuery( parent ), m_transferJob( NULL ), m_transferJobBuffer( NULL )
55
 
    {
56
 
        m_importer = new BibTeX::FileImporterBibTeX( FALSE );
57
 
        m_importer->setIgnoreComments( TRUE );
58
 
        m_widget = new WebQueryGoogleScholarWidget( parent );
59
 
    }
60
 
 
61
 
    WebQueryGoogleScholar::~WebQueryGoogleScholar()
62
 
    {
63
 
        delete m_widget;
64
 
        delete m_importer;
65
 
    }
66
 
 
67
 
    QString WebQueryGoogleScholar::title()
68
 
    {
69
 
        return i18n( "Google Scholar" );
70
 
    }
71
 
 
72
 
    QString WebQueryGoogleScholar::disclaimer()
73
 
    {
74
 
        return i18n( "About Google Scholar" );
75
 
    }
76
 
 
77
 
    QString WebQueryGoogleScholar::disclaimerURL()
78
 
    {
79
 
        return "http://scholar.google.com/intl/en/scholar/about.html";
80
 
    }
81
 
 
82
 
    WebQueryWidget *WebQueryGoogleScholar::widget()
83
 
    {
84
 
        return m_widget;
85
 
    }
86
 
 
87
 
    void WebQueryGoogleScholar::query()
88
 
    {
89
 
        WebQuery::query();
90
 
 
91
 
        /** save search term in settings */
92
 
        Settings *settings = Settings::self();
93
 
        settings->setWebQueryDefault( "GoogleScholar", m_widget->lineEditQuery->text() );
94
 
 
95
 
        /** generate web-save search term */
96
 
        m_searchTerm = m_widget->lineEditQuery->text().stripWhiteSpace().replace( '$', "" );
97
 
        m_searchTerm = m_searchTerm.replace( "%", "%25" ).replace( "+", "%2B" ).replace( " ", "%20" ).replace( "#", "%23" ).replace( "&", "%26" ).replace( "?", "%3F" );
98
 
        if ( m_searchTerm.isEmpty() )
99
 
        {
100
 
            setEndSearch( WebQuery::statusInvalidQuery );
101
 
            return;
102
 
        }
103
 
 
104
 
        /** initialize variables */
105
 
        m_abort = false;
106
 
        m_numberOfResults = m_widget->spinBoxMaxHits->value();
107
 
        setNumStages( m_numberOfResults + 5 );
108
 
 
109
 
        /** reset KDE configuration for cookie handling */
110
 
        readAndChangeConfig();
111
 
 
112
 
        /** prepare HTTP request (buffer, signals, job) */
113
 
        m_transferJobBuffer = new QBuffer();
114
 
        m_transferJobBuffer->open( IO_WriteOnly );
115
 
        KIO::TransferJob* m_transferJob = KIO::get( KURL( "http://scholar.google.com/scholar_ncr" ), false, false );
116
 
        connect( m_transferJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ), this, SLOT( slotData( KIO::Job *, const QByteArray & ) ) );
117
 
        connect( m_transferJob, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotFinishedStartpage( KIO::Job * ) ) );
118
 
    }
119
 
 
120
 
    void WebQueryGoogleScholar::cancelQuery()
121
 
    {
122
 
        /** user aborted search */
123
 
        m_abort = true;
124
 
        if ( m_transferJob != NULL ) m_transferJob->kill( false );
125
 
        setEndSearch( WebQuery::statusError );
126
 
    }
127
 
 
128
 
    void WebQueryGoogleScholar::slotFinishedStartpage( KIO::Job *job )
129
 
    {
130
 
        /** close and delete buffer (content does not matter) */
131
 
        m_transferJobBuffer->close();
132
 
        delete m_transferJobBuffer;
133
 
 
134
 
        /** if aborted in the mean time, clean up everything */
135
 
        if ( m_abort )
136
 
        {
137
 
            restoreConfig();
138
 
            return;
139
 
        }
140
 
 
141
 
        /** error occurred */
142
 
        if ( job->error() != 0 )
143
 
        {
144
 
            restoreConfig();
145
 
            kdDebug() << "Error in slotFinishedStartpage: " << job->error() << endl;
146
 
            setEndSearch( statusError );
147
 
            return;
148
 
        }
149
 
 
150
 
        /** update progress bar */
151
 
        enterNextStage();
152
 
 
153
 
        /** prepare next HTTP request for preferences page (buffer, signals, job) */
154
 
        m_transferJobBuffer = new QBuffer();
155
 
        m_transferJobBuffer->open( IO_WriteOnly );
156
 
        KIO::TransferJob* m_transferJob = KIO::get( KURL( "http://scholar.google.com/scholar_preferences?hl=en" ), false, false );
157
 
        connect( m_transferJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ), this, SLOT( slotData( KIO::Job *, const QByteArray & ) ) );
158
 
        connect( m_transferJob, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotFinishedLoadingSettings( KIO::Job * ) ) );
159
 
 
160
 
    }
161
 
 
162
 
    void WebQueryGoogleScholar::slotFinishedLoadingSettings( KIO::Job *job )
163
 
    {
164
 
        /** close and delete buffer (content does not matter) */
165
 
        m_transferJobBuffer->close();
166
 
        QString htmlCode = textFromBuffer( m_transferJobBuffer );
167
 
        delete m_transferJobBuffer;
168
 
 
169
 
        /** if aborted in the mean time, clean up everything */
170
 
        if ( m_abort )
171
 
        {
172
 
            restoreConfig();
173
 
            return;
174
 
        }
175
 
 
176
 
        /** error occurred */
177
 
        if ( job->error() != 0 )
178
 
        {
179
 
            restoreConfig();
180
 
            kdDebug() << "Error in slotFinishedLoadingSettings: " << job->error() << endl;
181
 
            setEndSearch( statusError );
182
 
            return;
183
 
        }
184
 
 
185
 
        /** update progress bar */
186
 
        enterNextStage();
187
 
 
188
 
        /** parse html code to get form values */
189
 
        QMap<QString, QString> keyValues = evalFormFields( htmlCode );
190
 
        /** set form values for BibTeX search */
191
 
        keyValues["scis"] = "yes";
192
 
        keyValues["scisf"] = "4";
193
 
        keyValues["submit"] = "Save+Preferences";
194
 
        keyValues["num"] = QString::number( m_numberOfResults );
195
 
 
196
 
        /** prepare next HTTP request to submit preferences (buffer, signals, job) */
197
 
        KURL nextUrl( formFieldsToUrl( "http://scholar.google.com/scholar_setprefs", keyValues ) );
198
 
        m_transferJobBuffer = new QBuffer();
199
 
        m_transferJobBuffer->open( IO_WriteOnly );
200
 
        KIO::TransferJob* m_transferJob = KIO::get( nextUrl, false, false );
201
 
        connect( m_transferJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ), this, SLOT( slotData( KIO::Job *, const QByteArray & ) ) );
202
 
        connect( m_transferJob, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotFinishedSavingSettings( KIO::Job * ) ) );
203
 
    }
204
 
 
205
 
    void WebQueryGoogleScholar::slotFinishedSavingSettings( KIO::Job *job )
206
 
    {
207
 
        /** close and delete buffer (content does not matter) */
208
 
        m_transferJobBuffer->close();
209
 
        QString htmlCode = textFromBuffer( m_transferJobBuffer );
210
 
        delete m_transferJobBuffer;
211
 
 
212
 
        /** if aborted in the mean time, clean up everything */
213
 
        if ( m_abort )
214
 
        {
215
 
            restoreConfig();
216
 
            return;
217
 
        }
218
 
 
219
 
        /** error occurred */
220
 
        if ( job->error() != 0 )
221
 
        {
222
 
            restoreConfig();
223
 
            kdDebug() << "Error in slotFinishedSavingSettings: " << job->error() << endl;
224
 
            setEndSearch( statusError );
225
 
            return;
226
 
        }
227
 
 
228
 
        /** update progress bar */
229
 
        enterNextStage();
230
 
 
231
 
        /** parse html code to get form values */
232
 
        QMap<QString, QString> keyValues = evalFormFields( htmlCode );
233
 
        /** set form values for search */
234
 
        keyValues["q"] = m_searchTerm;
235
 
        keyValues["num"] = QString::number( m_numberOfResults );
236
 
 
237
 
        /** prepare next HTTP request for actual search (buffer, signals, job) */
238
 
        KURL nextUrl( formFieldsToUrl( "http://scholar.google.com/scholar", keyValues ) );
239
 
        m_transferJobBuffer = new QBuffer();
240
 
        m_transferJobBuffer->open( IO_WriteOnly );
241
 
        KIO::TransferJob* m_transferJob = KIO::get( nextUrl, false, false );
242
 
        connect( m_transferJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ), this, SLOT( slotData( KIO::Job *, const QByteArray & ) ) );
243
 
        connect( m_transferJob, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotFinishedReceivingResultOverview( KIO::Job * ) ) );
244
 
    }
245
 
 
246
 
    void WebQueryGoogleScholar::slotFinishedReceivingResultOverview( KIO::Job *job )
247
 
    {
248
 
        /** close and delete buffer (content does not matter) */
249
 
        m_transferJobBuffer->close();
250
 
        QString htmlCode = textFromBuffer( m_transferJobBuffer );
251
 
        delete m_transferJobBuffer;
252
 
 
253
 
        /** if aborted in the mean time, clean up everything */
254
 
        if ( m_abort )
255
 
        {
256
 
            restoreConfig();
257
 
            return;
258
 
        }
259
 
 
260
 
        /** error occurred */
261
 
        if ( job->error() != 0 )
262
 
        {
263
 
            restoreConfig();
264
 
            kdDebug() << "Error in slotFinishedReceivingResultOverview: " << job->error() << endl;
265
 
            setEndSearch( statusError );
266
 
            return;
267
 
        }
268
 
 
269
 
        /** update progress bar */
270
 
        enterNextStage();
271
 
 
272
 
        /** find all links to BibTeX files in result page */
273
 
        QRegExp reBibUrl( "/scholar.bib[^ \">]+" );
274
 
        int pos = 0;
275
 
        while ( !m_aborted && ( pos = htmlCode.find( reBibUrl, pos + 1 ) ) > 0 )
276
 
        {
277
 
            /** download individual BibTeX file for each search hit */
278
 
            KURL bibUrl( "http://scholar.google.com" + reBibUrl.cap( 0 ).replace( "&amp;", "&" ) );
279
 
            BibTeX::File *tmpBibFile = downloadBibTeXFile( bibUrl );
280
 
 
281
 
            /** update progress bar */
282
 
            enterNextStage();
283
 
 
284
 
            /** parse, evaluate and store first BibTeX entry */
285
 
            if ( tmpBibFile != NULL )
286
 
            {
287
 
                BibTeX::File::ElementList::iterator it = tmpBibFile->begin();
288
 
                if ( it != tmpBibFile->end() )
289
 
                {
290
 
                    BibTeX::Entry *entry = dynamic_cast<BibTeX::Entry*>( *it );
291
 
                    if ( entry != NULL )
292
 
                        emit foundEntry( new BibTeX::Entry( entry ), false );
293
 
                }
294
 
                delete tmpBibFile;
295
 
            }
296
 
        }
297
 
 
298
 
        /** restore old cookie configuration */
299
 
        restoreConfig();
300
 
 
301
 
        /** set result status */
302
 
        if ( m_aborted )
303
 
            setEndSearch( statusAborted );
304
 
        else
305
 
            setEndSearch( statusSuccess );
306
 
    }
307
 
 
308
 
    void WebQueryGoogleScholar::readAndChangeConfig()
309
 
    {
310
 
        KConfig cfg( "kcookiejarrc" );
311
 
        cfg.setGroup( "Cookie Policy" );
312
 
        m_originalEnableCookies = cfg.readBoolEntry( "Cookies", true );
313
 
        m_originalSessionCookies = cfg.readBoolEntry( "AcceptSessionCookies", true );
314
 
        QStringList cookieSettingsList = QStringList::split( ',', cfg.readEntry( "CookieDomainAdvice", "" ) );
315
 
        m_originalCookieGlobalAdvice = cfg.readEntry( "CookieGlobalAdvice", "Accept" );
316
 
 
317
 
        for ( QStringList::Iterator it = cookieSettingsList.begin(); it != cookieSettingsList.end(); ++it )
318
 
        {
319
 
            QStringList keyValue = QStringList::split( ':', *it );
320
 
            if ( keyValue.size() == 2 )
321
 
            {
322
 
                m_originalCookieMap[keyValue[0]] = keyValue[1];
323
 
            }
324
 
        }
325
 
 
326
 
        cfg.writeEntry( "Cookies", true );
327
 
        cfg.writeEntry( "CookieGlobalAdvice", "Accept" );
328
 
        cfg.writeEntry( "AcceptSessionCookies", true );
329
 
        cookieSettingsList.clear();
330
 
        for ( QMap<QString, QString>::Iterator it = m_originalCookieMap.begin(); it != m_originalCookieMap.end(); ++it )
331
 
        {
332
 
            QString value = it.key().contains( ".google." ) ? "Accept" : it.data();
333
 
            cookieSettingsList << it.key() + ":" + value;
334
 
        }
335
 
        cfg.writeEntry( "CookieDomainAdvice", cookieSettingsList.join( "," ) );
336
 
        cfg.sync();
337
 
 
338
 
        ( void )DCOPRef( "kded", "kcookiejar" ).send( "reloadPolicy" );
339
 
    }
340
 
 
341
 
    void WebQueryGoogleScholar::restoreConfig()
342
 
    {
343
 
        KConfig cfg( "kcookiejarrc" );
344
 
        cfg.setGroup( "Cookie Policy" );
345
 
        cfg.writeEntry( "CookieGlobalAdvice", m_originalCookieGlobalAdvice );
346
 
        cfg.writeEntry( "Cookies", m_originalEnableCookies );
347
 
        cfg.writeEntry( "AcceptSessionCookies", m_originalSessionCookies );
348
 
        QStringList cookieSettingsList;
349
 
        for ( QMap<QString, QString>::Iterator it = m_originalCookieMap.begin(); it != m_originalCookieMap.end(); ++it )
350
 
            cookieSettingsList << it.key() + ":" + it.data();
351
 
        cfg.writeEntry( "CookieDomainAdvice", cookieSettingsList.join( "," ) );
352
 
        cfg.sync();
353
 
 
354
 
        if ( !m_originalEnableCookies )
355
 
            ( void )DCOPRef( "kded", "kcookiejar" ).send( "shutdown" );
356
 
        else
357
 
            ( void )DCOPRef( "kded", "kcookiejar" ).send( "reloadPolicy" );
358
 
    }
359
 
 
360
 
    QString WebQueryGoogleScholar::textFromBuffer( QBuffer *buffer )
361
 
    {
362
 
        QString htmlCode = "";
363
 
        buffer->open( IO_ReadOnly );
364
 
        QTextStream ts( buffer );
365
 
        while ( !ts.atEnd() )
366
 
            htmlCode.append( ts.readLine() );
367
 
        buffer->close();
368
 
        return htmlCode;
369
 
    }
370
 
 
371
 
    QMap <QString, QString> WebQueryGoogleScholar::evalFormFields( const QString &htmlCode )
372
 
    {
373
 
        QMap<QString, QString> keyValues;
374
 
 
375
 
        QRegExp reInput( "<input[^>]+>" );
376
 
        QRegExp reSplit( "[<>=\" ]+" );
377
 
        int pos = 0;
378
 
        while (( pos = htmlCode.find( reInput, pos + 1 ) ) > 5 )
379
 
        {
380
 
            QStringList elements = QStringList::split( reSplit, reInput.cap( 0 ) );
381
 
            bool checked = false;
382
 
            bool isCheckable = false;
383
 
            bool isSubmit = false;
384
 
            QString key = QString::null;
385
 
            QString value = QString::null;
386
 
            for ( QStringList::Iterator it = elements.begin(); it != elements.end(); ++it )
387
 
            {
388
 
                if ( *it == "name" )
389
 
                {
390
 
                    ++it; if ( it != elements.end() ) key = *it; else break;
391
 
                }
392
 
                if ( *it == "value" )
393
 
                {
394
 
                    ++it; if ( it != elements.end() ) value = *it; else
395
 
                    {
396
 
                        value = ""; break;
397
 
                    }
398
 
                }
399
 
                if ( *it == "checked" )
400
 
                    checked = true;
401
 
                if ( *it == "type" )
402
 
                {
403
 
                    ++it;
404
 
                    if ( it == elements.end() ) break;
405
 
                    isCheckable = *it == "radio" || *it == "checkbox";
406
 
                    isSubmit = *it == "submit";
407
 
                }
408
 
            }
409
 
            if (( !isCheckable || checked ) && ( !isSubmit || value == "submit" ) && value != QString::null && key != QString::null )
410
 
            {
411
 
                keyValues[key] = value;
412
 
            }
413
 
        }
414
 
 
415
 
        QRegExp reSelect( "<select name=([^ >\"]+).*</select>" );
416
 
        reSelect.setMinimal( true );
417
 
        QRegExp reOption( "<option[^>]+>" );
418
 
        int pos3 = 0;
419
 
        while (( pos3 = htmlCode.find( reSelect, pos3 + 1 ) ) > 5 )
420
 
        {
421
 
            QString key = reSelect.cap( 1 );
422
 
            QString sub = reSelect.cap( 0 );
423
 
            int pos2 = 0;
424
 
            while (( pos2 = sub.find( reOption, pos2 + 1 ) ) > 5 )
425
 
            {
426
 
                QStringList elements = QStringList::split( reSplit, reOption.cap( 0 ) );
427
 
                bool selected = false;
428
 
                QString value = QString::null;
429
 
                for ( QStringList::Iterator it = elements.begin(); it != elements.end(); ++it )
430
 
                {
431
 
                    if ( *it == "value" )
432
 
                    {
433
 
                        ++it; if ( it != elements.end() ) value = *it; else
434
 
                        {
435
 
                            value = ""; break;
436
 
                        }
437
 
                    }
438
 
                    if ( *it == "selected" )
439
 
                        selected = true;
440
 
                }
441
 
                if ( selected && value != QString::null && key != QString::null )
442
 
                {
443
 
                    keyValues[key] = value;
444
 
                }
445
 
            }
446
 
        }
447
 
 
448
 
        return keyValues;
449
 
    }
450
 
 
451
 
    QString WebQueryGoogleScholar::formFieldsToUrl( const QString &prefix, const QMap<QString, QString> &keyValues )
452
 
    {
453
 
        bool first = true;
454
 
        QString nextUrl = prefix;
455
 
        for ( QMap<QString, QString>::ConstIterator it = keyValues.begin(); it != keyValues.end(); ++it )
456
 
        {
457
 
            if ( first )
458
 
                nextUrl.append( "?" );
459
 
            else
460
 
                nextUrl.append( "&" );
461
 
            first = false;
462
 
            nextUrl.append( it.key() + "=" + it.data() );
463
 
        }
464
 
 
465
 
        return nextUrl;
466
 
    }
467
 
 
468
 
}