From cdd84a443d08a4f5748b52b102ce17dfd267acc5 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Wed, 29 Apr 2015 17:27:23 +0000 Subject: twitter moved to the kernel json driver git-svn-id: http://svn.miranda-ng.org/main/trunk@13248 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Twitter/src/connection.cpp | 12 - protocols/Twitter/src/stdafx.h | 1 + protocols/Twitter/src/tinyjson.hpp | 586 ------------------------------ protocols/Twitter/src/twitter.cpp | 334 ++++++----------- protocols/Twitter/src/ui.cpp | 14 +- protocols/Twitter/src/utility.cpp | 14 + protocols/Twitter/src/utility.h | 6 +- protocols/Twitter/src/version.h | 2 +- protocols/Twitter/twitter.vcxproj.filters | 331 ----------------- 9 files changed, 140 insertions(+), 1160 deletions(-) delete mode 100644 protocols/Twitter/src/tinyjson.hpp (limited to 'protocols/Twitter') diff --git a/protocols/Twitter/src/connection.cpp b/protocols/Twitter/src/connection.cpp index a92ea20cc6..f40a6294f3 100644 --- a/protocols/Twitter/src/connection.cpp +++ b/protocols/Twitter/src/connection.cpp @@ -281,17 +281,6 @@ bool TwitterProto::NegotiateConnection() } } - /* if( !db_get_s(0,m_szModuleName,TWITTER_KEY_PASS,&dbv)) { - CallService(MS_DB_CRYPT_DECODESTRING,strlen(dbv.pszVal)+1, - reinterpret_cast(dbv.pszVal)); - pass = dbv.pszVal; - db_free(&dbv); - } - else { - ShowPopup(TranslateT("Please enter a password.")); - return false; - }*/ - if (!db_get_s(0, m_szModuleName, TWITTER_KEY_BASEURL, &dbv)) { mir_cslock s(twitter_lock_); twit_.set_base_url(dbv.pszVal); @@ -308,7 +297,6 @@ bool TwitterProto::NegotiateConnection() bool success; { mir_cslock s(twitter_lock_); - success = twit_.set_credentials(screenName, ConsumerKey, ConsumerSecret, oauthAccessToken, oauthAccessTokenSecret, L"", true); } diff --git a/protocols/Twitter/src/stdafx.h b/protocols/Twitter/src/stdafx.h index b3ea09eaac..9c12e052fa 100644 --- a/protocols/Twitter/src/stdafx.h +++ b/protocols/Twitter/src/stdafx.h @@ -62,6 +62,7 @@ typedef std::basic_string tstring; #include #include #include +#include #include #pragma warning(pop) diff --git a/protocols/Twitter/src/tinyjson.hpp b/protocols/Twitter/src/tinyjson.hpp deleted file mode 100644 index 173b6b149c..0000000000 --- a/protocols/Twitter/src/tinyjson.hpp +++ /dev/null @@ -1,586 +0,0 @@ -/* - * TinyJson 1.3.0 - * A Minimalistic JSON Reader Based On Boost.Spirit, Boost.Any, and Boost.Smart_Ptr. - * - * Copyright (c) 2008 Thomas Jansen (thomas@beef.de) - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - * - * See http://blog.beef.de/projects/tinyjson/ for documentation. - * - * (view source with tab-size = 3) - * - * 16 Mar 2009 - allow root of JSON to be array (Jim Porter) - * 29 Mar 2008 - use strict_real_p for number parsing, small cleanup (Thomas Jansen) - * 26 Mar 2008 - made json::grammar a template (Boris Schaeling) - * 20 Mar 2008 - optimized by using boost::shared_ptr (Thomas Jansen) - * 29 Jan 2008 - Small bugfixes (Thomas Jansen) - * 04 Jan 2008 - Released to the public (Thomas Jansen) - * 13 Nov 2007 - initial release (Thomas Jansen) * - * - * 29 Mar 2008 - */ - - -#ifndef TINYJSON_HPP -#define TINYJSON_HPP - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -namespace json -{ - boost::spirit::classic::int_parser const - longlong_p = boost::spirit::classic::int_parser(); - - // ========================================================================================================== - // === U N I C O D E _ C O N V E R T === - // ========================================================================================================== - - template< typename Char > - struct unicodecvt - { - static std::basic_string< Char > convert(int iUnicode) - { - return std::basic_string< Char >(1, static_cast< Char >(iUnicode)); - } - }; - - - // ---[ TEMPLATE SPECIALIZATION FOR CHAR ]-------------------------------------------------------------------- - - template<> - struct unicodecvt< char > - { - static std::string convert(int iUnicode) - { - std::string strString; - - if(iUnicode < 0x0080) - { - // character 0x0000 - 0x007f... - - strString.push_back(0x00 | ((iUnicode & 0x007f) >> 0)); - } - else if(iUnicode < 0x0800) - { - // character 0x0080 - 0x07ff... - - strString.push_back(0xc0 | ((iUnicode & 0x07c0) >> 6)); - strString.push_back(0x80 | ((iUnicode & 0x003f) >> 0)); - } - else - { - // character 0x0800 - 0xffff... - - strString.push_back(0xe0 | ((iUnicode & 0x00f000) >> 12)); - strString.push_back(0x80 | ((iUnicode & 0x000fc0) >> 6)); - strString.push_back(0x80 | ((iUnicode & 0x00003f) >> 0)); - } - - return strString; - } - }; - - - // ========================================================================================================== - // === T H E J S O N G R A M M A R === - // ========================================================================================================== - - template< typename Char > - class grammar : public boost::spirit::classic::grammar< grammar< Char > > - { - public: - - // ---[ TYPEDEFINITIONS ]--------------------------------------------------------------------------------- - - typedef boost::shared_ptr< boost::any > variant; // pointer to a shared variant - - typedef std::stack< variant > stack; // a stack of json variants - typedef std::pair< std::basic_string< Char >, variant > pair; // a pair as it appears in json - - typedef std::deque< variant > array; // an array of json variants - typedef std::map< std::basic_string< Char >, variant > object; // an object with json pairs - - protected: - - // ---[ SEMANTIC ACTION: PUSH A STRING ON THE STACK (AND ENCODE AS UTF-8) ]------------------------------- - - struct push_string - { - stack & m_stack; - push_string(stack & stack) : m_stack(stack) { } - - template - void operator() (Iterator szStart, Iterator szEnd) const - { - // 1: skip the quotes... - - ++szStart; - --szEnd; - - // 2: traverse through the original string and check for escape codes.. - - std::basic_string< typename Iterator::value_type > strString; - - while(szStart < szEnd) - { - // 2.1: if it's no escape code, just append to the resulting string... - - if(*szStart != static_cast< typename Iterator::value_type >('\\')) - { - // 2.1.1: append the character... - - strString.push_back(*szStart); - } - else - { - // 2.1.2: otherwise, check the escape code... - - ++szStart; - - switch(*szStart) - { - default: - - strString.push_back(*szStart); - break; - - case 'b': - - strString.push_back(static_cast< typename Iterator::value_type >('\b')); - break; - - case 'f': - - strString.push_back(static_cast< typename Iterator::value_type >('\f')); - break; - - case 'n': - - strString.push_back(static_cast< typename Iterator::value_type >('\n')); - break; - - case 'r': - - strString.push_back(static_cast< typename Iterator::value_type >('\r')); - break; - - case 't': - - strString.push_back(static_cast< typename Iterator::value_type >('\t')); - break; - - case 'u': - { - // 2.1.2.1: convert the following hex value into an int... - - int iUnicode; - std::basic_istringstream< Char >(std::basic_string< typename Iterator::value_type >(&szStart[1], 4)) >> std::hex >> iUnicode; - - szStart += 4; - - // 2.1.2.2: append the unicode int... - - strString.append(unicodecvt< typename Iterator::value_type >::convert(iUnicode)); - } - } - } - - // 2.2: go on with the next character... - - ++szStart; - } - - // 3: finally, push the string on the stack... - - m_stack.push(variant(new boost::any(strString))); - } - }; - - - // ---[ SEMANTIC ACTION: PUSH A REAL ON THE STACK ]------------------------------------------------------- - - struct push_double - { - stack & m_stack; - push_double(stack & stack) : m_stack(stack) { } - - void operator() (double dValue) const - { - m_stack.push(variant(new boost::any(dValue))); - } - }; - - - // ---[ SEMANTIC ACTION: PUSH AN INT ON THE STACK ]------------------------------------------------------- - - struct push_int - { - stack & m_stack; - push_int(stack & stack) : m_stack(stack) { } - - void operator() (long long iValue) const - { - m_stack.push(variant(new boost::any(iValue))); - } - }; - - - // ---[ SEMANTIC ACTION: PUSH A BOOLEAN ON THE STACK ]---------------------------------------------------- - - struct push_boolean - { - stack & m_stack; - push_boolean(stack & stack) : m_stack(stack) { } - - template - void operator() (Iterator szStart, Iterator /* szEnd */ ) const - { - // 1: push a boolean that is "true" if the string starts with 't' and "false" otherwise... - - m_stack.push(variant(new boost::any(*szStart == static_cast< typename Iterator::value_type >('t')))); - } - }; - - - // ---[ SEMANTIC ACTION: PUSH A NULL VALUE ON THE STACK ]------------------------------------------------- - - struct push_null - { - stack & m_stack; - push_null(stack & stack) : m_stack(stack) { } - - template - void operator() (Iterator /* szStart */ , Iterator /* szEnd */ ) const - { - m_stack.push(variant(new boost::any())); - } - }; - - - // ---[ SEMANTIC ACTION: CREATE A "JSON PAIR" ON THE STACK ]---------------------------------------------- - - struct create_pair - { - stack & m_stack; - create_pair(stack & stack) : m_stack(stack) { } - - template - void operator() (Iterator /* szStart */, Iterator /* szEnd */ ) const - { - // 1: get the variant from the stack... - - variant var = m_stack.top(); - m_stack.pop(); - - // 2: get the name from the stack... - - std::basic_string< typename Iterator::value_type > strName; - - try - { - strName = boost::any_cast< std::basic_string< typename Iterator::value_type > >(*m_stack.top()); - } - catch(boost::bad_any_cast &) { /* NOTHING */ } - - m_stack.pop(); - - // 3: push a pair of both on the stack... - - m_stack.push(variant(new boost::any(pair(strName, var)))); - } - }; - - - // ---[ SEMANTIC ACTION: BEGIN AN ARRAY ]----------------------------------------------------------------- - - class array_delimiter { /* EMPTY CLASS */ }; - - struct begin_array - { - stack & m_stack; - begin_array(stack & stack) : m_stack(stack) { } - - template - void operator() (Iterator /* cCharacter */) const - { - m_stack.push(variant(new boost::any(array_delimiter()))); - } - }; - - - // ---[ SEMANTIC ACTION: CREATE AN ARRAY FROM THE VALUES ON THE STACK ]----------------------------------- - - struct end_array - { - stack & m_stack; - end_array(stack & stack) : m_stack(stack) { } - - // - -[ functional operator ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template - void operator() (Iterator /* cCharacter */) const - { - // 1: create an array object and push everything in it, that's on the stack... - - variant varArray(new boost::any(array())); - - while(!m_stack.empty()) - { - // 1.1: get the top most variant of the stack... - - variant var = m_stack.top(); - m_stack.pop(); - - // 1.2: is it the end of the array? if yes => break the loop... - - if(boost::any_cast< array_delimiter >(var.get()) != NULL) - { - break; - } - - // 1.3: otherwise, add to the array... - - boost::any_cast< array >(varArray.get())->push_front(var); - } - - // 2: finally, push the array at the end of the stack... - - m_stack.push(varArray); - } - }; - - - // ---[ SEMANTIC ACTION: BEGIN AN OBJECT ]---------------------------------------------------------------- - - class object_delimiter { /* EMPTY CLASS */ }; - - struct begin_object - { - stack & m_stack; - begin_object(stack & stack) : m_stack(stack) { } - - template - void operator() (Iterator /* cCharacter */) const - { - m_stack.push(variant(new boost::any(object_delimiter()))); - } - }; - - - // ---[ SEMANTIC ACTION: CREATE AN OBJECT FROM THE VALUES ON THE STACK ]---------------------------------- - - struct end_object - { - stack & m_stack; - end_object(stack & stack) : m_stack(stack) { } - - template - void operator() (Iterator /* cCharacter */) const - { - // 1: create an array object and push everything in it, that's on the stack... - - variant varObject(new boost::any(object())); - - while(!m_stack.empty()) - { - // 1.1: get the top most variant of the stack... - - variant var = m_stack.top(); - m_stack.pop(); - - // 1.2: is it the end of the array? if yes => break the loop... - - if(boost::any_cast< object_delimiter >(var.get()) != NULL) - { - break; - } - - // 1.3: if this is not a pair, we have a problem... - - pair * pPair = boost::any_cast< pair >(var.get()); - if(!pPair) - { - /* BIG PROBLEM!! */ - - continue; - } - - // 1.4: set the child of this object... - - boost::any_cast< object >(varObject.get())->insert(std::make_pair(pPair->first, pPair->second)); - } - - // 2: finally, push the array at the end of the stack... - - m_stack.push(varObject); - } - }; - - public: - - stack & m_stack; - grammar(stack & stack) : m_stack(stack) { } - - // ---[ THE ACTUAL GRAMMAR DEFINITION ]------------------------------------------------------------------- - - template - class definition - { - boost::spirit::classic::rule< SCANNER > m_start; - boost::spirit::classic::rule< SCANNER > m_object; - boost::spirit::classic::rule< SCANNER > m_array; - boost::spirit::classic::rule< SCANNER > m_pair; - boost::spirit::classic::rule< SCANNER > m_value; - boost::spirit::classic::rule< SCANNER > m_string; - boost::spirit::classic::rule< SCANNER > m_number; - boost::spirit::classic::rule< SCANNER > m_boolean; - boost::spirit::classic::rule< SCANNER > m_null; - - public: - - boost::spirit::classic::rule< SCANNER > const & start() const { return m_start; } - - // - -[ create the definition ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - definition(grammar const & self) - { - using namespace boost::spirit::classic; - - // 0: JSON can either be an object or an array - - m_start - = m_object - | m_array; - - // 1: an object is an unordered set of pairs (seperated by commas)... - - m_object - = ch_p('{') [ begin_object(self.m_stack) ] >> - !(m_pair >> *(ch_p(',') >> m_pair)) >> - ch_p('}') [ end_object (self.m_stack) ]; - - // 2: an array is an ordered collection of values (seperated by commas)... - - m_array - = ch_p('[') [ begin_array(self.m_stack) ] >> - !(m_value >> *(ch_p(',') >> m_value)) >> - ch_p(']') [ end_array (self.m_stack) ]; - - // 3: a pair is given by a name and a value... - - m_pair - = ( m_string >> ch_p(':') >> m_value ) - [ create_pair(self.m_stack) ] - ; - - // 4: a value can be a string in double quotes, a number, a boolean, an object or an array. - - m_value - = m_string - | m_number - | m_object - | m_array - | m_boolean - | m_null - ; - - // 5: a string is a collection of zero or more unicode characters, wrapped in double quotes... - - m_string - = lexeme_d - [ - ( ch_p('"') >> *( - ( (anychar_p - (ch_p('"') | ch_p('\\'))) - | ch_p('\\') >> - ( ch_p('\"') - | ch_p('\\') - | ch_p('/') - | ch_p('b') - | ch_p('f') - | ch_p('n') - | ch_p('r') - | ch_p('t') - | (ch_p('u') >> repeat_p(4)[ xdigit_p ]) - ) - )) >> ch_p('"') - ) - [ push_string(self.m_stack) ] - ] - ; - - // 6: a number is very much like a C or java number... - - m_number - = strict_real_p [ push_double(self.m_stack) ] - | longlong_p [ push_int (self.m_stack) ] - ; - - // 7: a boolean can be "true" or "false"... - - m_boolean - = ( str_p("true") - | str_p("false") - ) - [ push_boolean(self.m_stack) ] - ; - - // 8: finally, a value also can be a 'null', i.e. an empty item... - - m_null - = str_p("null") - [ push_null(self.m_stack) ] - ; - } - }; - }; - - - // ========================================================================================================== - // === T H E F I N A L P A R S I N G R O U T I N E === - // ========================================================================================================== - - template - typename json::grammar< typename Iterator::value_type >::variant parse(Iterator const & szFirst, Iterator const & szEnd) - { - // 1: parse the input... - - json::grammar< typename Iterator::value_type >::stack st; - json::grammar< typename Iterator::value_type > gr(st); - - boost::spirit::classic::parse_info pi = boost::spirit::classic::parse(szFirst, szEnd, gr, boost::spirit::classic::space_p); - - // 2: skip any spaces at the end of the parsed section... - - while((pi.stop != szEnd) && (*pi.stop == static_cast< typename Iterator::value_type >(' '))) - { - ++pi.stop; - } - - // 3: if the input's end wasn't reached or if there is more than one object on the stack => cancel... - - if((pi.stop != szEnd) || (st.size() != 1)) - { - return json::grammar< typename Iterator::value_type >::variant(new boost::any()); - } - - // 4: otherwise, return the result... - - return st.top(); - } -}; - - -#endif // TINYJSON_HPP diff --git a/protocols/Twitter/src/twitter.cpp b/protocols/Twitter/src/twitter.cpp index 1a762ec08d..06ac5f8792 100644 --- a/protocols/Twitter/src/twitter.cpp +++ b/protocols/Twitter/src/twitter.cpp @@ -18,57 +18,10 @@ along with this program. If not, see . #include "stdafx.h" #include "twitter.h" - -#include "tinyjson.hpp" -#include - -typedef json::grammar js; +#include "utility.h" // utility functions -template -static T cast_and_decode(boost::any &a, bool allow_null) -{ - if (allow_null && a.type() == typeid(void)) - return T(); - return boost::any_cast(a); -} - -template <> -static std::string cast_and_decode(boost::any &a, bool allow_null) -{ - if (allow_null && a.type() == typeid(void)) - return std::string(); - std::string s = boost::any_cast(a); - - // Twitter *only* encodes < and >, so decode them - size_t off; - while ((off = s.find("<")) != std::string::npos) - s.replace(off, 4, "<"); - while ((off = s.find(">")) != std::string::npos) - s.replace(off, 4, ">"); - - return s; -} - -template -static T retrieve(const js::object &o, const std::string &key, bool allow_null = false) -{ - using boost::any_cast; - - js::object::const_iterator i = o.find(key); - if (i == o.end()) - throw std::exception(("unable to retrieve key '" + key + "'").c_str()); - try { - return cast_and_decode(*i->second, allow_null); - } - catch (const boost::bad_any_cast &) { - throw std::exception(("unable to cast key '" + key + "' to target type").c_str()); - } -} - - - twitter::twitter() : base_url_("https://api.twitter.com/") {} @@ -113,85 +66,39 @@ const std::string & twitter::get_base_url() const return base_url_; } -// this whole function is wrong i think. should be calling friends/ids, not followers -/*js::array twitter::buildFriendList() { - - INT_PTR friendCursor = -1; - js::array IDs; // an array for the userIDs. i dunno if js::array is the right thing to use..? - js::array masterIDs; // the list that contains all the users that the user follows - - std::vector friends; - - while (friendCursor != 0) { - http::response resp = slurp(base_url_ + "/1.1/followers/ids.json?cursor=" + friendCursor + "&screen_name=" + username_,http::get); - if(resp.code != 200) - throw bad_response(); - - const js::variant var = json::parse( resp.data.begin(),resp.data.end() ); // pull the data out of the http response - if(var->type() == typeid(js::object)) // make sure the parsed data is of type js::object (??) - { - const js::object &friendIDs = boost::any_cast(*var); // cast the object into the type we can use - if(friendIDs.find("error") != friendIDs.end()) // don't really know why error should be at the end here? - throw std::exception("error while parsing friendIDs object from ids.json"); - - // ok need to find out how to convert all the IDs into an array. dunno if i can magically make it happen, or - // if i will have to parse it myself and add them one by one :( - IDs = retrieve(friendIDs,"ids"); - for(js::array::const_iterator i=IDs.begin(); i!=IDs.end(); ++i) { - //debugLogA("friends ID: " + i); - // add array to master array - js::object one = boost::any_cast(**i); - masterIDs.push_back(one); // i don't understand this. how do we push into the array? should i just use C++ arrays (list?) and bail on boost? - } - - // now we need to pick out the cursor stuff, and keep punching IDs into the array - } - else { - throw std::exception("in buildFriendList(), return type is not js::object"); - } - } - - - }*/ - - std::vector twitter::get_friends() { - // maybe once i have the buildFriendLIst() func working.. but for now let's just get twitter working. - //js::array friendArray = buildFriendList(); - std::vector friends; http::response resp = slurp(base_url_ + "1.1/statuses/friends.json", http::get); if (resp.code != 200) throw bad_response(); - const js::variant var = json::parse(resp.data.begin(), resp.data.end()); - if (var->type() != typeid(js::array)) + JSONNODE *root = json_parse(resp.data.c_str()); + if (root == NULL) throw std::exception("unable to parse response"); - const js::array &list = boost::any_cast(*var); - for (js::array::const_iterator i = list.begin(); i != list.end(); ++i) { - if ((*i)->type() == typeid(js::object)) { - const js::object &one = boost::any_cast(**i); + JSONNODE *nodes = json_as_array(root); + for (int i = 0;; i++) { + JSONNODE *pNode = json_at(nodes, i); + if (pNode == NULL) + break; - twitter_user user; - user.username = retrieve(one, "screen_name"); - user.real_name = retrieve(one, "name", true); - user.profile_image_url = retrieve(one, "profile_image_url", true); + twitter_user user; + user.username = json_as_pstring(json_get(pNode, "screen_name")); + user.real_name = json_as_pstring(json_get(pNode, "name")); + user.profile_image_url = json_as_pstring(json_get(pNode, "profile_image_url")); - if (one.find("status") != one.end()) { - js::object &status = retrieve(one, "status"); - user.status.text = retrieve(status, "text"); + JSONNODE *pStatus = json_get(pNode, "status"); + if (pStatus != NULL) { + user.status.text = json_as_pstring(json_get(pStatus, "text")); + user.status.id = json_as_int(json_get(pStatus, "id")); - user.status.id = retrieve(status, "id"); - - std::string timestr = retrieve(status, "created_at"); - user.status.time = parse_time(timestr); - } - - friends.push_back(user); + std::string timestr = json_as_pstring(json_get(pStatus, "created_at")); + user.status.time = parse_time(timestr); } + + friends.push_back(user); } return friends; @@ -208,20 +115,17 @@ bool twitter::get_info(const std::string &name, twitter_user *info) if (resp.code != 200) throw bad_response(); - const js::variant var = json::parse(resp.data.begin(), resp.data.end()); - if (var->type() == typeid(js::object)) { - const js::object &user_info = boost::any_cast(*var); - if (user_info.find("error") != user_info.end()) - return false; - - info->username = retrieve(user_info, "screen_name"); - info->real_name = retrieve(user_info, "name", true); - info->profile_image_url = retrieve(user_info, "profile_image_url", true); + JSONNODE *root = json_parse(resp.data.c_str()); + if (root == NULL) + return false; - return true; - } - else + if (json_get(root, "error") != NULL) return false; + + info->username = json_as_pstring(json_get(root, "screen_name")); + info->real_name = json_as_pstring(json_get(root, "name")); + info->profile_image_url = json_as_pstring(json_get(root, "profile_image_url")); + return true; } bool twitter::get_info_by_email(const std::string &email, twitter_user *info) @@ -235,44 +139,40 @@ bool twitter::get_info_by_email(const std::string &email, twitter_user *info) if (resp.code != 200) throw bad_response(); - js::variant var = json::parse(resp.data.begin(), resp.data.end()); - if (var->type() == typeid(js::object)) { - const js::object &user_info = boost::any_cast(*var); - if (user_info.find("error") != user_info.end()) - return false; - - info->username = retrieve(user_info, "screen_name"); - info->real_name = retrieve(user_info, "name", true); - info->profile_image_url = retrieve(user_info, "profile_image_url", true); + JSONNODE *root = json_parse(resp.data.c_str()); + if (root == NULL) + return false; - return true; - } - else + if (json_get(root, "error") != NULL) return false; + + info->username = json_as_pstring(json_get(root, "screen_name")); + info->real_name = json_as_pstring(json_get(root, "name")); + info->profile_image_url = json_as_pstring(json_get(root, "profile_image_url")); + return true; } twitter_user twitter::add_friend(const std::string &name) { std::string url = base_url_ + "1.1/friendships/create/" + http::url_encode(name) + ".json"; - twitter_user ret; http::response resp = slurp(url, http::post); if (resp.code != 200) throw bad_response(); - js::variant var = json::parse(resp.data.begin(), resp.data.end()); - if (var->type() != typeid(js::object)) + JSONNODE *root = json_parse(resp.data.c_str()); + if (root == NULL) throw std::exception("unable to parse response"); - const js::object &user_info = boost::any_cast(*var); - ret.username = retrieve(user_info, "screen_name"); - ret.real_name = retrieve(user_info, "name", true); - ret.profile_image_url = retrieve(user_info, "profile_image_url", true); - - if (user_info.find("status") != user_info.end()) { - // TODO: fill in more fields - const js::object &status = retrieve(user_info, "status"); - ret.status.text = retrieve(status, "text"); + twitter_user ret; + ret.username = json_as_pstring(json_get(root, "screen_name")); + ret.real_name = json_as_pstring(json_get(root, "name")); + ret.profile_image_url = json_as_pstring(json_get(root, "profile_image_url")); + + JSONNODE *pStatus = json_get(root, "status"); + if (pStatus != NULL) { + ret.status.text = json_as_pstring(json_get(pStatus, "text")); + ret.status.id = json_as_int(json_get(pStatus, "id")); } return ret; @@ -307,70 +207,67 @@ void twitter::send_direct(const std::string &name, const std::string &text) std::vector twitter::get_statuses(int count, twitter_id id) { - using boost::lexical_cast; std::vector statuses; std::string url = base_url_ + "1.1/statuses/home_timeline.json?count=" + - lexical_cast(count); + int2str(count); if (id != 0) - url += "&since_id=" + boost::lexical_cast(id); + url += "&since_id=" + int2str(id); http::response resp = slurp(url, http::get); if (resp.code != 200) throw bad_response(); - js::variant var = json::parse(resp.data.begin(), resp.data.end()); - if (var->type() != typeid(js::array)) + JSONNODE *root = json_parse(resp.data.c_str()); + if (root == NULL) throw std::exception("unable to parse response"); - const js::array &list = boost::any_cast(*var); - for (js::array::const_iterator i = list.begin(); i != list.end(); ++i) { - if ((*i)->type() == typeid(js::object)) { - const js::object &one = boost::any_cast(**i); - const js::object &user = retrieve(one, "user"); - - twitter_user u; - u.username = retrieve(user, "screen_name"); - u.profile_image_url = retrieve(user, "profile_image_url"); - - // the tweet will be truncated unless we take action. i hate you twitter API - if (one.find("retweeted_status") != one.end()) { - //MessageBox(NULL, L"retweeted: TRUE", L"long tweets", MB_OK); - // here we grab the "retweeted_status" um.. section? it's in here that all the info we need is - // at this point the user will get no tweets and an error popup if the tweet happens to be exactly 140 chars, start with - // "RT @", end in " ...", and notactually be a real retweet. it's possible but unlikely, wish i knew how to get - // the retweet_count variable to work :( - const js::object &Retweet = retrieve(one, "retweeted_status"); - const js::object &RTUser = retrieve(Retweet, "user"); - - std::string retweeteesName = retrieve(RTUser, "screen_name"); // the user that is being retweeted - std::string retweetText = retrieve(Retweet, "text"); // their tweet in all it's untruncated glory - - // fix "&" in the tweets :( - for (size_t pos = 0; (pos = retweetText.find("&", pos)) != std::string::npos; pos++) { - retweetText.replace(pos, 5, "&"); - } - - u.status.text = "RT @" + retweeteesName + " " + retweetText; // mash it together in some format people will understand - } - else { - // if it's not truncated, then the twitter API returns the native RT correctly anyway, - std::string rawText = retrieve(one, "text"); - // ok here i'm trying some way to fix all the "&" things that are showing up - // i dunno why it's happening, so i'll just find and replace each occurance :/ - for (size_t pos = 0; (pos = rawText.find("&", pos)) != std::string::npos; pos++) { - rawText.replace(pos, 5, "&"); - } - - u.status.text = rawText; - } - - u.status.id = retrieve(one, "id"); - std::string timestr = retrieve(one, "created_at"); - u.status.time = parse_time(timestr); - - statuses.push_back(u); + JSONNODE *pNodes = json_as_array(root); + for (int i = 0;; i++) { + JSONNODE *pNode = json_at(pNodes, i); + if (pNode == NULL) + break; + + JSONNODE *pUser = json_get(pNode, "user"); + + twitter_user u; + u.username = json_as_pstring(json_get(pUser, "screen_name")); + u.profile_image_url = json_as_pstring(json_get(pUser, "profile_image_url")); + + // the tweet will be truncated unless we take action. i hate you twitter API + JSONNODE *pStatus = json_get(pNode, "retweeted_status"); + if (pStatus != NULL) { + // here we grab the "retweeted_status" um.. section? it's in here that all the info we need is + // at this point the user will get no tweets and an error popup if the tweet happens to be exactly 140 chars, start with + // "RT @", end in " ...", and notactually be a real retweet. it's possible but unlikely, wish i knew how to get + // the retweet_count variable to work :( + JSONNODE *pUser2 = json_get(pStatus, "user"); + + std::string retweeteesName = json_as_pstring(json_get(pUser2, "screen_name")); // the user that is being retweeted + std::string retweetText = json_as_pstring(json_get(pUser2, "text")); // their tweet in all it's untruncated glory + + // fix "&" in the tweets :( + for (size_t pos = 0; (pos = retweetText.find("&", pos)) != std::string::npos; pos++) + retweetText.replace(pos, 5, "&"); + + u.status.text = "RT @" + retweeteesName + " " + retweetText; // mash it together in some format people will understand + } + else { + // if it's not truncated, then the twitter API returns the native RT correctly anyway, + std::string rawText = json_as_pstring(json_get(pNode, "text")); + // ok here i'm trying some way to fix all the "&" things that are showing up + // i dunno why it's happening, so i'll just find and replace each occurance :/ + for (size_t pos = 0; (pos = rawText.find("&", pos)) != std::string::npos; pos++) + rawText.replace(pos, 5, "&"); + + u.status.text = rawText; } + + u.status.id = json_as_int(json_get(pNode, "id")); + std::string timestr = json_as_pstring(json_get(pNode, "created_at")); + u.status.time = parse_time(timestr); + + statuses.push_back(u); } @@ -383,31 +280,30 @@ std::vector twitter::get_direct(twitter_id id) std::string url = base_url_ + "1.1/direct_messages.json"; if (id != 0) - url += "?since_id=" + boost::lexical_cast(id); + url += "?since_id=" + int2str(id); http::response resp = slurp(url, http::get); if (resp.code != 200) throw bad_response(); - js::variant var = json::parse(resp.data.begin(), resp.data.end()); - if (var->type() != typeid(js::array)) + JSONNODE *root = json_parse(resp.data.c_str()); + if (root == NULL) throw std::exception("unable to parse response"); - const js::array &list = boost::any_cast(*var); - for (js::array::const_iterator i = list.begin(); i != list.end(); ++i) { - if ((*i)->type() == typeid(js::object)) { - const js::object &one = boost::any_cast(**i); - - twitter_user u; - u.username = retrieve(one, "sender_screen_name"); + JSONNODE *pNodes = json_as_array(root); + for (int i = 0;; i++) { + JSONNODE *pNode = json_at(pNodes, i); + if (pNode == NULL) + break; - u.status.text = retrieve(one, "text"); - u.status.id = retrieve(one, "id"); - std::string timestr = retrieve(one, "created_at"); - u.status.time = parse_time(timestr); + twitter_user u; + u.username = json_as_pstring(json_get(pNode, "sender_screen_name")); - messages.push_back(u); - } + u.status.text = json_as_pstring(json_get(pNode, "text")); + u.status.id = json_as_int(json_get(pNode, "id")); + std::string timestr = json_as_pstring(json_get(pNode, "created_at")); + u.status.time = parse_time(timestr); + messages.push_back(u); } return messages; @@ -422,8 +318,8 @@ string twitter::urlencode(const string &c) if ((48 <= c[i] && c[i] <= 57) ||//0-9 (65 <= c[i] && c[i] <= 90) ||//ABC...XYZ (97 <= c[i] && c[i] <= 122) || //abc...xyz - (c[i] == '~' || c[i] == '-' || c[i] == '_' || c[i] == '.') - ) { + (c[i] == '~' || c[i] == '-' || c[i] == '_' || c[i] == '.')) + { escaped.append(&c[i], 1); } else { diff --git a/protocols/Twitter/src/ui.cpp b/protocols/Twitter/src/ui.cpp index c9b78db00f..de33178bbd 100644 --- a/protocols/Twitter/src/ui.cpp +++ b/protocols/Twitter/src/ui.cpp @@ -229,16 +229,12 @@ INT_PTR CALLBACK options_proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPar GetDlgItemTextA(hwndDlg, IDC_UN, str, SIZEOF(str)); db_set_s(0, proto->ModuleName(), TWITTER_KEY_UN, str); - /*GetDlgItemTextA(hwndDlg,IDC_PW,str,SIZEOF(str)); - CallService(MS_DB_CRYPT_ENCODESTRING,sizeof(str),reinterpret_cast(str)); - db_set_s(0,proto->ModuleName(),TWITTER_KEY_PASS,str);*/ - GetDlgItemTextA(hwndDlg, IDC_BASEURL, str, SIZEOF(str) - 1); if (str[strlen(str) - 1] != '/') strncat(str, "/", sizeof(str)); db_set_s(0, proto->ModuleName(), TWITTER_KEY_BASEURL, str); - db_set_b(0, proto->ModuleName(), TWITTER_KEY_CHATFEED, IsDlgButtonChecked(hwndDlg, IDC_CHATFEED)); + db_set_b(0, proto->ModuleName(), TWITTER_KEY_CHATFEED, IsDlgButtonChecked(hwndDlg, IDC_CHATFEED) != 0); GetDlgItemTextA(hwndDlg, IDC_POLLRATE, str, SIZEOF(str)); int rate = atoi(str); @@ -246,7 +242,7 @@ INT_PTR CALLBACK options_proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPar rate = 80; db_set_dw(0, proto->ModuleName(), TWITTER_KEY_POLLRATE, rate); - db_set_b(0, proto->ModuleName(), TWITTER_KEY_TWEET_TO_MSG, IsDlgButtonChecked(hwndDlg, IDC_TWEET_MSG)); + db_set_b(0, proto->ModuleName(), TWITTER_KEY_TWEET_TO_MSG, IsDlgButtonChecked(hwndDlg, IDC_TWEET_MSG) != 0); proto->UpdateSettings(); return true; @@ -275,7 +271,7 @@ namespace popup_options { if (IsDlgButtonChecked(hwndDlg, IDC_COL_WINDOWS)) { if (for_db) - return -1; + return (COLORREF)-1; else return GetSysColor(COLOR_WINDOWTEXT); } @@ -289,7 +285,7 @@ namespace popup_options { if (IsDlgButtonChecked(hwndDlg, IDC_COL_WINDOWS)) { if (for_db) - return -1; + return (COLORREF)-1; else return GetSysColor(COLOR_WINDOW); } @@ -449,7 +445,7 @@ INT_PTR CALLBACK popup_options_proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARA if (reinterpret_cast(lParam)->code == PSN_APPLY) { proto = reinterpret_cast(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); - db_set_b(0, proto->ModuleName(), TWITTER_KEY_POPUP_SHOW, IsDlgButtonChecked(hwndDlg, IDC_SHOWPOPUPS)); + db_set_b(0, proto->ModuleName(), TWITTER_KEY_POPUP_SHOW, IsDlgButtonChecked(hwndDlg, IDC_SHOWPOPUPS) != 0); db_set_b(0, proto->ModuleName(), TWITTER_KEY_POPUP_SIGNON, BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_NOSIGNONPOPUPS)); // ***** Write color settings diff --git a/protocols/Twitter/src/utility.cpp b/protocols/Twitter/src/utility.cpp index 46e3c07d60..dcdda75a9e 100644 --- a/protocols/Twitter/src/utility.cpp +++ b/protocols/Twitter/src/utility.cpp @@ -26,6 +26,20 @@ std::string b64encode(const std::string &s) return std::string(ptrA(mir_base64_encode((BYTE*)s.c_str(), (unsigned)s.length()))); } +std::string int2str(int32_t iVal) +{ + char buf[100]; + _itoa_s(iVal, buf, 10); + return std::string(buf); +} + +std::string int2str(uint64_t iVal) +{ + char buf[100]; + _i64toa_s(iVal, buf, _countof(buf), 10); + return std::string(buf); +} + http::response mir_twitter::slurp(const std::string &url, http::method meth, OAuthParameters postParams) { NETLIBHTTPREQUEST req = { sizeof(req) }; diff --git a/protocols/Twitter/src/utility.h b/protocols/Twitter/src/utility.h index fec8d6b23c..3736ca2928 100644 --- a/protocols/Twitter/src/utility.h +++ b/protocols/Twitter/src/utility.h @@ -23,6 +23,9 @@ along with this program. If not, see . std::string b64encode(const std::string &s); +std::string int2str(int32_t); +std::string int2str(uint64_t); + class mir_twitter : public twitter { public: @@ -51,8 +54,7 @@ public: std::wstring OAuthWebRequestSubmit( const OAuthParameters& parameters, - const std::wstring& url - ); + const std::wstring& url); std::wstring UrlGetQuery( const std::wstring& url ); diff --git a/protocols/Twitter/src/version.h b/protocols/Twitter/src/version.h index b4ea3e65fb..9776a81b61 100644 --- a/protocols/Twitter/src/version.h +++ b/protocols/Twitter/src/version.h @@ -1,5 +1,5 @@ #define __MAJOR_VERSION 1 -#define __MINOR_VERSION 2 +#define __MINOR_VERSION 3 #define __RELEASE_NUM 0 #define __BUILD_NUM 1 diff --git a/protocols/Twitter/twitter.vcxproj.filters b/protocols/Twitter/twitter.vcxproj.filters index 6e2fab6493..de5ad9f66c 100644 --- a/protocols/Twitter/twitter.vcxproj.filters +++ b/protocols/Twitter/twitter.vcxproj.filters @@ -1,335 +1,4 @@  - - - Source Files - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - Source Files - - - - - - - - - - - - - - - - Header Files - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - Header Files - - - - - - - - - - - - - - - Resource Files - - - - Resource Files - - - \ No newline at end of file -- cgit v1.2.3