I'm no longer interested in releasing a full C++ example. But, since I keep receiving emails from people interested in this I decided I would post some functions I wrote in my C++ evernote project.
Connected
void cEvernoteManager::connected()
{
try
{
const std::string client_name = getClientName();
std::string site = getHostName();
const std::string user = "/edam/user";
const std::string consumer_key = getConsumerKey();
const std::string consumer_secret = getConsumerSecret();
const std::string auth_token = getToken();
QString note_store_url = getStoreUrl().c_str();
mOpaquePtr->mNotestoreUrl = note_store_url.toUtf8().constData();
mShard = note_store_url.replace( "notestore" , "").toUtf8().constData();
// Get the Evernote NoteStore URL
boost::shared_ptr<THttpClient> auth_http( new THttpClient(site, 80, user) );
auth_http->open();
boost::shared_ptr<TBinaryProtocol> userStoreProt( new TBinaryProtocol(auth_http) );
UserStoreClient userStore(userStoreProt, userStoreProt );
std::string notestoreUrl = "";
userStore.getNoteStoreUrl(notestoreUrl, auth_token);
auth_http->close();
QString note_store_url_original = notestoreUrl.c_str();
mOpaquePtr->mNotestoreUrl = notestoreUrl;
mShard = note_store_url_original.replace( "notestore" , "").toUtf8().constData();
QString path = mOpaquePtr->mNotestoreUrl.c_str();
path.replace("https://","");
path.replace(site.c_str(),"");
boost::shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
boost::shared_ptr<TSSLSocket> socket = factory->createSocket(site, 443);
boost::shared_ptr<TBufferedTransport> transport ( new TBufferedTransport(socket) );
mOpaquePtr->mStoreHTTPClient.reset( new THttpClient(transport,site,path.toUtf8().constData()));
mOpaquePtr->mStoreHTTPClient->open();
mOpaquePtr->mStoreProtocol.reset( new TBinaryProtocol(mOpaquePtr->mStoreHTTPClient) );
mOpaquePtr->mNoteStore = new NoteStoreClient(mOpaquePtr->mStoreProtocol, mOpaquePtr->mStoreProtocol);
mRefreshTime = clock() + REFRESH_TIMEOUT;
_setConnectionStatus( CONNECTIONSTATUS_CONNECTED );
_setDefaultNotebook();
_setTrashNotebook();
_setFavoriteTag();
_synchronize();
}
catch (...) { _displayException(); }
}
Create a note from a string content object
std::string cEvernoteManager::createNote( const std::string & title, const std::string & content )
{
if( getConnected() )
{
Note reference_note;
reference_note.__isset.title = true;
reference_note.title = title;
reference_note.__isset.content = true;
reference_note.__isset.contentHash = true;
reference_note.__isset.contentLength = true;
reference_note.notebookGuid = getNotebookGuid();
reference_note.__isset.notebookGuid = true;
std::string assembled_content = content;
assembled_content = CONTENT_HEADER + assembled_content + CONTENT_FOOTER;
reference_note.content = assembled_content;
reference_note.contentLength = assembled_content.size();
QCryptographicHash hash( QCryptographicHash::Md5 );
hash.addData(reference_note.content.c_str(), reference_note.contentLength);
reference_note.contentHash = " ";
const char * hash_data = hash.result().data();
memcpy( const_cast<char *>(reference_note.contentHash.c_str()), hash_data, 16);
mOpaquePtr->mNoteStore->createNote( reference_note, getToken(), reference_note );
return reference_note.guid;
}
return "";
}
Create a note using a QMimeData object
std::string cEvernoteManager::createNote( const std::string & title, const QMimeData * content )
{
if( getConnected() )
{
try
{
Note reference_note;
reference_note.__isset.title = true;
reference_note.title = title;
reference_note.__isset.content = true;
reference_note.__isset.contentHash = true;
reference_note.__isset.contentLength = true;
reference_note.__isset.resources = true;
reference_note.__isset.attributes = true;
reference_note.notebookGuid = getNotebookGuid();
reference_note.__isset.notebookGuid = true;
//Put searchable content in if possible
std::string assembled_content = "";
std::vector<Resource> *resource_array = new std::vector<Resource>;
if( content->hasText() )
assembled_content += content->text().toUtf8().constData();
else if( content->hasUrls() )
assembled_content += content->urls().at(0).path().toUtf8().constData();
std::replace( assembled_content.begin(), assembled_content.end(), '\"', ' ');
std::replace( assembled_content.begin(), assembled_content.end(), ' ', ' ');
std::replace( assembled_content.begin(), assembled_content.end(), ':', ' ');
std::replace( assembled_content.begin(), assembled_content.end(), '<', ' ');
std::replace( assembled_content.begin(), assembled_content.end(), '>', ' ');
std::replace( assembled_content.begin(), assembled_content.end(), '/', ' ');
std::replace( assembled_content.begin(), assembled_content.end(), '\\', ' ');
std::replace( assembled_content.begin(), assembled_content.end(), '&', ' ');
//Do we have any files that we need to copy
if( content->hasUrls() )
{
QList<QUrl> url_list = content->urls();
for( int i = 0; i < url_list.size() ; ++i)
{
QUrl file = url_list.at(i);
QString path = file.path();
}
}
//Copy remaining standard mime types
QStringList format_list = content->formats();
for( int i = 0; i < format_list.size();++i)
{
QString mime_type = format_list.at(i);
std::string mime_type_string = mime_type.toUtf8().constData();
//Ignore QT types
if( mime_type_string.find('\"') != std::string::npos )
continue;
std::replace( assembled_content.begin(), assembled_content.end(), '\"', '\'');
//If URL we should copy the file
QByteArray mime_data = content->data(mime_type);
QCryptographicHash hash(QCryptographicHash::Md5 );
hash.addData(mime_data);
QByteArray hashMd5 = hash.result();
//Copy data to evernote container
Data *data = new Data();
data->size = mime_data.size();
data->body.reserve(mime_data.size());
for(int i=0;i<mime_data.size();++i)
data->body += " ";
memcpy( const_cast<char*>(data->body.c_str()), mime_data.data(),mime_data.size());
data->bodyHash = hashMd5.data();
data->__isset.body = true;
data->__isset.bodyHash = true;
data->__isset.size = true;
ResourceAttributes * resource_attributes = new ResourceAttributes();
resource_attributes->fileName = title;// + mime_type.toUtf8().constData();
resource_attributes->__isset.fileName = true;
Resource *resource = new Resource();
resource->mime = mime_type_string;
resource->data = *data;
resource->attributes = *resource_attributes;
resource->__isset.data = true;
resource->__isset.mime = true;
resource->__isset.attributes = true;
resource_array->push_back(*resource);
std::replace( mime_type_string.begin(), mime_type_string.end(), '\"', '\'');
assembled_content += std::string("<en-media type=\"")+mime_type_string+"\" hash=\""+std::string(hashMd5.toHex().data())+"\"/>";
}
//Remove double quotes
assembled_content = CONTENT_HEADER + assembled_content + CONTENT_FOOTER;
reference_note.content = assembled_content;
reference_note.contentLength = assembled_content.size();
QCryptographicHash hash( QCryptographicHash::Md5 );
QString qstring_content = reference_note.content.c_str();
hash.addData(qstring_content.toUtf8().constData(), qstring_content.length());
reference_note.contentHash = " ";
QByteArray hash_data_md5 = hash.result();
const char * hash_data = hash_data_md5.data();
memcpy( const_cast<char *>(reference_note.contentHash.c_str()), hash_data, 16);
reference_note.resources = * resource_array;
mOpaquePtr->mNoteStore->createNote( reference_note, getToken(), reference_note );
return reference_note.guid;
}
catch (...) { _displayException(); }
}
return "";
}
Working OAuth using QTKOAuth
#include <QCoreApplication>
#include <QStringList>
#include <QtDebug>
#include "EvernoteOauth.h"
#include "EvernoteManager.h"
#include <QMessageBox>
#include <QtKOAuth>
#include "OAuthBrowser.h"
cEvernoteOauth::cEvernoteOauth() : mOauthRequest(0),mOauthManager(0)
{
}
void cEvernoteOauth::init( void )
{
deinit();
mOauthRequest = new KQOAuthRequest;
mOauthManager = new KQOAuthManager(this);
mOauthRequest->setEnableDebugOutput(true);
connect(mOauthManager, SIGNAL(receivedToken(QString,QString)),
this, SLOT(onReceivedToken(QString, QString)));
connect(mOauthManager, SIGNAL(temporaryTokenReceived(QString,QString)),
this, SLOT(onTemporaryTokenReceived(QString, QString)));
connect(mOauthManager, SIGNAL(authorizationReceived(QString,QString)),
this, SLOT( onAuthorizationReceived(QString, QString)));
connect(mOauthManager, SIGNAL(accessTokenReceived(QString,QString)),
this, SLOT(onAccessTokenReceived(QString,QString)));
connect(mOauthManager, SIGNAL(requestReady(QByteArray)),
this, SLOT(onRequestReady(QByteArray)));
cOauthBrowser * browser = cOauthBrowser::createManager();
}
void cEvernoteOauth::deinit()
{
if(mOauthRequest)
{
delete mOauthRequest;
mOauthRequest = 0;
}
if(mOauthManager)
{
disconnect(mOauthManager, SIGNAL(receivedToken(QString,QString)),
this, SLOT(onReceivedToken(QString, QString)));
disconnect(mOauthManager, SIGNAL(temporaryTokenReceived(QString,QString)),
this, SLOT(onTemporaryTokenReceived(QString, QString)));
disconnect(mOauthManager, SIGNAL(authorizationReceived(QString,QString)),
this, SLOT( onAuthorizationReceived(QString, QString)));
disconnect(mOauthManager, SIGNAL(accessTokenReceived(QString,QString)),
this, SLOT(onAccessTokenReceived(QString,QString)));
disconnect(mOauthManager, SIGNAL(requestReady(QByteArray)),
this, SLOT(onRequestReady(QByteArray)));
delete mOauthManager;
mOauthManager = 0;
}
}
cEvernoteOauth::~cEvernoteOauth()
{
deinit();
}
void cEvernoteOauth::getAccess()
{
init();
cEvernoteManager * evernote_mgr = cEvernoteManager::getSingletonPtr();
QString url = QString("https://")+evernote_mgr->getHostName().c_str()+"/oauth";
mOauthRequest->initRequest(KQOAuthRequest::TemporaryCredentials, QUrl(url)); //"https://www.evernote.com/oauth"
QString consumer_key = evernote_mgr->getConsumerKey().c_str();
QString consumer_secret = evernote_mgr->getConsumerSecret().c_str();
mOauthRequest->setConsumerKey(consumer_key);
mOauthRequest->setConsumerSecretKey(consumer_secret);
mOauthManager->setHandleUserAuthorization(true);
if( ! mOauthRequest->isValid() )
{
qDebug() << "Invalid request";
QMessageBox::warning(0,"Failed to Authorize","getAccess :: Invalid request");
evernote_mgr->disconnect();
}
mOauthManager->executeRequest(mOauthRequest);
}
void cEvernoteOauth::onTemporaryTokenReceived(QString token, QString tokenSecret)
{
qDebug() << "Temporary token received: " << token << tokenSecret;
cEvernoteManager * evernote_mgr = cEvernoteManager::getSingletonPtr();
QString url = QString("https://")+evernote_mgr->getHostName().c_str()+"/OAuth.action";
QUrl userAuthURL(url);
if( mOauthManager->lastError() == KQOAuthManager::NoError)
{
qDebug() << "Asking for user's permission to access protected resources. Opening URL: " << userAuthURL;
mOauthManager->getUserAuthorization(userAuthURL);
}
else
{
QMessageBox::warning(0,"Failed to Authorize","onTemporaryTokenReceived :: OAuth with Evernote failed!");
cEvernoteManager::getSingletonPtr()->disconnect();
}
}
void cEvernoteOauth::onAuthorizationReceived(QString token, QString verifier)
{
qDebug() << "User authorization received: " << token << verifier;
cEvernoteManager * evernote_mgr = cEvernoteManager::getSingletonPtr();
QString url = QString("https://")+evernote_mgr->getHostName().c_str()+"/oauth";
mOauthManager->getUserAccessTokens(QUrl(url));
if( mOauthManager->lastError() != KQOAuthManager::NoError)
{
QMessageBox::warning(0,"Failed to Authorize","onAuthorizationReceived :: OAuth with Evernote failed!");
cEvernoteManager::getSingletonPtr()->disconnect();
}
}
void cEvernoteOauth::onAccessTokenReceived(QString token, QString store_url)
{
qDebug() << "Access token received: " << token << store_url;
mOauthSettings.setValue("oauth_token", token);
mOauthSettings.setValue("edam_noteStoreUrl", store_url);
qDebug() << "Access tokens now stored!";
cOauthBrowser::getSingletonPtr()->hide();
cEvernoteManager::getSingletonPtr()->setAuthenticationInfo( token, store_url );
cEvernoteManager::getSingletonPtr()->connected();
}
void cEvernoteOauth::onRequestReady(QByteArray response)
{
qDebug() << "Response from the service: " << response;
if( response == "" )
{
QMessageBox::warning(0,"Failed to Authorize", "onRequestReady :: Failed to authorize, empty response from evernote" );
cEvernoteManager::getSingletonPtr()->disconnect();
}
}
void cEvernoteOauth::onReceivedToken( QString oauth_token, QString oauth_token_secret )
{
qDebug() << "onReceivedToken: " << oauth_token << oauth_token_secret;
}
Misc functions
void cEvernoteManager::_setDefaultNotebook( void )
{
std::vector<Notebook> notebooks;
//Todo tomorrow, probably crashing because I changed OpenSSL in this project but not in thrift
mOpaquePtr->mNoteStore->listNotebooks(notebooks,getToken());
for (int i=0;i<notebooks.size();++i)
{
Notebook & notebook = notebooks.at(i);
if( notebook.name == getNotebookName() )
{
//The notebook already exists, return
//Todo switch assignment to a class, so we can delete memory
mOpaquePtr->mNotebook = new Notebook(notebook);
return;
}
}
//We failed to find our notebook, make one instead
std::string guid = createNotebook(getNotebookName());
Notebook new_notebook;
mOpaquePtr->mNoteStore->getNotebook( new_notebook, getToken(), guid );
mOpaquePtr->mNotebook = new Notebook( new_notebook );
}
void cEvernoteManager::_setTrashNotebook( void )
{
std::vector<Notebook> notebooks;
mOpaquePtr->mNoteStore->listNotebooks(notebooks,getToken());
for (int i=0;i<notebooks.size();++i)
{
Notebook & notebook = notebooks.at(i);
if( notebook.name == getNotebookTrashName() )
{
mOpaquePtr->mTrashNotebook = new Notebook(notebook);
return;
}
}
//We failed to find our notebook, make one instead
std::string guid = createNotebook(getNotebookTrashName());
Notebook new_notebook;
mOpaquePtr->mNoteStore->getNotebook( new_notebook, getToken(), guid );
mOpaquePtr->mTrashNotebook = new Notebook( new_notebook );
}
void cEvernoteManager::_setFavoriteTag( void )
{
std::vector<Tag> tags;
mOpaquePtr->mNoteStore->listTags( tags,getToken());
for (int i=0;i<tags.size();++i)
{
Tag & tag = tags.at(i);
if( tag.name == getFavoriteTagName() )
{
//The notebook already exists, return
//Todo switch assignment to a class, so we can delete memory
mOpaquePtr->mFavoriteTag = new Tag(tag);
return;
}
}
//We failed to find our notebook, make one instead
std::string guid = createTag(getFavoriteTagName());
Tag new_tag;
mOpaquePtr->mNoteStore->getTag( new_tag, getToken(), guid );
mOpaquePtr->mFavoriteTag = new Tag( new_tag );
}
void cEvernoteManager::_displayException( void )
{
QString error_message = "Unknown Exception";
try
{
// this function is meant to be called from a catch block
// rethrow the exception to catch it again
throw;
}
catch (const EDAMNotFoundException & e)
{
error_message = QString("Tried to sync, but something went wrong.\n")+ EvernoteExceptionHelper::createNotFoundExceptionMessage(e);
}
catch (const EDAMSystemException & e)
{
error_message = QString("Tried to sync, but something went wrong.\n")+ EvernoteExceptionHelper::createSystemExceptionMessage(e);
}
catch (const EDAMUserException & e)
{
error_message = QString("Tried to sync, but something went wrong.\n") + EvernoteExceptionHelper::createUserExceptionMessage(e);
}
catch (const TTransportException & e)
{
error_message =QString("Encountered a network error.")+ EvernoteExceptionHelper::createTransportExceptionMessage(e);
}
catch (const TException & e)
{
error_message = QString("Tried to sync, but something went wrong.\n")+ EvernoteExceptionHelper::createExceptionMessage(e);
}
catch (const std::exception & e)
{
QString message;
message.append("exception(");
message.append(e.what());
message.append(")");
error_message = QString("Tried to sync, but something went wrong.\n") + message;
}
catch (...)
{
error_message = "Tried to sync, but something went wrong.\n Unknown exception.";
}
QMessageBox::warning(0, "Error, System Exception", error_message);
disconnect();
}
std::string cEvernoteManager::createNotebook( const std::string & title )
{
if( getConnected() )
{
try
{
Notebook reference_notebook;
reference_notebook.name = title;
reference_notebook.__isset.name = true;
mOpaquePtr->mNoteStore->createNotebook( reference_notebook, getToken(), reference_notebook );
return reference_notebook.guid;
}
catch (...) { _displayException(); }
}
return "";
}
std::string cEvernoteManager::createTag( const std::string & title )
{
if( getConnected() )
{
try
{
Tag reference_tag;
reference_tag.name = title;
reference_tag.__isset.name = true;
mOpaquePtr->mNoteStore->createTag( reference_tag, getToken(), reference_tag );
return reference_tag.guid;
}
catch (...) { _displayException(); }
}
return "";
}
boost::shared_ptr<cEvernoteManager::tNote> cEvernoteManager::getNote( const std::string & guid )
{
Note returned_note;
mOpaquePtr->mNoteStore->getNote(returned_note,getToken(),guid,true,true,true,true);
return boost::shared_ptr<tNote>(new cEvernoteManager::tNote(returned_note.guid,returned_note.title,returned_note.updated,returned_note.content));
}
bool cEvernoteManager::trashNote( const std::string & guid )
{
if( getConnected() )
{
//_refreshConnnection();
try
{
int expunge_result = mOpaquePtr->mNoteStore->expungeNote( getToken(), guid );
}
catch( ... )
{
//Assume we failed because of rights
try
{
Note note;
mOpaquePtr->mNoteStore->getNote( note, getToken(),guid,false,false,false,false);
note.notebookGuid = getNotebookTrashGuid();
note.__isset.notebookGuid = true;
mOpaquePtr->mNoteStore->updateNote( note, getToken(), note );
}
catch (...) { _displayException(); }
}
}
return false;
}
bool cEvernoteManager::favoriteNote( const std::string & guid )
{
if( getConnected() )
{
try
{
Note returned_note;
mOpaquePtr->mNoteStore->getNote(returned_note,getToken(),guid,false,false,false,false);
std::vector<std::string>::iterator itr = find(returned_note.tagGuids.begin(), returned_note.tagGuids.end(), getFavoriteTagGuid() );
if (itr != returned_note.tagGuids.end()) // Exists
returned_note.tagGuids.erase( itr );
else // doesn't exist
returned_note.tagGuids.push_back( getFavoriteTagGuid() );
returned_note.__isset.tagGuids = true;
mOpaquePtr->mNoteStore->updateNote( returned_note, getToken(), returned_note );
}
catch (...) { _displayException(); }
}
return false;
}
bool cEvernoteManager::search( std::vector<boost::shared_ptr<tNote>> & return_results, const std::string & search_string , bool only_favorites, int limit)
{
if( getConnected() )
{
try
{
int pageSize = limit;
NoteFilter *filter = new NoteFilter();
filter->order = UPDATED;
filter->words = "*"+search_string+"*";
filter->__isset.order = true;
filter->__isset.words = true;
if( only_favorites )
{
const std::string fav_guid = getFavoriteTagGuid();
filter->tagGuids.push_back( fav_guid );
filter->__isset.tagGuids = true;
}
filter->notebookGuid = getNotebookGuid();
filter->__isset.notebookGuid = true;
NotesMetadataResultSpec *spec = new NotesMetadataResultSpec();
spec->includeTitle = true;
spec->includeTagGuids = true;
spec->includeUpdated = true;
spec->__isset.includeTitle = true;
spec->__isset.includeTagGuids = true;
spec->__isset.includeUpdated = true;
NotesMetadataList notes;
notes.__isset.searchedWords = false;
notes.__isset.stoppedWords = false;
notes.__isset.updateCount = false;
mOpaquePtr->mNoteStore->findNotesMetadata(notes,getToken(), *filter, 0, pageSize, *spec);
int matchingNotes = notes.totalNotes;
int notesThisPage = notes.notes.size();
for( int i =0;i < notesThisPage;++i)
{
NoteMetadata simple_note = notes.notes.at(i);
Note extended_note;
bool favorite = (std::find( simple_note.tagGuids.begin(), simple_note.tagGuids.end(), getFavoriteTagGuid()) != simple_note.tagGuids.end());
return_results.push_back( boost::shared_ptr<tNote>(new tNote(simple_note.guid, simple_note.title,simple_note.updated,"",favorite)));
}
return true;
}
catch (...) { _displayException(); }
}
return false;
}