diff options
Diffstat (limited to 'protocols/Weather/src/weather_update.cpp')
-rw-r--r-- | protocols/Weather/src/weather_update.cpp | 590 |
1 files changed, 256 insertions, 334 deletions
diff --git a/protocols/Weather/src/weather_update.cpp b/protocols/Weather/src/weather_update.cpp index fc71bfc0a7..806d41002c 100644 --- a/protocols/Weather/src/weather_update.cpp +++ b/protocols/Weather/src/weather_update.cpp @@ -26,15 +26,12 @@ menu items). #include "stdafx.h" -UPDATELIST *UpdateListHead = nullptr, *UpdateListTail = nullptr; - -//============ RETRIEVE NEW WEATHER ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // retrieve weather info and display / log them // hContact = current contact -int UpdateWeather(MCONTACT hContact) + +int CWeatherProto::UpdateWeather(MCONTACT hContact) { - wchar_t str2[MAX_TEXT_SIZE]; DBVARIANT dbv; BOOL Ch = FALSE; @@ -44,10 +41,10 @@ int UpdateWeather(MCONTACT hContact) dbv.pszVal = ""; // log to netlib log for debug purpose - Netlib_LogfW(hNetlibUser, L"************************************************************************"); - int dbres = g_plugin.getWString(hContact, "Nick", &dbv); + Netlib_LogfW(m_hNetlibUser, L"************************************************************************"); + int dbres = getWString(hContact, "Nick", &dbv); - Netlib_LogfW(hNetlibUser, L"<-- Start update for station -->"); + Netlib_LogfW(m_hNetlibUser, L"<-- Start update for station -->"); // download the info and parse it // result are stored in database @@ -62,12 +59,15 @@ int UpdateWeather(MCONTACT hContact) WPShowMessage(str, SM_WARNING); } // log to netlib - Netlib_LogfW(hNetlibUser, L"Error! Update cannot continue... Start to free memory"); - Netlib_LogfW(hNetlibUser, L"<-- Error occurs while updating station: %s -->", dbv.pwszVal); - if (!dbres) db_free(&dbv); + Netlib_LogfW(m_hNetlibUser, L"Error! Update cannot continue... Start to free memory"); + Netlib_LogfW(m_hNetlibUser, L"<-- Error occurs while updating station: %s -->", dbv.pwszVal); + if (!dbres) + db_free(&dbv); return 1; } - if (!dbres) db_free(&dbv); + + if (!dbres) + db_free(&dbv); // initialize, load new weather Data WEATHERINFO winfo = LoadWeatherInfo(hContact); @@ -77,19 +77,19 @@ int UpdateWeather(MCONTACT hContact) // compare the old condition and determine if the weather had changed if (opt.UpdateOnlyConditionChanged) { // consider condition change - if (!g_plugin.getWString(hContact, "LastCondition", &dbv)) { + if (!getWString(hContact, "LastCondition", &dbv)) { if (mir_wstrcmpi(winfo.cond, dbv.pwszVal)) Ch = TRUE; // the weather condition is changed db_free(&dbv); } else Ch = TRUE; - if (!g_plugin.getWString(hContact, "LastTemperature", &dbv)) { + if (!getWString(hContact, "LastTemperature", &dbv)) { if (mir_wstrcmpi(winfo.temp, dbv.pwszVal)) Ch = TRUE; // the temperature is changed db_free(&dbv); } else Ch = TRUE; } else { // consider update time change - if (!g_plugin.getWString(hContact, "LastUpdate", &dbv)) { + if (!getWString(hContact, "LastUpdate", &dbv)) { if (mir_wstrcmpi(winfo.update, dbv.pwszVal)) Ch = TRUE; // the update time is changed db_free(&dbv); } @@ -99,74 +99,60 @@ int UpdateWeather(MCONTACT hContact) // have weather alert issued? dbres = db_get_ws(hContact, WEATHERCONDITION, "Alert", &dbv); if (!dbres && dbv.pwszVal[0] != 0) { - if (opt.AlertPopup && !g_plugin.getByte(hContact, "DPopUp") && Ch) { + if (opt.AlertPopup && !getByte(hContact, "DPopUp") && Ch) { // display alert popup CMStringW str(FORMAT, L"Alert for %s%c%s", winfo.city, 255, dbv.pwszVal); WPShowMessage(str, SM_WEATHERALERT); } // alert issued, set display to italic if (opt.MakeItalic) - g_plugin.setWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); + setWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); Skin_PlaySound("weatheralert"); } // alert dropped, set the display back to normal - else g_plugin.delSetting(hContact, "ApparentMode"); + else delSetting(hContact, "ApparentMode"); if (!dbres) db_free(&dbv); // backup current condition for checking if the weather is changed or not - g_plugin.setWString(hContact, "LastLog", winfo.update); - g_plugin.setWString(hContact, "LastCondition", winfo.cond); - g_plugin.setWString(hContact, "LastTemperature", winfo.temp); - g_plugin.setWString(hContact, "LastUpdate", winfo.update); + setWString(hContact, "LastLog", winfo.update); + setWString(hContact, "LastCondition", winfo.cond); + setWString(hContact, "LastTemperature", winfo.temp); + setWString(hContact, "LastUpdate", winfo.update); // display condition on contact list int iStatus = MapCondToStatus(winfo.hContact); if (opt.DisCondIcon && iStatus != ID_STATUS_OFFLINE) - g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE); + setWord(hContact, "Status", ID_STATUS_ONLINE); else - g_plugin.setWord(hContact, "Status", iStatus); + setWord(hContact, "Status", iStatus); AvatarDownloaded(hContact); - GetDisplay(&winfo, GetTextValue('C'), str2); - db_set_ws(hContact, "CList", "MyHandle", str2); + db_set_ws(hContact, "CList", "MyHandle", GetDisplay(&winfo, GetTextValue('C'))); - GetDisplay(&winfo, GetTextValue('S'), str2); - if (str2[0]) + CMStringW str2(GetDisplay(&winfo, GetTextValue('S'))); + if (!str2.IsEmpty()) db_set_ws(hContact, "CList", "StatusMsg", str2); else db_unset(hContact, "CList", "StatusMsg"); - - ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, nullptr, (LPARAM)(str2[0] ? str2 : nullptr)); + ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, nullptr, (LPARAM)(str2.IsEmpty() ? nullptr : str2.c_str())); // save descriptions in MyNotes - GetDisplay(&winfo, GetTextValue('N'), str2); - db_set_ws(hContact, "UserInfo", "MyNotes", str2); - GetDisplay(&winfo, GetTextValue('X'), str2); - db_set_ws(hContact, WEATHERCONDITION, "WeatherInfo", str2); + db_set_ws(hContact, "UserInfo", "MyNotes", GetDisplay(&winfo, GetTextValue('N'))); + db_set_ws(hContact, WEATHERCONDITION, "WeatherInfo", GetDisplay(&winfo, GetTextValue('X'))); // set the update tag - g_plugin.setByte(hContact, "IsUpdated", TRUE); - - // save info for default weather condition - if (!mir_wstrcmp(winfo.id, opt.Default) && !opt.NoProtoCondition) { - // save current condition for default station to be displayed after the update - old_status = status; - status = iStatus; - // a workaround for a default station that currently have an n/a icon assigned - if (status == ID_STATUS_OFFLINE) status = NOSTATUSDATA; - ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status); - } + setByte(hContact, "IsUpdated", TRUE); // logging if (Ch) { // play the sound event Skin_PlaySound("weatherupdated"); - if (g_plugin.getByte(hContact, "File")) { + if (getByte(hContact, "File")) { // external log - if (!g_plugin.getWString(hContact, "Log", &dbv)) { + if (!getWString(hContact, "Log", &dbv)) { // for the option for overwriting the file, delete old file first - if (g_plugin.getByte(hContact, "Overwrite")) + if (getByte(hContact, "Overwrite")) DeleteFile(dbv.pwszVal); // open the file and set point to the end of file @@ -174,22 +160,19 @@ int UpdateWeather(MCONTACT hContact) db_free(&dbv); if (file != nullptr) { // write data to the file and close - GetDisplay(&winfo, GetTextValue('E'), str2); - fputws(str2, file); + fputws(GetDisplay(&winfo, GetTextValue('E')), file); fclose(file); } } } - if (g_plugin.getByte(hContact, "History")) { + if (getByte(hContact, "History")) { // internal log using history - GetDisplay(&winfo, GetTextValue('H'), str2); - - T2Utf szMessage(str2); + T2Utf szMessage(GetDisplay(&winfo, GetTextValue('H'))); DBEVENTINFO dbei = {}; - dbei.szModule = MODULENAME; - dbei.timestamp = (uint32_t)time(0); + dbei.szModule = m_szModuleName; + dbei.iTimestamp = (uint32_t)time(0); dbei.flags = DBEF_READ | DBEF_UTF; dbei.eventType = EVENTTYPE_MESSAGE; dbei.pBlob = szMessage; @@ -198,11 +181,11 @@ int UpdateWeather(MCONTACT hContact) } // show the popup - NotifyEventHooks(hHookWeatherUpdated, hContact, (LPARAM)Ch); + WeatherPopup(hContact, Ch); } - Netlib_LogfW(hNetlibUser, L"Update Completed - Start to free memory"); - Netlib_LogfW(hNetlibUser, L"<-- Update successful for station -->"); + Netlib_LogfW(m_hNetlibUser, L"Update Completed - Start to free memory"); + Netlib_LogfW(m_hNetlibUser, L"<-- Update successful for station -->"); // Update frame data UpdateMwinData(hContact); @@ -214,111 +197,84 @@ int UpdateWeather(MCONTACT hContact) return 0; } -//============ UPDATE LIST ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // a linked list queue for updating weather station // this function add a weather contact to the end of queue for update // hContact = current contact -void UpdateListAdd(MCONTACT hContact) -{ - UPDATELIST *newItem = (UPDATELIST*)mir_alloc(sizeof(UPDATELIST)); - newItem->hContact = hContact; - newItem->next = nullptr; - - WaitForSingleObject(hUpdateMutex, INFINITE); - - if (UpdateListTail == nullptr) UpdateListHead = newItem; - else UpdateListTail->next = newItem; - UpdateListTail = newItem; - ReleaseMutex(hUpdateMutex); +void CWeatherProto::UpdateListAdd(MCONTACT hContact) +{ + mir_cslock lck(m_csUpdate); + m_updateList.push_back(hContact); } // get the first item from the update queue and remove it from the queue // return value = the contact for next update -MCONTACT UpdateGetFirst() +MCONTACT CWeatherProto::UpdateGetFirst() { - MCONTACT hContact = NULL; - - WaitForSingleObject(hUpdateMutex, INFINITE); - - if (UpdateListHead != nullptr) { - UPDATELIST *Item = UpdateListHead; - - hContact = Item->hContact; - UpdateListHead = Item->next; - mir_free(Item); - - if (UpdateListHead == nullptr) - UpdateListTail = nullptr; - } - - ReleaseMutex(hUpdateMutex); + mir_cslock lck(m_csUpdate); + if (m_updateList.empty()) + return 0; + auto it = m_updateList.begin(); + MCONTACT hContact = *it; + m_updateList.erase(it); return hContact; } -void DestroyUpdateList(void) +void CWeatherProto::DestroyUpdateList(void) { - WaitForSingleObject(hUpdateMutex, INFINITE); - - // free the list one by one - UPDATELIST *temp = UpdateListHead; - while (temp != nullptr) { - UpdateListHead = temp->next; - mir_free(temp); - temp = UpdateListHead; - } - // make sure the entire list is clear - UpdateListTail = nullptr; - - ReleaseMutex(hUpdateMutex); + mir_cslock lck(m_csUpdate); + m_updateList.clear(); } +///////////////////////////////////////////////////////////////////////////////////////// // update all weather thread // this thread update each weather station from the queue -static void UpdateThreadProc(void *) + +void CWeatherProto::UpdateThread(void *) { - WaitForSingleObject(hUpdateMutex, INFINITE); - if (ThreadRunning) { - ReleaseMutex(hUpdateMutex); - return; + { mir_cslock lck(m_csUpdate); + if (m_bThreadRunning) + return; + + m_bThreadRunning = true; // prevent 2 instance of this thread running } - ThreadRunning = TRUE; // prevent 2 instance of this thread running - ReleaseMutex(hUpdateMutex); // update weather by getting the first station from the queue until the queue is empty - while (UpdateListHead != nullptr && !Miranda_IsTerminated()) + while (!m_updateList.empty() && !Miranda_IsTerminated()) UpdateWeather(UpdateGetFirst()); // exit the update thread - ThreadRunning = FALSE; + m_bThreadRunning = false; } -//============ UPDATE WEATHER ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // update all weather station // AutoUpdate = true if it is from automatic update using timer // false if it is from update by clicking the main menu -void UpdateAll(BOOL AutoUpdate, BOOL RemoveData) + +void CWeatherProto::UpdateAll(BOOL AutoUpdate, BOOL RemoveData) { // add all weather contact to the update queue list - for (auto &hContact : Contacts(MODULENAME)) - if (!g_plugin.getByte(hContact, "AutoUpdate") || !AutoUpdate) { + for (auto &hContact : AccContacts()) + if (!getByte(hContact, "AutoUpdate") || !AutoUpdate) { if (RemoveData) - DBDataManage(hContact, WDBM_REMOVE, 0, 0); + db_delete_module(hContact, WEATHERCONDITION); UpdateListAdd(hContact); } // if it is not updating, then start the update thread process // if it is updating, the stations just added to the queue will get updated by the already-running process - if (!ThreadRunning) - mir_forkthread(UpdateThreadProc); + if (!m_bThreadRunning) + ForkThread(&CWeatherProto::UpdateThread); } +///////////////////////////////////////////////////////////////////////////////////////// // update a single station // wParam = handle for the weather station that is going to be updated -INT_PTR UpdateSingleStation(WPARAM wParam, LPARAM) + +INT_PTR CWeatherProto::UpdateSingleStation(WPARAM wParam, LPARAM) { if (IsMyContact(wParam)) { // add the station to the end of the update queue @@ -327,278 +283,244 @@ INT_PTR UpdateSingleStation(WPARAM wParam, LPARAM) // if it is not updating, then start the update thread process // if it is updating, the stations just added to the queue will get // updated by the already-running process - if (!ThreadRunning) - mir_forkthread(UpdateThreadProc); + if (!m_bThreadRunning) + ForkThread(&CWeatherProto::UpdateThread); } return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // update a single station with removing the old data // wParam = handle for the weather station that is going to be updated -INT_PTR UpdateSingleRemove(WPARAM wParam, LPARAM) + +INT_PTR CWeatherProto::UpdateSingleRemove(WPARAM hContact, LPARAM) { - if (IsMyContact(wParam)) { + if (IsMyContact(hContact)) { // add the station to the end of the update queue, and also remove old data - DBDataManage(wParam, WDBM_REMOVE, 0, 0); - UpdateListAdd(wParam); + db_delete_module(hContact, WEATHERCONDITION); + UpdateListAdd(hContact); // if it is not updating, then start the update thread process // if it is updating, the stations just added to the queue will get updated by the already-running process - if (!ThreadRunning) - mir_forkthread(UpdateThreadProc); + if (!m_bThreadRunning) + ForkThread(&CWeatherProto::UpdateThread); } return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // the "Update All" menu item in main menu -INT_PTR UpdateAllInfo(WPARAM, LPARAM) + +INT_PTR CWeatherProto::UpdateAllInfo(WPARAM, LPARAM) { - if (!ThreadRunning) + if (!m_bThreadRunning) UpdateAll(FALSE, FALSE); return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // the "Update All" menu item in main menu and remove the old data -INT_PTR UpdateAllRemove(WPARAM, LPARAM) + +INT_PTR CWeatherProto::UpdateAllRemove(WPARAM, LPARAM) { - if (!ThreadRunning) + if (!m_bThreadRunning) UpdateAll(FALSE, TRUE); return 0; } -//============ GETTING WEATHER DATA ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // getting weather data and save them into the database // hContact = the contact to get the data -int GetWeatherData(MCONTACT hContact) -{ - // get each part of the id's - wchar_t id[256]; - GetStationID(hContact, id, _countof(id)); - - // test ID format - wchar_t *szInfo = wcschr(id, '/'); - if (szInfo == nullptr) - return INVALID_ID_FORMAT; - - GetID(id); - - wchar_t Svc[256]; - GetStationID(hContact, Svc, _countof(Svc)); - GetSvc(Svc); - - // check for invalid station - if (id[0] == 0) return INVALID_ID; - if (Svc[0] == 0) return INVALID_SVC; - // get the update strings (loaded to memory from ini files) - WIDATA *Data = GetWIData(Svc); - if (Data == nullptr) - return SVC_NOT_FOUND; // the ini for the station cannot be found +static wchar_t *moon2str(double phase) +{ + if (phase < 0.05) return TranslateT("New moon"); + if (phase < 0.26) return TranslateT("Waxing crescent"); + if (phase < 0.51) return TranslateT("Waxing gibbous"); + if (phase < 0.76) return TranslateT("Waning gibbous"); + return TranslateT("Waning crescent"); +} - uint16_t cond = NA; - char loc[256]; - for (int i = 0; i < 4; ++i) { - // generate update URL - switch (i) { - case 0: - mir_snprintf(loc, Data->UpdateURL, _T2A(id).get()); +static CMStringW parseConditions(const CMStringW &str) +{ + CMStringW ret; + int iStart = 0; + while (true) { + auto substr = str.Tokenize(L",", iStart); + if (substr.IsEmpty()) break; - case 1: - mir_snprintf(loc, Data->UpdateURL2, _T2A(id).get()); - break; + substr.Trim(); + if (!ret.IsEmpty()) + ret += ", "; + ret += TranslateW(substr); + } + return ret; +} - case 2: - mir_snprintf(loc, Data->UpdateURL3, _T2A(id).get()); - break; +static double g_elevation = 0; - case 3: - mir_snprintf(loc, Data->UpdateURL4, _T2A(id).get()); - break; +static void getData(OBJLIST<WIDATAITEM> &arValues, const JSONNode &node) +{ + arValues.insert(new WIDATAITEM(LPGENW("Date"), L"", node["datetime"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Condition"), L"", parseConditions(node["conditions"].as_mstring()))); + arValues.insert(new WIDATAITEM(LPGENW("Temperature"), L"C", node["temp"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("High"), L"C", node["tempmax"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Low"), L"C", node["tempmin"].as_mstring())); + + CMStringW wszPressure(FORMAT, L"%lf", node["pressure"].as_float() - g_elevation); + arValues.insert(new WIDATAITEM(LPGENW("Pressure"), L"mb", wszPressure)); + + arValues.insert(new WIDATAITEM(LPGENW("Sunset"), L"", node["sunset"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Sunrise"), L"", node["sunrise"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Moon phase"), L"", moon2str(node["moonphase"].as_float()))); + arValues.insert(new WIDATAITEM(LPGENW("Wind speed"), L"km/h", node["windspeed"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Wind direction"), L"grad", node["winddir"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Dew point"), L"C", node["dew"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Visibility"), L"km", node["visibility"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Humidity"), L"", node["humidity"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Feel"), L"C", node["feelslike"].as_mstring())); +} - default: - continue; - } +int CWeatherProto::GetWeatherData(MCONTACT hContact) +{ + // get each part of the id's + CMStringW wszID(getMStringW(hContact, "ID")); + if (wszID.IsEmpty()) + return INVALID_ID; - if (loc[0] == 0) - continue; + uint16_t cond = NA; - // download the html file from the internet - wchar_t *szData = nullptr; - int retval = InternetDownloadFile(loc, Data->Cookie, Data->UserAgent, &szData); - if (retval != 0) { - mir_free(szData); - return retval; - } - if (wcsstr(szData, L"Document Not Found") != nullptr) { - mir_free(szData); - return DOC_NOT_FOUND; - } + // download the html file from the internet + WeatherReply reply(RunQuery(wszID, 7)); + if (!reply) + return reply.error(); + + auto &root = reply.data(); + + // writing current conditions + auto &curr = root["currentConditions"]; + g_elevation = root["elevation"].as_float() / 7.877; + + WIDATAITEMLIST arValues; + getData(arValues, curr); + + auto szIcon = curr["icon"].as_string(); + if (szIcon == "snow") + cond = SNOW; + else if (szIcon == "snow-showers-day" || szIcon == "snow-showers-night") + cond = SSHOWER; + else if (szIcon == "thunder" || szIcon == "thunder-showers-day" || szIcon == "thunder-showers-night") + cond = LIGHT; + else if (szIcon == "partly-cloudy-day" || szIcon == "partly-cloudy-night" || szIcon == "wind") + cond = PCLOUDY; + else if (szIcon == "fog") + cond = FOG; + else if (szIcon == "rain") + cond = RAIN; + else if (szIcon == "showers-day" || szIcon == "showers-night") + cond = RSHOWER; + else if (szIcon == "clear-day" || szIcon == "clear-night") + cond = SUNNY; + else if (szIcon == "rain") + cond = RAIN; + else if (szIcon == "cloudy") + cond = CLOUDY; + + // writing forecast + db_set_ws(hContact, WEATHERCONDITION, "Update", curr["datetime"].as_mstring()); + + for (auto &it : arValues) { + ConvertDataValue(it); + if (!it->Value.IsEmpty()) + db_set_ws(hContact, WEATHERCONDITION, _T2A(it->Name), it->Value); + } - szInfo = szData; - WIDATAITEMLIST *Item = Data->UpdateData; + int iFore = 0; + for (auto &fore : root["days"]) { + WIDATAITEMLIST arDaily; + getData(arDaily, fore); - // begin parsing item by item - while (Item != nullptr) { - if (Item->Item.Url[0] != 0 && Item->Item.Url[0] != (i + '1')) { - Item = Item->Next; + CMStringW result; + for (auto &it : arDaily) { + ConvertDataValue(it); + if (it->Value.IsEmpty()) continue; - } - wchar_t DataValue[MAX_DATA_LEN]; - switch (Item->Item.Type) { - case WID_NORMAL: - // if it is a normal item with start= and end=, then parse through the downloaded string - // to get a data value. - GetDataValue(&Item->Item, DataValue, &szInfo); - if (mir_wstrcmp(Item->Item.Name, L"Condition") && mir_wstrcmpi(Item->Item.Unit, L"Cond")) - wcsncpy(DataValue, TranslateW(DataValue), MAX_DATA_LEN - 1); - break; - - case WID_SET: - { - // for the "Set Data=" operation - DBVARIANT dbv; - wchar_t *chop, *str, str2[MAX_DATA_LEN]; - BOOL hasvar = FALSE; - size_t stl; - - // get the set data operation string - str = Item->Item.End; - DataValue[0] = 0; - // go through each part of the operation string seperated by the & operator - do { - // the end of the string, last item - chop = wcsstr(str, L" & "); - if (chop == nullptr) - chop = wcschr(str, '\0'); - - stl = min(sizeof(str2) - 1, (unsigned)(chop - str - 2)); - wcsncpy(str2, str + 1, stl); - str2[stl] = 0; - - switch (str[0]) { - case '[': // variable, add the value to the result string - hasvar = TRUE; - if (!DBGetData(hContact, _T2A(str2), &dbv)) { - mir_wstrncat(DataValue, TranslateW(dbv.pwszVal), _countof(DataValue) - mir_wstrlen(DataValue)); - DataValue[_countof(DataValue) - 1] = 0; - db_free(&dbv); - } - break; - - case'\"': // constant, add it to the result string - mir_wstrncat(DataValue, TranslateW(str2), _countof(DataValue) - mir_wstrlen(DataValue)); - DataValue[_countof(DataValue) - 1] = 0; - break; - } - - // remove the front part of the string that is done and continue parsing - str = chop + 3; - } while (chop[0] && str[0]); - - if (!hasvar) ConvertDataValue(&Item->Item, DataValue); - break; - } - case WID_BREAK: - { - // for the "Break Data=" operation - DBVARIANT dbv; - if (!DBGetData(hContact, _T2A(Item->Item.Start), &dbv)) { - wcsncpy(DataValue, dbv.pwszVal, _countof(DataValue)); - DataValue[_countof(DataValue) - 1] = 0; - db_free(&dbv); - } - else { - DataValue[0] = 0; - break; // do not continue if the source is invalid - } - - // generate the strings - wchar_t *end = wcsstr(DataValue, Item->Item.Break); - if (end == nullptr) { - DataValue[0] = 0; - break; // exit if break string is not found - } - *end = '\0'; - end += mir_wstrlen(Item->Item.Break); - while (end[0] == ' ') - end++; // remove extra space - - ConvertDataValue(&Item->Item, DataValue); - - // write the 2 strings created from the break operation - if (Item->Item.End[0]) - db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.End), end); - break; - } - } + // insert missing values from day 0 into current + if (iFore == 0) + if (auto *pOld = arValues.Find(it->Name)) + if (pOld->Value.IsEmpty() || pOld->Value == NODATA) + db_set_ws(hContact, WEATHERCONDITION, _T2A(it->Name), it->Value); - // don't store data if it is not available - if ((DataValue[0] != 0 && mir_wstrcmp(DataValue, NODATA) && - mir_wstrcmp(DataValue, TranslateW(NODATA)) && mir_wstrcmp(Item->Item.Name, L"Ignore")) || - (!mir_wstrcmp(Item->Item.Name, L"Alert") && i == 0)) { - // temporary workaround for mToolTip to show feel-like temperature - if (!mir_wstrcmp(Item->Item.Name, L"Feel")) - db_set_ws(hContact, WEATHERCONDITION, "Heat Index", DataValue); - GetStationID(hContact, Svc, _countof(Svc)); - if (!mir_wstrcmp(Svc, opt.Default)) - db_set_ws(0, DEFCURRENTWEATHER, _T2A(Item->Item.Name), DataValue); - if (!mir_wstrcmp(Item->Item.Name, L"Condition")) { - wchar_t buf[128], *cbuf; - mir_snwprintf(buf, L"#%s Weather", DataValue); - cbuf = TranslateW(buf); - if (cbuf[0] == '#') - cbuf = TranslateW(DataValue); - db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), cbuf); - CharLowerBuff(DataValue, (uint32_t)mir_wstrlen(DataValue)); - cond = GetIcon(DataValue, Data); - } - else if (mir_wstrcmpi(Item->Item.Unit, L"Cond") == 0) { - wchar_t buf[128], *cbuf; - mir_snwprintf(buf, L"#%s Weather", DataValue); - cbuf = TranslateW(buf); - if (cbuf[0] == '#') - cbuf = TranslateW(DataValue); - db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), cbuf); - } - else db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), DataValue); - } - Item = Item->Next; + if (!result.IsEmpty()) + result += L"; "; + result.AppendFormat(L"%s: %s", TranslateW(it->Name), it->Value.c_str()); } - mir_free(szData); + + CMStringA szSetting(FORMAT, "Forecast Day %d", iFore++); + db_set_ws(hContact, WEATHERCONDITION, szSetting, result); + arValues.destroy(); } // assign condition icon - g_plugin.setWord(hContact, "StatusIcon", cond); + setWord(hContact, "StatusIcon", cond); return 0; } -//============ UPDATE TIMERS ============ -// +///////////////////////////////////////////////////////////////////////////////////////// + +static int enumSettings(const char *pszSetting, void *param) +{ + auto *pList = (OBJLIST<char>*)param; + if (!pList->find((char*)pszSetting)) + pList->insert(newStr(pszSetting)); + return 0; +} + +void CWeatherProto::GetVarsDescr(CMStringW &wszDescr) +{ + OBJLIST<char> vars(10, strcmp); + for (int i = 1; i <= 7; i++) + vars.insert(newStr(CMStringA(FORMAT, "Forecast Day %d", i))); + + for (auto &cc : AccContacts()) + db_enum_settings(cc, &enumSettings, WEATHERCONDITION, &vars); + + CMStringW str; + for (auto &it : vars) { + if (!str.IsEmpty()) + str.Append(L", "); + str.AppendFormat(L"%%[%S]", it); + } + wszDescr += str; +} + +///////////////////////////////////////////////////////////////////////////////////////// // main auto-update timer -void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD) + +void CWeatherProto::DoUpdate() { // only run if it is not current updating and the auto update option is enabled - if (!ThreadRunning && opt.CAutoUpdate && !Miranda_IsTerminated() && (opt.NoProtoCondition || status == ID_STATUS_ONLINE)) + if (!m_bThreadRunning && opt.CAutoUpdate && !Miranda_IsTerminated() && m_iStatus == ID_STATUS_ONLINE) UpdateAll(TRUE, FALSE); } - // temporary timer for first run // when this is run, it kill the old startup timer and create the permenant one above -void CALLBACK timerProc2(HWND, UINT, UINT_PTR, DWORD) + +void CWeatherProto::StartUpdate() { - KillTimer(nullptr, timerId); - ThreadRunning = FALSE; + m_bThreadRunning = false; - if (Miranda_IsTerminated()) - return; + if (!Miranda_IsTerminated()) + m_impl.m_update.Start(opt.UpdateTime * 60000); +} - if (opt.StartupUpdate && opt.NoProtoCondition) - UpdateAll(FALSE, FALSE); - timerId = SetTimer(nullptr, 0, ((int)opt.UpdateTime) * 60000, timerProc); +void CWeatherProto::RestartTimer() +{ + m_impl.m_update.Stop(); + m_impl.m_update.Start(opt.UpdateTime * 60000); } |