summaryrefslogtreecommitdiff
path: root/protocols/Weather/src/weather_data.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Weather/src/weather_data.cpp')
-rw-r--r--protocols/Weather/src/weather_data.cpp420
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 &minus;
- if ((endloc - startloc) > 7 && wcsncmp(szInfo + startloc, L"&minus;", 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;
}