/* ============================================================ * * This file is a part of kipi-plugins project * http://www.kipi-plugins.org * * Date : 2005-07-07 * Description : a kipi plugin to export images to Flickr web service * * Copyright (C) 2005-2008 by Vardhman Jain * Copyright (C) 2008 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ // C++ includes. #include #include #include #include // TQt includes. #include #include #include #include #include #include #include #include #include #include #include // KDE includes. #include #include #include #include #include #include #include // LibKExiv2 includes. #include // LibKDcraw includes. #include #include #if KDCRAW_VERSION < 0x000106 #include #endif // Local includes. #include "pluginsversion.h" #include "mpform.h" #include "flickritem.h" #include "flickrwindow.h" #include "flickrtalker.h" #include "flickrtalker.moc" namespace KIPIFlickrExportPlugin { FlickrTalker::FlickrTalker(TQWidget* parent) { m_parent = parent; m_job = 0; m_apikey = "49d585bafa0758cb5c58ab67198bf632"; m_secret = "34b39925e6273ffd"; connect(this, TQT_SIGNAL(signalAuthenticate()), this, TQT_SLOT(slotAuthenticate())); } FlickrTalker::~FlickrTalker() { if (m_job) m_job->kill(); } /** Compute MD5 signature using url queries keys and values following Flickr notice: http://www.flickr.com/services/api/auth.spec.html */ TQString FlickrTalker::getApiSig(const TQString& secret, const KURL& url) { TQMap queries = url.queryItems(); TQString compressed(secret); // NOTE: iterator TQMap iterator will sort alphabetically items based on key values. for (TQMap::iterator it = queries.begin() ; it != queries.end(); ++it) { compressed.append(it.key()); compressed.append(it.data()); } KMD5 context(compressed.utf8()); return context.hexDigest().data(); } /**get the Api sig and send it to the server server should return a frob. */ void FlickrTalker::getFrob() { if (m_job) { m_job->kill(); m_job = 0; } KURL url("http://www.flickr.com/services/rest/"); url.addQueryItem("method", "flickr.auth.getFrob"); url.addQueryItem("api_key", m_apikey); TQString md5 = getApiSig(m_secret, url); url.addQueryItem("api_sig", md5); kdDebug() << "Get frob url: " << url << endl; TQByteArray tmp; TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false); job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded"); connect(job, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)), this, TQT_SLOT(data(TDEIO::Job*, const TQByteArray&))); connect(job, TQT_SIGNAL(result(TDEIO::Job *)), this, TQT_SLOT(slotResult(TDEIO::Job *))); m_state = FE_GETFROB; m_authProgressDlg->setLabelText(i18n("Getting the Frob")); m_authProgressDlg->setProgress(1, 4); m_job = job; m_buffer.resize(0); emit signalBusy(true); } void FlickrTalker::checkToken(const TQString& token) { if (m_job) { m_job->kill(); m_job = 0; } KURL url("http://www.flickr.com/services/rest/"); url.addQueryItem("method", "flickr.auth.checkToken"); url.addQueryItem("api_key", m_apikey); url.addQueryItem("auth_token", token); TQString md5 = getApiSig(m_secret, url); url.addQueryItem("api_sig", md5); kdDebug() << "Check token url: " << url << endl; TQByteArray tmp; TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false); job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded"); connect(job, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)), this, TQT_SLOT(data(TDEIO::Job*, const TQByteArray&))); connect(job, TQT_SIGNAL(result(TDEIO::Job *)), this, TQT_SLOT(slotResult(TDEIO::Job *))); m_state = FE_CHECKTOKEN; m_authProgressDlg->setLabelText(i18n("Checking if previous token is still valid")); m_authProgressDlg->setProgress(1, 4); m_job = job; m_buffer.resize(0); emit signalBusy( true ); } void FlickrTalker::slotAuthenticate() { if (m_job) { m_job->kill(); m_job = 0; } KURL url("http://www.flickr.com/services/auth/"); url.addQueryItem("api_key", m_apikey); url.addQueryItem("frob", m_frob); url.addQueryItem("perms", "write"); TQString md5 = getApiSig(m_secret, url); url.addQueryItem("api_sig", md5); kdDebug() << "Authenticate url: " << url << endl; TDEApplication::kApplication()->invokeBrowser(url.url()); int valueOk = KMessageBox::questionYesNo(TQT_TQWIDGET(kapp->activeWindow()), i18n("Please Follow through the instructions in the browser window and " "return back to press ok if you are authenticated or press No"), i18n("Flickr Service Web Authorization")); if( valueOk == KMessageBox::Yes) { getToken(); m_authProgressDlg->setLabelText(i18n("Authenticating the User on web")); m_authProgressDlg->setProgress(2, 4); emit signalBusy(false); } else { kdDebug() << "User didn't proceed with getToken Authorization, cannot proceed further, aborting" << endl; cancel(); } } void FlickrTalker::getToken() { if (m_job) { m_job->kill(); m_job = 0; } KURL url("http://www.flickr.com/services/rest/"); url.addQueryItem("api_key", m_apikey); url.addQueryItem("method", "flickr.auth.getToken"); url.addQueryItem("frob", m_frob); TQString md5 = getApiSig(m_secret, url); url.addQueryItem("api_sig", md5); kdDebug() << "Get token url: " << url << endl; TQByteArray tmp; TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false); job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded"); connect(job, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)), this, TQT_SLOT(data(TDEIO::Job*, const TQByteArray&))); connect(job, TQT_SIGNAL(result(TDEIO::Job *)), this, TQT_SLOT(slotResult(TDEIO::Job *))); m_state = FE_GETTOKEN; m_job = job; m_buffer.resize(0); emit signalBusy(true); m_authProgressDlg->setLabelText(i18n("Getting the Token from the server")); m_authProgressDlg->setProgress(3, 4); } void FlickrTalker::listPhotoSets() { KURL url("http://www.flickr.com/services/rest/"); url.addQueryItem("api_key", m_apikey); url.addQueryItem("method", "flickr.photosets.getList"); url.addQueryItem("user_id", m_userId); TQString md5 = getApiSig(m_secret, url); url.addQueryItem("api_sig", md5); kdDebug() << "List photo sets url: " << url << endl; TQByteArray tmp; TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false); job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded" ); connect(job, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)), this, TQT_SLOT(data(TDEIO::Job*, const TQByteArray&))); connect(job, TQT_SIGNAL(result(TDEIO::Job *)), this, TQT_SLOT(slotResult(TDEIO::Job *))); m_state = FE_LISTPHOTOSETS; m_job = job; m_buffer.resize(0); emit signalBusy(true); } void FlickrTalker::getPhotoProperty(const TQString& method, const TQStringList& argList) { if (m_job) { m_job->kill(); m_job = 0; } KURL url("http://www.flickr.com/services/rest/"); url.addQueryItem("api_key", m_apikey); url.addQueryItem("method", method); url.addQueryItem("frob", m_frob); for (TQStringList::const_iterator it = argList.begin(); it != argList.end(); ++it) { TQStringList str = TQStringList::split("=", (*it)); url.addQueryItem(str[0], str[1]); } TQString md5 = getApiSig(m_secret, url); url.addQueryItem("api_sig", md5); kdDebug() << "Get photo property url: " << url << endl; TQByteArray tmp; TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false); job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded" ); connect(job, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)), this, TQT_SLOT(data(TDEIO::Job*, const TQByteArray&))); connect(job, TQT_SIGNAL(result(TDEIO::Job *)), this, TQT_SLOT(slotResult(TDEIO::Job *))); m_state = FE_GETPHOTOPROPERTY; m_job = job; m_buffer.resize(0); emit signalBusy( true ); // m_authProgressDlg->setLabelText("Getting the Token from the server"); // m_authProgressDlg->setProgress(3,4); } void FlickrTalker::listPhotos(const TQString& /*albumName*/) { // TODO } void FlickrTalker::createAlbum(const TQString& /*parentAlbumName*/, const TQString& /*albumName*/, const TQString& /*albumTitle*/, const TQString& /*albumCaption*/) { //TODO: The equivalent for Album is sets. } bool FlickrTalker::addPhoto(const TQString& photoPath, const FPhotoInfo& info, bool rescale, int maxDim, int imageQuality) { if (m_job) { m_job->kill(); m_job = 0; } KURL url("http://www.flickr.com/services/upload/"); TQString path = photoPath; MPForm form; form.addPair("auth_token", m_token); url.addQueryItem("auth_token", m_token); form.addPair("api_key", m_apikey); url.addQueryItem("api_key", m_apikey); TQString ispublic = (info.is_public == 1) ? "1" : "0"; form.addPair("is_public", ispublic); url.addQueryItem("is_public", ispublic); TQString isfamily = (info.is_family == 1) ? "1" : "0"; form.addPair("is_family", isfamily); url.addQueryItem("is_family", isfamily); TQString isfriend = (info.is_friend == 1) ? "1" : "0"; form.addPair("is_friend", isfriend); url.addQueryItem("is_friend", isfriend); TQString tags = info.tags.join(" "); if(tags.length() > 0) { form.addPair("tags", tags); url.addQueryItem("tags", tags); } if (!info.title.isEmpty()) { form.addPair("title", info.title); url.addQueryItem("title", info.title); } if (!info.description.isEmpty()) { form.addPair("description", info.description); url.addQueryItem("description", info.description); } TQString md5 = getApiSig(m_secret, url); form.addPair("api_sig", md5); url.addQueryItem("api_sig", md5); TQImage image; // Check if RAW file. #if KDCRAW_VERSION < 0x000106 TQString rawFilesExt(KDcrawIface::DcrawBinary::instance()->rawFiles()); #else TQString rawFilesExt(KDcrawIface::KDcraw::rawFiles()); #endif TQFileInfo fileInfo(photoPath); if (rawFilesExt.upper().contains(fileInfo.extension(false).upper())) KDcrawIface::KDcraw::loadDcrawPreview(image, photoPath); else image.load(photoPath); kdDebug() << "Add photo query: " << url << endl; if (!image.isNull()) { path = locateLocal("tmp", TQFileInfo(photoPath).baseName().stripWhiteSpace() + ".jpg"); if (rescale && (image.width() > maxDim || image.height() > maxDim)) image = image.smoothScale(maxDim, maxDim, TQ_ScaleMin); image.save(path, "JPEG", imageQuality); // Restore all metadata. KExiv2Iface::KExiv2 exiv2Iface; if (exiv2Iface.load(photoPath)) { exiv2Iface.setImageDimensions(image.size()); // NOTE: see B.K.O #153207: Flickr use IPTC keywords to create Tags in web interface // As IPTC do not support UTF-8, we need to remove it. exiv2Iface.removeIptcTag("Iptc.Application2.Keywords", false); exiv2Iface.setImageProgramId(TQString("Kipi-plugins"), TQString(kipiplugins_version)); exiv2Iface.save(path); } else { kdWarning(51000) << "(flickrExport::Image doesn't have metdata)" << endl; } kdDebug() << "Resizing and saving to temp file: " << path << endl; } if (!form.addFile("photo", path)) return false; form.finish(); TDEIO::TransferJob* job = TDEIO::http_post(url, form.formData(), false); job->addMetaData("content-type", form.contentType()); connect(job, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)), this, TQT_SLOT(data(TDEIO::Job*, const TQByteArray&))); connect(job, TQT_SIGNAL(result(TDEIO::Job *)), this, TQT_SLOT(slotResult(TDEIO::Job *))); m_state = FE_ADDPHOTO; m_job = job; m_buffer.resize(0); emit signalBusy(true); return true; } TQString FlickrTalker::getUserName() { return m_username; } TQString FlickrTalker::getUserId() { return m_userId; } void FlickrTalker::cancel() { if (m_job) { m_job->kill(); m_job = 0; } if (m_authProgressDlg && !m_authProgressDlg->isHidden()) m_authProgressDlg->hide(); } void FlickrTalker::data(TDEIO::Job*, const TQByteArray& data) { if (data.isEmpty()) return; int oldSize = m_buffer.size(); m_buffer.resize(m_buffer.size() + data.size()); memcpy(m_buffer.data()+oldSize, data.data(), data.size()); } void FlickrTalker::slotError(const TQString& error) { TQString transError; int errorNo = atoi(error.latin1()); switch (errorNo) { case 2: transError = i18n("No photo specified"); break; case 3: transError = i18n("General upload failure"); break; case 4: transError = i18n("Filesize was zero"); break; case 5: transError = i18n("Filetype was not recognised"); break; case 6: transError = i18n("User exceeded upload limit"); break; case 96: transError = i18n("Invalid signature"); break; case 97: transError = i18n("Missing signature"); break; case 98: transError = i18n("Login Failed / Invalid auth token"); break; case 100: transError = i18n("Invalid API Key"); break; case 105: transError = i18n("Service currently unavailable"); break; case 108: transError = i18n("Invalid Frob"); break; case 111: transError = i18n("Format \"xxx\" not found"); break; case 112: transError = i18n("Method \"xxx\" not found"); break; case 114: transError = i18n("Invalid SOAP envelope"); break; case 115: transError = i18n("Invalid XML-RPC Method Call"); break; case 116: transError = i18n("The POST method is now required for all setters"); break; default: transError = i18n("Unknown error"); break; }; KMessageBox::error(TQT_TQWIDGET(kapp->activeWindow()), i18n("Error Occured: %1\n We can not proceed further").arg(transError)); // kdDebug() << "Not handling the error now will see it later" << endl; } void FlickrTalker::slotResult(TDEIO::Job *job) { m_job = 0; emit signalBusy(false); if (job->error()) { if (m_state == FE_ADDPHOTO) emit signalAddPhotoFailed( job->errorString()); else job->showErrorDialog(m_parent); return; } switch(m_state) { case(FE_LOGIN): //parseResponseLogin(m_buffer); break; case(FE_LISTPHOTOSETS): parseResponseListPhotoSets(m_buffer); break; case(FE_GETFROB): parseResponseGetFrob(m_buffer); break; case(FE_GETTOKEN): parseResponseGetToken(m_buffer); break; case(FE_CHECKTOKEN): parseResponseCheckToken(m_buffer); break; case(FE_GETAUTHORIZED): //parseResponseGetToken(m_buffer); break; case(FE_LISTPHOTOS): parseResponseListPhotos(m_buffer); break; case(FE_GETPHOTOPROPERTY): parseResponsePhotoProperty(m_buffer); break; case(FE_ADDPHOTO): parseResponseAddPhoto(m_buffer); break; } /* if (m_state == FE_LOGIN && m_loggedIn) { // listAlbums(); }*/ } void FlickrTalker::parseResponseGetFrob(const TQByteArray& data) { bool success = false; TQString errorString; TQDomDocument doc("mydocument"); if (!doc.setContent(data)) { return; } TQDomElement docElem = doc.documentElement(); TQDomNode node = docElem.firstChild(); while(!node.isNull()) { if (node.isElement() && node.nodeName() == "frob") { TQDomElement e = node.toElement(); // try to convert the node to an element. kdDebug() << "Frob is" << e.text() << endl; m_frob = e.text(); // this is what is obtained from data. success = true; } if (node.isElement() && node.nodeName() == "err") { kdDebug() << "Checking Error in response" << endl; errorString = node.toElement().attribute("code"); kdDebug() << "Error code=" << errorString << endl; kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl; } node = node.nextSibling(); } kdDebug() << "GetFrob finished" << endl; m_authProgressDlg->setProgress(2, 4); m_state = FE_GETAUTHORIZED; if(success) emit signalAuthenticate(); else emit signalError(errorString); } void FlickrTalker::parseResponseCheckToken(const TQByteArray& data) { bool success = false; TQString errorString; TQString username; TQString transReturn; TQDomDocument doc("checktoken"); if (!doc.setContent(data)) { return; } TQDomElement docElem = doc.documentElement(); TQDomNode node = docElem.firstChild(); TQDomElement e; while(!node.isNull()) { if (node.isElement() && node.nodeName() == "auth") { e = node.toElement(); // try to convert the node to an element. TQDomNode details = e.firstChild(); while(!details.isNull()) { if(details.isElement()) { e = details.toElement(); if(details.nodeName() == "token") { kdDebug() << "Token=" << e.text() << endl; m_token = e.text();//this is what is obtained from data. } if(details.nodeName() == "perms") { kdDebug() << "Perms=" << e.text() << endl; TQString perms = e.text();//this is what is obtained from data. if(perms == "write") transReturn = i18n("As in the persmission to", "write"); else if(perms == "read") transReturn = i18n("As in the permission to", "read"); else if(perms == "delete") transReturn = i18n("As in the permission to", "delete"); } if(details.nodeName() == "user") { kdDebug() << "nsid=" << e.attribute("nsid") << endl; m_userId = e.attribute("nsid"); username = e.attribute("username"); m_username = username; kdDebug() << "username=" << e.attribute("username") << endl; kdDebug() << "fullname=" << e.attribute("fullname") << endl; } } details = details.nextSibling(); } m_authProgressDlg->hide(); emit signalTokenObtained(m_token); success = true; } if (node.isElement() && node.nodeName() == "err") { kdDebug() << "Checking Error in response" << endl; errorString = node.toElement().attribute("code"); kdDebug() << "Error code=" << errorString << endl; kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl; int valueOk = KMessageBox::questionYesNo(TQT_TQWIDGET(kapp->activeWindow()), i18n("Your token is invalid. Would you like to " "get a new token to proceed ?\n")); if(valueOk == KMessageBox::Yes) { getFrob(); return; } else { m_authProgressDlg->hide(); //will popup the result for the checktoken failure below } } node = node.nextSibling(); } if(!success) emit signalError(errorString); kdDebug() << "CheckToken finished" << endl; } void FlickrTalker::parseResponseGetToken(const TQByteArray& data) { bool success = false; TQString errorString; TQDomDocument doc("gettoken"); if (!doc.setContent( data )) return; TQDomElement docElem = doc.documentElement(); TQDomNode node = docElem.firstChild(); TQDomElement e; while(!node.isNull()) { if (node.isElement() && node.nodeName() == "auth") { e = node.toElement(); // try to convert the node to an element. TQDomNode details = e.firstChild(); while(!details.isNull()) { if(details.isElement()) { e = details.toElement(); if(details.nodeName() == "token") { kdDebug() << "Token=" << e.text() << endl; m_token = e.text(); //this is what is obtained from data. } if(details.nodeName() == "perms") { kdDebug() << "Perms=" << e.text() << endl; } if(details.nodeName() == "user") { kdDebug() << "nsid=" << e.attribute("nsid") << endl; kdDebug() << "username=" << e.attribute("username") << endl; kdDebug() << "fullname=" << e.attribute("fullname") << endl; m_username = e.attribute("username"); m_userId = e.attribute("nsid"); } } details = details.nextSibling(); } success = true; } else if (node.isElement() && node.nodeName() == "err") { kdDebug() << "Checking Error in response" << endl; errorString = node.toElement().attribute("code"); kdDebug() << "Error code=" << errorString << endl; kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl; //emit signalError(code); } node = node.nextSibling(); } kdDebug() << "GetToken finished" << endl; //emit signalBusy( false ); m_authProgressDlg->hide(); if(success) emit signalTokenObtained(m_token); else emit signalError(errorString); } void FlickrTalker::parseResponseListPhotoSets(const TQByteArray& data) { bool success = false; TQDomDocument doc("getListPhotoSets"); if (!doc.setContent(data)) return; TQDomElement docElem = doc.documentElement(); TQDomNode node = docElem.firstChild(); TQDomElement e; TQString photoSet_id, photoSet_title, photoSet_description; TQValueList photoSetList; while(!node.isNull()) { if (node.isElement() && node.nodeName() == "photosets") { e = node.toElement(); TQDomNode details = e.firstChild(); FPhotoSet fps; TQDomNode detailsNode = details; while(!detailsNode.isNull()) { if(detailsNode.isElement()) { e = detailsNode.toElement(); if(detailsNode.nodeName() == "photoset") { kdDebug() << "id=" << e.attribute("id") << endl; photoSet_id = e.attribute("id"); //this is what is obtained from data. fps.id = photoSet_id; TQDomNode photoSetDetails = detailsNode.firstChild(); TQDomElement e_detail; while(!photoSetDetails.isNull()) { e_detail = photoSetDetails.toElement(); if(photoSetDetails.nodeName() == "title") { kdDebug() << "Title=" << e_detail.text() << endl; photoSet_title = e_detail.text(); fps.title = photoSet_title; } else if(photoSetDetails.nodeName() == "description") { kdDebug() << "Description =" << e_detail.text() << endl; photoSet_description = e_detail.text(); fps.description = photoSet_description; } photoSetDetails = photoSetDetails.nextSibling(); } } } detailsNode = detailsNode.nextSibling(); } photoSetList.append(fps); details = details.nextSibling(); success = true; } if (node.isElement() && node.nodeName() == "err") { kdDebug() << "Checking Error in response" << endl; TQString code = node.toElement().attribute("code"); kdDebug() << "Error code=" << code << endl; kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl; emit signalError(code); } node = node.nextSibling(); } kdDebug() << "GetPhotoList finished" << endl; if (!success) { emit signalListPhotoSetsFailed(i18n("Failed to fetch photoSets List")); } else { emit signalListPhotoSetsSucceeded(photoSetList); } } void FlickrTalker::parseResponseListPhotos(const TQByteArray& data) { TQDomDocument doc("getPhotosList"); if (!doc.setContent( data)) return; TQDomElement docElem = doc.documentElement(); TQDomNode node = docElem.firstChild(); //TQDomElement e; //TODO } void FlickrTalker::parseResponseCreateAlbum(const TQByteArray& data) { TQDomDocument doc("getCreateAlbum"); if (!doc.setContent(data)) return; TQDomElement docElem = doc.documentElement(); TQDomNode node = docElem.firstChild(); //TODO } void FlickrTalker::parseResponseAddPhoto(const TQByteArray& data) { bool success = false; TQString line; TQDomDocument doc("AddPhoto Response"); if (!doc.setContent(data)) return; TQDomElement docElem = doc.documentElement(); TQDomNode node = docElem.firstChild(); TQDomElement e; while(!node.isNull()) { if (node.isElement() && node.nodeName() == "photoid") { e = node.toElement(); // try to convert the node to an element. TQDomNode details = e.firstChild(); kdDebug() << "Photoid= " << e.text() << endl; success = true; } if (node.isElement() && node.nodeName() == "err") { kdDebug() << "Checking Error in response" << endl; TQString code = node.toElement().attribute("code"); kdDebug() << "Error code=" << code << endl; kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl; emit signalError(code); } node = node.nextSibling(); } kdDebug() << "GetToken finished" << endl; if (!success) { emit signalAddPhotoFailed(i18n("Failed to upload photo")); } else { emit signalAddPhotoSucceeded(); } } void FlickrTalker::parseResponsePhotoProperty(const TQByteArray& data) { bool success = false; TQString line; TQDomDocument doc("Photos Properties"); if (!doc.setContent(data)) return; TQDomElement docElem = doc.documentElement(); TQDomNode node = docElem.firstChild(); TQDomElement e; while(!node.isNull()) { if (node.isElement() && node.nodeName() == "photoid") { e = node.toElement(); // try to convert the node to an element. TQDomNode details = e.firstChild(); kdDebug() << "Photoid=" << e.text() << endl; success = true; } if (node.isElement() && node.nodeName() == "err") { kdDebug() << "Checking Error in response" << endl; TQString code = node.toElement().attribute("code"); kdDebug() << "Error code=" << code << endl; kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl; emit signalError(code); } node = node.nextSibling(); } kdDebug() << "GetToken finished" << endl; if (!success) { emit signalAddPhotoFailed(i18n("Failed to query photo information")); } else { emit signalAddPhotoSucceeded(); } } } // namespace KIPIFlickrExportPlugin