2
This file is part of choqoK, the KDE micro-blogging client
4
Copyright (C) 2008-2009 Mehrdad Momeny <mehrdad.momeny@gmail.com>
6
This program is free software; you can redistribute it and/or
7
modify it under the terms of the GNU General Public License as
8
published by the Free Software Foundation; either version 2 of
9
the License or (at your option) version 3 or any later version
10
accepted by the membership of KDE e.V. (or its successor approved
11
by the membership of KDE e.V.), which shall act as a proxy
12
defined in Section 14 of version 3 of the license.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, see http://www.gnu.org/licenses/
25
#include "twittersearch.h"
27
#include <KDE/KLocale>
28
#include <QDomDocument>
29
#include <kio/jobclasses.h>
32
#include <kio/netaccess.h>
37
TwitterSearch::TwitterSearch( Account* account, const QString searchUrl, QObject *parent ) :
38
Search(account, searchUrl, parent)
41
mSearchTypes[CustomSearch].first = i18n( "Custom Search" );
42
mSearchTypes[CustomSearch].second = true;
44
mSearchTypes[ToUser].first = i18n( "Tweets To This User" );
45
mSearchTypes[ToUser].second = true;
47
mSearchTypes[FromUser].first = i18n( "Tweets From This User" );
48
mSearchTypes[FromUser].second = true;
50
mSearchTypes[ReferenceUser].first = i18n( "Tweets Including This User's Name" );
51
mSearchTypes[ReferenceUser].second = true;
53
mSearchTypes[ReferenceHashtag].first = i18n( "Tweets Including This Hashtag" );
54
mSearchTypes[ReferenceHashtag].second = true;
57
TwitterSearch::~TwitterSearch()
62
KUrl TwitterSearch::buildUrl( QString query, int option, uint sinceStatusId, uint count, uint page )
65
QString baseUrl = "http://search.twitter.com/search.atom?";
67
baseUrl += "since_id=" + QString::number( sinceStatusId ) + '&';
68
if( count && count <= 100 )
69
baseUrl += "rpp=" + QString::number( count ) + '&';
70
baseUrl += "page=" + QString::number( page ) + '&';
73
QString formattedQuery;
76
formattedQuery = query;
79
formattedQuery = "to:" + query;
82
formattedQuery = "from:" + query;
85
formattedQuery = '@' + query;
87
case ReferenceHashtag:
88
formattedQuery = "%23" + query;
91
formattedQuery = query;
96
url.setUrl( baseUrl + formattedQuery );
101
void TwitterSearch::requestSearchResults( QString query, int option, uint sinceStatusId, uint count, uint page )
105
KUrl url = buildUrl( query, option, sinceStatusId, count, page );
107
KIO::StoredTransferJob *job = KIO::storedGet( url, KIO::Reload, KIO::HideProgressInfo );
109
kDebug() << "Cannot create a http GET request!";
110
emit error( i18n( "Unable to fetch search results." ) );
114
connect( job, SIGNAL( result( KJob* ) ), this, SLOT( searchResultsReturned( KJob* ) ) );
118
void TwitterSearch::searchResultsReturned( KJob* job )
122
kDebug() << "job is a null pointer";
123
emit error( i18n( "Unable to fetch search results." ) );
128
kError() << "Error: " << job->errorString();
129
emit error( i18n( "Unable to fetch search results. Error: %1", job->errorString() ) );
132
KIO::StoredTransferJob *jj = qobject_cast<KIO::StoredTransferJob *>( job );
133
QList<Status>* statusList = parseAtom( jj->data() );
135
emit searchResultsReceived( *statusList );
138
QList<Status>* TwitterSearch::parseAtom( const QByteArray &buffer )
141
QDomDocument document;
142
QList<Status> *statusList = new QList<Status>;
144
document.setContent( buffer );
146
QDomElement root = document.documentElement();
148
if ( root.tagName() != "feed" ) {
149
kDebug() << "There is no feed element in Atom feed " << buffer.data();
153
QDomNode node = root.firstChild();
155
while ( !node.isNull() ) {
156
if ( node.toElement().tagName() != "entry" ) {
157
node = node.nextSibling();
161
QDomNode entryNode = node.firstChild();
163
status.isDMessage = false;
165
while ( !entryNode.isNull() ) {
166
if ( entryNode.toElement().tagName() == "id" ) {
167
// Fomatting example: "tag:search.twitter.com,2005:1235016836"
169
sscanf( qPrintable( entryNode.toElement().text() ),
170
"tag:search.twitter.com,%*d:%d", &id);
171
status.statusId = id;
172
} else if ( entryNode.toElement().tagName() == "published" ) {
173
// Formatting example: "2009-02-21T19:42:39Z"
174
// Need to extract date in similar fashion to dateFromString
175
int year, month, day, hour, minute, second;
176
sscanf( qPrintable( entryNode.toElement().text() ),
177
"%d-%d-%dT%d:%d:%d%*s", &year, &month, &day, &hour, &minute, &second);
178
QDateTime recognized( QDate( year, month, day), QTime( hour, minute, second ) );
179
recognized.setTimeSpec( Qt::UTC );
180
status.creationDateTime = recognized;
181
} else if ( entryNode.toElement().tagName() == "title" ) {
182
status.content = entryNode.toElement().text();
183
} else if ( entryNode.toElement().tagName() == "twitter:source" ) {
184
status.source = entryNode.toElement().text();
185
} else if ( entryNode.toElement().tagName() == "link" &&
186
entryNode.toElement().attributeNode( "rel" ).value() == "image") {
188
QDomAttr imageAttr = entryNode.toElement().attributeNode( "href" );
189
status.user.profileImageUrl = imageAttr.value();
191
} else if ( entryNode.toElement().tagName() == "author") {
193
QDomNode userNode = entryNode.firstChild();
194
while ( !userNode.isNull() )
196
if ( userNode.toElement().tagName() == "name" )
198
QString fullName = userNode.toElement().text();
199
int bracketPos = fullName.indexOf( " ", 0 );
201
QString screenName = fullName.left( bracketPos );
202
QString name = fullName.right ( fullName.size() - bracketPos - 2 );
205
status.user.name = name;
206
status.user.screenName = screenName;
208
userNode = userNode.nextSibling();
213
entryNode = entryNode.nextSibling();
215
status.isFavorited = false;
216
status.isTruncated = false;
217
status.replyToStatusId = 0;
218
statusList->insert( 0, status );
219
node = node.nextSibling();