View Single Post
helex's Avatar
Posts: 543 | Thanked: 802 times | Joined on Apr 2010 @ Germany
#1
Hi!

I would like to create a application to store and manage my N900 / N9(50) bookmarks in "the cloud" - to be exact: at google bookmarks!

Sadly there is no API and I've already searched for a good alterative, without success.

I would like to give google a second try. Because of the missing API and hence the missing OAuth I have to act like a webbrowser and after faking a logging in provide the stored cookies to let google believe I'm logged in into their website correctly.

I looked into the code from gmarks for android to have a working example how to do it:

Here is the login part - Have a look here if you like to see the whole source: BookmarksQueryService.java (Link to github)
Code:
public void login( String user, String passwd ) {
		try {
			List<NameValuePair> queryParams = new ArrayList<NameValuePair>();
			queryParams.add( new BasicNameValuePair("service", "bookmarks") );
			queryParams.add( new BasicNameValuePair("passive", "true") );
			queryParams.add( new BasicNameValuePair("nui", "1") );
			queryParams.add( new BasicNameValuePair("continue", "https://www.google.com/bookmarks/l") );
			queryParams.add( new BasicNameValuePair("followup", "https://www.google.com/bookmarks/l") );
			HttpGet get = new HttpGet( "https://www.google.com/accounts/ServiceLogin?" + 
					URLEncodedUtils.format(queryParams, "UTF-8") );
			HttpResponse resp = http.execute(get, this.ctx);
			// this just gets the cookie but I can ignore it...
			
			if ( resp.getStatusLine().getStatusCode() != 200 )
				throw new RuntimeException( "Invalid status code for ServiceLogin " +
						resp.getStatusLine().getStatusCode() );
			resp.getEntity().consumeContent();
			
			String galx = null;
			for ( Cookie c : cookieStore.getCookies() )
				if ( c.getName().equals( "GALX" ) ) galx = c.getValue(); 
			
			if ( galx == null ) throw new RuntimeException( "GALX cookie not found!" );
			
			HttpPost loginMethod = new HttpPost("https://www.google.com/accounts/ServiceLoginAuth");
			// post parameters:
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			nvps.add(new BasicNameValuePair("Email", user));
			nvps.add(new BasicNameValuePair("Passwd", passwd));
			nvps.add(new BasicNameValuePair("PersistentCookie", "yes"));
			nvps.add(new BasicNameValuePair("GALX", galx));			
			nvps.add(new BasicNameValuePair("continue", "https://www.google.com/bookmarks/l"));
			loginMethod.setEntity(new UrlEncodedFormEntity(nvps));
			resp = http.execute( loginMethod, this.ctx );
			
			if ( resp.getStatusLine().getStatusCode() != 302 )
				throw new RuntimeException( "Unexpected status code for ServiceLoginAuth" +
						resp.getStatusLine().getStatusCode() );
			resp.getEntity().consumeContent();
			
			Header checkCookieLocation = resp.getFirstHeader("Location");
			if ( checkCookieLocation == null ) 
				throw new RuntimeException("Missing checkCookie redirect location!");

			// CheckCookie:
			get = new HttpGet( checkCookieLocation.getValue() );
			resp = http.execute( get, this.ctx );
			
			if ( resp.getStatusLine().getStatusCode() != 302 )
				throw new RuntimeException( "Unexpected status code for CheckCookie" +
						resp.getStatusLine().getStatusCode() );
			resp.getEntity().consumeContent();
			
			this.authInitialized = true;
			Log.i(TAG, "Final redirect location: " + resp.getFirstHeader("Location").getValue() );
			Log.i(TAG, "Logged in.");
		}
		catch ( IOException ex ) {
			Log.e(TAG, "Error during login", ex );
			throw new RuntimeException("IOException during login", ex);
		}
	}



I tried now to rebuild the same mechanism in Qt: (I shortened the code a little bit and removed the unessential parts)

.h
Code:
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QUrl>
#include <QHttp>
#include <QNetworkCookie>
#include <QNetworkCookieJar>

[...]

private:
    QString galx;
    QNetworkAccessManager* nManLoginStep_1;
    QNetworkAccessManager* nManLoginStep_2;
    QNetworkAccessManager* nManLoginStep_3;

    QNetworkCookieJar* CookieJar;

init:
Code:
 galx = "";
    nManLoginStep_1 = new QNetworkAccessManager(this);
    nManLoginStep_2 = new QNetworkAccessManager(this);
    nManLoginStep_3 = new QNetworkAccessManager(this);

    CookieJar = new QNetworkCookieJar(this);

    nManLoginStep_1->setCookieJar(CookieJar);
    nManLoginStep_2->setCookieJar(CookieJar);
    nManLoginStep_3->setCookieJar(CookieJar);

  connect(nManLoginStep_1, SIGNAL(finished(QNetworkReply*)), this, SLOT(LoginStep_1_cookie(QNetworkReply*)));
    connect(nManLoginStep_2, SIGNAL(finished(QNetworkReply*)), this, SLOT(LoginStep_2_ServiceLoginAuth(QNetworkReply*)));
    connect(nManLoginStep_3, SIGNAL(finished(QNetworkReply*)), this, SLOT(LoginStep_3_check(QNetworkReply*)));
The essence of the problem:
Code:
void Application::Login()
{
    QUrl url("https://accounts.google.com/ServiceLogin");

    url.addQueryItem("service","bookmarks");
    url.addQueryItem("passive", "true");
    url.addQueryItem("nui", "1");
    url.addQueryItem("continue", "https://www.google.com/bookmarks/l");
    url.addQueryItem("followup", "https://www.google.com/bookmarks/l");

    nManLoginStep_1->get(QNetworkRequest(url));
}

void Application::LoginStep_1_cookie(QNetworkReply *r)
{
    QByteArray data = r->readAll();
    QString str(data);   //here I'm able to check the content of the website

    QUrl url1("https://accounts.google.com/ServiceLogin");
    QList<QNetworkCookie>  cookies = CookieJar->cookiesForUrl(url1);
   foreach (QNetworkCookie c, cookies)
   {
       QByteArray a(c.name());
       QString s(a);
              if (s.toStdString() == "GALX" ) {galx = c.value();}
}
    if (galx.trimmed() == "")
    {
    std::cout << "ERROR: No GALX cookie found!\n";
    }

    //--------------------------------------------------------------


    QUrl url("https://www.google.com/accounts/ServiceLoginAuth");
    QUrl postData;

    postData.addQueryItem("Email","EMAIL@EMAIL.COM");
    postData.addQueryItem("Passwd", "PASSWORD");
    postData.addQueryItem("PersistentCookie", "yes");
    postData.addQueryItem("GALX", galx);
    postData.addQueryItem("continue", "https://www.google.com/bookmarks/l");
    QNetworkRequest request(url);
    nManLoginStep_2->post(request, postData.encodedQuery() );

}

void Application::LoginStep_2_ServiceLoginAuth(QNetworkReply *r)
{
    QByteArray data = r->readAll();
    QString str(data);   
    //here I get a website with the error: "the cookies in your webbrowser are deactivated
}
Even before the verification I get a website with the error: "the cookies in your webbrowser are deactivated, please activate" - if I ignore this and proceed I get a "The document has moved Temporarily" website without layout and a redirectionlink to a website where I'm able to manage my google account data.


My code seems to doesn't provide the previously generated cookie to the website. I don't understand why. It is perhaps only a small mistake, a flag not set? The cookies are definitively generated and stored in the CookieJar.

Has anybody here some kind of experience with QNetworkAccessManager and cookies?
Please help! Any kind of hint is very welcome.
__________________
I was a Qt Ambassador!

Please DONATE if you like my work!
It's the best way to motivate me to create more stuff for your Device.