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, "tag:search.twitter.com,[0-9]+:([0-9]+)", searchUrl, parent)
41
mSearchTypes[CustomSearch].first = i18n( "Custom Search" );
42
mSearchTypes[CustomSearch].second = true;
44
mSearchTypes[ToUser].first = i18nc( "Tweets are Twitter posts", "Tweets To This User" );
45
mSearchTypes[ToUser].second = true;
47
mSearchTypes[FromUser].first = i18nc( "Tweets are Twitter posts", "Tweets From This User" );
48
mSearchTypes[FromUser].second = true;
50
mSearchTypes[ReferenceUser].first = i18nc( "Tweets are Twitter posts", "Tweets Including This User's Name" );
51
mSearchTypes[ReferenceUser].second = true;
53
mSearchTypes[ReferenceHashtag].first = i18nc( "Tweets are Twitter posts", "Tweets Including This Hashtag" );
54
mSearchTypes[ReferenceHashtag].second = true;
57
TwitterSearch::~TwitterSearch()
62
KUrl TwitterSearch::buildUrl( QString query, int option, qulonglong sinceStatusId, qulonglong count, qulonglong page )
65
QString formattedQuery;
68
formattedQuery = query;
71
formattedQuery = "to:" + query;
74
formattedQuery = "from:" + query;
77
formattedQuery = '@' + query;
79
case ReferenceHashtag:
80
formattedQuery = "#" + query;
83
formattedQuery = query;
86
KUrl url( "http://search.twitter.com/search.atom" );
87
url.addQueryItem("q", formattedQuery);
89
url.addQueryItem( "since_id", QString::number( sinceStatusId ) );
90
if( count && count <= 100 )
91
url.addQueryItem( "rpp", QString::number( count ) );
92
url.addQueryItem( "page", QString::number( page ) );
97
void TwitterSearch::requestSearchResults( QString query, int option, qulonglong sinceStatusId, qulonglong count, qulonglong page )
101
KUrl url = buildUrl( query, option, sinceStatusId, count, page );
103
KIO::StoredTransferJob *job = KIO::storedGet( url, KIO::Reload, KIO::HideProgressInfo );
105
kDebug() << "Cannot create a http GET request!";
106
emit error( i18n( "Unable to fetch search results." ) );
110
connect( job, SIGNAL( result( KJob* ) ), this, SLOT( searchResultsReturned( KJob* ) ) );
114
void TwitterSearch::searchResultsReturned( KJob* job )
118
kDebug() << "job is a null pointer";
119
emit error( i18n( "Unable to fetch search results." ) );
124
kError() << "Error: " << job->errorString();
125
emit error( i18n( "Unable to fetch search results: %1", job->errorString() ) );
128
KIO::StoredTransferJob *jj = qobject_cast<KIO::StoredTransferJob *>( job );
129
QList<Status>* statusList = parseAtom( jj->data() );
131
emit searchResultsReceived( *statusList );
134
QList<Status>* TwitterSearch::parseAtom( const QByteArray &buffer )
137
QDomDocument document;
138
QList<Status> *statusList = new QList<Status>;
140
document.setContent( buffer );
142
QDomElement root = document.documentElement();
144
if ( root.tagName() != "feed" ) {
145
kDebug() << "There is no feed element in Atom feed " << buffer.data();
149
QDomNode node = root.firstChild();
151
while ( !node.isNull() ) {
152
if ( node.toElement().tagName() != "entry" ) {
153
node = node.nextSibling();
157
QDomNode entryNode = node.firstChild();
159
status.isDMessage = false;
161
while ( !entryNode.isNull() ) {
162
QDomElement elm = entryNode.toElement();
163
if ( elm.tagName() == "id" ) {
164
// Fomatting example: "tag:search.twitter.com,2005:1235016836"
166
if(m_rId.exactMatch(elm.text())) {
167
id = m_rId.cap(1).toULongLong();
169
/* sscanf( qPrintable( elm.text() ),
170
"tag:search.twitter.com,%*d:%d", &id);*/
171
status.statusId = id;
172
} else if ( elm.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( elm.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 ( elm.tagName() == "title" ) {
182
status.content = elm.text();
183
} else if ( elm.tagName() == "twitter:source" ) {
184
status.source = elm.text();
185
} else if ( elm.tagName() == "link" &&
186
elm.attributeNode( "rel" ).value() == "image") {
187
QDomAttr imageAttr = elm.attributeNode( "href" );
188
status.user.profileImageUrl = imageAttr.value();
189
} else if ( elm.tagName() == "author") {
190
QDomNode userNode = entryNode.firstChild();
191
while ( !userNode.isNull() )
193
if ( userNode.toElement().tagName() == "name" )
195
QString fullName = userNode.toElement().text();
196
int bracketPos = fullName.indexOf( " ", 0 );
198
QString screenName = fullName.left( bracketPos );
199
QString name = fullName.right ( fullName.size() - bracketPos - 2 );
202
status.user.name = name;
203
status.user.screenName = screenName;
205
userNode = userNode.nextSibling();
208
entryNode = entryNode.nextSibling();
210
status.isFavorited = false;
211
status.isTruncated = false;
212
status.replyToStatusId = 0;
213
statusList->insert( 0, status );
214
node = node.nextSibling();