#include "StdAfx.h" extern bool g_bAutoUpdate; extern HANDLE g_hEventWorkThreadStop; struct CQuotesProviderBase::CXMLFileInfo { CXMLFileInfo() : m_qs(_T("Unknown")){} IQuotesProvider::CProviderInfo m_pi; CQuotesProviderBase::CQuoteSection m_qs; tstring m_sURL; }; namespace { inline tstring get_ini_file_name(LPCTSTR pszFileName) { return CreateFilePath(pszFileName); } bool parse_quote(const IXMLNode::TXMLNodePtr& pTop,CQuotesProviderBase::CQuote& q) { tstring sSymbol; tstring sDescription; tstring sID; size_t cChild = pTop->GetChildCount(); for(size_t i = 0;i < cChild;++i) { IXMLNode::TXMLNodePtr pNode = pTop->GetChildNode(i); tstring sName = pNode->GetName(); if(0 == quotes_stricmp(_T("symbol"),sName.c_str())) { sSymbol = pNode->GetText(); if(true == sSymbol.empty()) { return false; } } else if(0 == quotes_stricmp(_T("description"),sName.c_str())) { sDescription = pNode->GetText(); } else if(0 == quotes_stricmp(_T("id"),sName.c_str())) { sID = pNode->GetText(); if(true == sID.empty()) { return false; } } } q = CQuotesProviderBase::CQuote(sID,TranslateTS(sSymbol.c_str()),TranslateTS(sDescription.c_str())); return true; } bool parse_section(const IXMLNode::TXMLNodePtr& pTop,CQuotesProviderBase::CQuoteSection& qs) { CQuotesProviderBase::CQuoteSection::TSections aSections; CQuotesProviderBase::CQuoteSection::TQuotes aQuotes; tstring sSectionName; size_t cChild = pTop->GetChildCount(); for(size_t i = 0;i < cChild;++i) { IXMLNode::TXMLNodePtr pNode = pTop->GetChildNode(i); tstring sName = pNode->GetName(); if(0 == quotes_stricmp(_T("section"),sName.c_str())) { CQuotesProviderBase::CQuoteSection qs; if(true == parse_section(pNode,qs)) { aSections.push_back(qs); } } else if(0 == quotes_stricmp(_T("quote"),sName.c_str())) { CQuotesProviderBase::CQuote q; if(true == parse_quote(pNode,q)) { aQuotes.push_back(q); } } else if(0 == quotes_stricmp(_T("name"),sName.c_str())) { sSectionName = pNode->GetText(); if(true == sSectionName.empty()) { return false; } } } qs = CQuotesProviderBase::CQuoteSection(TranslateTS(sSectionName.c_str()),aSections,aQuotes); return true; } IXMLNode::TXMLNodePtr find_provider(const IXMLNode::TXMLNodePtr& pRoot) { IXMLNode::TXMLNodePtr pProvider; size_t cChild = pRoot->GetChildCount(); for(size_t i = 0;i < cChild;++i) { IXMLNode::TXMLNodePtr pNode = pRoot->GetChildNode(i); tstring sName = pNode->GetName(); if(0 == quotes_stricmp(_T("Provider"),sName.c_str())) { pProvider = pNode; break; } else { pProvider = find_provider(pNode); if(pProvider) { break; } } } return pProvider; } CQuotesProviderBase::CXMLFileInfo parse_ini_file(const tstring& rsXMLFile,bool& rbSucceded) { CQuotesProviderBase::CXMLFileInfo res; CQuotesProviderBase::CQuoteSection::TSections aSections; const CModuleInfo::TXMLEnginePtr& pXMLEngine = CModuleInfo::GetXMLEnginePtr(); IXMLNode::TXMLNodePtr pRoot = pXMLEngine->LoadFile(rsXMLFile); if(pRoot) { IXMLNode::TXMLNodePtr pProvider = find_provider(pRoot); if(pProvider) { rbSucceded = true; size_t cChild = pProvider->GetChildCount(); for(size_t i = 0;i < cChild;++i) { IXMLNode::TXMLNodePtr pNode = pProvider->GetChildNode(i); tstring sName = pNode->GetName(); if(0 == quotes_stricmp(_T("section"),sName.c_str())) { CQuotesProviderBase::CQuoteSection qs; if(true == parse_section(pNode,qs)) { aSections.push_back(qs); } } else if(0 == quotes_stricmp(_T("Name"),sName.c_str())) { res.m_pi.m_sName = pNode->GetText(); } else if(0 == quotes_stricmp(_T("ref"),sName.c_str())) { res.m_pi.m_sURL = pNode->GetText(); } else if(0 == quotes_stricmp(_T("url"),sName.c_str())) { res.m_sURL = pNode->GetText(); } } } } res.m_qs = CQuotesProviderBase::CQuoteSection(res.m_pi.m_sName,aSections); return res; } CQuotesProviderBase::CXMLFileInfo init_xml_info(LPCTSTR pszFileName,bool& rbSucceded) { rbSucceded = false; tstring sIniFile = get_ini_file_name(pszFileName); return parse_ini_file(sIniFile,rbSucceded); } } CQuotesProviderBase::CQuotesProviderBase() : m_hEventSettingsChanged(::CreateEvent(NULL,FALSE,FALSE,NULL)), m_hEventRefreshContact(::CreateEvent(NULL,FALSE,FALSE,NULL)), m_bRefreshInProgress(false) { } CQuotesProviderBase::~CQuotesProviderBase() { ::CloseHandle(m_hEventSettingsChanged); ::CloseHandle(m_hEventRefreshContact); } bool CQuotesProviderBase::Init() { bool bSucceded = m_pXMLInfo != NULL; if(!m_pXMLInfo) { CQuotesProviderVisitorDbSettings visitor; Accept(visitor); assert(visitor.m_pszXMLIniFileName); m_pXMLInfo.reset(new CXMLFileInfo(init_xml_info(visitor.m_pszXMLIniFileName,bSucceded))); } return bSucceded; } CQuotesProviderBase::CXMLFileInfo* CQuotesProviderBase::GetXMLFileInfo()const { // if(!m_pXMLInfo) // { // CQuotesProviderVisitorDbSettings visitor; // Accept(visitor); // assert(visitor.m_pszXMLIniFileName); // m_pXMLInfo.reset(new CXMLFileInfo(init_xml_info(visitor.m_pszXMLIniFileName))); // } return m_pXMLInfo.get(); } const CQuotesProviderBase::CProviderInfo& CQuotesProviderBase::GetInfo()const { return GetXMLFileInfo()->m_pi; } const CQuotesProviderBase::CQuoteSection& CQuotesProviderBase::GetQuotes()const { return GetXMLFileInfo()->m_qs; } const tstring& CQuotesProviderBase::GetURL()const { return GetXMLFileInfo()->m_sURL; } bool CQuotesProviderBase::IsOnline() { return /*g_bAutoUpdate*/true; } void CQuotesProviderBase::AddContact(MCONTACT hContact) { // CCritSection cs(m_cs); assert(m_aContacts.end() == std::find(m_aContacts.begin(),m_aContacts.end(),hContact)); m_aContacts.push_back(hContact); } void CQuotesProviderBase::DeleteContact(MCONTACT hContact) { CGuard cs(m_cs); TContracts::iterator i = std::find(m_aContacts.begin(),m_aContacts.end(),hContact); if(i != m_aContacts.end()) { m_aContacts.erase(i); } } void CQuotesProviderBase::SetContactStatus(MCONTACT hContact,int nNewStatus) { int nStatus = db_get_w(hContact,QUOTES_PROTOCOL_NAME,DB_STR_STATUS,ID_STATUS_OFFLINE); if(nNewStatus != nStatus) { db_set_w(hContact,QUOTES_PROTOCOL_NAME,DB_STR_STATUS,nNewStatus); if(ID_STATUS_ONLINE != nNewStatus) { db_unset(hContact,LIST_MODULE_NAME,STATUS_MSG_NAME); tstring sSymbol = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_SYMBOL); if(false == sSymbol.empty()) { db_set_ts(hContact,LIST_MODULE_NAME,CONTACT_LIST_NAME,sSymbol.c_str()); } CExtraImages::GetInstance().SetContactExtraImage(hContact,CExtraImages::eiEmpty); } } } namespace { class CTendency { enum{NumValues = 2}; enum EComparison { NonValid, Greater, Less, Equal, GreaterOrEqual, LessOrEqual }; public: enum EResult { NotChanged, Up, Down }; public: CTendency() : m_nComparison(NonValid){} bool Parse(const IQuotesProvider* pProvider,const tstring& rsFrmt,MCONTACT hContact) { m_abValueFlags[0] = false; m_abValueFlags[1] = false; m_nComparison = NonValid; bool bValid = true; int nCurValue = 0; for(tstring::const_iterator i = rsFrmt.begin();i != rsFrmt.end() && bValid && nCurValue < NumValues;) { TCHAR chr = *i; switch(chr) { default: if(false == std::isspace(chr)) { bValid = false; } else { ++i; } break; case _T('%'): ++i; if(i != rsFrmt.end()) { TCHAR t = *i; ++i; CQuotesProviderVisitorTendency visitor(hContact,t); pProvider->Accept(visitor); if(false == visitor.IsValid()) { bValid = false; } else { double d = visitor.GetResult(); m_adValues[nCurValue] = d; m_abValueFlags[nCurValue] = true; ++nCurValue; } } else { bValid = false; } break; case _T('>'): m_nComparison = Greater; ++i; break; case _T('<'): m_nComparison = Less; ++i; break; case _T('='): switch(m_nComparison) { default: bValid = false; break; case NonValid: m_nComparison = Equal; break; case Greater: m_nComparison = GreaterOrEqual; break; case Less: m_nComparison = LessOrEqual; break; } ++i; break; } } return (bValid && IsValid()); } bool IsValid()const{return (m_abValueFlags[0] && m_abValueFlags[1] && (m_nComparison != NonValid));} EResult Compare()const { switch(m_nComparison) { case Greater: if(true == IsWithinAccuracy(m_adValues[0],m_adValues[1])) { return NotChanged; } else if(m_adValues[0] > m_adValues[1]) { return Up; } else //if(m_adValues[0] < m_adValues[1]) { return Down; } break; case GreaterOrEqual: if((true == IsWithinAccuracy(m_adValues[0],m_adValues[1])) || (m_adValues[0] > m_adValues[1])) { return Up; } else //if(m_adValues[0] < m_adValues[1]) { return Down; } break; case Less: if(true == IsWithinAccuracy(m_adValues[0],m_adValues[1])) { return NotChanged; } else if(m_adValues[0] < m_adValues[1]) { return Up; } else //if(m_adValues[0] > m_adValues[1]) { return Down; } break; case LessOrEqual: if((true == IsWithinAccuracy(m_adValues[0],m_adValues[1])) || (m_adValues[0] < m_adValues[1])) { return Up; } else //if(m_adValues[0] > m_adValues[1]) { return Down; } break; case Equal: if(true == IsWithinAccuracy(m_adValues[0],m_adValues[1])) { return Up; } else { return Down; } break; } return NotChanged; } private: double m_adValues[NumValues]; bool m_abValueFlags[NumValues]; EComparison m_nComparison; }; tstring format_rate(const IQuotesProvider* pProvider, MCONTACT hContact, const tstring& rsFrmt, double dRate) { tstring sResult; for(tstring::const_iterator i = rsFrmt.begin();i != rsFrmt.end();) { TCHAR chr = *i; switch(chr) { default: sResult += chr; ++i; break; case _T('\\'): ++i; if(i != rsFrmt.end()) { TCHAR t = *i; switch(t) { case _T('%'):sResult += _T("%"); break; case _T('t'):sResult += _T("\t"); break; case _T('n'):sResult += _T("\n"); break; case _T('\\'):sResult += _T("\\"); break; default:sResult += chr;sResult += t;break; } ++i; } else { sResult += chr; } break; case _T('%'): ++i; if(i != rsFrmt.end()) { chr = *i; byte nWidth = 0; if(::isdigit(chr)) { nWidth = chr-0x30; ++i; if(i == rsFrmt.end()) { sResult += chr; break; } else { chr = *i; } } CQuotesProviderVisitorFormater visitor(hContact,chr,nWidth); pProvider->Accept(visitor); const tstring& s = visitor.GetResult(); sResult += s; ++i; } else { sResult += chr; } break; } } return sResult; } void log_to_file(const IQuotesProvider* pProvider, MCONTACT hContact, double dRate, const tstring& rsLogFileName, const tstring& rsFormat) { // USES_CONVERSION; // const char* pszPath = CT2A(rsLogFileName.c_str()); std::string sPath = quotes_t2a(rsLogFileName.c_str()); std::string::size_type n = sPath.find_last_of("\\/"); if(std::string::npos != n) { sPath.erase(n); } DWORD dwAttributes = ::GetFileAttributesA(sPath.c_str()); if((0xffffffff == dwAttributes) || (0 == (dwAttributes&FILE_ATTRIBUTE_DIRECTORY))) CreateDirectoryTree(sPath.c_str()); tofstream file(rsLogFileName.c_str(),std::ios::app|std::ios::out); file.imbue(GetSystemLocale()); if(file.good()) { tstring s = format_rate(pProvider,hContact,rsFormat,dRate); file << s; } } void log_to_history(const IQuotesProvider* pProvider, MCONTACT hContact, double dRate, time_t nTime, const tstring& rsFormat) { tstring s = format_rate(pProvider,hContact,rsFormat,dRate); ptrA psz( mir_utf8encodeT(s.c_str())); DBEVENTINFO dbei = { sizeof(dbei) }; dbei.szModule = QUOTES_PROTOCOL_NAME; dbei.timestamp = static_cast(nTime); dbei.flags = DBEF_READ|DBEF_UTF; dbei.eventType = EVENTTYPE_MESSAGE; dbei.cbBlob = ::lstrlenA(psz)+1; dbei.pBlob = (PBYTE)(char*)psz; db_event_add(hContact, &dbei); } bool do_set_contact_extra_icon(MCONTACT hContact,const CTendency& tendency) { bool bResult = false; CTendency::EResult nComparison = tendency.Compare(); //if(true == IsWithinAccuracy(dCurrRate,dPrevRate)) if(CTendency::NotChanged == nComparison) { bResult = CExtraImages::GetInstance().SetContactExtraImage(hContact,CExtraImages::eiNotChanged); } else if(CTendency::Up == nComparison)//(dCurrRate > dPrevRate) { bResult = CExtraImages::GetInstance().SetContactExtraImage(hContact,CExtraImages::eiUp); } else if(CTendency::Down == nComparison)//(dCurrRate < dPrevRate) { bResult = CExtraImages::GetInstance().SetContactExtraImage(hContact,CExtraImages::eiDown); } return bResult; } bool show_popup(const IQuotesProvider* pProvider, MCONTACT hContact, double dRate, // double dPrevRate, // bool bValidPrevRate, const CTendency& tendency, const tstring& rsFormat, const CPopupSettings& ps) { if(1 == ServiceExists(MS_POPUP_ADDPOPUPT)) { POPUPDATAT ppd; ZeroMemory((void *)&ppd, sizeof(ppd)); ppd.lchContact = hContact; //if((true == bValidPrevRate)) if(tendency.IsValid()) { CTendency::EResult nComparison = tendency.Compare(); if(CTendency::NotChanged == nComparison)//(true == IsWithinAccuracy(dRate,dPrevRate)) { ppd.lchIcon = Quotes_LoadIconEx(ICON_STR_QUOTE_NOT_CHANGED); } else if(CTendency::Up == nComparison)//(dRate > dPrevRate) { ppd.lchIcon = Quotes_LoadIconEx(ICON_STR_QUOTE_UP); } else if(CTendency::Down == nComparison) { ppd.lchIcon = Quotes_LoadIconEx(ICON_STR_QUOTE_DOWN); } } CQuotesProviderVisitorFormater visitor(hContact,_T('s'),0); pProvider->Accept(visitor); const tstring& sTitle = visitor.GetResult(); lstrcpyn(ppd.lptzContactName,sTitle.c_str(),MAX_CONTACTNAME); mir_safe_string ss(variables_parsedup((TCHAR*)rsFormat.c_str(), 0, hContact)); tstring sText = format_rate(pProvider,hContact,ss.m_p,dRate); lstrcpyn(ppd.lptzText,sText.c_str(),MAX_SECONDLINE); if(CPopupSettings::colourDefault == ps.GetColourMode()) { ppd.colorText = CPopupSettings::GetDefColourText(); ppd.colorBack = CPopupSettings::GetDefColourBk(); } else { ppd.colorText = ps.GetColourText(); ppd.colorBack = ps.GetColourBk(); } switch(ps.GetDelayMode()) { default: assert(!"Unknown popup delay mode"); case CPopupSettings::delayFromPopup: ppd.iSeconds = 0; break; case CPopupSettings::delayPermanent: ppd.iSeconds = -1; break; case CPopupSettings::delayCustom: ppd.iSeconds = ps.GetDelayTimeout(); break; } LPARAM lp = 0; if(false == ps.GetHistoryFlag()) { lp |= 0x08; } return (0 == CallService(MS_POPUP_ADDPOPUPT,reinterpret_cast(&ppd),lp)); } else { return false; } } } void CQuotesProviderBase::WriteContactRate(MCONTACT hContact,double dRate,const tstring& rsSymbol/* = ""*/) { time_t nTime = ::time(NULL); if(false == rsSymbol.empty()) { db_set_ts(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_SYMBOL,rsSymbol.c_str()); } double dPrev = 0.0; bool bValidPrev = Quotes_DBReadDouble(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_CURR_VALUE,dPrev); if(true == bValidPrev) { Quotes_DBWriteDouble(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_PREV_VALUE,dPrev); } Quotes_DBWriteDouble(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_CURR_VALUE,dRate); db_set_dw(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FETCH_TIME,nTime); tstring sSymbol = rsSymbol; tostringstream oNick; oNick.imbue(GetSystemLocale()); if(false == m_sContactListFormat.empty()) { tstring s = format_rate(this,hContact,m_sContactListFormat,dRate); oNick << s; } else { if(true == sSymbol.empty()) { sSymbol = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_SYMBOL); } oNick << std::setfill(_T(' ')) << std::setw(10) << std::left << sSymbol << std::setw(6) << std::right << dRate; } CTendency tendency; if (true == tendency.Parse(this, m_sTendencyFormat, hContact)) do_set_contact_extra_icon(hContact, tendency); db_set_ts(hContact,LIST_MODULE_NAME,CONTACT_LIST_NAME,oNick.str().c_str()); tstring sStatusMsg = format_rate(this,hContact,m_sStatusMsgFormat,dRate); if(false == sStatusMsg.empty()) { db_set_ts(hContact,LIST_MODULE_NAME,STATUS_MSG_NAME,sStatusMsg.c_str()); } else { db_unset(hContact,LIST_MODULE_NAME,STATUS_MSG_NAME); } bool bUseContactSpecific = (db_get_b(hContact,QUOTES_PROTOCOL_NAME,DB_STR_CONTACT_SPEC_SETTINGS,0) > 0); CAdvProviderSettings global_settings(this); WORD dwMode = (bUseContactSpecific) ? db_get_w(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG,static_cast(lmDisabled)) : global_settings.GetLogMode(); if(dwMode&lmExternalFile) { bool bAdd = true; bool bOnlyIfChanged = (bUseContactSpecific) ? (db_get_w(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG_FILE_CONDITION,1) > 0) : global_settings.GetLogOnlyChangedFlag(); if(true == bOnlyIfChanged) { bAdd = ((false == bValidPrev) || (false == IsWithinAccuracy(dRate,dPrev))); } if(true == bAdd) { tstring sLogFileName = (bUseContactSpecific) ? Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG_FILE,global_settings.GetLogFileName().c_str()) : global_settings.GetLogFileName(); if(true == sSymbol.empty()) { sSymbol = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_SYMBOL); } sLogFileName = GenerateLogFileName(sLogFileName,sSymbol); tstring sFormat = global_settings.GetLogFormat(); if(bUseContactSpecific) { CQuotesProviderVisitorDbSettings visitor; Accept(visitor); sFormat = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_LOG_FILE,visitor.m_pszDefLogFileFormat); } log_to_file(this,hContact,dRate,sLogFileName,sFormat); } } if(dwMode&lmInternalHistory) { bool bAdd = true; bool bOnlyIfChanged = (bUseContactSpecific) ? (db_get_w(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_HISTORY_CONDITION,1) > 0) : global_settings.GetHistoryOnlyChangedFlag(); if(true == bOnlyIfChanged) { bAdd = ((false == bValidPrev) || (false == IsWithinAccuracy(dRate,dPrev))); } if(true == bAdd) { tstring sFormat = (bUseContactSpecific) ? Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_HISTORY,global_settings.GetHistoryFormat().c_str()) : global_settings.GetHistoryFormat(); log_to_history(this,hContact,dRate,nTime,sFormat); } } if(dwMode&lmPopup) { bool bOnlyIfChanged = (bUseContactSpecific) ? (1 == db_get_b(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_CONDITION,1) > 0) : global_settings.GetShowPopupIfValueChangedFlag(); if((false == bOnlyIfChanged) || ((true == bOnlyIfChanged) && (true == bValidPrev) && (false == IsWithinAccuracy(dRate,dPrev)))) { tstring sFormat = (bUseContactSpecific) ? Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_POPUP,global_settings.GetPopupFormat().c_str()) : global_settings.GetPopupFormat(); CPopupSettings ps = *(global_settings.GetPopupSettingsPtr()); ps.InitForContact(hContact); show_popup(this,hContact,dRate,tendency,sFormat,ps); } } // if((true == IsOnline())) { SetContactStatus(hContact,ID_STATUS_ONLINE); } } MCONTACT CQuotesProviderBase::CreateNewContact(const tstring& rsName) { MCONTACT hContact = MCONTACT(CallService(MS_DB_CONTACT_ADD,0,0)); if(hContact) { if(0 == CallService(MS_PROTO_ADDTOCONTACT, WPARAM(hContact), (LPARAM)QUOTES_PROTOCOL_NAME)) { tstring sProvName = GetInfo().m_sName; db_set_ts(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_PROVIDER,sProvName.c_str()); db_set_ts(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_SYMBOL,rsName.c_str()); db_set_ts(hContact,LIST_MODULE_NAME,CONTACT_LIST_NAME,rsName.c_str()); CGuard cs(m_cs); m_aContacts.push_back(hContact); } else { CallService(MS_DB_CONTACT_DELETE, WPARAM(hContact), 0); hContact = NULL; } } return hContact; } namespace { DWORD get_refresh_timeout_miliseconds(const CQuotesProviderVisitorDbSettings& visitor) { if(!g_bAutoUpdate) { return INFINITE; } assert(visitor.m_pszDbRefreshRateType); assert(visitor.m_pszDbRefreshRateValue); int nRefreshRateType = db_get_w(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbRefreshRateType,RRT_MINUTES); if(nRefreshRateType < RRT_SECONDS || nRefreshRateType > RRT_HOURS) { nRefreshRateType = RRT_MINUTES; } DWORD nTimeout = db_get_w(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbRefreshRateValue,1); switch(nRefreshRateType) { default: case RRT_SECONDS: if(nTimeout < 1 || nTimeout > 60) { nTimeout = 1; } nTimeout *= 1000; break; case RRT_MINUTES: if(nTimeout < 1 || nTimeout > 60) { nTimeout = 1; } nTimeout *= 1000*60; break; case RRT_HOURS: if(nTimeout < 1 || nTimeout > 24) { nTimeout = 1; } nTimeout *= 1000*60*60; break; } return nTimeout; } } namespace { class CBoolGuard { public: CBoolGuard(bool& rb) : m_b(rb){m_b = true;} ~CBoolGuard(){m_b = false;} private: bool m_b; }; } void CQuotesProviderBase::Run() { CQuotesProviderVisitorDbSettings visitor; Accept(visitor); DWORD nTimeout = get_refresh_timeout_miliseconds(visitor); m_sContactListFormat = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbDisplayNameFormat,visitor.m_pszDefDisplayFormat); m_sStatusMsgFormat = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbStatusMsgFormat,visitor.m_pszDefStatusMsgFormat); m_sTendencyFormat = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbTendencyFormat,visitor.m_pszDefTendencyFormat); enum{ STOP_THREAD = 0, SETTINGS_CHANGED = 1, REFRESH_CONTACT = 2, COUNT_SYNC_OBJECTS = 3 }; HANDLE anEvents[COUNT_SYNC_OBJECTS]; anEvents[STOP_THREAD] = g_hEventWorkThreadStop; anEvents[SETTINGS_CHANGED] = m_hEventSettingsChanged; anEvents[REFRESH_CONTACT] = m_hEventRefreshContact; TContracts anContacts; { CGuard cs(m_cs); anContacts = m_aContacts; } bool bGoToBed = false; if(g_bAutoUpdate) { CBoolGuard bg(m_bRefreshInProgress); RefreshQuotes(anContacts); } while(false == bGoToBed) { anContacts.clear(); DWORD dwBegin = ::GetTickCount(); DWORD dwResult = ::WaitForMultipleObjects(COUNT_SYNC_OBJECTS,anEvents,FALSE,nTimeout); switch(dwResult) { case WAIT_FAILED: assert(!"WaitForMultipleObjects failed"); bGoToBed = true; break; case WAIT_ABANDONED_0+STOP_THREAD: case WAIT_ABANDONED_0+SETTINGS_CHANGED: case WAIT_ABANDONED_0+REFRESH_CONTACT: assert(!"WaitForMultipleObjects abandoned"); case WAIT_OBJECT_0+STOP_THREAD: bGoToBed = true; break; case WAIT_OBJECT_0+SETTINGS_CHANGED: nTimeout = get_refresh_timeout_miliseconds(visitor); m_sContactListFormat = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbDisplayNameFormat,visitor.m_pszDefDisplayFormat); m_sStatusMsgFormat = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbStatusMsgFormat,visitor.m_pszDefStatusMsgFormat); m_sTendencyFormat = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbTendencyFormat,visitor.m_pszDefTendencyFormat); { CGuard cs(m_cs); anContacts = m_aContacts; } break; case WAIT_OBJECT_0+REFRESH_CONTACT: { DWORD dwTimeRest = ::GetTickCount()-dwBegin; if(INFINITE != nTimeout && dwTimeRest < nTimeout) { nTimeout -= dwTimeRest; } { CGuard cs(m_cs); anContacts = m_aRefreshingContacts; m_aRefreshingContacts.clear(); } { CBoolGuard bg(m_bRefreshInProgress); RefreshQuotes(anContacts); } } break; case WAIT_TIMEOUT: nTimeout = get_refresh_timeout_miliseconds(visitor); { CGuard cs(m_cs); anContacts = m_aContacts; } { CBoolGuard bg(m_bRefreshInProgress); RefreshQuotes(anContacts); } break; default: assert(!"What is the hell?"); } } OnEndRun(); } void CQuotesProviderBase::OnEndRun() { TContracts anContacts; {// for CCritSection CGuard cs(m_cs); anContacts = m_aContacts; m_aRefreshingContacts.clear(); } CBoolGuard bg(m_bRefreshInProgress); std::for_each(anContacts.begin(),anContacts.end(),boost::bind(&SetContactStatus,_1,ID_STATUS_OFFLINE)); } void CQuotesProviderBase::Accept(CQuotesProviderVisitor& visitor)const { visitor.Visit(*this); } void CQuotesProviderBase::RefreshSettings() { BOOL b = ::SetEvent(m_hEventSettingsChanged); assert(b && "Failed to set event"); } void CQuotesProviderBase::RefreshAllContacts() { {// for CCritSection CGuard cs(m_cs); m_aRefreshingContacts.clear(); std::for_each(std::begin(m_aContacts),std::end(m_aContacts),[&](MCONTACT hContact){m_aRefreshingContacts.push_back(hContact);}); } BOOL b = ::SetEvent(m_hEventRefreshContact); assert(b && "Failed to set event"); } void CQuotesProviderBase::RefreshContact(MCONTACT hContact) { {// for CCritSection CGuard cs(m_cs); m_aRefreshingContacts.push_back(hContact); } BOOL b = ::SetEvent(m_hEventRefreshContact); assert(b && "Failed to set event"); } // void CQuotesProviderBase::SetContactExtraIcon(MCONTACT hContact)const // { // // tstring s = DBGetStringT(hContact,LIST_MODULE_NAME,CONTACT_LIST_NAME); // // tostringstream o; // // o << "Request on " << s << " refreshing\nIs online " << IsOnline() << ", is in progress " << m_bRefreshInProgress << "\n"; // // bool bResult = false; // if(/*true == IsOnline() && */(false == m_bRefreshInProgress)) // { // CTendency tendency; // if(tendency.Parse(this,m_sTendencyFormat,hContact) && (false == m_bRefreshInProgress)) // { // bResult = do_set_contact_extra_icon(hContact,tendency); // } // // double dCurrRate = 0.0; // // double dPrevRate = 0.0; // // if((true == Quotes_DBReadDouble(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_CURR_VALUE,dCurrRate)) // // && (true == Quotes_DBReadDouble(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_PREV_VALUE,dPrevRate)) // // && (false == m_bRefreshInProgress)) // // { // // // o << "Curr rate = " << dCurrRate << ", prev rate " << dPrevRate << "\n"; // // bResult = do_set_contact_extra_icon(hContact,dCurrRate,dPrevRate); // // } // } // // // o << "Result is " << bResult; // // LogIt(Info,o.str()); // }