summaryrefslogtreecommitdiff
path: root/protocols/Weather/src/weather_update.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Weather/src/weather_update.cpp')
-rw-r--r--protocols/Weather/src/weather_update.cpp590
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);
}