diff options
Diffstat (limited to 'protocols/Weather/src/weather_data.cpp')
-rw-r--r-- | protocols/Weather/src/weather_data.cpp | 420 |
1 files changed, 122 insertions, 298 deletions
diff --git a/protocols/Weather/src/weather_data.cpp b/protocols/Weather/src/weather_data.cpp index 0f3cf9ccc9..76e50ca139 100644 --- a/protocols/Weather/src/weather_data.cpp +++ b/protocols/Weather/src/weather_data.cpp @@ -25,31 +25,21 @@ saving individual weather data for a weather contact. #include "stdafx.h" -//============ LOAD WEATHER INFO FROM A CONTACT ============ -// get station ID from DB -// hContact = the current contact handle -// return value = the string for station ID -// -void GetStationID(MCONTACT hContact, wchar_t *id, int idlen) -{ - // accessing the database - if (db_get_wstatic(hContact, MODULENAME, "ID", id, idlen)) - id[0] = 0; -} - +///////////////////////////////////////////////////////////////////////////////////////// // initialize weather info by loading values from database // hContact = current contact handle // return value = the current weather information in WEATHERINFO struct -WEATHERINFO LoadWeatherInfo(MCONTACT hContact) + +WEATHERINFO CWeatherProto::LoadWeatherInfo(MCONTACT hContact) { // obtaining values from the DB // assuming station ID must exist at all time, but others does not have to // if the string is not found in database, a value of "N/A" is stored in the field WEATHERINFO winfo; winfo.hContact = hContact; - GetStationID(hContact, winfo.id, _countof(winfo.id)); + wcsncpy_s(winfo.id, getMStringW(hContact, "ID"), _countof(winfo.id)); - if (db_get_wstatic(hContact, MODULENAME, "Nick", winfo.city, _countof(winfo.city))) + if (db_get_wstatic(hContact, m_szModuleName, "Nick", winfo.city, _countof(winfo.city))) wcsncpy(winfo.city, NODATA, _countof(winfo.city) - 1); if (db_get_wstatic(hContact, WEATHERCONDITION, "Update", winfo.update, _countof(winfo.update))) wcsncpy(winfo.update, NODATA, _countof(winfo.update) - 1); @@ -82,64 +72,47 @@ WEATHERINFO LoadWeatherInfo(MCONTACT hContact) return winfo; } -// getting weather setting from database -// return 0 on success -int DBGetData(MCONTACT hContact, char *setting, DBVARIANT *dbv) -{ - if (db_get_ws(hContact, WEATHERCONDITION, setting, dbv)) { - size_t len = mir_strlen(setting) + 1; - char *set = (char*)alloca(len + 1); - *set = '#'; - memcpy(set + 1, setting, len); - - if (db_get_ws(hContact, WEATHERCONDITION, set, dbv)) - return 1; - } - return 0; -} - - -//============ ERASE OLD SETTINGS ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // erase all current weather information from database // lastver = the last used version number in dword (using PLUGIN_MAKE_VERSION) -void EraseAllInfo() + +void CWeatherProto::EraseAllInfo() { wchar_t str[255]; int ContactCount = 0; MCONTACT LastContact = NULL; DBVARIANT dbv; // loop through all contacts - for (auto &hContact : Contacts(MODULENAME)) { - g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE); - g_plugin.setWord(hContact, "StatusIcon", -1); + for (auto &hContact : AccContacts()) { + setWord(hContact, "Status", ID_STATUS_OFFLINE); + setWord(hContact, "StatusIcon", -1); db_unset(hContact, "CList", "MyHandle"); // clear all data - if (g_plugin.getWString(hContact, "Nick", &dbv)) { - g_plugin.setWString(hContact, "Nick", TranslateT("<Enter city name here>")); - g_plugin.setString(hContact, "LastLog", "never"); - g_plugin.setString(hContact, "LastCondition", "None"); - g_plugin.setString(hContact, "LastTemperature", "None"); + if (getWString(hContact, "Nick", &dbv)) { + setWString(hContact, "Nick", TranslateT("<Enter city name here>")); + setString(hContact, "LastLog", "never"); + setString(hContact, "LastCondition", "None"); + setString(hContact, "LastTemperature", "None"); } else db_free(&dbv); - DBDataManage(hContact, WDBM_REMOVE, 0, 0); + db_delete_module(hContact, WEATHERCONDITION); db_set_s(hContact, "UserInfo", "MyNotes", ""); // reset update tag - g_plugin.setByte(hContact, "IsUpdated", FALSE); + setByte(hContact, "IsUpdated", FALSE); // reset logging settings - if (!g_plugin.getWString(hContact, "Log", &dbv)) { - g_plugin.setByte(hContact, "File", (uint8_t)(dbv.pwszVal[0] != 0)); + if (!getWString(hContact, "Log", &dbv)) { + setByte(hContact, "File", (uint8_t)(dbv.pwszVal[0] != 0)); db_free(&dbv); } - else g_plugin.setByte(hContact, "File", FALSE); + else setByte(hContact, "File", FALSE); // if no default station find, assign a new one if (opt.Default[0] == 0) { - GetStationID(hContact, opt.Default, _countof(opt.Default)); + wcsncpy_s(opt.Default, getMStringW(hContact, "ID"), _countof(opt.Default)); opt.DefStn = hContact; - if (!g_plugin.getWString(hContact, "Nick", &dbv)) { + if (!getWString(hContact, "Nick", &dbv)) { mir_snwprintf(str, TranslateT("%s is now the default weather station"), dbv.pwszVal); db_free(&dbv); MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION); @@ -147,7 +120,7 @@ void EraseAllInfo() } // get the handle of the default station if (opt.DefStn == NULL) { - if (!g_plugin.getWString(hContact, "ID", &dbv)) { + if (!getWString(hContact, "ID", &dbv)) { if (!mir_wstrcmp(dbv.pwszVal, opt.Default)) opt.DefStn = hContact; db_free(&dbv); @@ -161,281 +134,132 @@ void EraseAllInfo() // if (ContactCount != 0) status = ONLINE; // in case where the default station is missing if (opt.DefStn == NULL && ContactCount != 0) { - if (!g_plugin.getWString(LastContact, "ID", &dbv)) { + if (!getWString(LastContact, "ID", &dbv)) { wcsncpy(opt.Default, dbv.pwszVal, _countof(opt.Default) - 1); db_free(&dbv); } opt.DefStn = LastContact; - if (!g_plugin.getWString(LastContact, "Nick", &dbv)) { + if (!getWString(LastContact, "Nick", &dbv)) { mir_snwprintf(str, TranslateT("%s is now the default weather station"), dbv.pwszVal); db_free(&dbv); MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION); } } // save option in case of default station changed - g_plugin.setWString("Default", opt.Default); + setWString("Default", opt.Default); } -void ConvertDataValue(WIDATAITEM *UpdateData, wchar_t *Data) -{ - wchar_t str[MAX_DATA_LEN]; +///////////////////////////////////////////////////////////////////////////////////////// - // convert the unit - if (mir_wstrcmp(Data, TranslateT("<Error>")) && mir_wstrcmp(Data, NODATA) && mir_wstrcmp(Data, TranslateW(NODATA))) { - // temperature - if (!mir_wstrcmp(UpdateData->Name, L"Temperature") || !mir_wstrcmp(UpdateData->Name, L"High") || - !mir_wstrcmp(UpdateData->Name, L"Low") || !mir_wstrcmp(UpdateData->Name, L"Feel") || - !mir_wstrcmp(UpdateData->Name, L"Dew point") || - !mir_wstrcmpi(UpdateData->Unit, L"C") || !mir_wstrcmpi(UpdateData->Unit, L"F") || - !mir_wstrcmpi(UpdateData->Unit, L"K")) { - GetTemp(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // pressure - else if (!mir_wstrcmp(UpdateData->Name, L"Pressure") || !mir_wstrcmpi(UpdateData->Unit, L"HPA") || - !mir_wstrcmpi(UpdateData->Unit, L"KPA") || !mir_wstrcmpi(UpdateData->Unit, L"MB") || - !mir_wstrcmpi(UpdateData->Unit, L"TORR") || !mir_wstrcmpi(UpdateData->Unit, L"IN") || - !mir_wstrcmpi(UpdateData->Unit, L"MM")) { - GetPressure(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // speed - else if (!mir_wstrcmp(UpdateData->Name, L"Wind Speed") || !mir_wstrcmpi(UpdateData->Unit, L"KM/H") || - !mir_wstrcmpi(UpdateData->Unit, L"M/S") || !mir_wstrcmpi(UpdateData->Unit, L"MPH") || - !mir_wstrcmpi(UpdateData->Unit, L"KNOTS")) { - GetSpeed(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // visibility - else if (!mir_wstrcmp(UpdateData->Name, L"Visibility") || !mir_wstrcmpi(UpdateData->Unit, L"KM") || - !mir_wstrcmpi(UpdateData->Unit, L"MILES")) { - GetDist(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // elevation - else if (!mir_wstrcmp(UpdateData->Name, L"Elevation") || !mir_wstrcmpi(UpdateData->Unit, L"FT") || - !mir_wstrcmpi(UpdateData->Unit, L"M")) { - GetElev(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // converting case for condition to the upper+lower format - else if (!mir_wstrcmpi(UpdateData->Unit, L"COND")) - CaseConv(Data); - // degree sign - else if (!mir_wstrcmpi(UpdateData->Unit, L"DEG")) { - if (!opt.DoNotAppendUnit) mir_wstrcat(Data, opt.DegreeSign); - } - // percent sign - else if (!mir_wstrcmpi(UpdateData->Unit, L"%")) { - if (!opt.DoNotAppendUnit) mir_wstrcat(Data, L"%"); - } - // truncating strings for day/month to 2 or 3 characters - else if (!mir_wstrcmpi(UpdateData->Unit, L"DAY") || !mir_wstrcmpi(UpdateData->Unit, L"MONTH")) - if (opt.dUnit > 1 && mir_wstrlen(Data) > opt.dUnit) - Data[opt.dUnit] = '\0'; - } -} +static wchar_t rumbs[][16] = { + LPGENW("N"), LPGENW("NNE"), LPGENW("NE"), LPGENW("ENE"), + LPGENW("E"), LPGENW("ESE"), LPGENW("ES"), LPGENW("SSE"), + LPGENW("S"), LPGENW("SSW"), LPGENW("SW"), LPGENW("WSW"), + LPGENW("W"), LPGENW("WNW"), LPGENW("WN"), LPGENW("NNW") +}; -//============ GET THE VALUE OF A DATAITEM ============ -// -// get the value of the data using the start, end strings -// UpdateData = the WIDATAITEM struct containing start, end, unit -// Data = the string containing weather data obtained from UpdateData -// global var. used: szInfo = the downloaded string -// -void GetDataValue(WIDATAITEM *UpdateData, wchar_t *Data, wchar_t **szData) +static wchar_t *degree2str(double angle) { - wchar_t last = 0, current, *start, *end; - unsigned startloc = 0, endloc = 0, respos = 0; - BOOL tag = FALSE, symb = FALSE; - wchar_t *szInfo = *szData; - - Data[0] = 0; - // parse the data if available - if (UpdateData->Start[0] == 0 && UpdateData->End[0] == 0) return; - start = szInfo; - // the start string must be found - if (UpdateData->Start[0] != 0) { - start = wcsstr(szInfo, UpdateData->Start); - if (start != nullptr) { - // set the starting location for getting data - start += mir_wstrlen(UpdateData->Start); - szInfo = start; - } - } - - // the end string must be found too - if (UpdateData->End[0] != 0) - end = wcsstr(szInfo, UpdateData->End); - else - end = wcschr(szInfo, ' '); - - if (end != nullptr) { - // set the ending location - startloc = 0; - endloc = end - szInfo; - end += mir_wstrlen(UpdateData->End); - last = '\n'; - } + double a = 11.25; - // ignore if not both of the string found - this prevent crashes - if (start != nullptr && end != nullptr) { - // begin reading the data from start location to end location - // remove all HTML tag in between, as well as leading space, ending space, - // multiple spaces, tabs, and return key - while (startloc < endloc) { - if (szInfo[startloc] == '<') tag = TRUE; - else if (szInfo[startloc] == '&' && - (szInfo[startloc + 1] == ';' || szInfo[startloc + 2] == ';' || szInfo[startloc + 3] == ';' || - szInfo[startloc + 4] == ';' || szInfo[startloc + 5] == ';' || szInfo[startloc + 6] == ';')) { - // ...but do NOT strip − - if ((endloc - startloc) > 7 && wcsncmp(szInfo + startloc, L"−", 7) == 0) { - Data[respos++] = '-'; - startloc += 7; - continue; - } - symb = TRUE; - } - else if (szInfo[startloc] == '>') tag = FALSE; - else if (szInfo[startloc] == ';') symb = FALSE; - else { - if (!tag && !symb) { - current = szInfo[startloc]; - if (current == '\n' || current == '\t' || current == ' ' || current == '\r') - current = ' '; - if (current != ' ' || last != ' ') { - if (last != '\n' && (respos != 0 || (respos == 0 && last != ' '))) - Data[respos++] = last; - last = current; - } - } - } - ++startloc; - // prevent crashes if the string go over maximun length -> generate an error - if (respos >= MAX_DATA_LEN) { - if (opt.ShowWarnings && UpdateData->Name[0] != 0 && mir_wstrcmp(UpdateData->Name, L"Ignore")) { - mir_snwprintf(Data, MAX_DATA_LEN, TranslateT("Error when obtaining data: %s"), UpdateData->Name); - WPShowMessage(Data, SM_WARNING); - } - wcsncpy(Data, TranslateT("<Error>"), MAX_DATA_LEN); - last = ' '; - respos = MAX_DATA_LEN - 1; - break; - } - } + for (int i = 0; i < _countof(rumbs); i++, a += 22.5) + if (angle < a) + return TranslateW(rumbs[i]); - // get the last character - if (last != ' ') - Data[respos++] = last; - - // null terminate the string - Data[respos] = 0; - - // convert the unit - ConvertDataValue(UpdateData, Data); - - // remove the string before the data from szInfo - szInfo = end; - } - *szData = szInfo; -} - -//============ ALLOCATE SPACE AND COPY STRING ============ -// -// copy a string into a new memory location -// Data = the field the data is copied to -// Value = the original string, the string where data is copied from - -bool g_bIsUtf = false; - -void wSetData(char *&Data, const char *Value) -{ - if (Value[0] != 0) - Data = mir_strdup(Value); - else - Data = ""; -} - -void wSetData(wchar_t *&Data, const char *Value) -{ - if (Value[0] != 0) - Data = (g_bIsUtf) ? mir_utf8decodeW(Value) : mir_a2u(Value); - else - Data = L""; + // area between 348.75 & 360 degrees + return TranslateT("N"); } -void wSetData(wchar_t *&Data, const wchar_t *Value) +void CWeatherProto::ConvertDataValue(WIDATAITEM *p) { - if (Value[0] != 0) - Data = mir_wstrdup(Value); - else - Data = L""; -} + wchar_t str[MAX_DATA_LEN]; -// A safer free function that free memory for a string -// Data = the string occuping the data to be freed -void wfree(char *&Data) -{ - if (Data && mir_strlen(Data) > 0) - mir_free(Data); - Data = nullptr; + // temperature + if (!mir_wstrcmp(p->Name, L"Temperature") || !mir_wstrcmp(p->Name, L"High") || + !mir_wstrcmp(p->Name, L"Low") || !mir_wstrcmp(p->Name, L"Feel") || + !mir_wstrcmp(p->Name, L"Dew point") || + !mir_wstrcmpi(p->Unit, L"C") || !mir_wstrcmpi(p->Unit, L"F") || + !mir_wstrcmpi(p->Unit, L"K")) { + GetTemp(p->Value, p->Unit, str); + p->Value = str; + } + // pressure + else if (!mir_wstrcmp(p->Name, L"Pressure") || !mir_wstrcmpi(p->Unit, L"HPA") || + !mir_wstrcmpi(p->Unit, L"KPA") || !mir_wstrcmpi(p->Unit, L"MB") || + !mir_wstrcmpi(p->Unit, L"TORR") || !mir_wstrcmpi(p->Unit, L"IN") || + !mir_wstrcmpi(p->Unit, L"MM")) { + GetPressure(p->Value, p->Unit, str); + p->Value = str; + } + // speed + else if (!mir_wstrcmp(p->Name, L"Wind Speed") || !mir_wstrcmpi(p->Unit, L"KM/H") || + !mir_wstrcmpi(p->Unit, L"M/S") || !mir_wstrcmpi(p->Unit, L"MPH") || + !mir_wstrcmpi(p->Unit, L"KNOTS")) { + GetSpeed(p->Value, p->Unit, str); + p->Value = str; + } + // visibility + else if (!mir_wstrcmp(p->Name, L"Visibility") || !mir_wstrcmpi(p->Unit, L"KM") || + !mir_wstrcmpi(p->Unit, L"MILES")) { + GetDist(p->Value, p->Unit, str); + p->Value = str; + } + // elevation + else if (!mir_wstrcmp(p->Name, L"Elevation") || !mir_wstrcmpi(p->Unit, L"FT") || + !mir_wstrcmpi(p->Unit, L"M")) { + GetElev(p->Value, p->Unit, str); + p->Value = str; + } + // convert degrees to compass + else if (!mir_wstrcmpi(p->Unit, L"GRAD")) { + p->Value = degree2str(_wtof(p->Value)); + } + // degree sign + else if (!mir_wstrcmpi(p->Unit, L"DEG")) { + if (!opt.DoNotAppendUnit) + p->Value.Append(opt.DegreeSign); + } + // percent sign + else if (!mir_wstrcmpi(p->Unit, L"%")) { + if (!opt.DoNotAppendUnit) + p->Value.Append(L"%"); + } + // truncating strings for day/month to 2 or 3 characters + else if (!mir_wstrcmpi(p->Unit, L"DAY") || !mir_wstrcmpi(p->Unit, L"MONTH")) + if (opt.dUnit > 1 && mir_wstrlen(p->Value) > opt.dUnit) + p->Value.SetAt(opt.dUnit, '\0'); } -void wfree(wchar_t *&Data) -{ - if (Data && mir_wstrlen(Data) > 0) - mir_free(Data); - Data = nullptr; -} +///////////////////////////////////////////////////////////////////////////////////////// +// data query -//============ MANAGE THE ITEMS STORED IN DB ============ -// get single setting that is found -// szSetting = the setting name -// lparam = the counter -int GetWeatherDataFromDB(const char *szSetting, void *lparam) +MHttpResponse* CWeatherProto::RunQuery(const wchar_t *id, int days) { - LIST<char> *pList = (LIST<char>*)lparam; - pList->insert(mir_strdup(szSetting)); - return 0; -} + wchar_t *pKey = m_szApiKey; + if (!mir_wstrlen(pKey)) { + WPShowMessage(TranslateT("You need to obtain the personal key and enter it in the account's Options dialog"), SM_WARNING); + return nullptr; + } -// remove or display the weather information for a contact -// hContact - the contact in which the info is going to be removed -// -void DBDataManage(MCONTACT hContact, uint16_t Mode, WPARAM wParam, LPARAM) -{ - // get all the settings and store them in a temporary list - LIST<char> arSettings(10); - db_enum_settings(hContact, GetWeatherDataFromDB, WEATHERCONDITION, &arSettings); + auto *pReq = new MHttpRequest(REQUEST_GET); + pReq->flags = NLHRF_HTTP11 | NLHRF_DUMPASTEXT; + pReq->m_szUrl = "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/" + mir_urlEncode(T2Utf(id).get()); - // begin deleting settings - auto T = arSettings.rev_iter(); - for (auto &str : T) { - ptrW wszText(db_get_wsa(hContact, WEATHERCONDITION, str)); - if (wszText == nullptr) - continue; + if (days) { + time_t today = time(0); + struct tm *p = localtime(&today); + pReq->m_szUrl.AppendFormat("/%04d-%02d-%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday); - switch (Mode) { - case WDBM_REMOVE: - db_unset(hContact, WEATHERCONDITION, str); - break; + today += 86400 * 7; // add one week + p = localtime(&today); + pReq->m_szUrl.AppendFormat("/%04d-%02d-%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday); + } - case WDBM_DETAILDISPLAY: - // skip the "WeatherInfo" variable - if (!mir_strcmp(str, "WeatherInfo") || !mir_strcmp(str, "Ignore") || str[0] == '#') - continue; + pReq << CHAR_PARAM("unitGroup", "metric") << WCHAR_PARAM("key", pKey) << CHAR_PARAM("contentType", "json"); + if (days) + pReq << CHAR_PARAM("elements", "+elevation"); - _A2T strW(str); - HWND hList = GetDlgItem((HWND)wParam, IDC_DATALIST); - LV_ITEM lvi = {}; - lvi.mask = LVIF_TEXT | LVIF_PARAM; - lvi.lParam = T.indexOf(&str); - lvi.pszText = TranslateW(strW); - lvi.iItem = ListView_InsertItem(hList, &lvi); - lvi.pszText = wszText; - ListView_SetItemText(hList, lvi.iItem, 1, wszText); - break; - } - mir_free(str); - } + auto *ret = Netlib_HttpTransaction(m_hNetlibUser, pReq); + delete pReq; + return ret; } |