diff options
Diffstat (limited to 'plugins/Quotes/QuotesProviderGoogle.cpp')
-rw-r--r-- | plugins/Quotes/QuotesProviderGoogle.cpp | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/plugins/Quotes/QuotesProviderGoogle.cpp b/plugins/Quotes/QuotesProviderGoogle.cpp new file mode 100644 index 0000000000..7711c2d9ba --- /dev/null +++ b/plugins/Quotes/QuotesProviderGoogle.cpp @@ -0,0 +1,543 @@ +#include "StdAfx.h"
+#include "QuotesProviderGoogle.h"
+#include "resource.h"
+#include "HTTPSession.h"
+#include "Log.h"
+#include "DBUtils.h"
+#include "EconomicRateInfo.h"
+#include "ModuleInfo.h"
+#include "QuotesProviders.h"
+#include "IHTMLParser.h"
+#include "IHTMLEngine.h"
+#include "CommonOptionDlg.h"
+#include "QuotesProviderVisitor.h"
+
+CQuotesProviderGoogle::CQuotesProviderGoogle()
+{
+}
+
+CQuotesProviderGoogle::~CQuotesProviderGoogle()
+{
+}
+
+namespace
+{
+ inline tstring make_contact_name(const tstring& rsSymbolFrom,const tstring& rsSymbolTo)
+ {
+ tostringstream o;
+ o << rsSymbolFrom << _T("/") << rsSymbolTo;
+ return o.str();
+ }
+
+ inline bool is_rate_watched(HANDLE hContact,
+ const CQuotesProviderBase::CQuote& from,
+ const CQuotesProviderBase::CQuote& to)
+ {
+ tstring sFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID);
+ tstring sTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID);
+ return ((0 == quotes_stricmp(from.GetID().c_str(),sFrom.c_str()))
+ && (0 == quotes_stricmp(to.GetID().c_str(),sTo.c_str())));
+ }
+}
+
+bool CQuotesProviderGoogle::WatchForRate(const CRateInfo& ri,
+ bool bWatch)
+{
+ TContracts::const_iterator i = std::find_if(m_aContacts.begin(),m_aContacts.end(),
+ boost::bind(is_rate_watched,_1,ri.m_from,ri.m_to));
+ if((true == bWatch) && (i == m_aContacts.end()))
+ {
+ tstring sName = make_contact_name(ri.m_from.GetSymbol(),ri.m_to.GetSymbol());
+ HANDLE hContact = CreateNewContact(sName);
+ if(hContact)
+ {
+ DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID,ri.m_from.GetID().c_str());
+ DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID,ri.m_to.GetID().c_str());
+ if(false == ri.m_from.GetName().empty())
+ {
+ DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_DESCRIPTION,ri.m_from.GetName().c_str());
+ }
+ if(false == ri.m_to.GetName().empty())
+ {
+ DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_DESCRIPTION,ri.m_to.GetName().c_str());
+ }
+
+ return true;
+ }
+ }
+ else if((false == bWatch) && (i != m_aContacts.end()))
+ {
+ HANDLE hContact = *i;
+ {// for CCritSection
+ CGuard<CLightMutex> cs(m_cs);
+ m_aContacts.erase(i);
+ }
+
+ CallService(MS_DB_CONTACT_DELETE,reinterpret_cast<WPARAM>(hContact),0);
+ return true;
+ }
+
+ return false;
+}
+
+size_t CQuotesProviderGoogle::GetWatchedRateCount()const
+{
+ return m_aContacts.size();
+}
+
+bool CQuotesProviderGoogle::GetWatchedRateInfo(size_t nIndex,CRateInfo& rRateInfo)
+{
+ if(nIndex < m_aContacts.size())
+ {
+ HANDLE hContact = m_aContacts[nIndex];
+ tstring sSymbolFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID);
+ tstring sSymbolTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID);
+ tstring sDescFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_DESCRIPTION);
+ tstring sDescTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_DESCRIPTION);
+
+ rRateInfo.m_from = CQuote(sSymbolFrom,sSymbolFrom,sDescFrom);
+ rRateInfo.m_to = CQuote(sSymbolTo,sSymbolTo,sDescTo);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+namespace
+{
+ tstring build_url(const tstring& rsURL,const tstring& from,const tstring& to,double dAmount)
+ {
+ tostringstream o;
+ o << rsURL << _T("?a=") << std::fixed << dAmount << _T("&from=") << from << _T("&to=") << to;
+ return o.str();
+ }
+ tstring build_url(HANDLE hContact,const tstring& rsURL,double dAmount = 1.0)
+ {
+ tstring sFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID);
+ tstring sTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID);
+ return build_url(rsURL,sFrom,sTo,dAmount);
+ }
+
+ typedef IHTMLNode::THTMLNodePtr THTMLNodePtr;
+
+ bool parse_html_node(const THTMLNodePtr& pNode,double& rdRate)
+ {
+ tstring sID = pNode->GetAttribute(_T("id"));
+ if((false == sID.empty()) && (0 == quotes_stricmp(sID.c_str(),_T("currency_converter_result"))))
+ {
+ size_t cChild = pNode->GetChildCount();
+// assert(1 == cChild);
+ if(cChild > 0)
+ {
+ THTMLNodePtr pChild = pNode->GetChildPtr(0);
+ tstring sRate = pChild->GetText();
+
+ tistringstream input(sRate);
+ input >> rdRate;
+
+ return ((false == input.bad()) && (false == input.fail()));
+ }
+ }
+ else
+ {
+ size_t cChild = pNode->GetChildCount();
+ for(size_t i = 0;i < cChild;++i)
+ {
+ THTMLNodePtr pChild = pNode->GetChildPtr(i);
+ if(pChild && (true == parse_html_node(pChild,rdRate)))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool parse_responce(const tstring& rsHTML,double& rdRate)
+ {
+ IHTMLEngine::THTMLParserPtr pHTMLParser = CModuleInfo::GetHTMLEngine()->GetParserPtr();
+ THTMLNodePtr pRoot = pHTMLParser->ParseString(rsHTML);
+ if(pRoot)
+ {
+ return parse_html_node(pRoot,rdRate);
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+void CQuotesProviderGoogle::RefreshQuotes(TContracts& anContacts)
+{
+ CHTTPSession http;
+ tstring sURL = GetURL();
+
+ bool bUseExtendedStatus = CModuleInfo::GetInstance().GetExtendedStatusFlag();
+
+ for(TContracts::const_iterator i = anContacts.begin();i != anContacts.end() && IsOnline();++i)
+ {
+ HANDLE hContact = *i;
+
+ if(bUseExtendedStatus)
+ {
+ SetContactStatus(hContact,ID_STATUS_OCCUPIED);
+ }
+
+ tstring sFullURL = build_url(hContact,sURL);
+// LogIt(Info,sFullURL);
+ if((true == http.OpenURL(sFullURL)) && (true == IsOnline()))
+ {
+ tstring sHTML;
+ if((true == http.ReadResponce(sHTML)) && (true == IsOnline()))
+ {
+// LogIt(Info,sHTML);
+
+ double dRate = 0.0;
+ if((true == parse_responce(sHTML,dRate)) && (true == IsOnline()))
+ {
+ WriteContactRate(hContact,dRate);
+ continue;
+ }
+ }
+ }
+
+ SetContactStatus(hContact,ID_STATUS_NA);
+ }
+}
+
+namespace
+{
+ inline tstring make_quote_name(const CQuotesProviderGoogle::CQuote& rQuote)
+ {
+ const tstring& rsDesc = rQuote.GetName();
+ return((false == rsDesc.empty()) ? rsDesc : rQuote.GetSymbol());
+ }
+
+ CQuotesProviderGoogle* get_google_provider()
+ {
+ CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr();
+ const CQuotesProviders::TQuotesProviders& rapQuotesProviders = pProviders->GetProviders();
+ for(CQuotesProviders::TQuotesProviders::const_iterator i = rapQuotesProviders.begin();i != rapQuotesProviders.end();++i)
+ {
+ const CQuotesProviders::TQuotesProviderPtr& pProvider = *i;
+ CQuotesProviderGoogle* pGoogle = dynamic_cast<CQuotesProviderGoogle*>(pProvider.get());
+ if(pGoogle)
+ {
+ return pGoogle;
+ }
+ }
+
+ assert(!"We should never get here!");
+ return NULL;
+ }
+
+ CQuotesProviderGoogle::CQuoteSection get_quotes()
+ {
+ const CQuotesProviderGoogle* pProvider = get_google_provider();
+ if(pProvider)
+ {
+ const CQuotesProviderGoogle::CQuoteSection& rQuotes = pProvider->GetQuotes();
+ if(rQuotes.GetSectionCount() > 0)
+ {
+ return rQuotes.GetSection(0);
+ }
+ }
+
+ return CQuotesProviderGoogle::CQuoteSection();
+ }
+
+ tstring make_rate_name(const CQuotesProviderGoogle::CQuote& rFrom,
+ const CQuotesProviderGoogle::CQuote& rTo)
+ {
+ if((false == rFrom.GetName().empty()) && (false == rTo.GetName().empty()))
+ {
+ return make_contact_name(rFrom.GetName(),rTo.GetName());
+ }
+ else
+ {
+ return make_contact_name(rFrom.GetSymbol(),rTo.GetSymbol());
+ }
+ }
+
+ typedef std::vector<CQuotesProviderGoogle::CRateInfo> TWatchedRates;
+ TWatchedRates g_aWatchedRates;
+
+ bool is_equal_rate(const CQuotesProviderGoogle::CRateInfo& riL,const CQuotesProviderGoogle::CRateInfo& riR)
+ {
+ return ((0 == quotes_stricmp(riL.m_from.GetID().c_str(),riR.m_from.GetID().c_str()))
+ && ((0 == quotes_stricmp(riL.m_to.GetID().c_str(),riR.m_to.GetID().c_str()))));
+ }
+
+ INT_PTR CALLBACK GoogleOptDlgProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam)
+ {
+ CQuotesProviderGoogle* pProvider = get_google_provider();
+
+ CCommonDlgProcData d(pProvider);
+ CommonOptionDlgProc(hdlg,message,wParam,lParam,d);
+
+ switch(message)
+ {
+ case WM_NOTIFY:
+ {
+ LPNMHDR pNMHDR = reinterpret_cast<LPNMHDR>(lParam);
+ switch(pNMHDR->code)
+ {
+ case PSN_APPLY:
+ {
+ if(pProvider)
+ {
+ TWatchedRates aTemp(g_aWatchedRates);
+ TWatchedRates aRemove;
+ size_t cWatchedRates = pProvider->GetWatchedRateCount();
+ for(size_t i = 0;i < cWatchedRates;++i)
+ {
+ CQuotesProviderGoogle::CRateInfo ri;
+ if(true == pProvider->GetWatchedRateInfo(i,ri))
+ {
+ TWatchedRates::iterator it =
+ std::find_if(aTemp.begin(),aTemp.end(),
+ boost::bind(is_equal_rate,_1,boost::cref(ri)));
+ if(it == aTemp.end())
+ {
+ aRemove.push_back(ri);
+ }
+ else
+ {
+ aTemp.erase(it);
+ }
+ }
+ }
+
+ std::for_each(aRemove.begin(),aRemove.end(),boost::bind(&CQuotesProviderGoogle::WatchForRate,pProvider,_1,false));
+ std::for_each(aTemp.begin(),aTemp.end(),boost::bind(&CQuotesProviderGoogle::WatchForRate,pProvider,_1,true));
+
+ pProvider->RefreshAll();
+ }
+ }
+ break;
+ }
+ }
+ break;
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hdlg);
+
+ g_aWatchedRates.clear();
+
+ HWND hcbxFrom = ::GetDlgItem(hdlg,IDC_COMBO_CONVERT_FROM);
+ HWND hcbxTo = ::GetDlgItem(hdlg,IDC_COMBO_CONVERT_INTO);
+
+ const CQuotesProviderGoogle::CQuoteSection& rSection = get_quotes();
+ size_t cQuotes = rSection.GetQuoteCount();
+ for(size_t i = 0;i < cQuotes;++i)
+ {
+ const CQuotesProviderGoogle::CQuote& rQuote = rSection.GetQuote(i);
+ tstring sName = make_quote_name(rQuote);
+ LPCTSTR pszName = sName.c_str();
+ ::SendMessage(hcbxFrom,CB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszName));
+ ::SendMessage(hcbxTo,CB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszName));
+ }
+
+ CQuotesProviderGoogle* pProvider = get_google_provider();
+ if(pProvider)
+ {
+ size_t cWatchedRates = pProvider->GetWatchedRateCount();
+ for(size_t i = 0;i < cWatchedRates;++i)
+ {
+ CQuotesProviderGoogle::CRateInfo ri;
+ if(true == pProvider->GetWatchedRateInfo(i,ri))
+ {
+ g_aWatchedRates.push_back(ri);
+ tstring sRate = make_rate_name(ri.m_from,ri.m_to);
+ LPCTSTR pszRateName = sRate.c_str();
+ ::SendMessage(::GetDlgItem(hdlg,IDC_LIST_RATES),LB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszRateName));
+ }
+ }
+ }
+
+ ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_ADD),FALSE);
+ ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_REMOVE),FALSE);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(HIWORD(wParam))
+ {
+ case CBN_SELCHANGE:
+ switch(LOWORD(wParam))
+ {
+ case IDC_COMBO_REFRESH_RATE:
+ break;
+ case IDC_COMBO_CONVERT_FROM:
+ case IDC_COMBO_CONVERT_INTO:
+ {
+ int nFrom = static_cast<int>(::SendMessage(::GetDlgItem(hdlg,IDC_COMBO_CONVERT_FROM),CB_GETCURSEL,0,0));
+ int nTo = static_cast<int>(::SendMessage(::GetDlgItem(hdlg,IDC_COMBO_CONVERT_INTO),CB_GETCURSEL,0,0));
+ bool bEnableAddButton = ((CB_ERR != nFrom) && (CB_ERR != nTo) && (nFrom != nTo));
+ EnableWindow(GetDlgItem(hdlg,IDC_BUTTON_ADD),bEnableAddButton);
+ }
+ break;
+ case IDC_LIST_RATES:
+ {
+ int nSel = ::SendMessage(::GetDlgItem(hdlg,IDC_LIST_RATES),LB_GETCURSEL,0,0);
+ ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_REMOVE),(LB_ERR != nSel));
+ }
+ break;
+ }
+ break;
+ case BN_CLICKED:
+ switch(LOWORD(wParam))
+ {
+ case IDC_BUTTON_ADD:
+ {
+ size_t nFrom = static_cast<size_t>(::SendMessage(::GetDlgItem(hdlg,IDC_COMBO_CONVERT_FROM),CB_GETCURSEL,0,0));
+ size_t nTo = static_cast<size_t>(::SendMessage(::GetDlgItem(hdlg,IDC_COMBO_CONVERT_INTO),CB_GETCURSEL,0,0));
+ if((CB_ERR != nFrom) && (CB_ERR != nTo) && (nFrom != nTo))
+ {
+ const CQuotesProviderGoogle::CQuoteSection& rSection = get_quotes();
+ size_t cQuotes = rSection.GetQuoteCount();
+ if((nFrom < cQuotes) && (nTo < cQuotes))
+ {
+ CQuotesProviderGoogle::CRateInfo ri;
+ ri.m_from = rSection.GetQuote(nFrom);
+ ri.m_to = rSection.GetQuote(nTo);
+
+ g_aWatchedRates.push_back(ri);
+
+ tstring sRate = make_rate_name(ri.m_from,ri.m_to);
+ LPCTSTR pszRateName = sRate.c_str();
+ ::SendMessage(::GetDlgItem(hdlg,IDC_LIST_RATES),LB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszRateName));
+ PropSheet_Changed(::GetParent(hdlg),hdlg);
+ }
+ }
+ }
+ break;
+ case IDC_BUTTON_REMOVE:
+ {
+ HWND hWnd = ::GetDlgItem(hdlg,IDC_LIST_RATES);
+ int nSel = ::SendMessage(hWnd,LB_GETCURSEL,0,0);
+ if(LB_ERR != nSel)
+ {
+ if((LB_ERR != ::SendMessage(hWnd, LB_DELETESTRING,nSel,0))
+ && (nSel < static_cast<int>(g_aWatchedRates.size())))
+ {
+
+ TWatchedRates::iterator i = g_aWatchedRates.begin();
+ std::advance(i,nSel);
+ g_aWatchedRates.erase(i);
+ PropSheet_Changed(::GetParent(hdlg),hdlg);
+ }
+ }
+
+ nSel = ::SendMessage(hWnd,LB_GETCURSEL,0,0);
+ ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_REMOVE),(LB_ERR != nSel));
+ }
+ break;
+ }
+ break;
+// case LBN_SELCHANGE:
+// switch(LOWORD(lParam))
+// {
+// case IDC_LIST_RATES:
+// {
+// int nSel = ::SendMessage(::GetDlgItem(hdlg,IDC_LIST_RATES),LB_GETCURSEL,0,0);
+// ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_REMOVE),(-1 != nSel));
+// }
+// }
+// break;
+ }
+ break;
+
+ }
+
+ return FALSE;
+ }
+}
+
+void CQuotesProviderGoogle::ShowPropertyPage(WPARAM wp,OPTIONSDIALOGPAGE& odp)
+{
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG_OPT_GOOGLE);
+ odp.pfnDlgProc = GoogleOptDlgProc;
+// #if MIRANDA_VER >= 0x0600
+ //odp.ptszTab = TranslateTS(const_cast<LPTSTR>(GetInfo().m_sName.c_str()));
+ odp.ptszTab = const_cast<LPTSTR>(GetInfo().m_sName.c_str());
+// #else
+// tostringstream o;
+// o << TranslateTS(QUOTES_PROTOCOL_NAME) << _T(" - ") << TranslateTS(GetInfo().m_sName.c_str());
+// tstring sTitle = o.str();
+// odp.ptszTitle = TranslateTS(const_cast<LPTSTR>(sTitle.c_str()));
+// #endif
+ CallService(MS_OPT_ADDPAGE,wp,reinterpret_cast<LPARAM>(&odp));
+}
+
+void CQuotesProviderGoogle::Accept(CQuotesProviderVisitor& visitor)const
+{
+ CQuotesProviderBase::Accept(visitor);
+ visitor.Visit(*this);
+}
+
+double CQuotesProviderGoogle::Convert(double dAmount,const CQuote& from,const CQuote& to)const
+{
+ tstring sFullURL = build_url(GetURL(),from.GetID(),to.GetID(),dAmount);
+// LogIt(Info,sFullURL);
+
+ CHTTPSession http;
+ if((true == http.OpenURL(sFullURL)))
+ {
+ tstring sHTML;
+ if((true == http.ReadResponce(sHTML)))
+ {
+// LogIt(Info,sHTML);
+
+ double dResult = 0.0;
+ if((true == parse_responce(sHTML,dResult)))
+ {
+ return dResult;
+ }
+ else
+ {
+ throw std::runtime_error(Translate("Error occurred during html parsing."));
+ }
+ }
+ else
+ {
+ throw std::runtime_error(Translate("Error occurred during site access."));
+ }
+ }
+ else
+ {
+ throw std::runtime_error(Translate("Error occurred during site access."));
+ }
+
+ return 0.0;
+}
+
+namespace
+{
+ bool is_equal_ids(HANDLE hContact,const tstring& rsFromID,const tstring& rsToID)
+ {
+ tstring sFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID);
+ tstring sTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID);
+ return ((0 == quotes_stricmp(rsFromID.c_str(),sFrom.c_str()))
+ && (0 == quotes_stricmp(rsToID.c_str(),sTo.c_str())));
+ }
+}
+
+HANDLE CQuotesProviderGoogle::GetContactByID(const tstring& rsFromID,const tstring& rsToID)const
+{
+ CGuard<CLightMutex> cs(m_cs);
+
+ TContracts::const_iterator i = std::find_if(m_aContacts.begin(),m_aContacts.end(),
+ boost::bind(is_equal_ids,_1,boost::cref(rsFromID),boost::cref(rsToID)));
+ if(i != m_aContacts.end())
+ {
+ return *i;
+ }
+ else
+ {
+ return NULL;
+ }
+}
|