Skip to content
Snippets Groups Projects
Commit 8c201305 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

CodePaster: Make pastebin.ca protocol work.

Replace deprecated QHttp by QNetworkReply.
Implement listing functionality, fix fetch
encoding.
parent 2a0f7098
No related branches found
No related tags found
No related merge requests found
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include "codepasterprotocol.h" #include "codepasterprotocol.h"
#include "codepastersettings.h" #include "codepastersettings.h"
#include "cpasterplugin.h" #include "cpasterplugin.h"
#include "cgi.h"
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
...@@ -130,13 +129,13 @@ void CodePasterProtocol::paste(const QString &text, ...@@ -130,13 +129,13 @@ void CodePasterProtocol::paste(const QString &text,
return; return;
QByteArray data = "command=processcreate&submit=submit&highlight_type=0&description="; QByteArray data = "command=processcreate&submit=submit&highlight_type=0&description=";
data += CGI::encodeURL(description).toLatin1(); data += QUrl::toPercentEncoding(description);
data += "&comment="; data += "&comment=";
data += CGI::encodeURL(comment).toLatin1(); data += QUrl::toPercentEncoding(comment);
data += "&code="; data += "&code=";
data += CGI::encodeURL(fixNewLines(text)).toLatin1(); data += QUrl::toPercentEncoding(fixNewLines(text));
data += "&poster="; data += "&poster=";
data += CGI::encodeURL(username).toLatin1(); data += QUrl::toPercentEncoding(username);
m_pasteReply = httpPost(QLatin1String("http://") + hostName, data); m_pasteReply = httpPost(QLatin1String("http://") + hostName, data);
connect(m_pasteReply, SIGNAL(finished()), this, SLOT(pasteFinished())); connect(m_pasteReply, SIGNAL(finished()), this, SLOT(pasteFinished()));
......
...@@ -28,24 +28,46 @@ ...@@ -28,24 +28,46 @@
**************************************************************************/ **************************************************************************/
#include "pastebindotcaprotocol.h" #include "pastebindotcaprotocol.h"
#include "cgi.h"
#include <utils/qtcassert.h>
#include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkReply>
#include <QtCore/QXmlStreamReader>
#include <QtCore/QXmlStreamAttributes>
#include <QtCore/QStringList>
static const char urlC[] = "http://pastebin.ca/";
namespace CodePaster { namespace CodePaster {
PasteBinDotCaProtocol::PasteBinDotCaProtocol(const NetworkAccessManagerProxyPtr &nw) : PasteBinDotCaProtocol::PasteBinDotCaProtocol(const NetworkAccessManagerProxyPtr &nw) :
NetworkProtocol(nw), NetworkProtocol(nw),
m_fetchReply(0), m_fetchReply(0),
m_postId(-1) m_listReply(0),
m_pasteReply(0)
{ {
connect(&m_http, SIGNAL(requestFinished(int,bool)), }
this, SLOT(postRequestFinished(int,bool)));
unsigned PasteBinDotCaProtocol::capabilities() const
{
return ListCapability | PostDescriptionCapability;
} }
void PasteBinDotCaProtocol::fetch(const QString &id) void PasteBinDotCaProtocol::fetch(const QString &id)
{ {
QString link = QLatin1String("http://pastebin.ca/raw/"); QTC_ASSERT(!m_fetchReply, return)
link.append(id); const QString url = QLatin1String(urlC);
const QString rawPostFix = QLatin1String("raw/");
// Create link as ""http://pastebin.ca/raw/[id]"
// If we get a complete URL, just insert 'raw', else build URL.
QString link = id;
if (link.startsWith(url)) {
const int lastSlashPos = link.lastIndexOf(QLatin1Char('/'));
if (lastSlashPos != -1)
link.insert(lastSlashPos + 1, rawPostFix);
} else {
link.insert(0, rawPostFix);
link.insert(0, url);
}
m_fetchReply = httpGet(link); m_fetchReply = httpGet(link);
connect(m_fetchReply, SIGNAL(finished()), this, SLOT(fetchFinished())); connect(m_fetchReply, SIGNAL(finished()), this, SLOT(fetchFinished()));
m_fetchId = id; m_fetchId = id;
...@@ -54,36 +76,34 @@ void PasteBinDotCaProtocol::fetch(const QString &id) ...@@ -54,36 +76,34 @@ void PasteBinDotCaProtocol::fetch(const QString &id)
void PasteBinDotCaProtocol::paste(const QString &text, void PasteBinDotCaProtocol::paste(const QString &text,
ContentType /* ct */, ContentType /* ct */,
const QString &username, const QString &username,
const QString &comment, const QString & /* comment */,
const QString &description) const QString &description)
{ {
Q_UNUSED(comment); QTC_ASSERT(!m_pasteReply, return)
Q_UNUSED(description); QByteArray data = "content=";
QString data = "content="; data += QUrl::toPercentEncoding(fixNewLines(text));
data += CGI::encodeURL(fixNewLines(text));
data += "&description="; data += "&description=";
data += CGI::encodeURL(description); data += QUrl::toPercentEncoding(description);
data += "&type=1&expiry=1%20day&name="; data += "&type=1&expiry=1%20day&name=";
data += CGI::encodeURL(username); data += QUrl::toPercentEncoding(username);
QHttpRequestHeader header("POST", "/quiet-paste.php"); // fire request
header.setValue("host", "pastebin.ca" ); const QString link = QLatin1String(urlC) + QLatin1String("quiet-paste.php");
header.setContentType("application/x-www-form-urlencoded"); m_pasteReply = httpPost(link, data);
m_http.setHost("pastebin.ca", QHttp::ConnectionModeHttp); connect(m_pasteReply, SIGNAL(finished()), this, SLOT(pasteFinished()));
header.setValue("User-Agent", "CreatorPastebin");
m_postId = m_http.request(header, data.toAscii());
} }
void PasteBinDotCaProtocol::postRequestFinished(int id, bool error) void PasteBinDotCaProtocol::pasteFinished()
{ {
QString link; if (m_pasteReply->error()) {
if (id == m_postId) { qWarning("Pastebin.ca protocol error: %s", qPrintable(m_pasteReply->errorString()));
if (!error) { } else {
QByteArray data = m_http.readAll(); /// returns ""SUCCESS:[id]""
link = QString::fromLatin1("http://pastebin.ca/") + QString(data).remove("SUCCESS:"); const QByteArray data = m_pasteReply->readAll();
} else const QString link = QString::fromLatin1(urlC) + QString::fromAscii(data).remove(QLatin1String("SUCCESS:"));
link = m_http.errorString();
emit pasteDone(link); emit pasteDone(link);
} }
m_pasteReply->deleteLater();
m_pasteReply = 0;
} }
void PasteBinDotCaProtocol::fetchFinished() void PasteBinDotCaProtocol::fetchFinished()
...@@ -95,10 +115,87 @@ void PasteBinDotCaProtocol::fetchFinished() ...@@ -95,10 +115,87 @@ void PasteBinDotCaProtocol::fetchFinished()
content = m_fetchReply->errorString(); content = m_fetchReply->errorString();
} else { } else {
title = QString::fromLatin1("Pastebin.ca: %1").arg(m_fetchId); title = QString::fromLatin1("Pastebin.ca: %1").arg(m_fetchId);
content = m_fetchReply->readAll(); const QByteArray data = m_fetchReply->readAll();
content = QString::fromUtf8(data);
content.remove(QLatin1Char('\r'));
} }
m_fetchReply->deleteLater(); m_fetchReply->deleteLater();
m_fetchReply = 0; m_fetchReply = 0;
emit fetchDone(title, content, error); emit fetchDone(title, content, error);
} }
void PasteBinDotCaProtocol::list()
{
QTC_ASSERT(!m_listReply, return);
m_listReply = httpGet(QLatin1String(urlC));
connect(m_listReply, SIGNAL(finished()), this, SLOT(listFinished()));
}
/* Quick & dirty: Parse the <div>-elements with the "Recent Posts" listing
* out of the page.
\code
<div class="menutitle"><h2>Recent Posts</h2></div>
<div class="items" id="idmenurecent-collapse">
<div class='recentlink'>
<a href="/[id]" class="rjt" rel="/preview.php?id=[id]">[nameTitle]</a>
<div class='recentdetail'>[time spec]</div>
</div>
...<h2>Create a New Pastebin Post</h2>
\endcode */
static inline QStringList parseLists(QIODevice *io)
{
enum State { OutsideRecentLink, InsideRecentLink };
QStringList rc;
const QString classAttribute = QLatin1String("class");
const QString divElement = QLatin1String("div");
const QString anchorElement = QLatin1String("a");
// Start parsing at the 'recent posts' entry as the HTML above is not well-formed
// as of 8.4.2010. This will then terminate with an error.
QByteArray data = io->readAll();
const QByteArray recentPosts("<h2>Recent Posts</h2></div>");
const int recentPostsPos = data.indexOf(recentPosts);
if (recentPostsPos == -1)
return rc;
data.remove(0, recentPostsPos + recentPosts.size());
QXmlStreamReader reader(data);
State state = OutsideRecentLink;
while (!reader.atEnd()) {
switch(reader.readNext()) {
case QXmlStreamReader::StartElement:
// Inside a <div> of an entry: Anchor or description
if (state == InsideRecentLink && reader.name() == anchorElement) { // Anchor
// Strip host from link
QString link = reader.attributes().value(QLatin1String("href")).toString();
if (link.startsWith(QLatin1Char('/')))
link.remove(0, 1);
const QString nameTitle = reader.readElementText();
rc.push_back(link + QLatin1Char(' ') + nameTitle);
} else if (state == OutsideRecentLink && reader.name() == divElement) { // "<div>" state switching
if (reader.attributes().value(classAttribute) == QLatin1String("recentlink"))
state = InsideRecentLink;
} // divElement
break;
default:
break;
} // switch reader
} // while reader.atEnd()
return rc;
}
void PasteBinDotCaProtocol::listFinished()
{
const bool error = m_listReply->error();
if (error) {
qWarning("pastebin.ca list failed: %s", qPrintable(m_listReply->errorString()));
} else {
emit listDone(name(), parseLists(m_listReply));
}
m_listReply->deleteLater();
m_listReply = 0;
}
} // namespace CodePaster } // namespace CodePaster
...@@ -32,8 +32,6 @@ ...@@ -32,8 +32,6 @@
#include "protocol.h" #include "protocol.h"
#include <QtNetwork/QHttp>
namespace CodePaster { namespace CodePaster {
class PasteBinDotCaProtocol : public NetworkProtocol class PasteBinDotCaProtocol : public NetworkProtocol
{ {
...@@ -42,26 +40,27 @@ public: ...@@ -42,26 +40,27 @@ public:
explicit PasteBinDotCaProtocol(const NetworkAccessManagerProxyPtr &nw); explicit PasteBinDotCaProtocol(const NetworkAccessManagerProxyPtr &nw);
QString name() const { return QLatin1String("Pastebin.Ca"); } QString name() const { return QLatin1String("Pastebin.Ca"); }
bool hasSettings() const { return false; } virtual bool hasSettings() const { return false; }
virtual unsigned capabilities() const { return 0; } virtual unsigned capabilities() const;
virtual void fetch(const QString &id);
virtual void paste(const QString &text,
ContentType ct = Text,
const QString &username = QString(),
const QString &comment = QString(),
const QString &description = QString());
virtual void list();
void fetch(const QString &id);
void paste(const QString &text,
ContentType ct = Text,
const QString &username = QString(),
const QString &comment = QString(),
const QString &description = QString());
public slots: public slots:
void fetchFinished(); void fetchFinished();
void listFinished();
void postRequestFinished(int id, bool error); void pasteFinished();
private: private:
QNetworkReply *m_fetchReply; QNetworkReply *m_fetchReply;
QNetworkReply *m_listReply;
QNetworkReply *m_pasteReply;
QString m_fetchId; QString m_fetchId;
QHttp m_http;
int m_postId;
}; };
} // namespace CodePaster } // namespace CodePaster
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment