summaryrefslogtreecommitdiff
path: root/plugins/Weather/src
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2012-11-28 18:45:54 +0000
committerGeorge Hazan <george.hazan@gmail.com>2012-11-28 18:45:54 +0000
commita70382b0e8bed265a1d314d9f6aae8f2dd48d20b (patch)
tree9a99a073c0d7b9483dab51a0eebf04a9119f61ed /plugins/Weather/src
parent68fb5b69ea8403a3f9dcb70b3133eb10e1711000 (diff)
ex-protos moved to the Plugins folder
git-svn-id: http://svn.miranda-ng.org/main/trunk@2545 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Weather/src')
-rw-r--r--plugins/Weather/src/resource.h176
-rw-r--r--plugins/Weather/src/stdafx.cpp18
-rw-r--r--plugins/Weather/src/version.h6
-rw-r--r--plugins/Weather/src/weather.cpp266
-rw-r--r--plugins/Weather/src/weather.h545
-rw-r--r--plugins/Weather/src/weather_addstn.cpp428
-rw-r--r--plugins/Weather/src/weather_contacts.cpp486
-rw-r--r--plugins/Weather/src/weather_conv.cpp644
-rw-r--r--plugins/Weather/src/weather_data.cpp472
-rw-r--r--plugins/Weather/src/weather_http.cpp206
-rw-r--r--plugins/Weather/src/weather_icons.cpp87
-rw-r--r--plugins/Weather/src/weather_info.cpp252
-rw-r--r--plugins/Weather/src/weather_ini.cpp613
-rw-r--r--plugins/Weather/src/weather_mwin.cpp420
-rw-r--r--plugins/Weather/src/weather_opt.cpp642
-rw-r--r--plugins/Weather/src/weather_popup.cpp438
-rw-r--r--plugins/Weather/src/weather_svcs.cpp386
-rw-r--r--plugins/Weather/src/weather_update.cpp615
-rw-r--r--plugins/Weather/src/weather_userinfo.cpp402
19 files changed, 7102 insertions, 0 deletions
diff --git a/plugins/Weather/src/resource.h b/plugins/Weather/src/resource.h
new file mode 100644
index 0000000000..e88e4c19de
--- /dev/null
+++ b/plugins/Weather/src/resource.h
@@ -0,0 +1,176 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by resource.rc
+//
+#define IDI_ICON 101
+#define IDD_USERINFO 201
+#define IDD_EDIT 202
+#define IDI_DISABLED 203
+#define IDD_POPUP 204
+#define IDD_OPTIONS 205
+#define IDI_LOG 206
+#define IDI_UPDATE2 208
+#define IDI_READ 209
+#define IDI_UPDATE 210
+#define IDI_S 211
+#define IDI_MAP 212
+#define IDR_PMENU 213
+#define IDI_POPUP 214
+#define IDI_NOPOPUP 215
+#define IDD_TEXTOPT 216
+#define IDD_BRIEF 217
+#define IDD_SETUP 218
+#define IDR_TMENU 219
+#define IDR_TMMENU 220
+#define IDI_EDIT 222
+#define IDD_INFO 224
+#define IDD_SEARCHCITY 225
+#define IDC_NAME 2000
+#define IDC_ID 2001
+#define IDC_LOG 2003
+#define IDC_UPDATETIME 2005
+#define IDC_CTEXT 2006
+#define IDC_AVATARSIZE 2006
+#define IDC_UPDATE 2007
+#define IDC_BTITLE 2008
+#define IDC_STARTUPUPD 2008
+#define IDC_CHANGE 2009
+#define IDC_BTITLE2 2009
+#define IDC_USEWINCOLORS 2010
+#define IDC_BTEXT 2011
+#define IDC_CH 2013
+#define IDC_NTEXT 2015
+#define IDC_DEGREE 2016
+#define IDC_E 2017
+#define IDC_W 2018
+#define IDC_POP1 2019
+#define IDC_XTEXT 2020
+#define IDC_POP2 2020
+#define IDC_PText 2021
+#define IDC_PTitle 2023
+#define IDC_Internal 2024
+#define IDC_ETEXT 2025
+#define IDC_DISCONDICON 2025
+#define IDC_External 2026
+#define IDC_DONOTAPPUNITS 2026
+#define IDC_DEFA 2027
+#define IDC_NOFRAC 2027
+#define IDC_HTEXT 2028
+#define IDC_DPop 2029
+#define IDC_DAutoUpdate 2030
+#define IDC_NEWWIN 2031
+#define IDC_IURL 2032
+#define IDC_MURL 2033
+#define IDC_PROTOCOND 2034
+#define IDC_Overwrite 2035
+#define IDC_UPDCONDCHG 2036
+#define IDC_REMOVEOLD 2037
+#define IDC_MAKEI 2039
+#define IDC_BGCOLOUR 2040
+#define IDC_TEXTCOLOUR 2041
+#define IDC_LeftClick 2042
+#define IDC_PREVIEW 2043
+#define IDC_VAR3 2044
+#define IDC_RightClick 2045
+#define IDC_DELAY 2046
+#define IDC_PDEF 2047
+#define IDC_T1 2048
+#define IDC_T2 2049
+#define IDC_W1 2050
+#define IDC_W2 2051
+#define IDC_W3 2052
+#define IDC_W4 2053
+#define IDC_BROWSE 2054
+#define IDC_VIEW1 2055
+#define IDC_RESET1 2056
+#define IDC_VIEW2 2057
+#define IDC_V1 2058
+#define IDC_V2 2059
+#define IDC_RESET2 2060
+#define IDC_SVCINFO 2061
+#define IDC_GETNAME 2062
+#define IDC_P1 2063
+#define IDC_P2 2064
+#define IDC_P3 2065
+#define IDC_P4 2066
+#define IDC_RESET 2067
+#define IDC_D1 2067
+#define IDC_D2 2068
+#define IDC_D3 2069
+#define IDC_INFO1 2069
+#define IDC_INFOICON 2070
+#define IDC_INFO11 2071
+#define IDC_INFO2 2072
+#define IDC_INFO3 2073
+#define IDC_VARLIST 2074
+#define IDC_INFO4 2075
+#define IDC_INFO5 2076
+#define IDC_PD1 2077
+#define IDC_PD2 2078
+#define IDC_PD3 2079
+#define IDC_INFO6 2079
+#define IDC_TM1 2080
+#define IDC_TM2 2081
+#define IDC_TM3 2082
+#define IDC_TM4 2083
+#define IDC_TM5 2084
+#define IDC_TM6 2085
+#define IDC_TM7 2086
+#define IDC_TM8 2087
+#define IDC_INFO7 2087
+#define IDC_TM9 2088
+#define IDC_INFO8 2089
+#define IDC_INFO9 2090
+#define IDC_INFO10 2091
+#define IDC_INFO12 2092
+#define IDC_INFO13 2093
+#define IDC_MORE 2094
+#define IDC_MOREDETAIL 2095
+#define IDC_DATALIST 2096
+#define IDC_MUPDATE 2097
+#define IDC_MFRAME 2099
+#define IDC_MTOGGLE 2101
+#define IDC_MWEBPAGE 2102
+#define IDC_MTEXT 2103
+#define IDC_STEP1 2107
+#define IDC_STEP2 2108
+#define IDC_STEP3 2109
+#define IDC_STEP4 2110
+#define IDC_INFOLIST 2117
+#define IDC_RELOADINI 2118
+#define IDC_MEMUSED 2119
+#define IDC_INICOUNT 2120
+#define IDC_AVATARSPIN 2124
+#define IDC_SEARCHCITY 2125
+#define IDC_HEADERBAR 2126
+#define IDC_E1 2128
+#define IDC_E2 2129
+#define OIC_HAND 32513
+#define OIC_QUES 32514
+#define OIC_BANG 32515
+#define OIC_NOTE 32516
+#define IDM_M1 40002
+#define IDM_M2 40003
+#define IDM_M3 40004
+#define IDM_M4 40005
+#define IDM_M5 40006
+#define IDM_M6 40007
+#define IDM_M7 40008
+#define IDM_M8 40009
+#define ID_T1 40010
+#define ID_T2 40011
+#define ID_MPREVIEW 40020
+#define ID_MRESET 40021
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 226
+#define _APS_NEXT_COMMAND_VALUE 40030
+#define _APS_NEXT_CONTROL_VALUE 2128
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/Weather/src/stdafx.cpp b/plugins/Weather/src/stdafx.cpp
new file mode 100644
index 0000000000..2d786344e5
--- /dev/null
+++ b/plugins/Weather/src/stdafx.cpp
@@ -0,0 +1,18 @@
+/*
+Copyright (c) 2012 Miranda NG team (http://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "weather.h" \ No newline at end of file
diff --git a/plugins/Weather/src/version.h b/plugins/Weather/src/version.h
new file mode 100644
index 0000000000..58a8f34a3c
--- /dev/null
+++ b/plugins/Weather/src/version.h
@@ -0,0 +1,6 @@
+#define __FILEVERSION_STRING 0,3,9,1
+#define __VERSION_STRING "0.3.9.1"
+#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 3, 9, 1)
+
+#define BETA FALSE
+#define AUTH "NoName, borkra"
diff --git a/plugins/Weather/src/weather.cpp b/plugins/Weather/src/weather.cpp
new file mode 100644
index 0000000000..9eb22252b5
--- /dev/null
+++ b/plugins/Weather/src/weather.cpp
@@ -0,0 +1,266 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+Main file for the Weather Protocol, includes loading, unloading,
+upgrading, support for plugin uninsaller, and anything that doesn't
+belong to any other file.
+*/
+
+#include "weather.h"
+
+//============ GLOBAL VARIABLES ============
+
+WIDATALIST *WIHead;
+WIDATALIST *WITail;
+
+HINSTANCE hInst;
+HWND hPopupWindow;
+
+HANDLE hHookWeatherUpdated;
+HANDLE hHookWeatherError;
+
+HANDLE hDataWindowList;
+HANDLE hWindowList;
+
+HANDLE hUpdateMutex;
+
+unsigned status;
+unsigned old_status;
+
+UINT_PTR timerId;
+int hLangpack;
+
+MYOPTIONS opt;
+
+// check if weather is currently updating
+BOOL ThreadRunning;
+
+// variable to determine if module loaded
+BOOL ModuleLoaded;
+
+
+
+
+// plugin info
+// VER = version, AUTH = author, defined in weather.h
+static const PLUGININFOEX pluginInfoEx =
+{
+ sizeof(PLUGININFOEX),
+ "Weather Protocol",
+ __VERSION_DWORD,
+ "Retrieves weather information and displays it in your contact list.",
+ AUTH,
+ "borkra@miranda-im.org",
+ "(c) 2002-2005 NoName, 2005-2010 Boris Krasnovskiy",
+ "http://miranda-ng.org/",
+ UNICODE_AWARE,
+ MIID_WEATHER
+};
+
+extern "C" __declspec(dllexport) const PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ return &pluginInfoEx;
+}
+
+// MirandaInterfaces - returns the protocol interface to the core
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST};
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ hInst = hinstDLL;
+ return TRUE;
+}
+
+
+int WeatherShutdown(WPARAM wParam,LPARAM lParam)
+{
+ KillTimer(NULL, timerId); // kill update timer
+
+ SaveOptions(); // save options once more
+ status = ID_STATUS_OFFLINE; // set status to offline
+
+ CallService(MS_NETLIB_SHUTDOWN, (WPARAM)hNetlibHttp, 0);
+
+ WindowList_Broadcast(hWindowList, WM_CLOSE, 0, 0);
+ WindowList_Broadcast(hDataWindowList, WM_CLOSE, 0, 0);
+ SendMessage(hWndSetup, WM_CLOSE, 0, 0);
+
+ return 0;
+}
+
+// update some settings/db values for new version
+// lastver = dword value for the last version made by PLUGIN_MAKE_VERSION
+void Upgrade(DWORD lastver)
+{
+ // for version below v0.3.2.3, remove the "TriggerText" setting
+ if (lastver < PLUGIN_MAKE_VERSION(0,3,2,3))
+ db_unset(NULL, WEATHERPROTONAME, "TriggerText");
+ if (lastver < PLUGIN_MAKE_VERSION(0,3,3,13))
+ db_unset(NULL, "KnownModules", "Weather");
+
+ db_set_dw(NULL, WEATHERPROTONAME, "Version", __VERSION_DWORD);
+}
+
+// weather protocol initialization function
+// run after the event ME_SYSTEM_MODULESLOADED occurs
+int WeatherInit(WPARAM wParam,LPARAM lParam)
+{
+ // initialize netlib
+ NetlibInit();
+
+ InitIcons();
+ InitMwin();
+
+ // load weather menu items
+ AddMenuItems();
+
+ // timer for the first update
+ timerId = SetTimer(NULL, 0, 5000, timerProc2); // first update is 5 sec after load
+
+ // weather user detail
+ HookEvent(ME_USERINFO_INITIALISE, UserInfoInit);
+
+ hDataWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ hWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+
+ return 0;
+}
+
+// update some settings/db values for new version, this one is for contact
+// lastver = dword value for the last version made by PLUGIN_MAKE_VERSION
+// hContact = current contact
+void UpgradeContact(DWORD lastver, HANDLE hContact)
+{
+ // for version below v0.3.2.3, suppress online notifications for all weather contacts
+ if (lastver < PLUGIN_MAKE_VERSION(0,3,2,3))
+ {
+ db_set_dw(hContact, "Ignore", "Mask", 8);
+ db_set_dw(hContact, "Ignore", "Mask1", 8);
+ }
+}
+
+//============ MISC FUNCTIONS ============
+
+// initialize the global variables at startup
+void InitVar()
+{
+ // setup the linklist for weather update list
+ UpdateListTail = NULL;
+ UpdateListHead = NULL;
+
+ // other settings
+ timerId = 0;
+ opt.DefStn = NULL;
+ ModuleLoaded = FALSE;
+}
+
+// unload function
+extern "C" int __declspec(dllexport) Unload(void)
+{
+ DestroyMwin();
+ DestroyWindow(hPopupWindow);
+
+ DestroyHookableEvent(hHookWeatherUpdated);
+ DestroyHookableEvent(hHookWeatherError);
+
+ NetlibHttpDisconnect();
+ Netlib_CloseHandle(hNetlibUser);
+
+ DestroyUpdateList();
+ DestroyOptions();
+ DestroyWIList(); // unload all ini data from memory
+
+ CloseHandle(hUpdateMutex);
+ return 0;
+}
+
+extern "C" int __declspec(dllexport) Load(void)
+{
+ DWORD lastver;
+
+ mir_getLP(&pluginInfoEx);
+
+ // initialize global variables
+ InitVar();
+
+ // load options and set defaults
+ LoadOptions();
+
+ // upgrade check
+ // I only support version check and upgrade for my own version, so check if the author is my name
+ if (strstr(AUTH, "NoName") != NULL)
+ {
+ lastver = db_get_dw(NULL, WEATHERPROTONAME, "Version", PLUGIN_MAKE_VERSION(0,3,1,8));
+ if (lastver < __VERSION_DWORD) Upgrade(lastver);
+ }
+ else // if it is not my build, ignore upgrade procedure
+ lastver = PLUGIN_MAKE_VERSION(255,255,255,255);
+
+ // reset the weather data at startup for individual contacts
+ EraseAllInfo(lastver);
+
+ // load weather update data
+ LoadWIData(TRUE);
+
+ // set status to online if "Do not display weather condition as protocol status" is enabled
+ old_status = status = ID_STATUS_OFFLINE;
+
+ // add an event on weather update and error
+ hHookWeatherUpdated = CreateHookableEvent(ME_WEATHER_UPDATED);
+ hHookWeatherError = CreateHookableEvent(ME_WEATHER_ERROR);
+
+ // initialize options and network
+ HookEvent(ME_OPT_INITIALISE, OptInit);
+ HookEvent(ME_SYSTEM_MODULESLOADED, WeatherInit);
+ HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted);
+ HookEvent(ME_CLIST_DOUBLECLICKED, BriefInfo);
+ HookEvent(ME_WEATHER_UPDATED, WeatherPopup);
+ HookEvent(ME_WEATHER_ERROR, WeatherError);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, WeatherShutdown);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, BuildContactMenu);
+
+ hUpdateMutex = CreateMutex(NULL, FALSE, NULL);
+
+ // register weather protocol
+ PROTOCOLDESCRIPTOR pd = { PROTOCOLDESCRIPTOR_V3_SIZE };
+ pd.szName = WEATHERPROTONAME;
+ pd.type = (opt.NoProtoCondition) ? PROTOTYPE_VIRTUAL : PROTOTYPE_PROTOCOL;
+ CallService(MS_PROTO_REGISTERMODULE,0, (LPARAM)&pd);
+
+ // initialize weather protocol services
+ InitServices();
+
+ // add our modules to the KnownModules list
+ db_set_s(NULL, "KnownModules", "Weather Protocol", "Weather,WeatherCondition,Current");
+
+ // add sound event
+ SkinAddNewSoundExT("weatherupdated", _T(WEATHERPROTONAME), LPGENT("Weather Condition Changed"));
+ SkinAddNewSoundExT("weatheralert", _T(WEATHERPROTONAME), LPGENT("Weather Alert Issued"));
+
+ // window needed for popup commands
+ TCHAR SvcFunc[100];
+ mir_sntprintf( SvcFunc, SIZEOF(SvcFunc), _T("%s__PopupWindow"), _T(WEATHERPROTONAME));
+ hPopupWindow = CreateWindowEx(WS_EX_TOOLWINDOW,_T("static"),SvcFunc,0,CW_USEDEFAULT,CW_USEDEFAULT,
+ CW_USEDEFAULT,CW_USEDEFAULT,HWND_DESKTOP,NULL, hInst,NULL);
+ SetWindowLongPtr(hPopupWindow, GWLP_WNDPROC, (LONG_PTR)PopupWndProc);
+
+ return 0;
+}
diff --git a/plugins/Weather/src/weather.h b/plugins/Weather/src/weather.h
new file mode 100644
index 0000000000..072860c914
--- /dev/null
+++ b/plugins/Weather/src/weather.h
@@ -0,0 +1,545 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contains the includes, weather constants/declarations,
+ the structs, and the primitives for some of the functions.
+*/
+
+//============ THE INCLUDES ===========
+
+#define _CRT_SECURE_NO_WARNINGS
+#include <m_stdhdr.h>
+
+#include <stdio.h>
+#include <io.h>
+#include <share.h>
+#include <direct.h>
+#include <process.h>
+#include <time.h>
+
+#include <windows.h>
+#include <commctrl.h>
+#include <richedit.h>
+
+#include <win2k.h>
+
+#define MIRANDA_VER 0x0A00
+
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_system_cpp.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_clist.h>
+#include <m_icolib.h>
+#include <m_options.h>
+#include <m_langpack.h>
+#include <m_skin.h>
+#include <m_database.h>
+#include <m_history.h>
+#include <m_utils.h>
+#include <m_userinfo.h>
+#include <m_netlib.h>
+#include <m_ignore.h>
+#include <m_findadd.h>
+#include <m_button.h>
+#include <m_avatars.h>
+#include <m_clui.h>
+#include <m_clc.h>
+#include <m_fontservice.h>
+#include <m_skin_eng.h>
+#include <m_cluiframes.h>
+
+#include <m_popup.h>
+
+#include "m_weather.h"
+#include "resource.h"
+#include "version.h"
+
+//============ CONSTANTS ============
+
+// status
+#define NOSTATUSDATA 1
+
+// limits
+#define MAX_TEXT_SIZE 4096
+#define MAX_DATA_LEN 1024
+
+// db info mangement mode
+#define WDBM_REMOVE 1
+#define WDBM_DETAILDISPLAY 2
+
+// more info list column width
+#define LIST_COLUMN 150
+
+// others
+#define NODATA TranslateT("N/A")
+#define UM_SETCONTACT 40000
+
+// weather update error codes
+#define INVALID_ID_FORMAT 10
+#define INVALID_SVC 11
+#define INVALID_ID 12
+#define SVC_NOT_FOUND 20
+#define NETLIB_ERROR 30
+#define DATA_EMPTY 40
+#define DOC_NOT_FOUND 42
+#define DOC_TOO_SHORT 43
+#define UNKNOWN_ERROR 99
+
+// weather update error text
+#define E10 TranslateT("Invalid ID format, missing \"/\" (10)")
+#define E11 TranslateT("Invalid service (11)")
+#define E12 TranslateT("Invalid station (12)")
+#define E20 TranslateT("Weather service ini for this station is not found (20)")
+#define E30 TranslateT("Netlib error - check your internet connection (30)")
+#define E40 TranslateT("Empty data is retrieved (40)")
+#define E42 TranslateT("Document not found (42)")
+#define E43 TranslateT("Document too short to contain any weather data (43)")
+#define E99 TranslateT("Unknown error (99)")
+
+// HTTP error... not all translated
+// 100 Continue
+// 101 Switching Protocols
+// 200 OK
+// 201 Created
+// 202 Accepted
+// 203 Non-Authoritative Information
+#define E204 TranslateT("HTTP Error: No content (204)")
+// 205 Reset Content
+// 206 Partial Content
+// 300 Multiple Choices
+#define E301 TranslateT("HTTP Error: Data moved (301)")
+// 302 Found
+// 303 See Other
+// 304 Not Modified
+#define E305 TranslateT("HTTP Error: Use proxy (305)")
+// 306 (Unused)
+#define E307 TranslateT("HTTP Error: Temporary redirect (307)")
+#define E400 TranslateT("HTTP Error: Bad request (400)")
+#define E401 TranslateT("HTTP Error: Unauthorized (401)")
+#define E402 TranslateT("HTTP Error: Payment required (402)")
+#define E403 TranslateT("HTTP Error: Forbidden (403)")
+#define E404 TranslateT("HTTP Error: Not found (404)")
+#define E405 TranslateT("HTTP Error: Method not allowed (405)")
+// 406 Not Acceptable
+#define E407 TranslateT("HTTP Error: Proxy authentication required (407)")
+// 408 Request Timeout
+// 409 Conflict
+#define E410 TranslateT("HTTP Error: Gone (410)")
+// 411 Length Required
+// 412 Precondition Failed
+// 413 Request Entity Too Large
+// 414 Request-URI Too Long
+// 415 Unsupported Media Type
+// 416 Requested Range Not Satisfiable
+// 417 Expectation Failed
+#define E500 TranslateT("HTTP Error: Internal server error (500)")
+// 501 Not Implemented
+#define E502 TranslateT("HTTP Error: Bad gateway (502)")
+#define E503 TranslateT("HTTP Error: Service unavailable (503)")
+#define E504 TranslateT("HTTP Error: Gateway timeout (504)")
+// 505 HTTP Version Not Supported
+
+// defaults constants
+#define C_DEFAULT TranslateT("%n [%t, %c]")
+#define N_DEFAULT TranslateT("%c\nTemperature: %t\nFeel-Like: %f\nPressure: %p\nWind: %i %w\nHumidity: %m\nDew Point: %e\nVisibility: %v\n\nSun Rise: %r\nSun Set: %y\n\n5 Days Forecast:\n%[Forecast Day 1]\n%[Forecast Day 2]\n%[Forecast Day 3]\n%[Forecast Day 4]\n%[Forecast Day 5]")
+#define B_DEFAULT TranslateT("Feel-Like: %f\nPressure: %p\nWind: %i %w\nHumidity: %m\nDew Point: %e\nVisibility: %v\n\nSun Rise: %r\nSun Set: %y\n\n5 Days Forecast:\n%[Forecast Day 1]\n%[Forecast Day 2]\n%[Forecast Day 3]\n%[Forecast Day 4]\n%[Forecast Day 5]")
+#define b_DEFAULT TranslateT("Weather Condition for %n as of %u")
+#define X_DEFAULT N_DEFAULT
+#define H_DEFAULT TranslateT("%c, %t (feel-like %f) Wind: %i %w Humidity: %m")
+#define E_DEFAULT TranslateT("%n at %u: %c, %t (feel-like %f) Wind: %i %w Humidity: %m")
+#define P_DEFAULT TranslateT("%n (%u)")
+#define p_DEFAULT TranslateT("%c, %t\nToday: High %h, Low %l")
+#define s_DEFAULT TranslateT("Temperature: %[Temperature]")
+
+
+//============ OPTION STRUCT ============
+
+// option struct
+typedef struct {
+// main options
+ BOOL AutoUpdate;
+ BOOL CAutoUpdate;
+ BOOL StartupUpdate;
+ WORD UpdateTime;
+ WORD AvatarSize;
+ BOOL NewBrowserWin;
+ BOOL NoProtoCondition;
+ BOOL UpdateOnlyConditionChanged;
+ BOOL RemoveOldData;
+ BOOL MakeItalic;
+// units
+ WORD tUnit;
+ WORD wUnit;
+ WORD vUnit;
+ WORD pUnit;
+ WORD dUnit;
+ WORD eUnit;
+ TCHAR DegreeSign[4];
+ BOOL DoNotAppendUnit;
+ BOOL NoFrac;
+// texts
+ TCHAR *cText;
+ TCHAR *bTitle;
+ TCHAR *bText;
+ TCHAR *nText;
+ TCHAR *eText;
+ TCHAR *hText;
+ TCHAR *xText;
+ TCHAR *sText;
+// advanced
+ BOOL DisCondIcon;
+// popup options
+ BOOL UsePopup;
+ BOOL UpdatePopup;
+ BOOL AlertPopup;
+ BOOL PopupOnChange;
+ BOOL ShowWarnings;
+// popup colors
+ BOOL UseWinColors;
+ COLORREF BGColour;
+ COLORREF TextColour;
+// popup actions
+ DWORD LeftClickAction;
+ DWORD RightClickAction;
+// popup delay
+ DWORD pDelay;
+// popup texts
+ TCHAR *pTitle;
+ TCHAR *pText;
+// other misc stuff
+ TCHAR Default[64];
+ HANDLE DefStn;
+} MYOPTIONS;
+
+void DestroyOptions(void);
+
+//============ STRUCT USED TO MAKE AN UPDATE LIST ============
+
+struct WCONTACTLIST {
+ HANDLE hContact;
+ struct WCONTACTLIST *next;
+};
+
+typedef struct WCONTACTLIST UPDATELIST;
+
+extern UPDATELIST *UpdateListHead;
+extern UPDATELIST *UpdateListTail;
+
+void DestroyUpdateList(void);
+
+//============ DATA FORMAT STRUCT ============
+
+#define WID_NORMAL 0
+#define WID_SET 1
+#define WID_BREAK 2
+
+typedef struct {
+ TCHAR *Name;
+ TCHAR *Start;
+ TCHAR *End;
+ TCHAR *Unit;
+ char *Url;
+ TCHAR *Break;
+ int Type;
+} WIDATAITEM;
+
+struct WITEMLIST {
+ WIDATAITEM Item;
+ struct WITEMLIST *Next;
+};
+
+typedef struct WITEMLIST WIDATAITEMLIST;
+
+typedef struct {
+ BOOL Available;
+ char *SearchURL;
+ TCHAR *NotFoundStr;
+ WIDATAITEM Name;
+} WIIDSEARCH;
+
+typedef struct {
+ BOOL Available;
+ TCHAR *First;
+ WIDATAITEM Name;
+ WIDATAITEM ID;
+} WINAMESEARCHTYPE;
+
+typedef struct {
+ char *SearchURL;
+ TCHAR *NotFoundStr;
+ TCHAR *SingleStr;
+ WINAMESEARCHTYPE Single;
+ WINAMESEARCHTYPE Multiple;
+} WINAMESEARCH;
+
+struct STRLIST {
+ TCHAR *Item;
+ struct STRLIST *Next;
+};
+
+typedef struct STRLIST WICONDITEM;
+
+typedef struct {
+ WICONDITEM *Head;
+ WICONDITEM *Tail;
+} WICONDLIST;
+
+typedef struct {
+ TCHAR *FileName;
+ TCHAR *ShortFileName;
+ BOOL Enabled;
+
+ // header
+ TCHAR *DisplayName;
+ TCHAR *InternalName;
+ TCHAR *Description;
+ TCHAR *Author;
+ TCHAR *Version;
+ int InternalVer;
+ size_t MemUsed;
+
+ // default
+ char *DefaultURL;
+ TCHAR *DefaultMap;
+ char *UpdateURL;
+ char *UpdateURL2;
+ char *UpdateURL3;
+ char *UpdateURL4;
+ char *Cookie;
+// items
+ int UpdateDataCount;
+ WIDATAITEMLIST *UpdateData;
+ WIDATAITEMLIST *UpdateDataTail;
+ WIIDSEARCH IDSearch;
+ WINAMESEARCH NameSearch;
+ WICONDLIST CondList[10];
+} WIDATA;
+
+//============ DATA LIST (LINKED LIST) ============
+
+struct DATALIST {
+ WIDATA Data;
+ struct DATALIST *next;
+};
+
+typedef struct DATALIST WIDATALIST;
+
+//============ GLOBAL VARIABLES ============
+
+extern WIDATALIST *WIHead;
+extern WIDATALIST *WITail;
+
+extern HINSTANCE hInst;
+extern HWND hPopupWindow;
+extern HWND hWndSetup;
+
+extern MYOPTIONS opt;
+
+extern unsigned status;
+extern unsigned old_status;
+
+extern HANDLE hDataWindowList;
+extern HANDLE hNetlibUser, hNetlibHttp;
+extern HANDLE hHookWeatherUpdated;
+extern HANDLE hHookWeatherError;
+extern HANDLE hWindowList;
+extern HANDLE hMwinMenu;
+
+extern UINT_PTR timerId;
+
+// check if weather is currently updating
+extern BOOL ThreadRunning;
+
+//============ FUNCTION PRIMITIVES ============
+
+// functions in weather.c
+void UpgradeContact(DWORD lastver, HANDLE hContact);
+
+// functions in weather_addstn.c
+INT_PTR WeatherAddToList(WPARAM wParam,LPARAM lParam);
+BOOL CheckSearch();
+
+int IDSearch(TCHAR *id, const int searchId);
+int NameSearch(TCHAR *name, const int searchId);
+
+INT_PTR WeatherBasicSearch(WPARAM wParam,LPARAM lParam);
+INT_PTR WeatherCreateAdvancedSearchUI(WPARAM wParam, LPARAM lParam);
+INT_PTR WeatherAdvancedSearch(WPARAM wParam, LPARAM lParam);
+
+int WeatherAdd(WPARAM wParam, LPARAM lParam);
+
+// functions used in weather_contacts.c
+INT_PTR ViewLog(WPARAM wParam,LPARAM lParam);
+INT_PTR LoadForecast(WPARAM wParam,LPARAM lParam);
+INT_PTR WeatherMap(WPARAM wParam,LPARAM lParam);
+
+INT_PTR EditSettings(WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK DlgProcChange(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+int ContactDeleted(WPARAM wParam,LPARAM lParam);
+
+BOOL IsMyContact(HANDLE hContact);
+
+// functions in weather_conv.c
+BOOL is_number(char *s);
+
+void GetTemp(TCHAR *tempchar, TCHAR *unit, TCHAR *str);
+void GetSpeed(TCHAR *tempchar, TCHAR *unit, TCHAR *str);
+void GetPressure(TCHAR *tempchar, TCHAR *unit, TCHAR *str);
+void GetDist(TCHAR *tempchar, TCHAR *unit, TCHAR *str);
+void GetElev(TCHAR *tempchar, TCHAR *unit, TCHAR *str);
+
+WORD GetIcon(const TCHAR* cond, WIDATA *Data);
+void CaseConv(TCHAR *str);
+void TrimString(char *str);
+void TrimString(WCHAR *str);
+void ConvertBackslashes(char *str);
+char *GetSearchStr(char *dis);
+
+TCHAR *GetDisplay(WEATHERINFO *w, const TCHAR *dis, TCHAR* str);
+INT_PTR GetDisplaySvcFunc(WPARAM wParam, LPARAM lParam);
+
+void GetSvc(TCHAR *pszID);
+void GetID(TCHAR *pszID);
+
+TCHAR *GetError(int code);
+
+// functions in weather_data.c
+void GetStationID(HANDLE hContact, TCHAR* id, size_t idlen);
+WEATHERINFO LoadWeatherInfo(HANDLE Change);
+int DBGetData(HANDLE hContact, char *setting, DBVARIANT *dbv);
+int DBGetStaticString(HANDLE hContact, const char *szModule, const char *valueName, TCHAR *dest, size_t dest_len);
+
+void EraseAllInfo(DWORD lastver);
+
+void LoadStationData(TCHAR *pszFile, TCHAR *pszShortFile, WIDATA *Data);
+void GetDataValue(WIDATAITEM *UpdateData, TCHAR *Data, TCHAR** szInfo);
+void ConvertDataValue(WIDATAITEM *UpdateData, TCHAR *Data);
+void wSetData(char **Data, const char *Value);
+void wSetData(WCHAR **Data, const char *Value);
+void wSetData(WCHAR **Data, const WCHAR *Value);
+void wfree(char **Data);
+void wfree(WCHAR **Data);
+
+void DBDataManage(HANDLE hContact, WORD Mode, WPARAM wParam, LPARAM lParam);
+
+// functions in weather_http.c
+int InternetDownloadFile (char *szUrl, char *cookie, TCHAR** szData);
+void NetlibInit();
+void NetlibHttpDisconnect(void);
+
+// functions in weather_ini.c
+void WIListAdd(WIDATA Data);
+WIDATA* GetWIData(TCHAR *pszServ);
+
+BOOL IsContainedInCondList(const TCHAR *pszStr, WICONDLIST *List);
+
+void DestroyWIList();
+BOOL LoadWIData(BOOL dial);
+void FreeWIData(WIDATA *Data);
+
+INT_PTR CALLBACK DlgProcSetup(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// functions in weather_info.c
+void GetINIInfo(TCHAR *pszSvc);
+
+void MoreVarList();
+
+// functions in weather_opt.c
+void SetTextDefault(const char* in);
+void LoadOptions();
+void SaveOptions();
+
+int OptInit(WPARAM wParam,LPARAM lParam);
+
+INT_PTR CALLBACK OptionsProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam);
+void SetIconDefault();
+void RemoveIconSettings();
+
+BOOL CALLBACK TextOptionsProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam);
+BOOL CALLBACK AdvOptionsProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam);
+INT_PTR CALLBACK DlgProcText(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgPopUpOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// functions in weather_popup.c
+int WeatherPopup(WPARAM wParam, LPARAM lParam);
+int WeatherError(WPARAM wParam, LPARAM lParam);
+int WPShowMessage(TCHAR* lpzText, WORD kind);
+
+LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+// functions in weather_svcs.c
+void InitServices(void);
+
+INT_PTR WeatherSetStatus(WPARAM new_status, LPARAM lParam);
+INT_PTR WeatherGetCaps(WPARAM wParam, LPARAM lParam);
+INT_PTR WeatherGetName(WPARAM wParam, LPARAM lParam);
+INT_PTR WeatherGetStatus(WPARAM wParam, LPARAM lParam);
+INT_PTR WeatherLoadIcon(WPARAM wParam, LPARAM lParam);
+
+void UpdateMenu(BOOL State);
+void UpdatePopupMenu(BOOL State);
+void AddMenuItems();
+void AvatarDownloaded(HANDLE hContact);
+
+// functions in weather_update.c
+int UpdateWeather(HANDLE hContact);
+
+int RetrieveWeather(HANDLE hContact, WEATHERINFO *winfo);
+
+void UpdateAll(BOOL AutoUpdate, BOOL RemoveOld);
+void UpdateThreadProc(LPVOID hWnd);
+INT_PTR UpdateSingleStation(WPARAM wParam,LPARAM lParam);
+INT_PTR UpdateAllInfo(WPARAM wParam,LPARAM lParam);
+INT_PTR UpdateSingleRemove(WPARAM wParam,LPARAM lParam);
+INT_PTR UpdateAllRemove(WPARAM wParam,LPARAM lParam);
+
+int GetWeatherData(HANDLE hContact);
+
+void CALLBACK timerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+void CALLBACK timerProc2(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+
+// function from multiwin module
+void InitMwin(void);
+void DestroyMwin(void);
+INT_PTR Mwin_MenuClicked(WPARAM wParam, LPARAM lParam);
+int BuildContactMenu(WPARAM wparam, LPARAM lparam);
+void UpdateMwinData(HANDLE hContact);
+void removeWindow(HANDLE hContact);
+
+// functions in weather_userinfo.c
+int UserInfoInit(WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcUIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcMoreData(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#define WM_UPDATEDATA WM_USER + 2687
+
+int BriefInfo(WPARAM wParam, LPARAM lParam);
+INT_PTR BriefInfoSvc(WPARAM wParam, LPARAM lParam);
+void LoadBriefInfoText(HWND hwndDlg, HANDLE hContact);
+INT_PTR CALLBACK DlgProcBrief(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+void InitIcons(void);
+HICON LoadIconEx(const char* name, BOOL big);
+HANDLE GetIconHandle(const char* name);
+void ReleaseIconEx(HICON hIcon);
diff --git a/plugins/Weather/src/weather_addstn.cpp b/plugins/Weather/src/weather_addstn.cpp
new file mode 100644
index 0000000000..9a3f1fd19f
--- /dev/null
+++ b/plugins/Weather/src/weather_addstn.cpp
@@ -0,0 +1,428 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contain the source related to search and add a weather station
+to the contact list. Contain code for both name and ID search.
+*/
+
+#include "weather.h"
+
+// variables used for weather_addstn.c
+static int searchId = -1;
+static TCHAR name1[256];
+
+// ============ ADDING NEW STATION ============
+
+// protocol service function for adding a new contact onto contact list
+// lParam = PROTOSEARCHRESULT
+INT_PTR WeatherAddToList(WPARAM wParam, LPARAM lParam)
+{
+ PROTOSEARCHRESULT *psr = (PROTOSEARCHRESULT*)lParam;
+ WIDATA *sData;
+
+ // search for existing contact
+ HANDLE hContact = db_find_first();
+ while (hContact != NULL) {
+ // check if it is a weather contact
+ if ( IsMyContact(hContact)) {
+ DBVARIANT dbv;
+ // check ID to see if the contact already exist in the database
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "ID", &dbv)) {
+ if ( !_tcsicmp(psr->email, dbv.ptszVal)) {
+ // remove the flag for not on list and hidden, thus make the contact visible
+ // and add them on the list
+ if (db_get_b(hContact, "CList", "NotOnList", 1)) {
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Hidden");
+ }
+ db_free(&dbv);
+ // contact is added, function quitting
+ return (INT_PTR)hContact;
+ }
+ db_free(&dbv);
+ }
+ }
+ hContact = db_find_next(hContact);
+ }
+
+ // if contact with the same ID was not found, add it
+ if (psr->cbSize < sizeof(PROTOSEARCHRESULT)) return 0;
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0);
+ CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)WEATHERPROTONAME);
+ // suppress online notification for the new contact
+ CallService(MS_IGNORE_IGNORE, (WPARAM)hContact, IGNOREEVENT_USERONLINE);
+
+ // set contact info and settings
+ TCHAR svc[256];
+ _tcsncpy(svc, psr->email, SIZEOF(svc)); svc[SIZEOF(svc)-1] = 0;
+ GetSvc(svc);
+ // set settings by obtaining the default for the service
+ if (psr->lastName[0] != 0) {
+ sData = GetWIData(svc);
+ db_set_ts(hContact, WEATHERPROTONAME, "MapURL", sData->DefaultMap);
+ db_set_s(hContact, WEATHERPROTONAME, "InfoURL", sData->DefaultURL);
+ }
+ else { // if no valid service is found, create empty strings for MapURL and InfoURL
+ db_set_s(hContact, WEATHERPROTONAME, "MapURL", "");
+ db_set_s(hContact, WEATHERPROTONAME, "InfoURL", "");
+ }
+ // write the other info and settings to the database
+ db_set_ts(hContact, WEATHERPROTONAME, "ID", psr->email);
+ db_set_ts(hContact, WEATHERPROTONAME, "Nick", psr->nick);
+ db_set_w(hContact, WEATHERPROTONAME, "Status", ID_STATUS_OFFLINE);
+
+ AvatarDownloaded(hContact);
+
+ TCHAR str[256];
+ mir_sntprintf(str, SIZEOF(str), TranslateT("Current weather information for %s."), psr->nick);
+ db_set_ts(hContact, WEATHERPROTONAME, "About", str);
+
+ // make the last update tags to something invalid
+ db_set_s(hContact, WEATHERPROTONAME, "LastLog", "never");
+ db_set_s(hContact, WEATHERPROTONAME, "LastCondition", "None");
+ db_set_s(hContact, WEATHERPROTONAME, "LastTemperature", "None");
+
+ // ignore status change
+ db_set_dw(hContact, "Ignore", "Mask", 8);
+
+ // if no default station is found, set the new contact as default station
+ if (opt.Default[0] == 0) {
+ DBVARIANT dbv;
+ GetStationID(hContact, opt.Default, SIZEOF(opt.Default));
+
+ opt.DefStn = hContact;
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "Nick", &dbv)) {
+ // notification message box
+ wsprintf(str, TranslateT("%s is now the default weather station"), dbv.ptszVal);
+ db_free(&dbv);
+ MessageBox(NULL, str, TranslateT("Weather Protocol"), MB_OK|MB_ICONINFORMATION);
+ }
+ db_set_ts(NULL, WEATHERPROTONAME, "Default", opt.Default);
+ }
+ // display the Edit Settings dialog box
+ EditSettings((WPARAM)hContact, 0);
+ return (INT_PTR)hContact;
+}
+
+// ============ WARNING DIALOG ============
+
+// show a message box and cancel search if update is in process
+BOOL CheckSearch() {
+ if (UpdateListHead != NULL) {
+ MessageBox(NULL, TranslateT("Please try again after weather update is completed."), TranslateT("Weather Protocol"), MB_OK|MB_ICONERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// ============ BASIC ID SEARCH ============
+
+static TCHAR sID[32];
+
+// A timer process for the ID search (threaded)
+static void __cdecl BasicSearchTimerProc(LPVOID hWnd)
+{
+ int result;
+ // search only when it's not current updating weather.
+ if (CheckSearch())
+ result = IDSearch(sID, searchId);
+
+ // broadcast the search result
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)searchId, 0);
+
+ // exit the search
+ searchId = -1;
+}
+
+// the service function for ID search
+// lParam = ID search string
+INT_PTR WeatherBasicSearch(WPARAM wParam, LPARAM lParam)
+{
+ if (searchId != -1) return 0; //only one search at a time
+ _tcsncpy(sID, ( TCHAR* )lParam, SIZEOF(sID));
+ sID[SIZEOF(sID)-1] = 0;
+ searchId = 1;
+ // create a thread for the ID search
+ mir_forkthread(BasicSearchTimerProc, NULL);
+ return searchId;
+}
+
+// ============ NAME SEARCH ============
+
+// name search timer process (threaded)
+static void __cdecl NameSearchTimerProc(LPVOID hWnd)
+{
+ // search only when it's not current updating weather.
+ if (CheckSearch())
+ if (name1[0] != 0)
+ NameSearch(name1, searchId); // search nickname field
+
+ // broadcast the result
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)searchId, 0);
+
+ // exit the search
+ searchId = -1;
+}
+
+static INT_PTR CALLBACK WeatherSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetFocus(GetDlgItem(hwndDlg, IDC_SEARCHCITY));
+ return TRUE;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == EN_SETFOCUS)
+ PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg);
+ }
+ return FALSE;
+}
+
+INT_PTR WeatherCreateAdvancedSearchUI(WPARAM wParam, LPARAM lParam)
+{
+ HWND parent = (HWND)lParam;
+ if (parent)
+ return (INT_PTR)CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SEARCHCITY), parent, WeatherSearchAdvancedDlgProc, 0);
+
+ return 0;
+}
+
+// service function for name search
+INT_PTR WeatherAdvancedSearch(WPARAM wParam, LPARAM lParam)
+{
+ if (searchId != -1) return 0; //only one search at a time
+
+ searchId = 1;
+ GetDlgItemText((HWND)lParam, IDC_SEARCHCITY, name1, 256);
+
+ // search for the weather station using a thread
+ mir_forkthread(NameSearchTimerProc, NULL);
+ return searchId;
+}
+
+// ============ SEARCH FOR A WEATHER STATION USING ID ============
+
+// Seaching station ID from a single weather service (Threaded)
+// sID = search string for the station ID
+// searchId = -1
+// sData = the ID search data for that particular weather service
+// svcname = the name of the weather service that is currently searching (ie. Yahoo Weather)
+int IDSearchProc(TCHAR *sID, const int searchId, WIIDSEARCH *sData, TCHAR *svc, TCHAR *svcname)
+{
+ TCHAR str[MAX_DATA_LEN], newID[MAX_DATA_LEN];
+
+ if (sData->Available) {
+ char loc[255];
+ TCHAR *szData = NULL;
+
+ // load the page
+ mir_snprintf(loc, SIZEOF(loc), sData->SearchURL, sID);
+ if (InternetDownloadFile(loc, NULL, &szData) == 0) {
+ TCHAR* szInfo = szData;
+
+ // not found
+ if ( _tcsstr(szInfo, sData->NotFoundStr) == NULL)
+ GetDataValue(&sData->Name, str, &szInfo);
+ }
+ mir_free(szData);
+ // Station not found exit
+ if (str[0] == 0) return 1;
+ }
+
+ // give no station name but only ID if the search is unavailable
+ else _tcscpy(str, TranslateT("<Enter station name here>"));
+ mir_sntprintf(newID, SIZEOF(newID), _T("%s/%s"), svc, sID);
+
+ // set the search result and broadcast it
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_TCHAR;
+ psr.nick = str;
+ psr.firstName = _T(" ");
+ psr.lastName = svcname;
+ psr.email = newID;
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr);
+
+ return 0;
+}
+
+// ID search (Threaded)
+// sID: the ID to search for
+// searchId: don't change
+// return 0 if no error
+int IDSearch(TCHAR *sID, const int searchId)
+{
+ // for a normal ID search (ID != #)
+ if ( _tcscmp(sID, _T("#"))) {
+ WIDATALIST *Item = WIHead;
+
+ // search every weather service using the search station ID
+ while (Item != NULL) {
+ IDSearchProc(sID, searchId, &Item->Data.IDSearch, Item->Data.InternalName, Item->Data.DisplayName);
+ Item = Item->next;
+ }
+ NetlibHttpDisconnect();
+ }
+ // if the station ID is #, return a dummy result and quit the funciton
+ else {
+ // return an empty contact on "#"
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_TCHAR;
+ psr.nick = TranslateT("<Enter station name here>"); // to be entered
+ psr.firstName = _T(" ");
+ psr.lastName = _T("");
+ psr.email = TranslateT("<Enter station ID here>"); // to be entered
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr);
+ }
+
+ return 0;
+}
+
+// ============ SEARCH FOR A WEATHER STATION BY NAME ============
+
+// Seaching station name from a single weather service (Threaded)
+// name = the name of the weather station to be searched
+// searchId = -1
+// sData = the name search data for that particular weather service
+// svcname = the name of the weather service that is currently searching (ie. Yahoo Weather)
+int NameSearchProc(TCHAR *name, const int searchId, WINAMESEARCH *sData, TCHAR *svc, TCHAR *svcname)
+{
+ char loc[256];
+ TCHAR Name[MAX_DATA_LEN], str[MAX_DATA_LEN], sID[MAX_DATA_LEN], *szData = NULL, *search;
+
+ // replace spaces with %20
+ {
+ mir_ptr<char> szSearchName( mir_utf8encodeT(name));
+ char *pstr = (char*)CallService(MS_NETLIB_URLENCODE, 0, (LPARAM)(char*)szSearchName);
+ wsprintfA(loc, sData->SearchURL, pstr);
+ HeapFree(GetProcessHeap(), 0, pstr);
+ }
+
+ if (InternetDownloadFile(loc, NULL, &szData) == 0) {
+ TCHAR* szInfo = szData;
+ search = _tcsstr(szInfo, sData->NotFoundStr); // determine if data is available
+ if (search == NULL) { // if data is found
+ // test if it is single result
+ if (sData->Single.Available && sData->Multiple.Available)
+ search = _tcsstr(szInfo, sData->SingleStr);
+ // for single result
+ if (sData->Single.Available && (search != NULL || !sData->Multiple.Available)) { // single result
+ // if station ID appears first in the downloaded data
+ if ( !_tcsicmp(sData->Single.First, _T("ID"))) {
+ GetDataValue(&sData->Single.ID, str, &szInfo);
+ wsprintf(sID, _T("%s/%s"), svc, str);
+ GetDataValue(&sData->Single.Name, Name, &szInfo);
+ }
+ // if station name appears first in the downloaded data
+ else if ( !_tcsicmp(sData->Single.First, _T("NAME"))) {
+ GetDataValue(&sData->Single.Name, Name, &szInfo);
+ GetDataValue(&sData->Single.ID, str, &szInfo);
+ wsprintf(sID, _T("%s/%s"), svc, str);
+ }
+ // if no station ID is obtained, quit the search
+ if (str[0] == 0) {
+ mir_free(szData);
+ return 1;
+ }
+
+ // if can't get the name, use the search string as name
+ if (Name[0] == 0)
+ _tcscpy(Name, name);
+
+ // set the data and broadcast it
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_TCHAR;
+ psr.nick = Name;
+ psr.firstName = _T(" ");
+ psr.lastName = svcname;
+ psr.email = sID;
+ psr.id = sID;
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr);
+ mir_free(szData);
+ return 0;
+ }
+ // for multiple result
+ else if (sData->Multiple.Available) { // multiple results
+ // search for the next occurrence of the string
+ for (;;) {
+ // if station ID appears first in the downloaded data
+ if ( !_tcsicmp(sData->Multiple.First, _T("ID"))) {
+ GetDataValue(&sData->Multiple.ID, str, &szInfo);
+ wsprintf(sID, _T("%s/%s"), svc, str);
+ GetDataValue(&sData->Multiple.Name, Name, &szInfo);
+ }
+ // if station name appears first in the downloaded data
+ else if ( !_tcsicmp(sData->Multiple.First, _T("NAME"))) {
+ GetDataValue(&sData->Multiple.Name, Name, &szInfo);
+ GetDataValue(&sData->Multiple.ID, str, &szInfo);
+ wsprintf(sID, _T("%s/%s"), svc, str);
+ }
+ // if no station ID is obtained, search completed and quit the search
+ if (str[0] == 0) break;
+ // if can't get the name, use the search string as name
+ if (Name[0] == 0)
+ _tcscpy(Name, name);
+
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_TCHAR;
+ psr.nick = Name;
+ psr.firstName = _T("");
+ psr.lastName = svcname;
+ psr.email = sID;
+ psr.id = sID;
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr);
+ } } }
+
+ mir_free(szData);
+ return 0;
+ }
+
+ mir_free(szData);
+ return 1;
+}
+
+// name search (Threaded)
+// name: the station name to search for
+// searchId: don't change
+// return 0 if no error
+int NameSearch(TCHAR *name, const int searchId)
+{
+ WIDATALIST *Item = WIHead;
+
+ // search every weather service using the search station name
+ while (Item != NULL) {
+ if (Item->Data.NameSearch.Single.Available || Item->Data.NameSearch.Multiple.Available)
+ NameSearchProc(name, searchId, &Item->Data.NameSearch, Item->Data.InternalName, Item->Data.DisplayName);
+ Item = Item->next;
+ }
+
+ NetlibHttpDisconnect();
+ return 0;
+}
+
+// ======================MENU ITEM FUNCTION ============
+
+// add a new weather station via find/add dialog
+int WeatherAdd(WPARAM wParam, LPARAM lParam)
+{
+ db_set_s(NULL, "FindAdd", "LastSearched", "Weather");
+ CallService(MS_FINDADD_FINDADD, 0, 0);
+ return 0;
+}
diff --git a/plugins/Weather/src/weather_contacts.cpp b/plugins/Weather/src/weather_contacts.cpp
new file mode 100644
index 0000000000..4c049f5d26
--- /dev/null
+++ b/plugins/Weather/src/weather_contacts.cpp
@@ -0,0 +1,486 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contain the source that is related to weather contacts,
+include the links, edit settings, and loading weather information for
+the contact.
+*/
+
+#include "weather.h"
+
+static void OpenUrl( TCHAR* format, TCHAR* id )
+{
+ TCHAR loc[512];
+
+ GetID( id );
+ mir_sntprintf( loc, SIZEOF(loc), format, id );
+
+ CallService(MS_UTILS_OPENURL, opt.NewBrowserWin | OUF_TCHAR, (LPARAM)loc );
+}
+
+//============ BASIC CONTACTS FUNCTIONS AND LINKS ============
+
+// view weather log for the contact
+// wParam = current contact
+INT_PTR ViewLog(WPARAM wParam, LPARAM lParam)
+{
+ // see if the log path is set
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString((HANDLE)wParam, WEATHERPROTONAME, "Log", &dbv)) {
+ if (dbv.pszVal[0] != 0)
+ ShellExecute((HWND)lParam, _T("open"), dbv.ptszVal, _T(""), _T(""), SW_SHOW);
+ db_free(&dbv);
+ }
+ else // display warning dialog if no path is specified
+ MessageBox(NULL, TranslateT("Weather condition was not logged."),
+ TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION);
+ return 0;
+}
+
+// read complete forecast
+// wParam = current contact
+INT_PTR LoadForecast(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR id[256], loc2[256];
+ GetStationID((HANDLE)wParam, id, SIZEOF(id));
+ if (id[0] != 0) {
+ // check if the complte forecast URL is set. If it is not, display warning and quit
+ if ( DBGetStaticString((HANDLE)wParam, WEATHERPROTONAME, "InfoURL", loc2, SIZEOF(loc2)) || loc2[0] == 0) {
+ MessageBox(NULL, TranslateT("The URL for complete forcast have not been set. You can set it from the Edit Settings dialog."),
+ TranslateT("Weather Protocol"), MB_ICONINFORMATION);
+ return 1;
+ }
+ // set the url and open the webpage
+ OpenUrl(loc2, id );
+ }
+ return 0;
+}
+
+// load weather map
+// wParam = current contact
+INT_PTR WeatherMap(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR id[256], loc2[256];
+ GetStationID((HANDLE)wParam, id, SIZEOF(id));
+ if (id[0] != 0) {
+ // check if the weather map URL is set. If it is not, display warning and quit
+ if ( DBGetStaticString((HANDLE)wParam, WEATHERPROTONAME, "MapURL", loc2, SIZEOF(loc2)) || loc2[0] == 0) {
+ MessageBox(NULL, TranslateT("The URL for weather map have not been set. You can set it from the Edit Settings dialog."), TranslateT("Weather Protocol"), MB_ICONINFORMATION);
+ return 1;
+ }
+
+ // set the url and open the webpage
+ OpenUrl(loc2, id);
+ }
+
+ return 0;
+}
+
+//============ EDIT SETTINGS ============
+
+// show edit settings dialog
+// wParam = current contact
+INT_PTR EditSettings(WPARAM wParam, LPARAM lParam)
+{
+ HWND hEditDlg = WindowList_Find(hWindowList, (HANDLE)wParam);
+
+ // search the dialog list to prevent multiple instance of dialog for the same contact
+ if (hEditDlg != NULL) {
+ // if the dialog box already opened, bring it to the front
+ SetForegroundWindow(hEditDlg);
+ SetFocus(hEditDlg);
+ }
+ else {
+ // if the dialog box is not opened, open a new one
+ if (IsMyContact((HANDLE)wParam))
+ CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_EDIT), NULL, DlgProcChange, (LPARAM)wParam);
+ }
+
+ return 0;
+}
+
+typedef struct
+{
+ HANDLE hContact;
+ HICON hRename;
+ HICON hUserDetail;
+ HICON hFile;
+ HICON hSrchAll;
+} CntSetWndDataType;
+
+// edit weather settings
+// lParam = current contact
+INT_PTR CALLBACK DlgProcChange(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ TCHAR str[256], str2[256], city[256], filter[256], *pfilter, *chop;
+ char loc[512];
+ OPENFILENAME ofn; // common dialog box structure
+ HANDLE hContact;
+ WIDATA *sData;
+ CntSetWndDataType *wndData = NULL;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ wndData = ( CntSetWndDataType* )mir_alloc(sizeof(CntSetWndDataType));
+ wndData->hContact = hContact = (HANDLE)lParam;
+ wndData->hRename = LoadSkinnedIcon(SKINICON_OTHER_RENAME);
+ wndData->hUserDetail = LoadSkinnedIcon(SKINICON_OTHER_USERDETAILS);
+ wndData->hFile = LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ wndData->hSrchAll = LoadSkinnedIcon(SKINICON_OTHER_SEARCHALL);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)wndData);
+
+ // set button images
+ SendDlgItemMessage(hwndDlg, IDC_GETNAME, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hRename);
+ SendDlgItemMessage(hwndDlg, IDC_SVCINFO, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hUserDetail);
+ SendDlgItemMessage(hwndDlg, IDC_BROWSE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hFile);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW1, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hSrchAll);
+ SendDlgItemMessage(hwndDlg, IDC_RESET1, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hRename);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW2, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hSrchAll);
+ SendDlgItemMessage(hwndDlg, IDC_RESET2, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hRename);
+
+ // make all buttons flat
+ SendDlgItemMessage(hwndDlg, IDC_GETNAME, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_SVCINFO, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_BROWSE, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW1, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_RESET1, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW2, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_RESET2, BUTTONSETASFLATBTN, TRUE, 0);
+
+ // set tooltip for the buttons
+ SendDlgItemMessage(hwndDlg, IDC_GETNAME, BUTTONADDTOOLTIP, (WPARAM) LPGENT("Get city name from ID"), BATF_TCHAR);
+ SendDlgItemMessage(hwndDlg, IDC_SVCINFO, BUTTONADDTOOLTIP, (WPARAM) LPGENT("Weather INI information"), BATF_TCHAR);
+ SendDlgItemMessage(hwndDlg, IDC_BROWSE, BUTTONADDTOOLTIP, (WPARAM) LPGENT("Browse"), BATF_TCHAR);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW1, BUTTONADDTOOLTIP, (WPARAM) LPGENT("View webpage"), BATF_TCHAR);
+ SendDlgItemMessage(hwndDlg, IDC_RESET1, BUTTONADDTOOLTIP, (WPARAM) LPGENT("Reset to default"), BATF_TCHAR);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW2, BUTTONADDTOOLTIP, (WPARAM) LPGENT("View webpage"), BATF_TCHAR);
+ SendDlgItemMessage(hwndDlg, IDC_RESET2, BUTTONADDTOOLTIP, (WPARAM) LPGENT("Reset to default"), BATF_TCHAR);
+
+ // save the handle for the contact
+ WindowList_Add(hWindowList, hwndDlg, hContact);
+
+ // start to get the settings
+ // if the setting not exist, leave the dialog box blank
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "ID", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_ID, dbv.ptszVal);
+ // check if the station is a default station
+ CheckDlgButton(hwndDlg, IDC_DEFA, _tcscmp(dbv.ptszVal, opt.Default) != 0);
+ db_free(&dbv);
+ }
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "Nick", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_NAME, dbv.ptszVal);
+ db_free(&dbv);
+ }
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "Log", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_LOG, dbv.ptszVal);
+ // if the log path is not empty, check the checkbox for external log
+ if (dbv.ptszVal[0]) CheckDlgButton(hwndDlg, IDC_External, TRUE);
+ db_free(&dbv);
+ }
+ // enable/disable the browse button depending on the value of external log checkbox
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External));
+
+ // other checkbox options
+ CheckDlgButton(hwndDlg, IDC_DPop, db_get_b(hContact, WEATHERPROTONAME, "DPopUp", FALSE));
+ CheckDlgButton(hwndDlg, IDC_DAutoUpdate, db_get_b(hContact, WEATHERPROTONAME, "DAutoUpdate", FALSE));
+ CheckDlgButton(hwndDlg, IDC_Internal, db_get_b(hContact, WEATHERPROTONAME, "History", 0));
+
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "InfoURL", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_IURL, dbv.ptszVal);
+ db_free(&dbv);
+ }
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "MapURL", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_MURL, dbv.ptszVal);
+ db_free(&dbv);
+ }
+
+ // display the dialog box and free memory
+ Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, WEATHERPROTONAME, "EditSetting_");
+ ShowWindow(hwndDlg, SW_SHOW);
+ break;
+
+ case WM_COMMAND:
+ wndData = (CntSetWndDataType*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ hContact = wndData ? wndData->hContact : NULL;
+
+ switch(LOWORD(wParam)) {
+ case IDC_ID:
+ // check if there are 2 parts in the ID (svc/id) seperated by "/"
+ // if not, don't let user change the setting
+ GetDlgItemText(hwndDlg, IDC_ID, str, SIZEOF(str));
+ chop = _tcsstr(str, _T("/"));
+ if (chop == NULL)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHANGE), FALSE);
+ else
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHANGE), TRUE);
+ break;
+
+ case IDC_NAME:
+ // check if station name is entered
+ // if not, don't let user change the setting
+ GetDlgItemText(hwndDlg, IDC_NAME, str, SIZEOF(str));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHANGE), str[0] != 0);
+ break;
+
+ case IDC_GETNAME:
+ {
+ // the button for getting station name from the internet
+ // this function uses the ID search for add/find weather station
+
+ if ( !CheckSearch()) return TRUE; // don't download if update is in progress
+ // get the weather update data using the string in the ID field
+ GetDlgItemText(hwndDlg, IDC_ID, str, SIZEOF(str));
+ GetSvc(str);
+ WIDATA *sData = GetWIData(str);
+ GetDlgItemText(hwndDlg, IDC_ID, str, SIZEOF(str));
+ GetID(str);
+ // if ID search is available, do it
+ if (sData->IDSearch.Available) {
+ TCHAR *szData = NULL;
+
+ // load the page
+ wsprintfA(loc, sData->IDSearch.SearchURL, str);
+ str[0] = 0;
+ if (InternetDownloadFile(loc, NULL, &szData) == 0) {
+ TCHAR *szInfo = szData;
+ TCHAR* search = _tcsstr(szInfo, sData->IDSearch.NotFoundStr);
+
+ // if the page is found (ie. valid ID), get the name of the city
+ if (search == NULL)
+ GetDataValue(&sData->IDSearch.Name, str, &szInfo);
+
+ // free memory
+ mir_free(szData);
+ }
+ NetlibHttpDisconnect();
+ }
+ // give no station name but only ID if the search is unavailable
+ if (str[0] != 0) SetDlgItemText(hwndDlg, IDC_NAME, str);
+ break;
+ }
+ case IDC_External:
+ // enable/disable the borwse button depending if the external log is enabled
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External));
+ if ( !(BYTE)IsDlgButtonChecked(hwndDlg, IDC_External)) return TRUE;
+
+ case IDC_BROWSE: // fall through
+ // browse for the external log file
+ GetDlgItemText(hwndDlg, IDC_LOG, str, SIZEOF(str));
+ // Initialize OPENFILENAME
+ ZeroMemory(&ofn, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndDlg;
+ ofn.lpstrFile = str;
+ ofn.nMaxFile = SIZEOF(str);
+ // set filters
+ _tcscpy(filter, TranslateT("Text Files"));
+ _tcscat(filter, _T(" (*.txt)"));
+ pfilter = filter + _tcslen(filter)+1;
+ _tcscpy(pfilter, _T("*.txt"));
+ pfilter = pfilter + _tcslen(pfilter)+1;
+ _tcscpy(pfilter, TranslateT("All Files"));
+ _tcscat(pfilter, _T(" (*.*)"));
+ pfilter = pfilter + _tcslen(pfilter)+1;
+ _tcscpy(pfilter, _T("*.*"));
+ pfilter = pfilter + _tcslen(pfilter)+1;
+ *pfilter = '\0';
+ ofn.lpstrFilter = filter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.Flags = OFN_PATHMUSTEXIST;
+
+ // Display a Open dialog box and put the file name on the dialog
+ if (GetOpenFileName(&ofn))
+ SetDlgItemText(hwndDlg, IDC_LOG, ofn.lpstrFile);
+ // if there is no log file specified, disable external logging
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHANGE), ofn.lpstrFile[0] != 0);
+ break;
+
+ case IDC_VIEW1:
+ // view the page for more info
+ GetDlgItemText(hwndDlg, IDC_IURL, str, SIZEOF(str));
+ if (str[0] == 0) return TRUE;
+ GetDlgItemText(hwndDlg, IDC_ID, str2, SIZEOF(str2));
+ OpenUrl(str, str2);
+ break;
+
+ case IDC_VIEW2:
+ // view the page for weather map
+ GetDlgItemText(hwndDlg, IDC_MURL, str, SIZEOF(str));
+ if (str[0] == 0) return TRUE;
+ GetDlgItemText(hwndDlg, IDC_ID, str2, SIZEOF(str2));
+ OpenUrl(str, str2);
+ break;
+
+ case IDC_RESET1:
+ // reset the more info url to service default
+ GetDlgItemText(hwndDlg, IDC_ID, str, SIZEOF(str));
+ GetSvc(str);
+ sData = GetWIData(str);
+ SetDlgItemTextA(hwndDlg, IDC_IURL, sData->DefaultURL);
+ break;
+
+ case IDC_RESET2:
+ // reset the weathe map url to service default
+ GetDlgItemText(hwndDlg, IDC_ID, str, SIZEOF(str));
+ GetSvc(str);
+ sData = GetWIData(str);
+ SetDlgItemText(hwndDlg, IDC_MURL, sData->DefaultMap);
+ break;
+
+ case IDC_SVCINFO:
+ // display the information of the ini file used by the weather station
+ GetDlgItemText(hwndDlg, IDC_ID, str, SIZEOF(str));
+ GetSvc(str);
+ GetINIInfo(str);
+ break;
+
+ case IDC_CHANGE:
+ // temporary disable the protocol while applying the change
+ // start writing the new settings to database
+ GetDlgItemText(hwndDlg, IDC_ID, str, SIZEOF(str));
+ db_set_ts(hContact, WEATHERPROTONAME, "ID", str);
+ if ((BYTE)IsDlgButtonChecked(hwndDlg, IDC_DEFA)) { // if default station is set
+ _tcscpy(opt.Default, str);
+ opt.DefStn = hContact;
+ db_set_ts(NULL, WEATHERPROTONAME, "Default", opt.Default);
+ }
+ GetDlgItemText(hwndDlg, IDC_NAME, city, SIZEOF(city));
+ db_set_ts(hContact, WEATHERPROTONAME, "Nick", city);
+ wsprintf(str2, TranslateT("Current weather information for %s."), city);
+ if ((BYTE)IsDlgButtonChecked(hwndDlg, IDC_External)) {
+ GetDlgItemText(hwndDlg, IDC_LOG, str, SIZEOF(str));
+ db_set_ts(hContact, WEATHERPROTONAME, "Log", str);
+ }
+ else db_unset(hContact, WEATHERPROTONAME, "Log");
+
+ GetDlgItemText(hwndDlg, IDC_IURL, str, SIZEOF(str));
+ db_set_ts(hContact, WEATHERPROTONAME, "InfoURL", str);
+
+ GetDlgItemText(hwndDlg, IDC_MURL, str, SIZEOF(str));
+ db_set_ts(hContact, WEATHERPROTONAME, "MapURL", str);
+ db_set_w(hContact, WEATHERPROTONAME, "Status", ID_STATUS_OFFLINE);
+ db_set_w(hContact, WEATHERPROTONAME, "StatusIcon", ID_STATUS_OFFLINE);
+ AvatarDownloaded(hContact);
+ db_set_ts(hContact, WEATHERPROTONAME, "About", str2);
+ db_set_b(hContact, WEATHERPROTONAME, "History", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_Internal));
+ db_set_b(hContact, WEATHERPROTONAME, "Overwrite", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_Overwrite));
+ db_set_b(hContact, WEATHERPROTONAME, "File", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External));
+ db_set_b(hContact, WEATHERPROTONAME, "DPopUp", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DPop));
+ db_set_b(hContact, WEATHERPROTONAME, "DAutoUpdate", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DAutoUpdate));
+
+ // re-enable the protocol and update the data for the station
+ db_set_s(hContact, WEATHERPROTONAME, "LastCondition", "None");
+ UpdateSingleStation((WPARAM)hContact, 0);
+
+ case IDCANCEL: // fall through
+ // remove the dialog from window list and close it
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ // remove the dialog from window list and close it
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ wndData = (CntSetWndDataType*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ Skin_ReleaseIcon(wndData->hFile);
+ Skin_ReleaseIcon(wndData->hRename);
+ Skin_ReleaseIcon(wndData->hSrchAll);
+ Skin_ReleaseIcon(wndData->hUserDetail);
+ mir_free(wndData);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+
+ WindowList_Remove(hWindowList, hwndDlg);
+ Utils_SaveWindowPosition(hwndDlg, NULL, WEATHERPROTONAME, "EditSetting_");
+ break;
+ }
+ return FALSE;
+}
+
+//============ CONTACT DELETION ============
+
+// when a contact is deleted, make sure some other contact take over the default station
+// wParam = deleted contact
+int ContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ if ( !IsMyContact((HANDLE)wParam))
+ return 0;
+
+ removeWindow((HANDLE)wParam);
+
+ // exit this function if it is not default station
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString((HANDLE)wParam, WEATHERPROTONAME, "ID", &dbv)) {
+ if ( _tcscmp(dbv.ptszVal, opt.Default)) {
+ db_free(&dbv);
+ return 0;
+ }
+ db_free(&dbv);
+ }
+
+ // now the default station is deleted, try to get a new one
+
+ // start looking for other weather stations
+ HANDLE hContact = db_find_first();
+ while(hContact) {
+ if (IsMyContact(hContact)) {
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "ID", &dbv)) {
+ // if the station is not a default station, set it as the new default station
+ // this is the first weather station encountered from the search
+ if ( _tcscmp(opt.Default, dbv.ptszVal)) {
+ _tcscpy(opt.Default, dbv.ptszVal);
+ opt.DefStn = hContact;
+ db_free(&dbv);
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "Nick", &dbv)) {
+ TCHAR str[255];
+ mir_sntprintf(str, SIZEOF(str), TranslateT("%s is now the default weather station"), dbv.ptszVal);
+ db_free(&dbv);
+ MessageBox(NULL, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION);
+ }
+ db_set_ts(NULL, WEATHERPROTONAME, "Default", opt.Default);
+ return 0; // exit this function quickly
+ }
+ db_free(&dbv);
+ }
+ }
+ hContact = db_find_next(hContact);
+ }
+ // got here if no more weather station left
+ opt.Default[0] = 0; // no default station
+ opt.DefStn = NULL;
+ db_set_ts(NULL, WEATHERPROTONAME, "Default", opt.Default);
+ return 0;
+}
+
+BOOL IsMyContact(HANDLE hContact)
+{
+ const char* szProto = GetContactProto(hContact);
+ return szProto != NULL && strcmp(WEATHERPROTONAME, szProto) == 0;
+}
diff --git a/plugins/Weather/src/weather_conv.cpp b/plugins/Weather/src/weather_conv.cpp
new file mode 100644
index 0000000000..780253b8ac
--- /dev/null
+++ b/plugins/Weather/src/weather_conv.cpp
@@ -0,0 +1,644 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related unit conversion, icon assignment,
+string conversions, display text parsing, etc
+*/
+
+#include "weather.h"
+
+//============ SOME HELPER FUNCTIONS ============
+
+// see if a string is a number
+// s = the string to be determined
+// return value = true if the string is a number, false if it isn't
+BOOL is_number(TCHAR *s)
+{
+ BOOL tag = FALSE;
+ // looking character by character
+ // for a number: numerous spaces in front, then optional +/-, then the number
+ // don't care anything that comes after it
+ while(*s != '\0')
+ {
+ if (*s >= '0' && *s <= '9') return TRUE;
+ else if (*s == ' ');
+ else if (*s != '+' && *s != '-') return FALSE;
+ else if ((*s == '+' || *s == '-') && !tag) tag = TRUE;
+ else return FALSE;
+ s++;
+ }
+ return FALSE;
+}
+
+static void numToStr(double num, TCHAR* str)
+{
+ int i = (int)(num * (opt.NoFrac ? 10 : 100));
+ int u = abs(i);
+
+ int r = u % 10;
+ int w = u / 10 + (r >= 5);
+
+ if (opt.NoFrac)
+ r = 0;
+ else {
+ r = w % 10;
+ w /= 10;
+ }
+
+ if (i < 0 && (w || r)) *(str++) = '-';
+ if (r)
+ wsprintf(str, _T("%i.%i"), w, r);
+ else
+ wsprintf(str, _T("%i"), w);
+}
+
+//============ UNIT CONVERSIONS ============
+
+// temperature conversion
+// tempchar = the string containing the temperature value
+// unit = the unit for temperature
+// return value = the converted temperature with degree sign and unit; if fails, return N/A
+void GetTemp(TCHAR *tempchar, TCHAR *unit, TCHAR* str)
+{
+ // unit can be C, F
+ double temp;
+ TCHAR tstr[20];
+
+ TrimString(tempchar);
+ if (tempchar[0] == '-' && tempchar[1] == ' ')
+ memmove(&tempchar[1], &tempchar[2], sizeof(TCHAR)*(_tcslen(&tempchar[2])+1));
+
+ // quit if the value obtained is N/A or not a number
+ if ( !_tcscmp(tempchar, NODATA) || !_tcscmp(tempchar, _T("N/A"))) {
+ _tcscpy(str, tempchar);
+ return;
+ }
+ if ( !is_number(tempchar)) {
+ _tcscpy(str, NODATA);
+ return;
+ }
+
+ // convert the string to an integer
+ temp = _ttof(tempchar);
+
+ // convert all to F first
+ if ( !_tcsicmp(unit, _T("C"))) temp = (temp*9/5)+32;
+ else if ( !_tcsicmp(unit, _T("K"))) temp = ((temp-273.15)*9/5)+32;
+
+ // convert to apporiate unit
+ switch (opt.tUnit) {
+ case 1:
+ // rounding
+ numToStr((temp-32)/9*5, tstr);
+ if (opt.DoNotAppendUnit)
+ wsprintf(str, _T("%s"), tstr);
+ else
+ wsprintf(str, _T("%s%sC"), tstr, opt.DegreeSign);
+ break;
+
+ case 2:
+ numToStr(temp, tstr);
+ if (opt.DoNotAppendUnit)
+ wsprintf(str, _T("%s"), tstr);
+ else
+ wsprintf(str, _T("%s%sF"), tstr, opt.DegreeSign);
+ break;
+ }
+}
+
+// temperature conversion
+// tempchar = the string containing the pressure value
+// unit = the unit for pressure
+// return value = the converted pressure with unit; if fail, return the original string
+void GetPressure(TCHAR *tempchar, TCHAR *unit, TCHAR* str)
+{
+ // unit can be kPa, hPa, mb, in, mm, torr
+ double tempunit = 0, output;
+ int intunit;
+
+ // convert the string to a floating point number (always positive)
+ // if it end up with 0, then it's not a number, return the original string and quit
+ output = _ttof(tempchar);
+ if (output == 0) {
+ _tcscpy(str, tempchar);
+ return;
+ }
+
+ // convert all to mb first
+ if ( !_tcsicmp(unit, _T("KPA")))
+ tempunit = (double)output * 10;
+ else if ( !_tcsicmp(unit, _T("HPA")))
+ tempunit = (double)output;
+ else if ( !_tcsicmp(unit, _T("MB")))
+ tempunit = (double)output;
+ else if ( !_tcsicmp(unit, _T("IN")))
+ tempunit = (double)output * 33.86388;
+ else if ( !_tcsicmp(unit, _T("MM")))
+ tempunit = (double)output * 1.33322;
+ else if ( !_tcsicmp(unit, _T("TORR")))
+ tempunit = (double)output * 1.33322;
+
+ // convert to apporiate unit
+ switch (opt.pUnit) {
+ case 1:
+ intunit = (int)(tempunit + 0.5);
+ wsprintf(str, _T("%i.%i %s"), intunit/10, intunit%10, opt.DoNotAppendUnit ? _T("") : TranslateT("kPa"));
+ break;
+ case 2:
+ intunit = (int)(tempunit + 0.5);
+ wsprintf(str, _T("%i %s"), intunit, opt.DoNotAppendUnit ? _T("") : TranslateT("mb"));
+ break;
+ case 3:
+ intunit = (int)((tempunit*10 / 33.86388) + 0.5);
+ wsprintf(str, _T("%i.%i %s"), intunit/10, intunit%10, opt.DoNotAppendUnit ? _T("") : TranslateT("in"));
+ break;
+ case 4:
+ intunit = (int)((tempunit*10 / 1.33322) + 0.5);
+ wsprintf(str, _T("%i.%i %s"), intunit/10, intunit%10, opt.DoNotAppendUnit ? _T("") : TranslateT("mm"));
+ break;
+ default:
+ _tcscpy(str, tempchar);
+ break;
+
+ }
+}
+
+// speed conversion
+// tempchar = the string containing the speed value
+// unit = the unit for speed
+// return value = the converted speed with unit; if fail, return _T(""
+void GetSpeed(TCHAR *tempchar, TCHAR *unit, TCHAR *str)
+{
+ // unit can be km/h, mph, m/s, knots
+ double tempunit;
+ TCHAR tstr[20];
+
+ str[0] = 0;
+
+ // convert the string into an integer (always positive)
+ // if the result is 0, then the string is not a number, return _T(""
+ tempunit = _ttof(tempchar);
+ if (tempunit == 0 && tempchar[0] != '0')
+ return;
+
+ // convert all to m/s first
+ if ( !_tcsicmp(unit, _T("KM/H")))
+ tempunit /= 3.6;
+// else if ( !_tcsicmp(unit, _T("M/S"))
+// tempunit = tempunit;
+ else if ( !_tcsicmp(unit, _T("MPH")))
+ tempunit *= 0.44704;
+ else if ( !_tcsicmp(unit, _T("KNOTS")))
+ tempunit *= 0.514444;
+
+ // convert to apporiate unit
+ switch (opt.wUnit) {
+ case 1:
+ numToStr(tempunit * 3.6, tstr);
+ wsprintf(str, _T("%s %s"), tstr, opt.DoNotAppendUnit ? _T("") : TranslateT("km/h"));
+ break;
+ case 2:
+ numToStr(tempunit, tstr);
+ wsprintf(str, _T("%s %s"), tstr, opt.DoNotAppendUnit ? _T("") : TranslateT("m/s"));
+ break;
+ case 3:
+ numToStr(tempunit / 0.44704, tstr);
+ wsprintf(str, _T("%s %s"), tstr, opt.DoNotAppendUnit ? _T("") : TranslateT("mph"));
+ break;
+ case 4:
+ numToStr(tempunit / 0.514444, tstr);
+ wsprintf(str, _T("%s %s"), tstr, opt.DoNotAppendUnit ? _T("") : TranslateT("knots"));
+ break;
+ }
+}
+
+// distance conversion
+// tempchar = the string containing the distance value
+// unit = the unit for distance
+// return value = the converted distance with unit; if fail, return original string
+void GetDist(TCHAR *tempchar, TCHAR *unit, TCHAR *str)
+{
+ // unit can be km, miles
+ double tempunit = 0, output;
+ int intunit;
+
+ // convert the string to a floating point number (always positive)
+ // if it end up with 0, then it's not a number, return the original string and quit
+ output = _ttof(tempchar);
+ if (output == 0) {
+ _tcscpy(str, tempchar);
+ return;
+ }
+
+ // convert all to km first
+ if ( !_tcsicmp(unit, _T("KM")))
+ tempunit = (double)output;
+ else if ( !_tcsicmp(unit, _T("MILES")))
+ tempunit = (double)output * 1.609;
+
+ // convert to apporiate unit
+ switch (opt.vUnit) {
+ case 1:
+ intunit = (int)((tempunit*10) + 0.5);
+ wsprintf(str, _T("%i.%i %s"), intunit/10, intunit%10, opt.DoNotAppendUnit ? _T("") : TranslateT("km"));
+ break;
+ case 2:
+ intunit = (int)((tempunit*10 / 1.609) + 0.5);
+ wsprintf(str, _T("%i.%i %s"), intunit/10, intunit%10, opt.DoNotAppendUnit ? _T("") : TranslateT("miles"));
+ break;
+ default:
+ _tcscpy(str, tempchar);
+ break;
+ }
+}
+
+// elevation conversion
+// tempchar = the string containing the elevation value
+// unit = the unit for elevation
+// return value = the converted elevation with unit; if fail, return original string
+void GetElev(TCHAR *tempchar, TCHAR *unit, TCHAR *str)
+{
+ // unit can be ft, m
+ double tempunit = 0, output;
+ int intunit;
+
+ // convert the string to a floating point number (always positive)
+ // if it end up with 0, then it's not a number, return the original string and quit
+ output = _ttof(tempchar);
+ if (output == 0) {
+ _tcscpy(str, tempchar);
+ return;
+ }
+
+ // convert all to m first
+ if ( !_tcsicmp(unit, _T("M")))
+ tempunit = (double)output;
+ else if ( !_tcsicmp(unit, _T("FT")))
+ tempunit = (double)output / 3.28;
+
+ // convert to apporiate unit
+ switch (opt.eUnit) {
+ case 1:
+ intunit = (int)((tempunit*10 * 3.28) + 0.5);
+ wsprintf(str, _T("%i.%i %s"), intunit/10, intunit%10, opt.DoNotAppendUnit ? _T("") : TranslateT("ft"));
+ break;
+ case 2:
+ intunit = (int)((tempunit*10) + 0.5);
+ wsprintf(str, _T("%i.%i %s"), intunit/10, intunit%10, opt.DoNotAppendUnit ? _T("") : TranslateT("m"));
+ break;
+ default:
+ _tcscpy(str, tempchar);
+ break;
+ }
+}
+
+//============ CONDITION ICON ASSIGNMENT ============
+
+// assign the contact icon (status) from the condition string
+// the description may be different between different sources
+// cond = the string for weather condition
+// return value = status for the icon (ONLINE, OFFLINE, etc)
+
+static const TCHAR *statusStr[10] = { _T("Lightning"), _T("Fog"), _T("Snow Shower"), _T("Snow"), _T("Rain Shower"), _T("Rain"), _T("Partly Cloudy"), _T("Cloudy"), _T("Sunny"), _T("N/A") };
+static const WORD statusValue[10] = { LIGHT, FOG, SSHOWER, SNOW, RSHOWER, RAIN, PCLOUDY, CLOUDY, SUNNY, NA };
+
+WORD GetIcon(const TCHAR* cond, WIDATA *Data)
+{
+ int i;
+
+ // set the icon using ini
+ for (i=0; i<10; i++)
+ if ( IsContainedInCondList(cond, &Data->CondList[i]))
+ return statusValue[i];
+
+ // internal detection
+ if (
+ _tcsstr(cond, _T("mainy sunny")) != NULL ||
+ _tcsstr(cond, _T("mainy clear")) != NULL ||
+ _tcsstr(cond, _T("partly cloudy")) != NULL ||
+ _tcsstr(cond, _T("mostly")) != NULL ||
+ _tcsstr(cond, _T("clouds")) != NULL) {
+ return PCLOUDY;
+ }
+ else if (
+ _tcsstr(cond, _T("sunny")) != NULL ||
+ _tcsstr(cond, _T("clear")) != NULL ||
+ _tcsstr(cond, _T("fair")) != NULL) {
+ return SUNNY;
+ }
+ else if (
+ _tcsstr(cond, _T("thunder")) != NULL ||
+ _tcsstr(cond, _T("t-storm")) != NULL) {
+ return LIGHT;
+ }
+ else if (
+ _tcsstr(cond, _T("cloud")) != NULL ||
+ _tcsstr(cond, _T("overcast")) != NULL) {
+ return CLOUDY;
+ }
+ else if (
+ _tcsstr(cond, _T("fog")) != NULL ||
+ _tcsstr(cond, _T("mist")) != NULL ||
+ _tcsstr(cond, _T("smoke")) != NULL ||
+ _tcsstr(cond, _T("sand")) != NULL ||
+ _tcsstr(cond, _T("dust")) != NULL ||
+ _tcsstr(cond, _T("haze")) != NULL) {
+ return FOG;
+ }
+ else if (
+ (_tcsstr(cond, _T("shower")) != NULL && _tcsstr(cond, _T("snow")) != NULL) ||
+ _tcsstr(cond, _T("flurries")) != NULL) {
+ return SSHOWER;
+ }
+ else if (
+ _tcsstr(cond, _T("rain shower")) != NULL ||
+ _tcsstr(cond, _T("shower")) != NULL)
+ {
+ return RSHOWER;
+ }
+ else if (
+ _tcsstr(cond, _T("snow")) != NULL ||
+ _tcsstr(cond, _T("ice")) != NULL ||
+ _tcsstr(cond, _T("freezing")) != NULL ||
+ _tcsstr(cond, _T("wintry")) != NULL) {
+ return SNOW;
+ }
+ else if (
+ _tcsstr(cond, _T("drizzle")) != NULL ||
+ _tcsstr(cond, _T("rain")) != NULL)
+ {
+ return RAIN;
+ }
+
+ // set the icon using langpack
+ for (i=0; i < 9; i++) {
+ TCHAR LangPackStr[64], LangPackStr1[128];
+ int j = 0;
+ do {
+ j++;
+ // using the format _T("# Weather <condition name> <counter> #"
+ mir_sntprintf(LangPackStr, SIZEOF(LangPackStr), _T("# Weather %s %i #"), statusStr[i], j);
+ mir_sntprintf(LangPackStr1, SIZEOF(LangPackStr1), _T("%s"), TranslateTS(LangPackStr));
+ CharLowerBuff(LangPackStr1, (DWORD)_tcslen(LangPackStr1));
+ if (_tcsstr(cond, LangPackStr1) != NULL)
+ return statusValue[i];
+ // loop until the translation string exists (ie, the translated string is differ from original)
+ }
+ while ( _tcscmp(TranslateTS(LangPackStr), LangPackStr));
+ }
+
+ return NA;
+}
+
+//============ STRING CONVERSIONS ============
+
+// this function convert the string to the format with 1 upper case followed by lower case char
+void CaseConv(TCHAR *str)
+{
+ TCHAR *pstr;
+ BOOL nextUp = TRUE;
+
+ CharLowerBuff(str, (DWORD)_tcslen(str));
+ for(pstr = str; *pstr; pstr++) {
+ if (*pstr == ' ' || *pstr == '-')
+ nextUp = TRUE;
+ else {
+ TCHAR ch = *(TCHAR*)pstr;
+ if (nextUp)
+ *pstr = ( TCHAR )CharUpper((LPTSTR)ch);
+ nextUp = FALSE;
+} } }
+
+// the next 2 functions are copied from miranda source
+// str = the string to modify
+
+void TrimString(char *str)
+{
+ size_t len, start;
+
+ len = strlen(str);
+ while(len && (unsigned char)str[len-1] <= ' ') str[--len] = 0;
+ for(start=0; (unsigned char)str[start] <= ' ' && str[start]; start++);
+ memmove(str, str+start, len-start+1);
+}
+
+void TrimString(WCHAR *str)
+{
+ size_t len, start;
+
+ len = wcslen(str);
+ while(len && (unsigned char)str[len-1] <= ' ') str[--len] = 0;
+ for(start=0; (unsigned char)str[start] <= ' ' && str[start]; start++);
+ memmove(str, str+start, (len-start+1)*sizeof(WCHAR));
+}
+
+// convert \t to tab and \n to linefeed
+void ConvertBackslashes(char *str)
+{
+ for (char *pstr=str; *pstr; pstr = CharNextA(pstr)) {
+ if (*pstr == '\\') {
+ switch(pstr[1]) {
+ case 'n': *pstr = '\n'; break;
+ case 't': *pstr = '\t'; break;
+ default: *pstr = pstr[1]; break;
+ }
+ memmove(pstr+1, pstr+2, strlen(pstr+2)+1);
+} } }
+
+// replace spaces with _T("%20"
+// dis = original string
+// return value = the modified string with space -> _T("%20"
+char *GetSearchStr(char *dis)
+{
+ char *pstr = dis;
+ size_t len = strlen(dis);
+ while (*pstr != 0)
+ {
+ if (*pstr == ' ')
+ {
+ memmove(pstr+3, pstr+1, len);
+ memcpy(pstr, _T("%20"), 3);
+ pstr += 2;
+ }
+ pstr++;
+ len--;
+ }
+ return dis;
+}
+
+//============ ICON ASSIGNMENT ============
+
+// make display and history strings
+// w = WEATHERINFO data to be parsed
+// dis = the string to parse
+// return value = the parsed string
+TCHAR* GetDisplay(WEATHERINFO *w, const TCHAR *dis, TCHAR* str)
+{
+ TCHAR lpzDate[32], chr;
+ char name[256], temp[2];
+ DBVARIANT dbv;
+ size_t i;
+
+ // Clear the string
+ str[0] = 0;
+
+ // looking character by character
+ for (i=0; i < _tcslen(dis); i++) {
+ // for the escape characters
+ if (dis[i] == '\\') {
+ i++;
+ chr = dis[i];
+ switch (chr) {
+ case '%': _tcscat(str, _T("%")); break;
+ case 't': _tcscat(str, _T("\t")); break;
+ case 'n': _tcscat(str, _T("\r\n")); break;
+ case '\\': _tcscat(str, _T("\\")); break;
+ }
+ }
+
+ // for the % varaibles
+ else if (dis[i] == '%')
+ {
+ i++;
+ chr = dis[i];
+ // turn capitalized characters to small case
+ if (chr < 'a' && chr != '[' && chr != '%') chr = (char)((int)chr + 32);
+ switch (chr) {
+ case 'c': _tcscat(str, w->cond); break;
+ case 'd': // get the current date
+ GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, lpzDate, SIZEOF(lpzDate));
+ _tcscat(str, lpzDate); break;
+ case 'e': _tcscat(str, w->dewpoint); break;
+ case 'f': _tcscat(str, w->feel); break;
+ case 'h': _tcscat(str, w->high); break;
+ case 'i': _tcscat(str, w->winddir); break;
+ case 'l': _tcscat(str, w->low); break;
+ case 'm': _tcscat(str, w->humid); break;
+ case 'n': _tcscat(str, w->city); break;
+ case 'p': _tcscat(str, w->pressure); break;
+ case 'r': _tcscat(str, w->sunrise); break;
+ case 's': _tcscat(str, w->id); break;
+ case 't': _tcscat(str, w->temp); break;
+ case 'u':
+ if (_tcscmp(w->update, NODATA)) _tcscat(str, w->update);
+ else _tcscat(str, TranslateT("<unknown time>"));
+ break;
+ case 'v': _tcscat(str, w->vis); break;
+ case 'w': _tcscat(str, w->wind); break;
+ case 'y': _tcscat(str, w->sunset); break;
+ case '%': _tcscat(str, _T("%")); break;
+ case '[': // custom variables
+ i++;
+ name[0] = 0;
+ // read the entire variable name
+ while (dis[i] != ']' && i < _tcslen(dis)) {
+ wsprintfA(temp, "%c", dis[i++]);
+ strcat(name, temp);
+ }
+ // access the database to get its value
+ if ( !DBGetContactSettingTString(w->hContact, WEATHERCONDITION, name, &dbv)) {
+ if (dbv.ptszVal != TranslateTS(NODATA) && dbv.ptszVal != TranslateT("<Error>"))
+ _tcscat(str, dbv.ptszVal);
+ db_free(&dbv);
+ }
+ break;
+ }
+ }
+ // if the character is not a variable, write the original character to the new string
+ else {
+ wsprintf( lpzDate, _T("%c"), dis[i]);
+ _tcscat(str, lpzDate);
+ } }
+
+ return str;
+}
+
+TCHAR svcReturnText[MAX_TEXT_SIZE];
+INT_PTR GetDisplaySvcFunc(WPARAM wParam, LPARAM lParam)
+{
+ WEATHERINFO winfo = LoadWeatherInfo((HANDLE)wParam);
+ return (INT_PTR)GetDisplay(&winfo, (TCHAR*)lParam, svcReturnText);
+}
+
+//============ ID MANAGEMENT ============
+
+// get service data module internal name
+// mod/id <- the mod part
+// pszID = original 2-part id, return the service internal name
+void GetSvc(TCHAR *pszID)
+{
+ TCHAR *chop = _tcsstr(pszID, _T("/"));
+ if (chop != NULL) *chop = '\0';
+ else pszID[0] = 0;
+}
+
+// get the id use for update without the service internal name
+// mod/id <- the id part
+// pszID = original 2-part id, return the single part id
+void GetID(TCHAR *pszID)
+{
+ TCHAR *chop = _tcsstr(pszID, _T("/"));
+ if (chop != NULL) _tcscpy(pszID, chop+1);
+ else pszID[0] = 0;
+}
+
+//============ WEATHER ERROR CODE ============
+
+// Get the text when an error code is specified
+// code = the error code obtained when updating weather
+// str = the string for the error
+
+TCHAR *GetError(int code)
+{
+ TCHAR *str, str2[100];
+ switch (code) {
+ case 10: str = E10; break;
+ case 11: str = E11; break;
+ case 12: str = E12; break;
+ case 20: str = E20; break;
+ case 30: str = E30; break;
+ case 40: str = E40; break;
+ case 42: str = E42; break;
+ case 43: str = E43; break;
+ case 99: str = E99; break;
+ case 204: str = E204; break;
+ case 301: str = E301; break;
+ case 305: str = E305; break;
+ case 307: str = E307; break;
+ case 400: str = E400; break;
+ case 401: str = E401; break;
+ case 402: str = E402; break;
+ case 403: str = E403; break;
+ case 404: str = E404; break;
+ case 405: str = E405; break;
+ case 407: str = E407; break;
+ case 410: str = E410; break;
+ case 500: str = E500; break;
+ case 502: str = E502; break;
+ case 503: str = E503; break;
+ case 504: str = E504; break;
+ default:
+ mir_sntprintf(str2, SIZEOF(str2), TranslateT("HTTP Error %i"), code);
+ str = str2;
+ break;
+ }
+ return str;
+}
diff --git a/plugins/Weather/src/weather_data.cpp b/plugins/Weather/src/weather_data.cpp
new file mode 100644
index 0000000000..5def028c3d
--- /dev/null
+++ b/plugins/Weather/src/weather_data.cpp
@@ -0,0 +1,472 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related loading, obtaining, and
+saving individual weather data for a weather contact.
+*/
+
+#include "weather.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(HANDLE hContact, TCHAR* id, size_t idlen)
+{
+ // accessing the database
+ if ( DBGetStaticString(hContact, WEATHERPROTONAME, "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(HANDLE 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, SIZEOF(winfo.id));
+
+ if ( DBGetStaticString(hContact, WEATHERPROTONAME, "Nick", winfo.city, SIZEOF(winfo.city)))
+ _tcscpy(winfo.city, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Update", winfo.update, SIZEOF(winfo.update)))
+ _tcscpy(winfo.update, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Condition", winfo.cond, SIZEOF(winfo.cond)))
+ _tcscpy(winfo.cond, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Temperature", winfo.temp, SIZEOF(winfo.temp)))
+ _tcscpy(winfo.temp, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "High", winfo.high, SIZEOF(winfo.high)))
+ _tcscpy(winfo.high, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Low", winfo.low, SIZEOF(winfo.low)))
+ _tcscpy(winfo.low, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Sunset", winfo.sunset, SIZEOF(winfo.sunset)))
+ _tcscpy(winfo.sunset, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Sunrise", winfo.sunrise, SIZEOF(winfo.sunrise)))
+ _tcscpy(winfo.sunrise, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Wind Speed", winfo.wind, SIZEOF(winfo.wind)))
+ _tcscpy(winfo.wind, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Wind Direction", winfo.winddir, SIZEOF(winfo.winddir)))
+ _tcscpy(winfo.winddir, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Dewpoint", winfo.dewpoint, SIZEOF(winfo.dewpoint)))
+ _tcscpy(winfo.dewpoint, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Pressure", winfo.pressure, SIZEOF(winfo.pressure)))
+ _tcscpy(winfo.pressure, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Visibility", winfo.vis, SIZEOF(winfo.vis)))
+ _tcscpy(winfo.vis, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Humidity", winfo.humid, SIZEOF(winfo.humid)))
+ _tcscpy(winfo.humid, NODATA);
+ if ( DBGetStaticString(hContact, WEATHERCONDITION, "Feel", winfo.feel, SIZEOF(winfo.feel)))
+ _tcscpy(winfo.feel, NODATA);
+
+ winfo.status = (WORD)db_get_w(hContact, WEATHERPROTONAME, "StatusIcon", ID_STATUS_OFFLINE);
+ return winfo;
+}
+
+// getting weather setting from database
+// return 0 on success
+int DBGetData(HANDLE hContact, char *setting, DBVARIANT *dbv)
+{
+ if ( DBGetContactSettingTString(hContact, WEATHERCONDITION, setting, dbv)) {
+ size_t len = strlen(setting) + 1;
+ char *set = (char*)alloca(len + 1);
+ *set = '#';
+ memcpy(set + 1, setting, len);
+
+ if ( DBGetContactSettingTString(hContact, WEATHERCONDITION, set, dbv))
+ return 1;
+ }
+ return 0;
+}
+
+int DBGetStaticString(HANDLE hContact, const char *szModule, const char *valueName, TCHAR *dest, size_t dest_len)
+{
+ DBVARIANT dbv;
+ if ( DBGetContactSettingTString( hContact, szModule, valueName, &dbv ))
+ return 1;
+
+ _tcsncpy( dest, dbv.ptszVal, dest_len );
+ dest[ dest_len-1 ] = 0;
+ db_free( &dbv );
+ 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(DWORD lastver)
+{
+ TCHAR str[255];
+ int ContactCount = 0;
+ HANDLE LastContact = NULL;
+ DBVARIANT dbv;
+ // loop through all contacts
+ HANDLE hContact = db_find_first();
+ while(hContact) {
+ // see if the contact is a weather contact
+ if ( IsMyContact(hContact)) {
+ // check for upgrade
+ if (lastver < __VERSION_DWORD)
+ UpgradeContact(lastver, hContact);
+ db_set_w(hContact,WEATHERPROTONAME, "Status",ID_STATUS_OFFLINE);
+ db_set_w(hContact,WEATHERPROTONAME, "StatusIcon",ID_STATUS_OFFLINE);
+ db_unset(hContact, "CList", "MyHandle");
+ // clear all data
+ if ( DBGetContactSettingTString(hContact, WEATHERPROTONAME, "Nick", &dbv)) {
+ db_set_ts(hContact, WEATHERPROTONAME, "Nick", TranslateT("<Enter city name here>"));
+ db_set_s(hContact, WEATHERPROTONAME, "LastLog", "never");
+ db_set_s(hContact, WEATHERPROTONAME, "LastCondition", "None");
+ db_set_s(hContact, WEATHERPROTONAME, "LastTemperature", "None");
+ }
+ else db_free(&dbv);
+
+ DBDataManage(hContact, WDBM_REMOVE, 0, 0);
+ db_set_s(hContact, "UserInfo", "MyNotes", "");
+ // reset update tag
+ db_set_b(hContact,WEATHERPROTONAME, "IsUpdated",FALSE);
+ // reset logging settings
+ if ( !DBGetContactSettingTString(hContact,WEATHERPROTONAME, "Log", &dbv)) {
+ db_set_b(hContact,WEATHERPROTONAME, "File",(BYTE)(dbv.ptszVal[0] != 0));
+ db_free(&dbv);
+ }
+ else db_set_b(hContact,WEATHERPROTONAME, "File",FALSE);
+
+ // if no default station find, assign a new one
+ if (opt.Default[0] == 0) {
+ GetStationID(hContact, opt.Default, SIZEOF(opt.Default));
+
+ opt.DefStn = hContact;
+ if ( !DBGetContactSettingTString(hContact,WEATHERPROTONAME, "Nick",&dbv)) {
+ wsprintf(str, TranslateT("%s is now the default weather station"), dbv.ptszVal);
+ db_free(&dbv);
+ MessageBox(NULL, str, TranslateT("Weather Protocol"), MB_OK|MB_ICONINFORMATION);
+ }
+ }
+ // get the handle of the default station
+ if (opt.DefStn == NULL) {
+ if ( !DBGetContactSettingTString(hContact,WEATHERPROTONAME, "ID",&dbv)) {
+ if ( !_tcscmp(dbv.ptszVal, opt.Default))
+ opt.DefStn = hContact;
+ db_free(&dbv);
+ }
+ }
+ ContactCount++; // increment counter
+ LastContact = hContact;
+ }
+ hContact = db_find_next(hContact);
+ }
+
+ // if weather contact exists, set the status to online so it is ready for update
+ // if (ContactCount != 0) status = ONLINE;
+ // in case where the default station is missing
+ if (opt.DefStn == NULL && ContactCount != 0) {
+ if ( !DBGetContactSettingTString(LastContact, WEATHERPROTONAME, "ID", &dbv)) {
+ _tcscpy(opt.Default, dbv.ptszVal);
+ db_free(&dbv);
+ }
+ opt.DefStn = LastContact;
+ if ( !DBGetContactSettingTString(LastContact,WEATHERPROTONAME, "Nick",&dbv)) {
+ wsprintf(str, TranslateT("%s is now the default weather station"), dbv.ptszVal);
+ db_free(&dbv);
+ MessageBox(NULL, str, TranslateT("Weather Protocol"), MB_OK|MB_ICONINFORMATION);
+ }
+ }
+ // save option in case of default station changed
+ db_set_ts(NULL, WEATHERPROTONAME, "Default", opt.Default);
+}
+
+void ConvertDataValue(WIDATAITEM *UpdateData, TCHAR *Data)
+{
+ TCHAR str[MAX_DATA_LEN];
+
+ // convert the unit
+ if ( _tcscmp(Data, TranslateT("<Error>")) && _tcscmp(Data, NODATA) && _tcscmp(Data, TranslateTS(NODATA))) {
+ // temperature
+ if ( !_tcscmp(UpdateData->Name, _T("Temperature")) || !_tcscmp(UpdateData->Name, _T("High")) ||
+ !_tcscmp(UpdateData->Name, _T("Low")) || !_tcscmp(UpdateData->Name, _T("Feel")) ||
+ !_tcscmp(UpdateData->Name, _T("Dewpoint")) ||
+ !_tcsicmp(UpdateData->Unit, _T("C")) || !_tcsicmp(UpdateData->Unit, _T("F")) ||
+ !_tcsicmp(UpdateData->Unit, _T("K")))
+ {
+ GetTemp(Data, UpdateData->Unit, str);
+ _tcscpy(Data, str);
+ }
+ // pressure
+ else if ( !_tcscmp(UpdateData->Name, _T("Pressure")) || !_tcsicmp(UpdateData->Unit, _T("HPA")) ||
+ !_tcsicmp(UpdateData->Unit, _T("KPA")) || !_tcsicmp(UpdateData->Unit, _T("MB")) ||
+ !_tcsicmp(UpdateData->Unit, _T("TORR")) || !_tcsicmp(UpdateData->Unit, _T("IN")) ||
+ !_tcsicmp(UpdateData->Unit, _T("MM")))
+ {
+ GetPressure(Data, UpdateData->Unit, str);
+ _tcscpy(Data, str);
+ }
+ // speed
+ else if ( !_tcscmp(UpdateData->Name, _T("Wind Speed")) || !_tcsicmp(UpdateData->Unit, _T("KM/H")) ||
+ !_tcsicmp(UpdateData->Unit, _T("M/S")) || !_tcsicmp(UpdateData->Unit, _T("MPH")) ||
+ !_tcsicmp(UpdateData->Unit, _T("KNOTS")))
+ {
+ GetSpeed(Data, UpdateData->Unit, str);
+ _tcscpy(Data, str);
+ }
+ // visibility
+ else if ( !_tcscmp(UpdateData->Name, _T("Visibility")) || !_tcsicmp(UpdateData->Unit, _T("KM")) ||
+ !_tcsicmp(UpdateData->Unit, _T("MILES")))
+ {
+ GetDist(Data, UpdateData->Unit, str);
+ _tcscpy(Data, str);
+ }
+ // elevation
+ else if ( !_tcscmp(UpdateData->Name, _T("Elevation")) || !_tcsicmp(UpdateData->Unit, _T("FT")) ||
+ !_tcsicmp(UpdateData->Unit, _T("M")))
+ {
+ GetElev(Data, UpdateData->Unit, str);
+ _tcscpy(Data, str);
+ }
+ // converting case for condition to the upper+lower format
+ else if ( !_tcsicmp(UpdateData->Unit, _T("COND")))
+ CaseConv(Data);
+ // degree sign
+ else if ( !_tcsicmp(UpdateData->Unit, _T("DEG")))
+ {
+ if ( !opt.DoNotAppendUnit) _tcscat(Data, opt.DegreeSign);
+ }
+ // percent sign
+ else if ( !_tcsicmp(UpdateData->Unit, _T("%")))
+ {
+ if ( !opt.DoNotAppendUnit) _tcscat(Data, _T("%"));
+ }
+ // truncating strings for day/month to 2 or 3 characters
+ else if ( !_tcsicmp(UpdateData->Unit, _T("DAY")) || !_tcsicmp(UpdateData->Unit, _T("MONTH")))
+ if (opt.dUnit > 1 && _tcslen(Data) > opt.dUnit)
+ Data[opt.dUnit] = '\0';
+ }
+}
+
+//============ 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, TCHAR *Data, TCHAR** szData)
+{
+ TCHAR last = 0, current, *start, *end;
+ unsigned startloc = 0, endloc = 0, respos = 0;
+ BOOL tag = FALSE, symb = FALSE;
+ TCHAR *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 = _tcsstr(szInfo, UpdateData->Start);
+ if (start != NULL) {
+ // set the starting location for getting data
+ start += _tcslen(UpdateData->Start);
+ szInfo = start;
+ }
+ }
+ // the end string must be found too
+ if (UpdateData->End[0] != 0)
+ end = _tcsstr(szInfo, UpdateData->End);
+ else
+ end = _tcsstr(szInfo, _T(" "));
+
+ if (end != NULL) {
+ // set the ending location
+ startloc = 0;
+ endloc = end - szInfo;
+ end += _tcslen(UpdateData->End);
+ last = '\n';
+ }
+ // ignore if not both of the string found - this prevent crashes
+ if (start != NULL && end != NULL)
+ {
+ // 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] == ';'))
+ 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 && _tcscmp(UpdateData->Name, _T("Ignore"))) {
+ mir_sntprintf(Data, MAX_DATA_LEN, TranslateT("Error when obtaining data: %s"), UpdateData->Name);
+ WPShowMessage(Data, SM_WARNING);
+ }
+ _tcsncpy(Data, TranslateT("<Error>"), MAX_DATA_LEN);
+ last = ' ';
+ respos = MAX_DATA_LEN - 1;
+ break;
+ }
+ }
+
+ // 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
+void wSetData(char **Data, const char *Value)
+{
+ if (Value[0] != 0)
+ {
+ char *newData = (char*)mir_alloc(strlen(Value)+3);
+ strcpy(newData, Value);
+ *Data = newData;
+ }
+ else
+ *Data = "";
+}
+
+void wSetData(WCHAR **Data, const char *Value)
+{
+ if (Value[0] != 0)
+ *Data = mir_a2u( Value );
+ else
+ *Data = L"";
+}
+
+void wSetData(WCHAR **Data, const WCHAR *Value)
+{
+ if (Value[0] != 0) {
+ WCHAR *newData = (WCHAR*)mir_alloc( sizeof(WCHAR)*(wcslen(Value)+3));
+ wcscpy(newData, Value);
+ *Data = newData;
+ }
+ else *Data = L"";
+}
+
+// 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 && strlen(*Data) > 0) mir_free(*Data);
+ *Data = NULL;
+}
+
+void wfree(WCHAR **Data)
+{
+ if (*Data && wcslen(*Data) > 0)
+ mir_free(*Data);
+ *Data = NULL;
+}
+
+//============ MANAGE THE ITEMS STORED IN DB ============
+// get single setting that is found
+// szSetting = the setting name
+// lparam = the counter
+int GetWeatherDataFromDB(const char *szSetting, LPARAM lparam)
+{
+ LIST<char> *pList = (LIST<char>*)lparam;
+ pList->insert( mir_strdup(szSetting));
+ return 0;
+}
+
+// remove or display the weather information for a contact
+// hContact - the contact in which the info is going to be removed
+
+void DBDataManage(HANDLE hContact, WORD Mode, WPARAM wParam, LPARAM lParam)
+{
+ LIST<char> arSettings(10);
+
+ // get all the settings and stored them in a temporary list
+ DBCONTACTENUMSETTINGS dbces;
+ dbces.lParam = (LPARAM)&arSettings;
+ dbces.pfnEnumProc = GetWeatherDataFromDB;
+ dbces.szModule = WEATHERCONDITION;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)hContact, (LPARAM)&dbces);
+
+ // begin deleting settings
+ for (int i=arSettings.getCount()-1; i >= 0; i--) {
+ char *szSetting = arSettings[i];
+
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString(hContact, WEATHERCONDITION, szSetting, &dbv)) {
+ switch (Mode) {
+ case WDBM_REMOVE:
+ db_unset(hContact, WEATHERCONDITION, szSetting);
+ break;
+
+ case WDBM_DETAILDISPLAY:
+ // skip the "WeatherInfo" variable
+ if ( !strcmp(szSetting, "WeatherInfo") || !strcmp(szSetting, "Ignore") || szSetting[0] == '#')
+ continue;
+ else {
+ HWND hList = GetDlgItem((HWND)wParam, IDC_DATALIST);
+ LV_ITEM lvi = { 0 };
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.lParam = i;
+ lvi.pszText = TranslateTS( _A2T(szSetting ));
+ lvi.iItem = ListView_InsertItem(hList, &lvi);
+ lvi.pszText = dbv.ptszVal;
+ ListView_SetItemText(hList, lvi.iItem, 1, dbv.ptszVal );
+ break;
+ }
+ }
+ db_free(&dbv);
+ }
+ mir_free(szSetting);
+ }
+ arSettings.destroy();
+}
diff --git a/plugins/Weather/src/weather_http.cpp b/plugins/Weather/src/weather_http.cpp
new file mode 100644
index 0000000000..d9038db9c8
--- /dev/null
+++ b/plugins/Weather/src/weather_http.cpp
@@ -0,0 +1,206 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related to downloading weather info
+from the web using netlib
+*/
+
+#include "weather.h"
+
+HANDLE hNetlibUser, hNetlibHttp;
+
+int findHeader(NETLIBHTTPREQUEST *nlhrReply, char *hdr)
+{
+ int res = -1, i;
+ for (i=0; i<nlhrReply->headersCount; i++)
+ {
+ if (_stricmp(nlhrReply->headers[i].szName, hdr) == 0)
+ {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+
+//============ DOWNLOAD NEW WEATHER ============
+
+// function to download webpage from the internet
+// szUrl = URL of the webpage to be retrieved
+// return value = 0 for success, 1 or HTTP error code for failure
+// global var used: szData, szInfo = containing the retrieved data
+int InternetDownloadFile (char *szUrl, char* cookie, TCHAR** szData)
+{
+ int result = 0xBADBAD;
+ char* szRedirUrl = NULL;
+ NETLIBHTTPREQUEST nlhr = {0};
+ NETLIBHTTPHEADER headers[6];
+
+ // initialize the netlib request
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_PERSISTENT | NLHRF_REDIRECT;
+ nlhr.szUrl = szUrl;
+ nlhr.nlc = hNetlibHttp;
+
+ // change the header so the plugin is pretended to be IE 6 + WinXP
+ nlhr.headersCount = 5;
+ nlhr.headers = headers;
+ nlhr.headers[0].szName = "User-Agent";
+ nlhr.headers[0].szValue = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
+ nlhr.headers[1].szName = "Cache-Control";
+ nlhr.headers[1].szValue = "no-cache";
+ nlhr.headers[2].szName = "Pragma";
+ nlhr.headers[2].szValue = "no-cache";
+ nlhr.headers[3].szName = "Connection";
+ nlhr.headers[3].szValue = "close";
+ nlhr.headers[4].szName = "Cookie";
+ nlhr.headers[4].szValue = cookie;
+// nlhr.headers[5].szName = "If-Modified-Since";
+// nlhr.headers[5].szValue = "Tue, 24 Feb 2009 03:44:23 GMT";
+
+ if (cookie == NULL || cookie[0] == 0) --nlhr.headersCount;
+
+ while (result == 0xBADBAD) {
+ // download the page
+ NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION,
+ (WPARAM)hNetlibUser, (LPARAM)&nlhr);
+
+ if (nlhrReply) {
+ // if the recieved code is 200 OK
+ if (nlhrReply->resultCode == 200) {
+ if (nlhrReply->dataLength) {
+ result = 0;
+ bool bIsUtf = false;
+
+ // allocate memory and save the retrieved data
+ int i = findHeader(nlhrReply, "Content-Type");
+ if (i != -1 && strstr(_strlwr((char*)nlhrReply->headers[i].szValue), "utf-8"))
+ bIsUtf = true;
+ else {
+ char* end = nlhrReply->pData;
+ for (;;) {
+ char* beg = strstr(end, "<meta");
+ if (beg == NULL) break;
+ else {
+ char* method, tmp;
+ end = strchr(beg, '>');
+ tmp = *end; *end = 0;
+
+ method = strstr(beg, "http-equiv=\"");
+ if (method && _strnicmp(method+12, "Content-Type", 12) == 0 && strstr(method, "utf-8")) {
+ bIsUtf = true;
+ break;
+ }
+ else *end = tmp;
+ } } }
+
+ if ( bIsUtf )
+ *szData = mir_utf8decodeT( nlhrReply->pData );
+ else
+ *szData = mir_a2t( nlhrReply->pData );
+
+ }
+ else result = DATA_EMPTY;
+ }
+ // if the recieved code is 302 Moved, Found, etc
+ // workaround for url forwarding
+ else if (nlhrReply->resultCode == 302 || nlhrReply->resultCode == 301 || nlhrReply->resultCode == 303 ) // page moved
+ {
+ // get the url for the new location and save it to szInfo
+ // look for the reply header "Location"
+ int i = findHeader(nlhrReply, "Location");
+
+ if (i != -1)
+ {
+ size_t rlen = 0;
+ if (nlhrReply->headers[i].szValue[0] == '/')
+ {
+ char* szPath;
+ char* szPref = strstr(szUrl, "://");
+ szPref = szPref ? szPref + 3 : szUrl;
+ szPath = strchr(szPref, '/');
+ rlen = szPath != NULL ? szPath - szUrl : strlen(szUrl);
+ }
+
+ szRedirUrl = (char*)mir_realloc(szRedirUrl,
+ rlen + strlen(nlhrReply->headers[i].szValue)*3 + 1);
+
+ strncpy(szRedirUrl, szUrl, rlen);
+ strcpy(szRedirUrl+rlen, nlhrReply->headers[i].szValue);
+
+ GetSearchStr(szRedirUrl);
+
+ nlhr.szUrl = szRedirUrl;
+ }
+ }
+ // return error code if the recieved code is neither 200 OK nor 302 Moved
+ else {
+ *szData = ( TCHAR* )mir_alloc(512);
+ // store the error code in szData
+ wsprintf(*szData, _T("Error occured! HTTP Error: %i\n"), nlhrReply->resultCode);
+ result = (int)nlhrReply->resultCode;
+ }
+
+ hNetlibHttp = nlhrReply->nlc;
+ // make a copy of the retrieved data, then free the memory of the http reply
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0, (LPARAM)nlhrReply);
+ }
+ // if the data does not downloaded successfully (ie. disconnected), then return 1000 as error code
+ else
+ {
+ *szData = ( TCHAR* )mir_alloc(512);
+ // store the error code in szData
+ _tcscpy(*szData, _T("NetLib error occurred!!"));
+ result = NETLIB_ERROR;
+ hNetlibHttp = NULL;
+ }
+
+ }
+
+ mir_free(szRedirUrl);
+
+ return result;
+}
+
+//============ NETLIB INITIALIZATION ============
+
+// initialize netlib support for weather protocol
+void NetlibInit(void)
+{
+ NETLIBUSER nlu = {0};
+ nlu.cbSize = sizeof(nlu);
+ nlu.flags = NUF_OUTGOING|NUF_HTTPCONNS|NUF_NOHTTPSOPTION|NUF_TCHAR;
+ nlu.szSettingsModule = WEATHERPROTONAME;
+ nlu.ptszDescriptiveName = TranslateT("Weather HTTP connections");
+ hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER,0, (LPARAM)&nlu);
+}
+
+void NetlibHttpDisconnect(void)
+{
+ if (hNetlibHttp)
+ {
+ HANDLE hConn = hNetlibHttp;
+ hNetlibHttp = NULL;
+ Netlib_CloseHandle(hConn);
+ }
+}
+
diff --git a/plugins/Weather/src/weather_icons.cpp b/plugins/Weather/src/weather_icons.cpp
new file mode 100644
index 0000000000..321d758ca2
--- /dev/null
+++ b/plugins/Weather/src/weather_icons.cpp
@@ -0,0 +1,87 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "weather.h"
+
+HANDLE hIcoLibIconsChanged = NULL;
+
+struct _tag_iconList
+{
+ TCHAR* szDescr;
+ char* szName;
+ int defIconID;
+ HANDLE hIconLibItem;
+}
+static iconList[] =
+{
+ { LPGENT("Protocol icon"), "main", IDI_ICON },
+ { LPGENT("Update Disabled"), "disabled", IDI_DISABLED },
+ { LPGENT("View Log"), "log", IDI_LOG },
+ { LPGENT("Update with Clear"), "update2", IDI_UPDATE2 },
+ { LPGENT("View Brief"), "brief", IDI_S },
+ { LPGENT("View Complete"), "read", IDI_READ },
+ { LPGENT("Weather Update"), "update", IDI_UPDATE },
+ { LPGENT("Weather Map"), "map", IDI_MAP },
+ { LPGENT("Popup"), "popup", IDI_POPUP },
+ { LPGENT("No Popup"), "nopopup", IDI_NOPOPUP },
+ { LPGENT("Edit Settings"), "edit", IDI_EDIT },
+};
+
+void InitIcons(void)
+{
+ char szSettingName[100];
+ TCHAR szFile[MAX_PATH];
+ GetModuleFileName(hInst, szFile, MAX_PATH);
+
+ SKINICONDESC sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.ptszDefaultFile = szFile;
+ sid.pszName = szSettingName;
+ sid.ptszSection = _T(WEATHERPROTONAME);
+ sid.flags = SIDF_ALL_TCHAR;
+
+ for (int i = 0; i < SIZEOF(iconList); i++) {
+ mir_snprintf(szSettingName, SIZEOF( szSettingName ), "%s_%s", WEATHERPROTONAME, iconList[i].szName);
+
+ sid.ptszDescription = iconList[i].szDescr;
+ sid.iDefaultIndex = -iconList[i].defIconID;
+ iconList[i].hIconLibItem = Skin_AddIcon(&sid);
+} }
+
+HICON LoadIconEx(const char* name, BOOL big)
+{
+ char szSettingName[100];
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%s_%s", WEATHERPROTONAME, name);
+ return Skin_GetIcon(szSettingName, big);
+}
+
+HANDLE GetIconHandle(const char* name)
+{
+ unsigned i;
+ for (i=0; i < SIZEOF(iconList); i++)
+ if (strcmp(iconList[i].szName, name) == 0)
+ return iconList[i].hIconLibItem;
+ return NULL;
+}
+
+void ReleaseIconEx(HICON hIcon)
+{
+ Skin_ReleaseIcon(hIcon);
+}
diff --git a/plugins/Weather/src/weather_info.cpp b/plugins/Weather/src/weather_info.cpp
new file mode 100644
index 0000000000..f02fc79a28
--- /dev/null
+++ b/plugins/Weather/src/weather_info.cpp
@@ -0,0 +1,252 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+This file contain the source for displaying information for the
+ini files, as well as function that are used for debug purpose
+regrading the loading of ini contents
+*/
+
+#include "weather.h"
+
+//============ INI INFORMATION ============
+
+// List INI Information for all loaded INI files
+void INIInfo(HWND hwndDlg)
+{
+ TCHAR str[16];
+ size_t memused = 0;
+ LVITEM lvi = {0};
+ WIDATALIST *Item = WIHead;
+
+ HWND hIniList = GetDlgItem(hwndDlg, IDC_INFOLIST);
+
+ ListView_DeleteAllItems(hIniList);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iItem = 0;
+ while (Item != NULL)
+ {
+ // get the data for the ini file
+ lvi.iSubItem = 0;
+ lvi.pszText = Item->Data.InternalName;
+ ListView_InsertItem(hIniList, &lvi);
+ lvi.iSubItem = 1;
+ lvi.pszText = Item->Data.Author;
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 2;
+ lvi.pszText = Item->Data.Version;
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 3;
+ switch (Item->Data.InternalVer)
+ {
+ case 1: lvi.pszText = _T("1.0"); break;
+ case 2: lvi.pszText = _T("1.1"); break;
+ case 3: lvi.pszText = _T("1.1a"); break;
+ case 4: lvi.pszText = _T("1.2"); break;
+ case 5: lvi.pszText = _T("1.3"); break;
+ case 6: lvi.pszText = _T("1.4"); break;
+ default: lvi.pszText = _T(""); break;
+ }
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 4;
+ lvi.pszText = _ltot(Item->Data.UpdateDataCount, str, 10);
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 5;
+ lvi.pszText = Item->Data.DisplayName;
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 6;
+ lvi.pszText = Item->Data.ShortFileName;
+ ListView_SetItem(hIniList, &lvi);
+
+ memused += Item->Data.MemUsed;
+
+ Item = Item->next;
+ ++lvi.iItem;
+ }
+ SetDlgItemText(hwndDlg, IDC_INICOUNT, _itot(lvi.iItem, str, 10));
+ SetDlgItemText(hwndDlg, IDC_MEMUSED, _ltot((long)memused, str, 10));
+}
+
+static const struct tag_Columns
+{
+ const TCHAR *name;
+ unsigned size;
+}
+columns[] =
+{
+ { _T("Name"), 70 },
+ { _T("Author"), 100 },
+ { _T("File Version"), 70 },
+ { _T("INI Version"), 70 },
+ { _T("Items"), 40 },
+ { _T("Display Name"), 200 },
+ { _T("File Name"), 150 },
+};
+
+
+INT_PTR CALLBACK DlgProcINIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ HWND hIniList = GetDlgItem(hwndDlg, IDC_INFOLIST);
+ LVCOLUMN lvc = {0};
+
+ lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+ lvc.fmt = LVCFMT_LEFT;
+ for ( int i=0; i<7; ++i) {
+ lvc.iSubItem = i;
+ lvc.pszText = TranslateTS(columns[i].name);
+ lvc.cx = columns[i].size;
+ ListView_InsertColumn(hIniList, i, &lvc);
+ }
+ INIInfo(hwndDlg);
+ }
+
+ break;
+
+ case WM_DESTROY:
+ break;
+
+ case WM_COMMAND:
+ if ( HIWORD(wParam) == BN_CLICKED &&
+ LOWORD(wParam) == IDC_RELOADINI )
+ {
+ DestroyWIList();
+ LoadWIData(TRUE);
+ INIInfo(hwndDlg);
+ }
+ break;
+ }
+ return 0;
+}
+
+
+// get the info of individual ini file
+// pszSvc = the internal name of the service to get the data
+void GetINIInfo(TCHAR *pszSvc)
+{
+ TCHAR str2[2048];
+ WIDATA *sData = GetWIData(pszSvc);
+ // if the service does not exist among the loaded INI's
+ if (sData == NULL)
+ {
+ wsprintf(str2, TranslateT("The corresponding INI file for \"%s\" is not found."), pszSvc);
+ MessageBox(NULL, str2, TranslateT("Weather INI information"), MB_OK|MB_ICONINFORMATION);
+ }
+ // if exist, get the information
+ else
+ {
+ wsprintf(str2, TranslateT("Weather INI information for \"%s\":"), pszSvc);
+ _tcscat(str2,_T("\n\n"));
+ _tcscat(str2, TranslateT("Name:"));
+ _tcscat(str2,_T("\t\t"));
+ _tcscat(str2, sData->DisplayName);
+ _tcscat(str2,_T("\n"));
+ _tcscat(str2, TranslateT("Internal Name:"));
+ _tcscat(str2,_T("\t"));
+ _tcscat(str2, sData->InternalName);
+ _tcscat(str2,_T("\n"));
+ _tcscat(str2, TranslateT("Author:"));
+ _tcscat(str2,_T("\t\t"));
+ _tcscat(str2, sData->Author);
+ _tcscat(str2,_T("\n"));
+ _tcscat(str2, TranslateT("Version:"));
+ _tcscat(str2,_T("\t\t"));
+ _tcscat(str2, sData->Version);
+ _tcscat(str2,_T("\n"));
+ _tcscat(str2, TranslateT("INI Version:"));
+ _tcscat(str2,_T("\t"));
+ switch (sData->InternalVer) {
+ case 1: _tcscat(str2,_T("1.0")); break;
+ case 2: _tcscat(str2,_T("1.1")); break;
+ case 3: _tcscat(str2,_T("1.1a")); break;
+ case 4: _tcscat(str2,_T("1.2")); break;
+ case 5: _tcscat(str2,_T("1.3")); break;
+ case 6: _tcscat(str2,_T("1.4")); break;
+ }
+ _tcscat(str2,_T("\n"));
+ _tcscat(str2, TranslateT("File Name:"));
+ _tcscat(str2,_T("\t"));
+ _tcscat(str2, sData->ShortFileName);
+ _tcscat(str2, _T("\n"));
+ _tcscat(str2, TranslateT("Item Count:"));
+ wsprintf(str2, _T("%s\t%i\n"), str2, sData->UpdateDataCount);
+ _tcscat(str2, TranslateT("Memory Used:"));
+ wsprintf(str2, _T("%s\t%i "), str2, sData->MemUsed);
+ _tcscat(str2, TranslateT("bytes"));
+ _tcscat(str2,_T("\n\n"));
+ _tcscat(str2, TranslateT("Description:"));
+ _tcscat(str2,_T("\n"));
+ _tcscat(str2, sData->Description);
+
+ // display the message box and quit
+ MessageBox(NULL, str2, TranslateT("Weather INI information"), MB_OK|MB_ICONINFORMATION);
+ }
+}
+
+//============ DISPLAY A LIST FOR CUSTOM VARIABLES ============
+
+// a message box for displaying the list of custom variables
+// can be found when click on "More" in text option dialog
+void MoreVarList(void)
+{
+ TCHAR str[10240], tempstr[1024];
+
+ WIDATALIST *Item = WIHead;
+ // heading
+ _tcscpy(str, TranslateT("Here is a list of custom variables that are currently available"));
+ _tcscat(str, _T("\n\n"));
+ // loop through all weather services to find custom variables
+ while (Item != NULL)
+ {
+ WIDATAITEMLIST* WItem;
+ WItem = Item->Data.UpdateData;
+ // loop through all update items in a service
+ while (WItem != NULL)
+ {
+ // the custom variable is defined as "%[<variable name>]"
+ // ignore the "hi" item and hidden items
+ if ( _tcscmp(WItem->Item.Name, _T("Ignore")) && WItem->Item.Name[0] != '#') {
+ wsprintf(tempstr, _T("%c[%s]"), '%', WItem->Item.Name);
+ TCHAR* find = _tcsstr(str, tempstr);
+ // if the custom variable does not exist in the list, add it to the list
+ if (find == NULL) {
+ _tcscat(str, tempstr);
+ _tcscat(str, _T(", "));
+ }
+ }
+ WItem = WItem->Next;
+ }
+ Item = Item->next;
+ }
+ // remove the last comma in the list
+ TCHAR* find = _tcsrchr(str, ',');
+ if (find != NULL)
+ *find = '\0';
+
+ // display the list in a message box
+ MessageBox(NULL, str, TranslateT("More Variables"), MB_OK|MB_ICONINFORMATION|MB_TOPMOST);
+}
+
diff --git a/plugins/Weather/src/weather_ini.cpp b/plugins/Weather/src/weather_ini.cpp
new file mode 100644
index 0000000000..69f9ba40bb
--- /dev/null
+++ b/plugins/Weather/src/weather_ini.cpp
@@ -0,0 +1,613 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+This file contain the source related to loading the reading the
+weather ini files and store them into memory. Also containing
+code for unloading and getting weather data from the ini settings.
+*/
+
+#include "weather.h"
+
+HWND hWndSetup;
+
+//============ DATA LIST (LINKED LIST) ============
+
+// add an item into weather service data list
+// Data = the service data to be added to the list
+void WIListAdd(WIDATA Data)
+{
+ WIDATALIST *newItem;
+
+ // create a new datalist item and point to the data
+ newItem = (WIDATALIST*)mir_alloc(sizeof(WIDATALIST));
+ newItem->Data = Data;
+ // add to the linked list
+ newItem->next = NULL;
+ if (WITail == NULL) WIHead = newItem;
+ else WITail->next = newItem;
+ WITail = newItem;
+}
+
+// get the service data (from loaded ini file) by internal name
+// pszServ = internal name for the service
+// return value = the matching WIDATA struct for pszServ, NULL if no match found
+WIDATA* GetWIData(TCHAR *pszServ)
+{
+ WIDATALIST *Item = WIHead;
+
+ // loop through the list to find matching internal name
+ while (Item != NULL) {
+ // if internal name found, return the data
+ if ( _tcscmp(Item->Data.InternalName, pszServ) == 0)
+ return &Item->Data;
+ Item = Item->next;
+ }
+ // return NULL when no match found
+ return NULL;
+}
+
+// remove all service data from memory
+void DestroyWIList(void)
+{
+ // free the list one by one
+ while (WIHead != NULL)
+ {
+ WIDATALIST *wi = WIHead;
+ WIHead = wi->next;
+ FreeWIData(&wi->Data); // free the data struct
+ mir_free(wi);
+ }
+
+ // make sure the entire list is clear
+ WITail = NULL;
+}
+
+//============ DATA ITEM LIST (LINKED LIST) ============
+
+// add a new update item into the current list
+void WIItemListAdd(WIDATAITEM *DataItem, WIDATA *Data)
+{
+ WIDATAITEMLIST *newItem;
+
+ newItem = (WIDATAITEMLIST*)mir_alloc(sizeof(WIDATAITEMLIST));
+ newItem->Item = *DataItem;
+ newItem->Next = NULL;
+ if (Data->UpdateData == NULL) Data->UpdateData = newItem;
+ else Data->UpdateDataTail->Next = newItem;
+ Data->UpdateDataTail = newItem;
+}
+
+// reset the data item by using empty string
+// Item = the item to set
+// name = the string to store in the "name" field
+void ResetDataItem(WIDATAITEM *Item, const TCHAR *name)
+{
+ TCHAR str[] = _T("ID Search - Station Name");
+ Item->Name = ( TCHAR* )mir_alloc( sizeof(str));
+ _tcscpy(Item->Name, str);
+ Item->Start = _T("");
+ Item->End = _T("");
+ Item->Unit = _T("");
+ Item->Url = "";
+ Item->Break = _T("");
+ Item->Type = 0;
+}
+
+// free the data item by using empty string
+// Item = the item to free
+void FreeDataItem(WIDATAITEM *Item)
+{
+ wfree(&Item->Name);
+ wfree(&Item->Start);
+ wfree(&Item->End);
+ wfree(&Item->Unit);
+ wfree(&Item->Url);
+ wfree(&Item->Break);
+}
+
+//============ Condition Icon List ============
+
+// initiate icon assignmet list
+void WICondListInit(WICONDLIST *List)
+{
+ List->Tail = NULL;
+ List->Head = NULL;
+}
+
+// add a new update item into the current list
+void WICondListAdd(char *str, WICONDLIST *List)
+{
+ WICONDITEM *newItem = (WICONDITEM*)mir_alloc(sizeof(WICONDITEM));
+ wSetData(&newItem->Item, str);
+ CharLowerBuff(newItem->Item, (DWORD)_tcslen( newItem->Item ));
+ newItem->Next = NULL;
+ if (List->Tail == NULL) List->Head = newItem;
+ else List->Tail->Next = newItem;
+ List->Tail = newItem;
+}
+
+// check if the condition string matched for the assignment
+BOOL IsContainedInCondList(const TCHAR *pszStr, WICONDLIST *List)
+{
+ WICONDITEM *Item = List->Head;
+
+ // loop through the list to find matching internal name
+ while (Item != NULL) {
+ // if internal name found, return true indicating that the data is found
+ if ( _tcsstr(pszStr, Item->Item))
+ return TRUE;
+ Item = Item->Next;
+ }
+ // return false when no match found
+ return FALSE;
+}
+
+// free the memory for icon assignment list
+void DestroyCondList(WICONDLIST *List)
+{
+ WICONDITEM *temp;
+
+ temp = List->Head;
+
+ // free the list one by one
+ while (temp != NULL)
+ {
+ List->Head = temp->Next;
+ wfree(&temp->Item); // free the data struct
+ mir_free(temp);
+ temp = List->Head;
+ }
+ // make sure the entire list is clear
+ List->Tail = NULL;
+}
+
+
+//============ LOADING INI FILES ============
+
+// load the weather update data form INI files
+BOOL LoadWIData(BOOL dial)
+{
+ HANDLE hFind;
+ TCHAR szSearchPath[MAX_PATH], FileName[MAX_PATH], *chop;
+ WIN32_FIND_DATA fd;
+ WIDATA Data;
+
+ // make sure that the current service data list is empty
+ WITail = NULL;
+ WIHead = WITail;
+
+ // find all *.ini file in the plugin\weather directory
+ GetModuleFileName(GetModuleHandle(NULL), szSearchPath, SIZEOF(szSearchPath));
+ chop = _tcsrchr(szSearchPath, '\\');
+ *chop = '\0';
+ _tcscat(szSearchPath, _T("\\Plugins\\Weather\\*.ini"));
+ _tcscpy(FileName, szSearchPath);
+
+ hFind = FindFirstFile(szSearchPath, &fd);
+
+ // load the content of the ini file into memory
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ chop = _tcsrchr(FileName, '\\');
+ chop[1] = '\0';
+ _tcscat(FileName, fd.cFileName);
+ if ( _tcsicmp(fd.cFileName, _T("SAMPLE_INI.INI"))) {
+ LoadStationData(FileName, fd.cFileName, &Data);
+ if (Data.Enabled) WIListAdd(Data);
+ }
+ // look through the entire "plugins\weather" directory
+ }
+ while(FindNextFile(hFind, &fd));
+ FindClose(hFind);
+ }
+
+ if (WIHead == NULL) {
+ // no ini found, display an error message box.
+ if (dial)
+ hWndSetup = CreateDialog(hInst, MAKEINTRESOURCE(IDD_SETUP), NULL, DlgProcSetup);
+ else
+ MessageBox(NULL,
+ TranslateT("No update data file is found. Please check your Plugins\\Weather directory."),
+ TranslateT("Weather Protocol"), MB_OK | MB_ICONERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// load the station data from a file
+// pszFile = the file name + path for the ini file to be loaded
+// pszShortFile = the file name of the ini file, but not including the path
+// Data = the struct to load the ini content to, and return to previous function
+void LoadStationData(TCHAR *pszFile, TCHAR *pszShortFile, WIDATA *Data)
+{
+ WIDATAITEM DataItem;
+ FILE *pfile;
+ int i;
+ char *Group, *Temp;
+ char *ValName, *Value;
+
+ static const char *statusStr[10] =
+ {
+ "LIGHTNING",
+ "FOG",
+ "SNOW SHOWER",
+ "SNOW",
+ "RAIN SHOWER",
+ "RAIN",
+ "PARTLY CLOUDY",
+ "CLOUDY",
+ "SUNNY",
+ "N/A"
+ };
+
+ // clean up old stuff
+ ZeroMemory(Data, sizeof(Data));
+ Data->Enabled = FALSE;
+
+ // open the ini file
+ pfile = _tfsopen(pszFile, _T("rt"), _SH_DENYWR);
+ if (pfile != NULL) {
+ char Line[4096];
+ fgets(Line, SIZEOF(Line), pfile);
+ TrimString(Line);
+
+ // make sure it is a valid weather protocol ini file
+ if ( !strcmp(Line, "[Weather 0.3.x Update Data]"))
+ Data->InternalVer = 1;
+ else if ( !strcmp(Line, "[Weather 0.3.x Update Data 1.1]"))
+ Data->InternalVer = 2;
+ else if ( !strcmp(Line, "[Weather 0.3.x Update Data 1.1a]"))
+ Data->InternalVer = 3;
+ else if ( !strcmp(Line, "[Weather 0.3.x Update Data 1.2]"))
+ Data->InternalVer = 4;
+ else if ( !strcmp(Line, "[Weather 0.3.x Update Data 1.3]"))
+ Data->InternalVer = 5;
+ else if ( !strcmp(Line, "[Weather 0.3.x Update Data 1.4]"))
+ Data->InternalVer = 6;
+ else
+ {
+ wsprintfA(Line, Translate("Invalid ini format for: %s"), pszFile);
+ MessageBoxA(NULL, Line, Translate("Weather Protocol"), MB_OK|MB_ICONERROR);
+ fclose(pfile);
+ return;
+ }
+
+ // initialize all data fields
+ Group = "";
+
+ Data->DisplayName = _T("");
+ Data->InternalName = _T("");
+ Data->Description = _T("");
+ Data->Author = _T("");
+ Data->Version = _T("");
+ Data->DefaultURL = "";
+ Data->DefaultMap = _T("");
+ Data->UpdateURL = "";
+ Data->UpdateURL2 = "";
+ Data->UpdateURL3 = "";
+ Data->UpdateURL4 = "";
+ Data->Cookie = "";
+ Data->IDSearch.SearchURL = "";
+ Data->IDSearch.NotFoundStr = _T("");
+ Data->NameSearch.SearchURL = "";
+ Data->NameSearch.NotFoundStr = _T("");
+ Data->NameSearch.SingleStr = _T("");
+ Data->NameSearch.Single.First = _T("");
+ Data->NameSearch.Multiple.First = _T("");
+ Data->IDSearch.Available = FALSE;
+ Data->NameSearch.Single.Available = FALSE;
+ Data->NameSearch.Multiple.Available = FALSE;
+ wSetData(&Data->FileName, pszFile);
+ wSetData(&Data->ShortFileName, pszShortFile);
+
+ ResetDataItem(&Data->IDSearch.Name, _T("ID Search - Station Name"));
+ ResetDataItem(&Data->NameSearch.Single.Name, _T("Name Search Single Result - Station Name"));
+ ResetDataItem(&Data->NameSearch.Single.ID, _T("Name Search Single Result - Station ID"));
+ ResetDataItem(&Data->NameSearch.Multiple.Name, _T("Name Search Multiple Result - Station Name"));
+ ResetDataItem(&Data->NameSearch.Multiple.ID, _T("Name Search Multiple Result - Station ID"));
+
+ DataItem.Name = _T("");
+ DataItem.Start = _T("");
+ DataItem.End = _T("");
+ DataItem.Unit = _T("");
+ DataItem.Url = "";
+ DataItem.Break = _T("");
+ DataItem.Type = 0;
+
+ Temp = "";
+
+ // initialize the linked list for update items
+ Data->UpdateDataCount = 0;
+ Data->MemUsed = sizeof(WIDATA) + sizeof(WIDATALIST) + (_tcslen(pszShortFile) + _tcslen(pszFile) + 20)*sizeof( TCHAR );
+ Data->UpdateData = NULL;
+ Data->UpdateDataTail = NULL;
+
+ // initialize the icon assignment list
+ for (i=0; i<10; i++)
+ WICondListInit( &Data->CondList[i] );
+
+ while (!feof(pfile)) {
+ // determine current tag
+
+ if (fgets(Line, SIZEOF(Line), pfile) == NULL)
+ break;
+ TrimString(Line);
+
+ // if the line is a group header/footer
+ if (Line[0] == '[') {
+ char *chop = strchr(Line+1,']');
+ if (chop == NULL)
+ continue;
+
+ if (Line[1] != '/') { // if it is not a footer (for old ini)
+ // save the group name
+ Temp = (char *)mir_alloc(strlen(Line)+10);
+ strncpy(Temp, Line+1, chop-Line-1);
+ Temp[chop-Line-1] = 0;
+ wfree(&Group);
+ wSetData(&Group, Temp);
+ // see if it is a update item, if it is, add a new item to the linked list
+ // if (_stricmp(Group, "HEADER") && _stricmp(Group, "DEFAULT") && _stricmp(Group, "ID SEARCH") &&
+ // strcmpi(Group, "NAME SEARCH"))
+ // wSetData(&DataItem.Name, Group);
+ if (_stricmp(Group, "HEADER") && _stricmp(Group, "DEFAULT") && _stricmp(Group, "ID SEARCH") &&
+ _stricmp(Group, "NAME SEARCH") && _stricmp(Group, "ICONS"))
+ {
+ wSetData(&DataItem.Name, Temp);
+ DataItem.Type = WID_NORMAL;
+ WIItemListAdd(&DataItem, Data);
+ Data->UpdateDataCount++;
+ }
+ mir_free(Temp);
+ }
+ else
+ {
+ wfree(&Group);
+ wSetData(&Group, "");
+ }
+ }
+ // ignore comments and all lines without an '='
+ Value = strstr(Line, "=");
+ if (Value == NULL) continue;
+
+ // get the string before '=' (ValName) and after '=' (Value)
+ ValName = (char *)mir_alloc(strlen(Line)+1);
+ strncpy(ValName, Line, Value-Line);
+ ValName[Value-Line] = 0;
+ Value++;
+ ConvertBackslashes(Value);
+ // store the value for each string
+ if ( !_stricmp(Group, "HEADER")) {
+ if ( !_stricmp(ValName, "NAME")) wSetData(&Data->DisplayName, Value);
+ else if ( !_stricmp(ValName, "INTERNAL NAME")) wSetData(&Data->InternalName, Value);
+ else if ( !_stricmp(ValName, "DESCRIPTION")) wSetData(&Data->Description, Value);
+ else if ( !_stricmp(ValName, "AUTHOR")) wSetData(&Data->Author, Value);
+ else if ( !_stricmp(ValName, "VERSION")) wSetData(&Data->Version, Value);
+ }
+ else if ( !_stricmp(Group, "DEFAULT")) {
+ if ( !_stricmp(ValName, "DEFAULT URL")) wSetData(&Data->DefaultURL, Value);
+ else if ( !_stricmp(ValName, "DEFAULT MAP")) wSetData(&Data->DefaultMap, Value);
+ else if ( !_stricmp(ValName, "UPDATE URL")) wSetData(&Data->UpdateURL, Value);
+ else if ( !_stricmp(ValName, "UPDATE URL2")) wSetData(&Data->UpdateURL2, Value);
+ else if ( !_stricmp(ValName, "UPDATE URL3")) wSetData(&Data->UpdateURL3, Value);
+ else if ( !_stricmp(ValName, "UPDATE URL4")) wSetData(&Data->UpdateURL4, Value);
+ else if ( !_stricmp(ValName, "COOKIE")) wSetData(&Data->Cookie, Value);
+ }
+ else if ( !_stricmp(Group, "ID SEARCH")) {
+ if ( !_stricmp(ValName, "AVAILABLE")) {
+ if ( !_stricmp(Value, "TRUE")) Data->IDSearch.Available = TRUE;
+ else Data->IDSearch.Available = FALSE;
+ }
+ else if ( !_stricmp(ValName, "SEARCH URL")) wSetData(&Data->IDSearch.SearchURL, Value);
+ else if ( !_stricmp(ValName, "NOT FOUND STR")) wSetData(&Data->IDSearch.NotFoundStr, Value);
+ else if ( !_stricmp(ValName, "NAME START")) wSetData(&Data->IDSearch.Name.Start, Value);
+ else if ( !_stricmp(ValName, "NAME END")) wSetData(&Data->IDSearch.Name.End, Value);
+ }
+ else if ( !_stricmp(Group, "NAME SEARCH")) {
+ if ( !_stricmp(ValName, "SINGLE RESULT")) {
+ if ( !_stricmp(Value, "TRUE")) Data->NameSearch.Single.Available = TRUE;
+ else Data->NameSearch.Single.Available = FALSE;
+ }
+ else if ( !_stricmp(ValName, "MULTIPLE RESULT")) {
+ if ( !_stricmp(Value, "TRUE")) Data->NameSearch.Multiple.Available = TRUE;
+ else Data->NameSearch.Multiple.Available = FALSE;
+ }
+ else if ( !_stricmp(ValName, "SEARCH URL")) wSetData(&Data->NameSearch.SearchURL, Value);
+ else if ( !_stricmp(ValName, "NOT FOUND STR")) wSetData(&Data->NameSearch.NotFoundStr, Value);
+ else if ( !_stricmp(ValName, "SINGLE RESULT STR")) wSetData(&Data->NameSearch.SingleStr, Value);
+ else if ( !_stricmp(ValName, "SINGLE FIRST")) wSetData(&Data->NameSearch.Single.First, Value);
+ else if ( !_stricmp(ValName, "SINGLE NAME START"))wSetData(&Data->NameSearch.Single.Name.Start, Value);
+ else if ( !_stricmp(ValName, "SINGLE NAME END")) wSetData(&Data->NameSearch.Single.Name.End, Value);
+ else if ( !_stricmp(ValName, "SINGLE ID START")) wSetData(&Data->NameSearch.Single.ID.Start, Value);
+ else if ( !_stricmp(ValName, "SINGLE ID END")) wSetData(&Data->NameSearch.Single.ID.End, Value);
+ else if ( !_stricmp(ValName, "MULT FIRST")) wSetData(&Data->NameSearch.Multiple.First, Value);
+ else if ( !_stricmp(ValName, "MULT NAME START")) wSetData(&Data->NameSearch.Multiple.Name.Start, Value);
+ else if ( !_stricmp(ValName, "MULT NAME END")) wSetData(&Data->NameSearch.Multiple.Name.End, Value);
+ else if ( !_stricmp(ValName, "MULT ID START")) wSetData(&Data->NameSearch.Multiple.ID.Start, Value);
+ else if ( !_stricmp(ValName, "MULT ID END")) wSetData(&Data->NameSearch.Multiple.ID.End, Value);
+ }
+ else if ( !_stricmp(Group, "ICONS")) {
+ for (i=0; i<10; i++) {
+ if ( !_stricmp(ValName, statusStr[i])) {
+ WICondListAdd(Value, &Data->CondList[i]);
+ break;
+ }
+ }
+ }
+ else if (Data->UpdateDataCount != 0) {
+ if ( !_stricmp(ValName, "START")) wSetData(&Data->UpdateDataTail->Item.Start, Value);
+ else if ( !_stricmp(ValName, "SOURCE")) wSetData(&Data->UpdateDataTail->Item.Start, Value);
+ else if ( !_stricmp(ValName, "END")) wSetData(&Data->UpdateDataTail->Item.End, Value);
+ else if ( !_stricmp(ValName, "UNIT")) wSetData(&Data->UpdateDataTail->Item.Unit, Value);
+ else if ( !_stricmp(ValName, "URL")) wSetData(&Data->UpdateDataTail->Item.Url, Value);
+ else if ( !_stricmp(ValName, "HIDDEN")) {
+ if ( !_stricmp(Value, "TRUE")) {
+ TCHAR *nm = Data->UpdateDataTail->Item.Name;
+ size_t len = _tcslen(nm) + 1;
+
+ Data->UpdateDataTail->Item.Name = nm = ( TCHAR* )mir_realloc(nm, sizeof(TCHAR)*(len + 3));
+ memmove(nm + 1, nm, len*sizeof( TCHAR ));
+ *nm = '#';
+ }
+ }
+ else if ( !_stricmp(ValName, "SET DATA")) {
+ Data->UpdateDataTail->Item.Type = WID_SET;
+ wSetData(&Data->UpdateDataTail->Item.End, Value);
+ }
+ else if ( !_stricmp(ValName, "BREAK DATA")) {
+ Data->UpdateDataTail->Item.Type = WID_BREAK;
+ wSetData(&Data->UpdateDataTail->Item.Break, Value);
+ }
+ }
+ // recalculate memory used
+ Data->MemUsed += (strlen(Value) + 10);
+ wfree(&ValName);
+ }
+ // calcualate memory used for the ini and close the file
+ Data->MemUsed += sizeof(WIDATAITEMLIST)*Data->UpdateDataCount;
+ Data->Enabled = TRUE; // enable the service
+ fclose(pfile);
+ wfree(&Group);
+ }
+}
+
+//============ FREE WIDATA ITEM FROM MEMORY ============
+
+// free the WIDATA struct from memory
+// Data = the struct to be freed
+void FreeWIData(WIDATA *Data)
+{
+ WIDATAITEMLIST* WItem;
+ int i;
+
+ // free update items linked list first
+ WItem = Data->UpdateData;
+ while (WItem != NULL)
+ {
+ Data->UpdateData = WItem->Next;
+ FreeDataItem(&WItem->Item);
+ mir_free(WItem);
+ WItem = Data->UpdateData;
+ }
+
+ // free the strings in the rest of the struct
+ wfree(&Data->DisplayName);
+ wfree(&Data->InternalName);
+ wfree(&Data->Description);
+ wfree(&Data->Author);
+ wfree(&Data->Version);
+ wfree(&Data->DefaultURL);
+ wfree(&Data->DefaultMap);
+ wfree(&Data->UpdateURL);
+ wfree(&Data->UpdateURL2);
+ wfree(&Data->UpdateURL3);
+ wfree(&Data->UpdateURL4);
+ wfree(&Data->Cookie);
+ wfree(&Data->IDSearch.SearchURL);
+ wfree(&Data->IDSearch.NotFoundStr);
+ FreeDataItem(&Data->IDSearch.Name);
+ wfree(&Data->NameSearch.SearchURL);
+ wfree(&Data->NameSearch.NotFoundStr);
+ wfree(&Data->NameSearch.SingleStr);
+ wfree(&Data->NameSearch.Single.First);
+ FreeDataItem(&Data->NameSearch.Single.Name);
+ FreeDataItem(&Data->NameSearch.Single.ID);
+ wfree(&Data->NameSearch.Multiple.First);
+ FreeDataItem(&Data->NameSearch.Multiple.Name);
+ FreeDataItem(&Data->NameSearch.Multiple.ID);
+ wfree(&Data->ShortFileName);
+ wfree(&Data->FileName);
+ for (i=0; i<10; i++) DestroyCondList(&Data->CondList[i]);
+}
+
+//============ WEATHER INI SETUP DIALOG ============
+
+INT_PTR CALLBACK DlgProcSetup(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ // make the buttons flat
+ SendMessage(GetDlgItem(hwndDlg,IDC_STEP1), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_STEP2), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_STEP3), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hwndDlg,IDC_STEP4), BUTTONSETASFLATBTN, TRUE, 0);
+
+ // set icons
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIconEx("main", TRUE));
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconEx("main", FALSE));
+
+ WindowList_Add(hWindowList, hwndDlg, NULL);
+ ShowWindow(hwndDlg, SW_SHOW);
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDC_STEP1:
+ // update current data
+ CallService(MS_UTILS_OPENURL, opt.NewBrowserWin | OUF_TCHAR, (WPARAM)_T("http://miranda-ng.org/"));
+ break;
+
+ case IDC_STEP2:
+ {
+ TCHAR szPath[1024], *chop;
+ GetModuleFileName(GetModuleHandle(NULL), szPath, sizeof(szPath));
+ chop = _tcsrchr(szPath, '\\');
+ *chop = '\0';
+ _tcscat(szPath, _T("\\Plugins\\weather\\"));
+ _tmkdir(szPath);
+ ShellExecute((HWND)lParam, _T("open"), szPath, _T(""), _T(""), SW_SHOW);
+ break;
+ }
+
+ case IDC_STEP3:
+ if (LoadWIData(FALSE))
+ MessageBox(NULL,
+ TranslateT("All update data has been reloaded."),
+ TranslateT("Weather Protocol"), MB_OK|MB_ICONINFORMATION);
+ break;
+
+ case IDC_STEP4:
+ WeatherAdd(0, 0);
+
+ case IDCANCEL:
+ // close the info window
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ ReleaseIconEx((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0));
+ ReleaseIconEx((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, 0));
+ break;
+ }
+ return FALSE;
+}
+
diff --git a/plugins/Weather/src/weather_mwin.cpp b/plugins/Weather/src/weather_mwin.cpp
new file mode 100644
index 0000000000..8a7798b3b1
--- /dev/null
+++ b/plugins/Weather/src/weather_mwin.cpp
@@ -0,0 +1,420 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2006-2009 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2006 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "weather.h"
+#include "m_acc.h"
+
+#define MS_TOOLTIP_SHOWTIP "mToolTip/ShowTip"
+#define MS_TOOLTIP_HIDETIP "mToolTip/HideTip"
+
+typedef BOOL (WINAPI *ft_TrackMouseEvent) (LPTRACKMOUSEEVENT lpEventTrack);
+
+static ft_TrackMouseEvent f_TrackMouseEvent = NULL;
+static HANDLE hMwinWindowList;
+static HANDLE hFontHook;
+
+HANDLE hMwinMenu;
+
+typedef struct
+{
+ HANDLE hContact;
+ HWND hAvt;
+ BOOL haveAvatar;
+} MWinDataType;
+
+#define WM_REDRAWWIN (WM_USER + 17369)
+
+static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MWinDataType *data = (MWinDataType*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ switch(msg)
+ {
+ case WM_CREATE:
+ data = (MWinDataType*)mir_calloc(sizeof(MWinDataType));
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)data);
+
+ data->hContact = (HANDLE)((LPCREATESTRUCT)lParam)->lpCreateParams;
+ data->hAvt = CreateWindow(AVATAR_CONTROL_CLASS, TEXT(""), WS_CHILD,
+ 0, 0, opt.AvatarSize, opt.AvatarSize, hwnd, NULL, hInst, 0);
+ if (data->hAvt) SendMessage(data->hAvt, AVATAR_SETCONTACT, 0, (LPARAM)data->hContact);
+ break;
+
+ case WM_DESTROY:
+ mir_free(data);
+ break;
+
+ case WM_CONTEXTMENU:
+ {
+ POINT pt;
+
+ HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)data->hContact, 0);
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ if (f_TrackMouseEvent)
+ {
+ TRACKMOUSEEVENT tme = {0};
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.hwndTrack = hwnd;
+ tme.dwFlags = TME_QUERY;
+ f_TrackMouseEvent(&tme);
+
+ if (tme.dwFlags == 0)
+ {
+ tme.dwFlags = TME_HOVER | TME_LEAVE;
+ tme.hwndTrack = hwnd;
+ tme.dwHoverTime = CallService(MS_CLC_GETINFOTIPHOVERTIME, 0, 0);
+ f_TrackMouseEvent(&tme);
+ }
+ }
+ break;
+
+ case WM_MOUSEHOVER:
+ {
+ POINT pt;
+ CLCINFOTIP ti = {0};
+
+ GetCursorPos(&pt);
+ GetWindowRect(hwnd, &ti.rcItem);
+
+ ti.cbSize = sizeof(ti);
+ ti.hItem = data->hContact;
+ ti.ptCursor = pt;
+ ti.isTreeFocused = 1;
+ CallService(MS_TOOLTIP_SHOWTIP, 0, (LPARAM)&ti);
+ }
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ BriefInfo((WPARAM)data->hContact, 0);
+ break;
+
+ case WM_COMMAND: //Needed by the contact's context menu
+ if ( CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU), (LPARAM)data->hContact))
+ break;
+ return FALSE;
+
+ case WM_MEASUREITEM: //Needed by the contact's context menu
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+
+ case WM_DRAWITEM: //Needed by the contact's context menu
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == NM_AVATAR_CHANGED)
+ {
+ BOOL newava = CallService(MS_AV_GETAVATARBITMAP, (WPARAM)data->hContact, 0) != 0;
+ if (newava != data->haveAvatar)
+ {
+ LONG_PTR style = GetWindowLongPtr(data->hAvt, GWL_STYLE);
+ data->haveAvatar = newava;
+ SetWindowLongPtr(data->hAvt, GWL_STYLE, newava ? (style | WS_VISIBLE) : (style & ~WS_VISIBLE));
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+ }
+ }
+ break;
+
+ case WM_REDRAWWIN:
+ if (data->hAvt != NULL) MoveWindow(data->hAvt, 0, 0, opt.AvatarSize, opt.AvatarSize, TRUE);
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+ break;
+
+ case WM_PAINT:
+ {
+ RECT r, rc;
+
+ if (GetUpdateRect(hwnd, &r, FALSE))
+ {
+ DBVARIANT dbv = {0};
+ PAINTSTRUCT ps;
+ LOGFONT lfnt, lfnt1;
+ COLORREF fntc, fntc1;
+ COLORREF clr;
+ int picSize = opt.AvatarSize;
+ HICON hIcon = NULL;
+
+ if ( !data->haveAvatar)
+ {
+ int statusIcon = db_get_w(data->hContact, WEATHERPROTONAME, "Status", 0);
+
+ picSize = GetSystemMetrics(SM_CXICON);
+ hIcon = LoadSkinnedProtoIconBig(WEATHERPROTONAME, statusIcon);
+ if ((INT_PTR)hIcon == CALLSERVICE_NOTFOUND)
+ {
+ picSize = GetSystemMetrics(SM_CXSMICON);
+ hIcon = LoadSkinnedProtoIcon(WEATHERPROTONAME, statusIcon);
+ }
+ }
+
+ clr = db_get_dw(NULL, WEATHERPROTONAME, "ColorMwinFrame", GetSysColor(COLOR_3DFACE));
+
+ {
+ FontIDT fntid = {0};
+ _tcscpy(fntid.group, _T(WEATHERPROTONAME));
+ _tcscpy(fntid.name, LPGENT("Frame Font"));
+ fntc = CallService(MS_FONT_GETT, (WPARAM)&fntid, (LPARAM)&lfnt);
+
+ _tcscpy(fntid.name, LPGENT("Frame Title Font"));
+ fntc1 = CallService(MS_FONT_GETT, (WPARAM)&fntid, (LPARAM)&lfnt1);
+ }
+
+ DBGetContactSettingTString(data->hContact, WEATHERCONDITION, "WeatherInfo", &dbv);
+
+ GetClientRect(hwnd, &rc);
+
+ HDC hdc = BeginPaint(hwnd, &ps);
+
+ if ( ServiceExists(MS_SKIN_DRAWGLYPH)) {
+ SKINDRAWREQUEST rq;
+ memset(&rq, 0, sizeof(rq));
+ rq.hDC = hdc;
+ rq.rcDestRect = rc;
+ rq.rcClipRect = rc;
+
+ strcpy(rq.szObjectID, "Main,ID=WeatherFrame");
+ CallService(MS_SKIN_DRAWGLYPH, (WPARAM)&rq, 0);
+ }
+
+ if (clr != 0xFFFFFFFF) {
+ HBRUSH hBkgBrush = CreateSolidBrush(clr);
+ FillRect(hdc, &rc, hBkgBrush);
+ DeleteObject(hBkgBrush);
+ }
+
+ if ( !data->haveAvatar)
+ DrawIconEx(hdc, 1, 1, hIcon, 0, 0, 0, NULL, DI_NORMAL);
+
+ SetBkMode(hdc, TRANSPARENT);
+
+ HFONT hfnt = CreateFontIndirect(&lfnt1);
+ HFONT hfntold = ( HFONT )SelectObject(hdc, hfnt);
+ SIZE fontSize;
+
+ TCHAR *nick = ( TCHAR* )CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)data->hContact, GCDNF_TCHAR);
+
+ GetTextExtentPoint32(hdc, _T("|"), 1, &fontSize);
+
+ rc.top += 1;
+ rc.left += picSize + fontSize.cx;
+
+ SetTextColor(hdc, fntc1);
+ DrawText(hdc, nick, -1, &rc, DT_LEFT | DT_EXPANDTABS);
+
+ rc.top += fontSize.cy;
+
+ SelectObject(hdc, hfntold);
+ DeleteObject(hfnt);
+
+ if (dbv.pszVal)
+ {
+ HFONT hfnt = CreateFontIndirect(&lfnt);
+ HFONT hfntold = ( HFONT )SelectObject(hdc, hfnt);
+
+ SetTextColor(hdc, fntc);
+ DrawText(hdc, dbv.ptszVal, -1, &rc, DT_LEFT | DT_EXPANDTABS);
+
+ SelectObject(hdc, hfntold);
+ DeleteObject(hfnt);
+ }
+ EndPaint(hwnd, &ps);
+ Skin_ReleaseIcon(hIcon);
+ db_free(&dbv);
+ }
+ break;
+ }
+
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return(TRUE);
+}
+
+static void addWindow(HANDLE hContact)
+{
+ DBVARIANT dbv;
+ DBGetContactSettingTString(hContact, WEATHERPROTONAME, "Nick", &dbv);
+
+ TCHAR winname[512];
+ mir_sntprintf(winname, SIZEOF(winname), _T("Weather: %s"), dbv.ptszVal);
+ db_free(&dbv);
+
+ HWND hWnd = CreateWindow( _T("WeatherFrame"), _T(""), WS_CHILD | WS_VISIBLE,
+ 0, 0, 10, 10, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL, hInst, hContact);
+ WindowList_Add(hMwinWindowList, hWnd, hContact);
+
+ CLISTFrame Frame = {0};
+ Frame.tname = winname;
+ Frame.hIcon = LoadIconEx("main",FALSE);
+ Frame.cbSize = sizeof(Frame);
+ Frame.hWnd = hWnd;
+ Frame.align = alBottom;
+ Frame.Flags = F_VISIBLE|F_NOBORDER|F_TCHAR;
+ Frame.height = 32;
+ DWORD frameID = CallService(MS_CLIST_FRAMES_ADDFRAME, (WPARAM)&Frame, 0);
+
+ db_set_dw(hContact, WEATHERPROTONAME, "mwin", frameID);
+ db_set_b(hContact, "CList", "Hidden", TRUE);
+}
+
+void removeWindow(HANDLE hContact)
+{
+ DWORD frameId = db_get_dw(hContact, WEATHERPROTONAME, "mwin", 0);
+
+ WindowList_Remove(hMwinWindowList, WindowList_Find(hMwinWindowList, hContact));
+ CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0);
+
+ db_set_dw(hContact, WEATHERPROTONAME, "mwin", 0);
+ db_unset(hContact, "CList", "Hidden");
+}
+
+void UpdateMwinData(HANDLE hContact)
+{
+ HWND hwnd = WindowList_Find(hMwinWindowList, hContact);
+ if (hwnd != NULL)
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+}
+
+
+INT_PTR Mwin_MenuClicked(WPARAM wParam,LPARAM lParam)
+{
+ BOOL addwnd = WindowList_Find(hMwinWindowList, (HANDLE)wParam) == NULL;
+ if (addwnd)
+ addWindow((HANDLE)wParam);
+ else
+ removeWindow((HANDLE)wParam);
+ return 0;
+}
+
+
+int BuildContactMenu(WPARAM wparam,LPARAM lparam)
+{
+ CLISTMENUITEM mi = {0};
+
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS |
+ (db_get_dw((HANDLE)wparam, WEATHERPROTONAME, "mwin", 0) ? CMIF_CHECKED : 0);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMwinMenu, (LPARAM)&mi);
+ return 0;
+}
+
+
+int RedrawFrame(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_Broadcast(hMwinWindowList, WM_REDRAWWIN, 0, 0);
+ return 0;
+}
+
+
+void InitMwin(void)
+{
+ HMODULE hUser = GetModuleHandle(_T("user32.dll"));
+
+ if ( !ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) return;
+
+ f_TrackMouseEvent = (ft_TrackMouseEvent)GetProcAddress(hUser, "TrackMouseEvent");
+
+
+ hMwinWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+
+ {
+ WNDCLASS wndclass;
+ wndclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = wndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = hInst;
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wndclass.hbrBackground = 0; //(HBRUSH)(COLOR_3DFACE+1);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = _T("WeatherFrame");
+ RegisterClass(&wndclass);
+ }
+
+ {
+ ColourIDT colourid = {0};
+ colourid.cbSize = sizeof(ColourIDT);
+ strcpy(colourid.dbSettingsGroup, WEATHERPROTONAME);
+ strcpy(colourid.setting, "ColorMwinFrame");
+ _tcscpy(colourid.name, LPGENT("Frame Background"));
+ _tcscpy(colourid.group, _T(WEATHERPROTONAME));
+ colourid.defcolour = GetSysColor(COLOR_3DFACE);
+ ColourRegisterT(&colourid);
+
+ FontIDT fontid = {0};
+ fontid.cbSize = sizeof(FontIDT);
+ fontid.flags = FIDF_ALLOWREREGISTER | FIDF_DEFAULTVALID;
+ strcpy(fontid.dbSettingsGroup, WEATHERPROTONAME);
+ _tcscpy(fontid.group, _T(WEATHERPROTONAME));
+ _tcscpy(fontid.name, LPGENT("Frame Font"));
+ strcpy(fontid.prefix, "fnt0");
+
+ HDC hdc = GetDC(NULL);
+ fontid.deffontsettings.size = -13;
+ ReleaseDC(0, hdc);
+
+ fontid.deffontsettings.charset = DEFAULT_CHARSET;
+ _tcscpy(fontid.deffontsettings.szFace, _T("Verdana"));
+ _tcscpy(fontid.backgroundGroup, _T(WEATHERPROTONAME));
+ _tcscpy(fontid.backgroundName, LPGENT("Frame Background"));
+ FontRegisterT(&fontid);
+
+ fontid.deffontsettings.style = DBFONTF_BOLD;
+ _tcscpy(fontid.name, LPGENT("Frame Title Font"));
+ strcpy(fontid.prefix, "fnt1");
+ FontRegisterT(&fontid);
+ }
+
+ HANDLE hContact = db_find_first();
+ while(hContact)
+ {
+ // see if the contact is a weather contact
+ if (IsMyContact(hContact))
+ {
+ if (db_get_dw(hContact, WEATHERPROTONAME, "mwin", 0))
+ addWindow(hContact);
+ }
+ hContact = db_find_next(hContact);
+ }
+ hFontHook = HookEvent(ME_FONT_RELOAD, RedrawFrame);
+}
+
+void DestroyMwin(void)
+{
+ HANDLE hContact = db_find_first();
+ while(hContact)
+ {
+ // see if the contact is a weather contact
+ if (IsMyContact(hContact))
+ {
+ DWORD frameId = db_get_dw(hContact, WEATHERPROTONAME, "mwin", 0);
+ if (frameId)
+ CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0);
+ }
+ hContact = db_find_next(hContact);
+ }
+ UnregisterClass( _T("WeatherFrame"), hInst);
+ UnhookEvent(hFontHook);
+}
diff --git a/plugins/Weather/src/weather_opt.cpp b/plugins/Weather/src/weather_opt.cpp
new file mode 100644
index 0000000000..f242adb0f1
--- /dev/null
+++ b/plugins/Weather/src/weather_opt.cpp
@@ -0,0 +1,642 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contain the source related to weather option pages. It also
+contain code for saving/loading options from the database.
+*/
+
+#include "weather.h"
+
+static BOOL opt_startup;
+int RedrawFrame(WPARAM wParam, LPARAM lParam);
+
+//============ LOADING AND SAVING OPTIONS ===========
+
+// set a string to default
+// in = string to determine which field to set default "CBNEHXPp"
+void SetTextDefault(const char* in)
+{
+ TCHAR str[MAX_TEXT_SIZE];
+
+ if (strchr(in, 'C') != NULL)
+ {
+ _tcscpy(str, C_DEFAULT);
+ wSetData(&opt.cText, str);
+ }
+ if (strchr(in, 'b') != NULL)
+ {
+ _tcscpy(str, b_DEFAULT);
+ wSetData(&opt.bTitle, str);
+ }
+ if (strchr(in, 'B') != NULL)
+ {
+ _tcscpy(str, B_DEFAULT);
+ wSetData(&opt.bText, str);
+ }
+ if (strchr(in, 'N') != NULL)
+ {
+ _tcscpy(str, N_DEFAULT);
+ wSetData(&opt.nText, str);
+ }
+ if (strchr(in, 'E') != NULL)
+ {
+ _tcscpy(str, E_DEFAULT);
+ wSetData(&opt.eText, str);
+ }
+ if (strchr(in, 'H') != NULL)
+ {
+ _tcscpy(str, H_DEFAULT);
+ wSetData(&opt.hText, str);
+ }
+ if (strchr(in, 'X') != NULL)
+ {
+ _tcscpy(str, X_DEFAULT);
+ wSetData(&opt.xText, str);
+ }
+ if (strchr(in, 'P') != NULL)
+ {
+ _tcscpy(str, P_DEFAULT);
+ wSetData(&opt.pTitle, str);
+ }
+ if (strchr(in, 'p') != NULL)
+ {
+ _tcscpy(str, p_DEFAULT);
+ wSetData(&opt.pText, str);
+ }
+ if (strchr(in, 'S') != NULL)
+ {
+ _tcscpy(str, s_DEFAULT);
+ wSetData(&opt.sText, str);
+ }
+}
+
+void DestroyOptions(void)
+{
+ wfree(&opt.cText);
+ wfree(&opt.bTitle);
+ wfree(&opt.bText);
+ wfree(&opt.nText);
+ wfree(&opt.eText);
+ wfree(&opt.hText);
+ wfree(&opt.xText);
+ wfree(&opt.pTitle);
+ wfree(&opt.pText);
+ wfree(&opt.sText);
+}
+
+// load options from database + set default if the setting does not exist
+void LoadOptions(void)
+{
+ DBVARIANT dbv;
+ ZeroMemory(&opt, sizeof(opt));
+
+ // main options
+ opt.StartupUpdate = db_get_b(NULL, WEATHERPROTONAME, "StartupUpdate",TRUE);
+ opt.AutoUpdate = db_get_b(NULL, WEATHERPROTONAME, "AutoUpdate",TRUE);
+ opt.UpdateTime = db_get_w(NULL, WEATHERPROTONAME, "UpdateTime",30);
+ opt.NewBrowserWin = db_get_b(NULL, WEATHERPROTONAME, "NewWindow",TRUE);
+ opt.NoProtoCondition = db_get_b(NULL, WEATHERPROTONAME, "NoStatus",0);
+ opt.UpdateOnlyConditionChanged = db_get_b(NULL, WEATHERPROTONAME, "CondChangeAsUpdate",TRUE);
+ opt.RemoveOldData = db_get_b(NULL, WEATHERPROTONAME, "RemoveOld",FALSE);
+ opt.MakeItalic = db_get_b(NULL, WEATHERPROTONAME, "MakeItalic",TRUE);
+ opt.AvatarSize = db_get_b(NULL, WEATHERPROTONAME, "AvatarSize", 128);
+ // units
+ opt.tUnit = db_get_w(NULL, WEATHERPROTONAME, "tUnit", 1);
+ opt.wUnit = db_get_w(NULL, WEATHERPROTONAME, "wUnit", 2);
+ opt.vUnit = db_get_w(NULL, WEATHERPROTONAME, "vUnit", 1);
+ opt.pUnit = db_get_w(NULL, WEATHERPROTONAME, "pUnit", 4);
+ opt.dUnit = db_get_w(NULL, WEATHERPROTONAME, "dUnit", 1);
+ opt.eUnit = db_get_w(NULL, WEATHERPROTONAME, "eUnit", 2);
+ if (DBGetContactSettingTString(NULL, WEATHERPROTONAME, "DegreeSign",&dbv))
+ _tcscpy(opt.DegreeSign, _T(""));
+ else {
+ _tcscpy(opt.DegreeSign, dbv.ptszVal);
+ db_free(&dbv);
+ }
+ opt.DoNotAppendUnit = db_get_b(NULL, WEATHERPROTONAME, "DoNotAppendUnit", 0);
+ opt.NoFrac = db_get_b(NULL, WEATHERPROTONAME, "NoFractions", 0);
+ // texts
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "DisplayText",&dbv)) {
+ wSetData(&opt.cText, TranslateTS(dbv.ptszVal));
+ db_free(&dbv);
+ }
+ else SetTextDefault("C");
+
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "BriefTextTitle",&dbv)) {
+ wSetData(&opt.bTitle, TranslateTS(dbv.ptszVal));
+ db_free(&dbv);
+ }
+ else SetTextDefault("b");
+
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "BriefText",&dbv)) {
+ wSetData(&opt.bText, TranslateTS(dbv.ptszVal));
+ db_free(&dbv);
+ }
+ else SetTextDefault("B");
+
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "NoteText",&dbv)) {
+ wSetData(&opt.nText, TranslateTS(dbv.ptszVal));
+ db_free(&dbv);
+ }
+ else SetTextDefault("N");
+
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "ExtText",&dbv)) {
+ wSetData(&opt.eText, TranslateTS(dbv.ptszVal));
+ db_free(&dbv);
+ }
+ else SetTextDefault("E");
+
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "HistoryText",&dbv)) {
+ wSetData(&opt.hText, TranslateTS(dbv.ptszVal));
+ db_free(&dbv);
+ }
+ else SetTextDefault("H");
+
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "ExtraText",&dbv)) {
+ wSetData(&opt.xText, TranslateTS(dbv.ptszVal));
+ db_free(&dbv);
+ }
+ else SetTextDefault("X");
+
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "StatusText",&dbv)) {
+ wSetData(&opt.sText, TranslateTS(dbv.ptszVal));
+ db_free(&dbv);
+ }
+ else SetTextDefault("S");
+
+ // advanced
+ opt.DisCondIcon = db_get_b(NULL, WEATHERPROTONAME, "DisableConditionIcon",FALSE);
+ // popup options
+ opt.UsePopup = db_get_b(NULL, WEATHERPROTONAME, "UsePopUp",TRUE);
+ opt.UpdatePopup = db_get_b(NULL, WEATHERPROTONAME, "UpdatePopup",TRUE);
+ opt.AlertPopup = db_get_b(NULL, WEATHERPROTONAME, "AlertPopup",TRUE);
+ opt.PopupOnChange = db_get_b(NULL, WEATHERPROTONAME, "PopUpOnChange",TRUE);
+ opt.ShowWarnings = db_get_b(NULL, WEATHERPROTONAME, "ShowWarnings",TRUE);
+ // popup colors
+ opt.BGColour = db_get_dw(NULL, WEATHERPROTONAME, "BackgroundColour",GetSysColor(COLOR_BTNFACE));
+ opt.TextColour = db_get_dw(NULL, WEATHERPROTONAME, "TextColour",GetSysColor(COLOR_WINDOWTEXT));
+ opt.UseWinColors = (BOOL)db_get_b(NULL, WEATHERPROTONAME, "UseWinColors", FALSE);
+ // popup actions
+ opt.LeftClickAction = db_get_dw(NULL, WEATHERPROTONAME, "LeftClickAction",IDM_M2);
+ opt.RightClickAction = db_get_dw(NULL, WEATHERPROTONAME, "RightClickAction",IDM_M1);
+ // popup delay
+ opt.pDelay = db_get_dw(NULL, WEATHERPROTONAME, "PopupDelay",0);
+ // popup texts
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "PopupTitle",&dbv)) {
+ wSetData(&opt.pTitle, dbv.ptszVal);
+ db_free(&dbv);
+ }
+ else SetTextDefault("P");
+
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "PopupText",&dbv)) {
+ wSetData(&opt.pText, dbv.ptszVal);
+ db_free(&dbv);
+ }
+ else SetTextDefault("p");
+
+ // misc
+ if ( !DBGetContactSettingTString(NULL, WEATHERPROTONAME, "Default",&dbv)) {
+ _tcscpy(opt.Default, dbv.ptszVal);
+ db_free(&dbv);
+ }
+ else opt.Default[0] = 0;
+}
+
+// save the options to database
+void SaveOptions(void)
+{
+ // main options
+ db_set_b(NULL, WEATHERPROTONAME, "StartupUpdate", (BYTE)opt.StartupUpdate);
+ db_set_b(NULL, WEATHERPROTONAME, "AutoUpdate", (BYTE)opt.AutoUpdate);
+ db_set_w(NULL, WEATHERPROTONAME, "UpdateTime", opt.UpdateTime);
+ db_set_b(NULL, WEATHERPROTONAME, "NewWindow", (BYTE)opt.NewBrowserWin);
+ db_set_b(NULL, WEATHERPROTONAME, "NoStatus", (BYTE)opt.NoProtoCondition);
+ db_set_b(NULL, WEATHERPROTONAME, "CondChangeAsUpdate", (BYTE)opt.UpdateOnlyConditionChanged);
+ db_set_b(NULL, WEATHERPROTONAME, "RemoveOld", (BYTE)opt.RemoveOldData);
+ db_set_b(NULL, WEATHERPROTONAME, "MakeItalic", (BYTE)opt.MakeItalic);
+ db_set_b(NULL, WEATHERPROTONAME, "AvatarSize", (BYTE)opt.AvatarSize);
+ // units
+ db_set_w(NULL, WEATHERPROTONAME, "tUnit", opt.tUnit);
+ db_set_w(NULL, WEATHERPROTONAME, "wUnit", opt.wUnit);
+ db_set_w(NULL, WEATHERPROTONAME, "vUnit", opt.vUnit);
+ db_set_w(NULL, WEATHERPROTONAME, "pUnit", opt.pUnit);
+ db_set_w(NULL, WEATHERPROTONAME, "dUnit", opt.dUnit);
+ db_set_w(NULL, WEATHERPROTONAME, "eUnit", opt.eUnit);
+ db_set_ts(NULL, WEATHERPROTONAME, "DegreeSign", opt.DegreeSign);
+ db_set_b(NULL, WEATHERPROTONAME, "DoNotAppendUnit", (BYTE)opt.DoNotAppendUnit);
+ db_set_b(NULL, WEATHERPROTONAME, "NoFractions", (BYTE)opt.NoFrac);
+ // texts
+ db_set_ts(NULL, WEATHERPROTONAME, "DisplayText", opt.cText);
+ db_set_ts(NULL, WEATHERPROTONAME, "BriefTextTitle", opt.bTitle);
+ db_set_ts(NULL, WEATHERPROTONAME, "BriefText", opt.bText);
+ db_set_ts(NULL, WEATHERPROTONAME, "NoteText", opt.nText);
+ db_set_ts(NULL, WEATHERPROTONAME, "ExtText", opt.eText);
+ db_set_ts(NULL, WEATHERPROTONAME, "HistoryText", opt.hText);
+ db_set_ts(NULL, WEATHERPROTONAME, "ExtraText", opt.xText);
+ db_set_ts(NULL, WEATHERPROTONAME, "StatusText", opt.sText);
+ // advanced
+ db_set_b(NULL, WEATHERPROTONAME, "DisableConditionIcon", (BYTE)opt.DisCondIcon);
+ // popup options
+ db_set_b(NULL, WEATHERPROTONAME, "UsePopUp", (BYTE)opt.UsePopup);
+ db_set_b(NULL, WEATHERPROTONAME, "UpdatePopup", (BYTE)opt.UpdatePopup);
+ db_set_b(NULL, WEATHERPROTONAME, "AlertPopup", (BYTE)opt.AlertPopup);
+ db_set_b(NULL, WEATHERPROTONAME, "PopUpOnChange", (BYTE)opt.PopupOnChange);
+ db_set_b(NULL, WEATHERPROTONAME, "ShowWarnings", (BYTE)opt.ShowWarnings);
+ // popup colors
+ db_set_dw(NULL, WEATHERPROTONAME, "BackgroundColour", opt.BGColour);
+ db_set_dw(NULL, WEATHERPROTONAME, "TextColour", opt.TextColour);
+ db_set_b(NULL, WEATHERPROTONAME, "UseWinColors", (BYTE)opt.UseWinColors);
+ // popup actions
+ db_set_dw(NULL, WEATHERPROTONAME, "LeftClickAction", opt.LeftClickAction);
+ db_set_dw(NULL, WEATHERPROTONAME, "RightClickAction", opt.RightClickAction);
+ // popup delay
+ db_set_dw(NULL, WEATHERPROTONAME, "PopupDelay", opt.pDelay);
+ // popup texts
+ db_set_ts(NULL, WEATHERPROTONAME, "PopupTitle", opt.pTitle);
+ db_set_ts(NULL, WEATHERPROTONAME, "PopupText", opt.pText);
+ // misc stuff
+ db_set_ts(NULL, WEATHERPROTONAME, "Default", opt.Default);
+}
+
+//============ OPTION INITIALIZATION ============
+
+// register the weather option pages
+int OptInit(WPARAM wParam,LPARAM lParam) {
+ OPTIONSDIALOGPAGE odp = {0};
+
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hInst;
+
+ // plugin options
+ odp.position = 95600;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
+ odp.pfnDlgProc = OptionsProc;
+ odp.ptszGroup = LPGENT("Network");
+ odp.ptszTitle = _T(WEATHERPROTOTEXT);
+ odp.ptszTab = LPGENT("General");
+ odp.flags = ODPF_BOLDGROUPS|ODPF_TCHAR;
+ Options_AddPage(wParam, &odp);
+
+ // text options
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_TEXTOPT);
+ odp.pfnDlgProc = DlgProcText;
+ odp.ptszTab = LPGENT("Display");
+ Options_AddPage(wParam, &odp);
+
+ // if popup service exists, load the weather popup options
+ if (( ServiceExists(MS_POPUP_ADDPOPUPT))) {
+ odp.position = 100000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUP);
+ odp.ptszGroup = LPGENT("PopUps");
+ odp.groupPosition = 910000000;
+ odp.ptszTab = NULL;
+ odp.pfnDlgProc = DlgPopUpOpts;
+ Options_AddPage(wParam, &odp);
+ }
+
+ return 0;
+}
+
+//============ MAIN OPTIONS ============
+
+// weather options
+INT_PTR CALLBACK OptionsProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ TCHAR str[512];
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ opt_startup = TRUE;
+ TranslateDialogDefault(hdlg);
+ // load settings
+ _ltot(opt.UpdateTime, str, 10);
+ SetDlgItemText(hdlg, IDC_UPDATETIME, str);
+ SetDlgItemText(hdlg, IDC_DEGREE, opt.DegreeSign);
+
+ SendDlgItemMessage(hdlg, IDC_AVATARSPIN, UDM_SETRANGE32, 0, 999);
+ SendDlgItemMessage(hdlg, IDC_AVATARSPIN, UDM_SETPOS, 0, opt.AvatarSize);
+ SendDlgItemMessage(hdlg, IDC_AVATARSIZE, EM_LIMITTEXT, 3, 0);
+
+ CheckDlgButton(hdlg, IDC_STARTUPUPD, opt.StartupUpdate);
+ CheckDlgButton(hdlg, IDC_UPDATE, opt.AutoUpdate);
+ CheckDlgButton(hdlg, IDC_PROTOCOND, !opt.NoProtoCondition);
+ CheckDlgButton(hdlg, IDC_UPDCONDCHG, opt.UpdateOnlyConditionChanged);
+ CheckDlgButton(hdlg, IDC_NEWWIN, opt.NewBrowserWin);
+ CheckDlgButton(hdlg, IDC_REMOVEOLD, opt.RemoveOldData);
+ CheckDlgButton(hdlg, IDC_MAKEI, opt.MakeItalic);
+ CheckDlgButton(hdlg, IDC_DISCONDICON, opt.DisCondIcon);
+ CheckDlgButton(hdlg, IDC_DONOTAPPUNITS, opt.DoNotAppendUnit);
+ CheckDlgButton(hdlg, IDC_NOFRAC, opt.NoFrac);
+
+ // load units
+ switch (opt.tUnit) { // temperature
+ case 1: CheckRadioButton(hdlg, IDC_T1, IDC_T2, IDC_T1); break;
+ case 2: CheckRadioButton(hdlg, IDC_T1, IDC_T2, IDC_T2); break;
+ }
+ switch (opt.wUnit) { // wind
+ case 1: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W1); break;
+ case 2: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W2); break;
+ case 3: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W3); break;
+ case 4: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W4); break;
+ }
+ switch (opt.vUnit) { // visibility
+ case 1: CheckRadioButton(hdlg, IDC_V1, IDC_V2, IDC_V1); break;
+ case 2: CheckRadioButton(hdlg, IDC_V1, IDC_V2, IDC_V2); break;
+ }
+ switch (opt.pUnit) { // pressure
+ case 1: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P1); break;
+ case 2: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P2); break;
+ case 3: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P3); break;
+ case 4: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P4); break;
+ }
+ switch (opt.dUnit) { // pressure
+ case 1: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D1); break;
+ case 2: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D2); break;
+ case 3: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D3); break;
+ }
+
+ switch (opt.eUnit) { // elev
+ case 1: CheckRadioButton(hdlg, IDC_E1, IDC_E2, IDC_E1); break;
+ case 2: CheckRadioButton(hdlg, IDC_E1, IDC_E2, IDC_E2); break;
+ }
+
+ opt_startup = FALSE;
+ return 0;
+
+ case WM_COMMAND:
+ if (HIWORD(wparam)==BN_CLICKED && GetFocus()==(HWND)lparam)
+ if ( !opt_startup) SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
+ if ( !((LOWORD(wparam) == IDC_UPDATE || LOWORD(wparam) == IDC_DEGREE) &&
+ (HIWORD(wparam) != EN_CHANGE || (HWND)lparam != GetFocus())))
+ if ( !opt_startup) SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
+ return 0;
+
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lparam)->code) {
+ case PSN_APPLY:
+ // change the status for weather protocol
+ if (IsDlgButtonChecked(hdlg, IDC_PROTOCOND) && opt.DefStn != NULL) {
+ old_status = status;
+ status = db_get_w(opt.DefStn, WEATHERPROTONAME, "StatusIcon", NOSTATUSDATA);
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status);
+ }
+
+ // get update time and remove the old timer
+ GetDlgItemText(hdlg, IDC_UPDATETIME, str, sizeof(str));
+ opt.UpdateTime = (WORD)_ttoi(str);
+ if (opt.UpdateTime < 1) opt.UpdateTime = 1;
+ KillTimer(NULL, timerId);
+ timerId = SetTimer(NULL, 0, opt.UpdateTime*60000, (TIMERPROC)timerProc);
+
+ // other general options
+ GetDlgItemText(hdlg, IDC_DEGREE, opt.DegreeSign, sizeof(opt.DegreeSign));
+ opt.StartupUpdate = IsDlgButtonChecked(hdlg, IDC_STARTUPUPD);
+ opt.AutoUpdate = IsDlgButtonChecked(hdlg, IDC_UPDATE);
+ opt.NewBrowserWin = IsDlgButtonChecked(hdlg, IDC_NEWWIN);
+ opt.NoProtoCondition = !IsDlgButtonChecked(hdlg, IDC_PROTOCOND);
+ opt.DisCondIcon = IsDlgButtonChecked(hdlg, IDC_DISCONDICON);
+ opt.UpdateOnlyConditionChanged = (BYTE)IsDlgButtonChecked(hdlg, IDC_UPDCONDCHG);
+ opt.RemoveOldData = IsDlgButtonChecked(hdlg, IDC_REMOVEOLD);
+ opt.MakeItalic = IsDlgButtonChecked(hdlg, IDC_MAKEI);
+ opt.AvatarSize = GetDlgItemInt(hdlg, IDC_AVATARSIZE, NULL, FALSE);;
+ opt.DoNotAppendUnit = IsDlgButtonChecked(hdlg, IDC_DONOTAPPUNITS);
+ opt.NoFrac = IsDlgButtonChecked(hdlg, IDC_NOFRAC);
+ UpdateMenu(opt.AutoUpdate);
+
+ // save the units
+ if (IsDlgButtonChecked(hdlg, IDC_T1)) opt.tUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_T2)) opt.tUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_W1)) opt.wUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_W2)) opt.wUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_W3)) opt.wUnit = 3;
+ if (IsDlgButtonChecked(hdlg, IDC_W4)) opt.wUnit = 4;
+ if (IsDlgButtonChecked(hdlg, IDC_V1)) opt.vUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_V2)) opt.vUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_P1)) opt.pUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_P2)) opt.pUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_P3)) opt.pUnit = 3;
+ if (IsDlgButtonChecked(hdlg, IDC_P4)) opt.pUnit = 4;
+ if (IsDlgButtonChecked(hdlg, IDC_D1)) opt.dUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_D2)) opt.dUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_D3)) opt.dUnit = 3;
+ if (IsDlgButtonChecked(hdlg, IDC_E1)) opt.eUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_E2)) opt.eUnit = 2;
+
+ // save the new weather options
+ SaveOptions();
+
+ RedrawFrame(0, 0);
+
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+//============ TEXT OPTION DIALOG ============
+
+void LoadTextSettings(HWND hdlg)
+{
+ // load text option settings from memory
+ SetDlgItemText(hdlg, IDC_CTEXT, opt.cText);
+ SetDlgItemText(hdlg, IDC_BTITLE, opt.bTitle);
+ SetDlgItemText(hdlg, IDC_BTEXT, opt.bText);
+ SetDlgItemText(hdlg, IDC_ETEXT, opt.eText);
+ SetDlgItemText(hdlg, IDC_NTEXT, opt.nText);
+ SetDlgItemText(hdlg, IDC_HTEXT, opt.hText);
+ SetDlgItemText(hdlg, IDC_XTEXT, opt.xText);
+ SetDlgItemText(hdlg, IDC_BTITLE2, opt.sText);
+}
+
+// free the display text settings from memory
+void FreeTextVar(void)
+{
+ wfree(&opt.cText);
+ wfree(&opt.bText);
+ wfree(&opt.bTitle);
+ wfree(&opt.eText);
+ wfree(&opt.nText);
+ wfree(&opt.hText);
+ wfree(&opt.xText);
+ wfree(&opt.sText);
+}
+
+// text option dialog
+
+static const char *varname[8] = {"C", "b", "B", "N", "X", "E", "H", "S"};
+static const int cname[8] = {IDC_CTEXT, IDC_BTITLE, IDC_BTEXT, IDC_NTEXT, IDC_XTEXT, IDC_ETEXT, IDC_HTEXT, IDC_BTITLE2 };
+static TCHAR* const *var[8] = {&opt.cText, &opt.bTitle, &opt.bText, &opt.nText, &opt.xText, &opt.eText, &opt.hText, &opt.sText };
+
+INT_PTR CALLBACK DlgProcText(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ RECT rc, pos;
+ HWND button;
+ HMENU hMenu, hMenu1;
+ TCHAR str[4096];
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ opt_startup = TRUE;
+ // set windows position, make it top-most
+ GetWindowRect(hdlg, &rc);
+ SetWindowPos(hdlg, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
+ TranslateDialogDefault(hdlg);
+ // generate the display text for variable list
+ _tcscpy(str, TranslateT("%c\tcurrent condition\n%d\tcurrent date\n%e\tdewpoint\n%f\tfeel-like temp\n%h\ttoday's high\n%i\twind direction\n%l\ttoday's low\n%m\thumidity\n%n\tstation name\n%p\tpressure\n%r\tsunrise time\n%s\tstation ID\n%t\ttemperature\n%u\tupdate time\n%v\tvisibility\n%w\twind speed\n%y\tsun set"));
+ SetDlgItemText(hdlg, IDC_VARLIST, str);
+
+ // make the more variable and other buttons flat
+ SendMessage(GetDlgItem(hdlg,IDC_MORE), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_TM1), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_TM2), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_TM3), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_TM4), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_TM5), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_TM6), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_TM7), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_TM8), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_RESET), BUTTONSETASFLATBTN, TRUE, 0);
+ // load the settings
+ LoadTextSettings(hdlg);
+ opt_startup = FALSE;
+ return TRUE;
+
+ case WM_COMMAND:
+ if (opt_startup) return TRUE;
+ switch(LOWORD(wParam)) {
+ case IDC_CTEXT:
+ case IDC_BTITLE:
+ case IDC_BTEXT:
+ case IDC_NTEXT:
+ case IDC_XTEXT:
+ case IDC_ETEXT:
+ case IDC_HTEXT:
+ case IDC_BTITLE2:
+ if (HIWORD(wParam) == EN_CHANGE)
+ SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
+ break;
+
+ case IDC_MORE:
+ // display custom variables list
+ MoreVarList();
+ break;
+
+ case IDC_TM1:
+ case IDC_TM2:
+ case IDC_TM3:
+ case IDC_TM4:
+ case IDC_TM5:
+ case IDC_TM6:
+ case IDC_TM7:
+ case IDC_TM8:
+ {
+ WEATHERINFO winfo;
+
+ // display the menu
+ button = GetDlgItem(hdlg, LOWORD(wParam));
+ GetWindowRect(button, &pos);
+ hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_TMMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ TranslateMenu(hMenu1);
+ switch(TrackPopupMenu(hMenu1, TPM_LEFTBUTTON|TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, NULL)) {
+ case ID_MPREVIEW:
+ // show the preview in a message box, using the weather data from the default station
+ winfo = LoadWeatherInfo(opt.DefStn);
+ GetDisplay(&winfo, *var[LOWORD(wParam)-IDC_TM1], str);
+ MessageBox(NULL, str, TranslateT("Weather Protocol Text Preview"), MB_OK|MB_TOPMOST);
+ break;
+
+ case ID_MRESET:
+ {
+ unsigned varo = LOWORD(wParam) - IDC_TM1;
+ // remove the old setting from db and free memory
+ TCHAR* vartmp = *var[varo];
+ wfree(&vartmp);
+ SetTextDefault(varname[varo]);
+ SetDlgItemText(hdlg, cname[varo], *var[varo]);
+ }
+ break;
+ }
+ DestroyMenu(hMenu);
+ break;
+ }
+
+ case IDC_RESET:
+ // left click action selection menu
+ button = GetDlgItem(hdlg, IDC_RESET);
+ GetWindowRect(button, &pos);
+ hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_TMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ TranslateMenu(hMenu1);
+ switch(TrackPopupMenu(hMenu1, TPM_LEFTBUTTON|TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, NULL))
+ {
+ case ID_T1:
+ // reset to the strings in memory, discard all changes
+ LoadTextSettings(hdlg);
+ break;
+
+ case ID_T2:
+ // reset to the default setting
+ FreeTextVar();
+ SetTextDefault("CbBENHX");
+ LoadTextSettings(hdlg);
+ break;
+ }
+ DestroyMenu(hMenu);
+ break;
+ }
+ return TRUE;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ // save the option
+ TCHAR textstr[MAX_TEXT_SIZE];
+ // free memory for old settings
+ FreeTextVar();
+ // save new settings to memory
+ GetDlgItemText(hdlg, IDC_CTEXT, textstr, MAX_TEXT_SIZE);
+ wSetData(&opt.cText, textstr);
+ GetDlgItemText(hdlg, IDC_BTEXT, textstr, MAX_TEXT_SIZE);
+ wSetData(&opt.bText, textstr);
+ GetDlgItemText(hdlg, IDC_BTITLE, textstr, MAX_TEXT_SIZE);
+ wSetData(&opt.bTitle, textstr);
+ GetDlgItemText(hdlg, IDC_ETEXT, textstr, MAX_TEXT_SIZE);
+ wSetData(&opt.eText, textstr);
+ GetDlgItemText(hdlg, IDC_NTEXT, textstr, MAX_TEXT_SIZE);
+ wSetData(&opt.nText, textstr);
+ GetDlgItemText(hdlg, IDC_HTEXT, textstr, MAX_TEXT_SIZE);
+ wSetData(&opt.hText, textstr);
+ GetDlgItemText(hdlg, IDC_XTEXT, textstr, MAX_TEXT_SIZE);
+ wSetData(&opt.xText, textstr);
+ GetDlgItemText(hdlg, IDC_BTITLE2, textstr, MAX_TEXT_SIZE);
+ wSetData(&opt.sText, textstr);
+ SaveOptions();
+ UpdateAllInfo(0, 0);
+ break;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
diff --git a/plugins/Weather/src/weather_popup.cpp b/plugins/Weather/src/weather_popup.cpp
new file mode 100644
index 0000000000..2a3e3580e5
--- /dev/null
+++ b/plugins/Weather/src/weather_popup.cpp
@@ -0,0 +1,438 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2009 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contain the source related to weather popups, including popup
+ options, popup display, and the code for popup process.
+*/
+
+#include "weather.h"
+
+// variables for weather_popup.c
+static HANDLE hPopupContact;
+
+//============ SHOW WEATHER POPUPS ============
+
+// display weather popups
+// wParam = the contact to display popup
+// lParam = whether the weather data is changed or not
+int WeatherPopup(WPARAM wParam, LPARAM lParam)
+{
+ // determine if the popup should display or not
+ if (opt.UsePopup && opt.UpdatePopup && (!opt.PopupOnChange || (BOOL)lParam) &&
+ !db_get_b((HANDLE)wParam, WEATHERPROTONAME, "DPopUp", 0))
+ {
+ POPUPDATAT ppd = {0};
+ WEATHERINFO winfo;
+
+ // setup the popup
+ ppd.lchContact = (HANDLE)wParam;
+// if ((HANDLE)wParam != NULL) { // for actual contact
+ winfo = LoadWeatherInfo((HANDLE)wParam);
+ ppd.PluginData = ppd.lchIcon = LoadSkinnedProtoIcon(WEATHERPROTONAME, winfo.status);
+ GetDisplay(&winfo, opt.pTitle, ppd.lptzContactName);
+ GetDisplay(&winfo, opt.pText, ppd.lptzText);
+ ppd.PluginWindowProc = PopupDlgProc;
+// }
+// else { // for preview
+// ppd.lchIcon = LoadSkinnedProtoIcon(WEATHERPROTONAME, ONLINE);
+// strcpy(ppd.lpzContactName, Translate("This is the name of the city"));
+// strcpy(ppd.lpzText, Translate("Here is a short weather description"));
+// ppd.PluginWindowProc = NULL;
+// }
+ ppd.colorBack = (opt.UseWinColors)?GetSysColor(COLOR_BTNFACE):opt.BGColour;
+ ppd.colorText = (opt.UseWinColors)?GetSysColor(COLOR_WINDOWTEXT):opt.TextColour;
+ ppd.iSeconds = opt.pDelay;
+ PUAddPopUpT( &ppd );
+ }
+ return 0;
+}
+
+//============ WEATHER ERROR POPUPS ============
+
+// display weather error or notices (not threaded)
+// wParam = error text
+// lParam = display type
+// Type can either be SM_WARNING, SM_NOTIFY, or SM_WEATHERALERT
+
+int WeatherError(WPARAM wParam, LPARAM lParam)
+{
+ if ( !opt.UsePopup)
+ return 0;
+
+ TCHAR* tszMsg = ( TCHAR* )wParam;
+
+ if ((DWORD)lParam == SM_WARNING)
+ PUShowMessageT( tszMsg, SM_WARNING );
+ else if ((DWORD)lParam == SM_NOTIFY)
+ PUShowMessageT( tszMsg, SM_NOTIFY);
+ else if ((DWORD)lParam == SM_WEATHERALERT)
+ {
+ POPUPDATAT ppd = {0};
+ TCHAR *chop, str1[512], str2[512];
+
+ // get the 2 strings
+ _tcscpy(str1, tszMsg);
+ _tcscpy(str2, tszMsg);
+ chop = _tcschr(str1, 255);
+ if (chop != NULL) *chop = '\0';
+ else str1[0] = 0;
+ chop = _tcschr(str2, 255);
+ if (chop != NULL) _tcscpy(str2, chop+1);
+ else str2[0] = 0;
+
+ // setup the popup
+ ppd.lchIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(OIC_BANG), IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
+ _tcscpy(ppd.lptzContactName, str1);
+ _tcscpy(ppd.lptzText, str2);
+ ppd.colorBack = (opt.UseWinColors)?GetSysColor(COLOR_BTNFACE):opt.BGColour;
+ ppd.colorText = (opt.UseWinColors)?GetSysColor(COLOR_WINDOWTEXT):opt.TextColour;
+ ppd.iSeconds = opt.pDelay;
+ PUAddPopUpT( &ppd );
+ }
+ return 0;
+}
+
+// wrapper function for displaying weather warning popup by triggering an event
+// (threaded)
+// lpzText = error text
+// kind = display type (see m_popup.h)
+
+int WPShowMessage(TCHAR* lpzText, WORD kind)
+{
+ NotifyEventHooks(hHookWeatherError, (WPARAM)lpzText, (LPARAM)kind);
+ return 0;
+}
+
+//============ WEATHER POPUP PROCESSES ============
+
+// popup dialog pocess
+// for selecting actions when click on the popup window
+// use for displaying contact menu
+LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ DWORD ID = 0;
+ HANDLE hContact;
+ hContact = PUGetContact(hWnd);
+
+ switch(message) {
+ case WM_COMMAND:
+ ID = opt.LeftClickAction;
+ if (ID != IDM_M7) PUDeletePopUp(hWnd);
+ SendMessage(hPopupWindow, ID, (WPARAM)hContact, 0);
+ return TRUE;
+
+ case WM_CONTEXTMENU:
+ ID = opt.RightClickAction;
+ if (ID != IDM_M7) PUDeletePopUp(hWnd);
+ SendMessage(hPopupWindow, ID, (WPARAM)hContact, 0);
+ return TRUE;
+
+ case UM_FREEPLUGINDATA:
+ Skin_ReleaseIcon((HICON)PUGetPluginData(hWnd));
+ return FALSE;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+// process for the popup window
+// containing the code for popup actions
+LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ POINT pt;
+ HMENU hMenu;
+ switch (uMsg) {
+ case IDM_M2: // brief info
+ BriefInfo(wParam, 0);
+ break;
+
+ case IDM_M3: // read complete forecast
+ LoadForecast(wParam, 0);
+ break;
+
+ case IDM_M4: // display weather map
+ WeatherMap(wParam, 0);
+ break;
+
+ case IDM_M5: // open history window
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY, wParam, 0);
+ break;
+
+ case IDM_M6: // open external log
+ ViewLog(wParam, 0);
+ break;
+
+ case IDM_M7: // display contact menu
+ hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,wParam,0);
+ GetCursorPos(&pt);
+ hPopupContact = (HANDLE)wParam;
+ TrackPopupMenu(hMenu,TPM_LEFTALIGN,pt.x,pt.y,0,hWnd,NULL);
+ DestroyMenu(hMenu);
+ break;
+
+ case IDM_M8: // display contact detail
+ CallService(MS_USERINFO_SHOWDIALOG, wParam, 0);
+
+ case WM_COMMAND: //Needed by the contact's context menu
+ if ( CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU), (LPARAM)hPopupContact))
+ break;
+ return FALSE;
+
+ case WM_MEASUREITEM: //Needed by the contact's context menu
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM: //Needed by the contact's context menu
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);//FALSE;
+}
+
+//============ POPUP OPTIONS ============
+
+// used to select the menu item for popup action menu
+static void SelectMenuItem(HMENU hMenu, int Check)
+{
+ for (int i=0; i <= GetMenuItemCount(hMenu)-1; i++)
+ CheckMenuItem(hMenu, i, MF_BYPOSITION|((int)GetMenuItemID(hMenu, i) == Check)*8);
+}
+
+// temporary read the current option to memory
+// but does not write to the database
+void ReadPopupOpt(HWND hdlg)
+{
+ TCHAR text[MAX_TEXT_SIZE];
+ int num;
+ TCHAR str[512];
+
+ // popup colour
+ opt.TextColour = SendDlgItemMessage(hdlg,IDC_TEXTCOLOUR,CPM_GETCOLOUR,0,0);
+ opt.BGColour = SendDlgItemMessage(hdlg,IDC_BGCOLOUR,CPM_GETCOLOUR,0,0);
+
+ // get delay time
+ GetDlgItemText(hdlg, IDC_DELAY, str, sizeof(str));
+ num = _ttoi(str);
+ opt.pDelay = num;
+
+ // other options
+ opt.UseWinColors = (BYTE)IsDlgButtonChecked(hdlg, IDC_USEWINCOLORS);
+ opt.UsePopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_E);
+ opt.UpdatePopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_POP1);
+ opt.AlertPopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_POP2);
+ opt.PopupOnChange = (BYTE)IsDlgButtonChecked(hdlg, IDC_CH);
+ opt.ShowWarnings = (BYTE)IsDlgButtonChecked(hdlg, IDC_W);
+
+ // popup texts
+ wfree(&opt.pText);
+ wfree(&opt.pTitle);
+ GetDlgItemText(hdlg, IDC_PText, text, MAX_TEXT_SIZE);
+ wSetData(&opt.pText, text);
+ GetDlgItemText(hdlg, IDC_PTitle, text, MAX_TEXT_SIZE);
+ wSetData(&opt.pTitle, text);
+}
+
+// copied and modified from NewStatusNotify
+INT_PTR CALLBACK DlgPopUpOpts(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int ID;
+ TCHAR str[512];
+ HMENU hMenu, hMenu1;
+ RECT pos;
+ HWND button;
+ HANDLE hContact;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hdlg);
+ SaveOptions();
+
+ // click actions
+ hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ GetMenuString(hMenu1, opt.LeftClickAction, str, sizeof(str), MF_BYCOMMAND);
+ SetDlgItemText(hdlg, IDC_LeftClick, TranslateTS(str));
+ GetMenuString(hMenu1, opt.RightClickAction, str, sizeof(str), MF_BYCOMMAND);
+ SetDlgItemText(hdlg, IDC_RightClick, TranslateTS(str));
+ DestroyMenu(hMenu);
+
+ // other options
+ CheckDlgButton(hdlg, IDC_E, opt.UsePopup);
+ CheckDlgButton(hdlg, IDC_POP2, opt.AlertPopup);
+ CheckDlgButton(hdlg, IDC_POP1, opt.UpdatePopup);
+ CheckDlgButton(hdlg, IDC_CH, opt.PopupOnChange);
+ CheckDlgButton(hdlg, IDC_W, opt.ShowWarnings);
+ SetDlgItemText(hdlg,IDC_PText, opt.pText);
+ SetDlgItemText(hdlg,IDC_PTitle, opt.pTitle);
+ // setting popup delay option
+ _ltot(opt.pDelay, str, 10);
+ SetDlgItemText(hdlg,IDC_DELAY, str);
+ if (opt.pDelay == -1)
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD2);
+ else if (opt.pDelay == 0)
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD1);
+ else
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3);
+ //Colours. First step is configuring the colours.
+ SendDlgItemMessage(hdlg,IDC_BGCOLOUR,CPM_SETCOLOUR,0,opt.BGColour);
+ SendDlgItemMessage(hdlg,IDC_TEXTCOLOUR,CPM_SETCOLOUR,0,opt.TextColour);
+ //Second step is disabling them if we want to use default Windows ones.
+ CheckDlgButton(hdlg, IDC_USEWINCOLORS,opt.UseWinColors?BST_CHECKED:BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hdlg, IDC_BGCOLOUR), !opt.UseWinColors);
+ EnableWindow(GetDlgItem(hdlg, IDC_TEXTCOLOUR), !opt.UseWinColors);
+
+ // buttons
+ SendMessage(GetDlgItem(hdlg,IDC_PREVIEW), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_PDEF), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_LeftClick), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_RightClick), BUTTONSETASFLATBTN, TRUE, 0);
+ SendMessage(GetDlgItem(hdlg,IDC_VAR3), BUTTONSETASFLATBTN, TRUE, 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ // enable the "apply" button
+ if (HIWORD(wParam) == BN_CLICKED && GetFocus() == (HWND)lParam)
+ SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
+ if ( !((LOWORD(wParam) == IDC_UPDATE || LOWORD(wParam) == IDC_DEGREE) &&
+ (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())))
+ SendMessage(GetParent(hdlg),PSM_CHANGED,0,0);
+ //These are simple clicks: we don't save, but we tell the Options Page to enable the "Apply" button.
+ switch(LOWORD(wParam)) {
+ case IDC_BGCOLOUR: //Fall through
+ case IDC_TEXTCOLOUR:
+ // select new colors
+ if (HIWORD(wParam) == CPN_COLOURCHANGED)
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_USEWINCOLORS:
+ // use window color - enable/disable color selection controls
+ EnableWindow(GetDlgItem(hdlg, IDC_BGCOLOUR), !(opt.UseWinColors));
+ EnableWindow(GetDlgItem(hdlg, IDC_TEXTCOLOUR), !(opt.UseWinColors));
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_E:
+ case IDC_CH:
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_RightClick:
+ // right click action selection menu
+ button = GetDlgItem(hdlg, IDC_RightClick);
+ GetWindowRect(button, &pos);
+
+ hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ TranslateMenu(hMenu1);
+ SelectMenuItem(hMenu1, opt.RightClickAction);
+ ID = TrackPopupMenu(hMenu1, TPM_LEFTBUTTON|TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, NULL);
+ if (ID) opt.RightClickAction = ID;
+ DestroyMenu(hMenu);
+
+ hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ GetMenuString(hMenu1, opt.RightClickAction, str, sizeof(str), MF_BYCOMMAND);
+ SetDlgItemText(hdlg, IDC_RightClick, TranslateTS(str));
+ DestroyMenu(hMenu);
+ break;
+
+ case IDC_LeftClick:
+ // left click action selection menu
+ button = GetDlgItem(hdlg, IDC_LeftClick);
+ GetWindowRect(button, &pos);
+
+ hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ TranslateMenu(hMenu1);
+ SelectMenuItem(hMenu1, opt.LeftClickAction);
+ ID = TrackPopupMenu(hMenu1, TPM_LEFTBUTTON|TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, NULL);
+ if (ID) opt.LeftClickAction = ID;
+ DestroyMenu(hMenu);
+
+ hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ GetMenuString(hMenu1, opt.LeftClickAction, str, sizeof(str), MF_BYCOMMAND);
+ SetDlgItemText(hdlg, IDC_LeftClick, TranslateTS(str));
+ DestroyMenu(hMenu);
+ break;
+
+ case IDC_PD1:
+ // Popup delay setting from PopUp plugin
+ SetDlgItemText(hdlg, IDC_DELAY, _T("0"));
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD1);
+ break;
+
+ case IDC_PD2:
+ // Popup delay = permanent
+ SetDlgItemText(hdlg, IDC_DELAY, _T("-1"));
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD2);
+ break;
+
+ case IDC_DELAY:
+ // if text is edited
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3);
+ break;
+
+ case IDC_PDEF:
+ // set the default value for popup texts
+ SetTextDefault("Pp");
+ SetDlgItemText(hdlg,IDC_PText, opt.pText);
+ SetDlgItemText(hdlg,IDC_PTitle, opt.pTitle);
+ wfree(&opt.pText);
+ wfree(&opt.pTitle);
+ break;
+
+ case IDC_VAR3:
+ // display variable list
+ _tcscpy(str, _T(" \n")); // to make the message box wider
+ _tcscat(str, TranslateT("%c\tcurrent condition\n%d\tcurrent date\n%e\tdewpoint\n%f\tfeel-like temperature\n%h\ttoday's high\n%i\twind direction\n%l\ttoday's low\n%m\thumidity\n%n\tstation name\n%p\tpressure\n%r\tsunrise time\n%s\tstation ID\n%t\ttemperature\n%u\tupdate time\n%v\tvisibility\n%w\twind speed\n%y\tsun set"));
+ _tcscat(str, _T("\n"));
+ _tcscat(str, TranslateT("%[..]\tcustom variables"));
+ MessageBox(NULL, str, TranslateT("Variable List"), MB_OK|MB_ICONASTERISK|MB_TOPMOST);
+ break;
+
+ case IDC_PREVIEW:
+ // popup preview
+ hContact = opt.DefStn;
+ ReadPopupOpt(hdlg); // read new options to memory
+ WeatherPopup((WPARAM)opt.DefStn, (BOOL)TRUE); // display popup using new opt
+ DestroyOptions();
+ LoadOptions(); // restore old option in memory
+ opt.DefStn = hContact;
+ break;
+ }
+ break;
+
+ case WM_NOTIFY: //Here we have pressed either the OK or the APPLY button.
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY: {
+ ReadPopupOpt(hdlg);
+
+ // save the options, and update main menu
+ SaveOptions();
+ UpdatePopupMenu(opt.UsePopup);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/plugins/Weather/src/weather_svcs.cpp b/plugins/Weather/src/weather_svcs.cpp
new file mode 100644
index 0000000000..3872760fc6
--- /dev/null
+++ b/plugins/Weather/src/weather_svcs.cpp
@@ -0,0 +1,386 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related to weather protocol services
+as required for a Miranda protocol. Also, it contains functions for
+building/changing the weather menu items.
+*/
+
+#include "weather.h"
+
+static HGENMENU hEnableDisablePopupMenu;
+static HGENMENU hEnableDisableMenu;
+
+//============ MIRANDA PROTOCOL SERVICES ============
+
+// protocol service function for setting weather protocol status
+INT_PTR WeatherSetStatus(WPARAM new_status, LPARAM lParam)
+{
+ new_status = new_status != ID_STATUS_OFFLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+
+ // if we don't want to show status for default station
+ if (opt.NoProtoCondition && status != new_status) {
+ old_status = status;
+ status = new_status != ID_STATUS_OFFLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status);
+
+ UpdateMenu(new_status != ID_STATUS_OFFLINE);
+ if (new_status != ID_STATUS_OFFLINE)
+ UpdateAll(FALSE, FALSE);
+ }
+
+ return 0;
+}
+
+// get capabilities protocol service function
+INT_PTR WeatherGetCaps(WPARAM wParam, LPARAM lParam)
+{
+ INT_PTR ret = 0;
+
+ switch(wParam) {
+ case PFLAGNUM_1:
+ // support search and visible list
+ ret = PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_EXTSEARCH | PF1_VISLIST | PF1_MODEMSGRECV;
+ break;
+
+ case PFLAGNUM_2:
+ ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND |
+ PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
+ break;
+
+ case PFLAGNUM_4:
+ ret = PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEADDED |
+ PF4_FORCEAUTH;
+ break;
+
+ case PFLAGNUM_5: /* this is PFLAGNUM_5 change when alpha SDK is released */
+ ret = PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND |
+ PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
+ break;
+
+ case PFLAG_UNIQUEIDTEXT:
+ ret = (INT_PTR)Translate("Station ID");
+ break;
+
+ case PFLAG_UNIQUEIDSETTING:
+ ret = (INT_PTR)"ID";
+ break;
+ }
+ return ret;
+}
+
+// protocol service function to get weather protocol name
+INT_PTR WeatherGetName(WPARAM wParam,LPARAM lParam)
+{
+ strncpy((char*)lParam,WEATHERPROTOTEXT,wParam-1);
+ *((char*)lParam + wParam-1) = 0;
+ return 0;
+}
+
+// protocol service function to get the current status of the protocol
+INT_PTR WeatherGetStatus(WPARAM wParam,LPARAM lParam)
+{
+ return status;
+}
+
+// protocol service function to get the icon of the protocol
+INT_PTR WeatherLoadIcon(WPARAM wParam,LPARAM lParam)
+{
+ return (LOWORD(wParam) == PLI_PROTOCOL) ? (INT_PTR)CopyIcon(LoadIconEx("main", FALSE)) : 0;
+}
+
+static void __cdecl AckThreadProc(HANDLE param)
+{
+ Sleep(100);
+ ProtoBroadcastAck(WEATHERPROTONAME, param, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+}
+
+// nothing to do here because weather proto do not need to retrieve contact info form network
+// so just return a 0
+INT_PTR WeatherGetInfo(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ mir_forkthread(AckThreadProc, ccs->hContact);
+ return 0;
+}
+
+// avatars
+static const TCHAR *statusStr[] = { _T("Light"), _T("Fog"), _T("SShower"), _T("Snow"), _T("RShower"), _T("Rain"), _T("PCloudy"), _T("Cloudy"), _T("Sunny"), _T("NA") };
+static const WORD statusValue[] = { LIGHT, FOG, SSHOWER, SNOW, RSHOWER, RAIN, PCLOUDY, CLOUDY, SUNNY, NA };
+
+INT_PTR WeatherGetAvatarInfo(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR szSearchPath[MAX_PATH], *chop;
+ WORD status;
+ unsigned i;
+ PROTO_AVATAR_INFORMATIONT* ai = ( PROTO_AVATAR_INFORMATIONT* )lParam;
+
+ GetModuleFileName(GetModuleHandle(NULL), szSearchPath, sizeof(szSearchPath));
+ chop = _tcsrchr(szSearchPath, '\\');
+
+ if (chop) *chop = '\0';
+ else szSearchPath[0] = 0;
+
+ status = (WORD)db_get_w(ai->hContact, WEATHERPROTONAME, "StatusIcon",0);
+ for (i=0; i<10; i++)
+ if (statusValue[i] == status)
+ break;
+
+ if (i >= 10)
+ return GAIR_NOAVATAR;
+
+ ai->format = PA_FORMAT_PNG;
+ wsprintf(ai->filename, _T("%s\\Plugins\\Weather\\%s.png"), szSearchPath, statusStr[i]);
+ if ( _taccess(ai->filename, 4) == 0)
+ return GAIR_SUCCESS;
+
+ ai->format = PA_FORMAT_GIF;
+ wsprintf(ai->filename, _T("%s\\Plugins\\Weather\\%s.gif"), szSearchPath, statusStr[i]);
+ if ( _taccess(ai->filename, 4) == 0)
+ return GAIR_SUCCESS;
+
+ ai->format = PA_FORMAT_UNKNOWN;
+ ai->filename[0] = 0;
+ return GAIR_NOAVATAR;
+}
+
+
+void AvatarDownloaded(HANDLE hContact)
+{
+ PROTO_AVATAR_INFORMATIONT AI = {0};
+ AI.cbSize = sizeof(AI);
+ AI.hContact = hContact;
+
+ if (WeatherGetAvatarInfo(GAIF_FORCE, (LPARAM)&AI) == GAIR_SUCCESS)
+ ProtoBroadcastAck(WEATHERPROTONAME, hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &AI, 0);
+ else
+ ProtoBroadcastAck(WEATHERPROTONAME, hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
+}
+
+
+static void __cdecl WeatherGetAwayMsgThread(HANDLE hContact)
+{
+ Sleep(100);
+
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString(hContact, "CList", "StatusMsg", &dbv)) {
+ ProtoBroadcastAck(WEATHERPROTONAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.ptszVal);
+ db_free( &dbv );
+ }
+ else ProtoBroadcastAck(WEATHERPROTONAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, 0);
+}
+
+static INT_PTR WeatherGetAwayMsg(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ if (ccs == NULL)
+ return 0;
+
+ mir_forkthread(WeatherGetAwayMsgThread, ccs->hContact);
+ return 1;
+}
+
+//============ PROTOCOL INITIALIZATION ============
+// protocol services
+void InitServices(void)
+{
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_GETCAPS, WeatherGetCaps);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_GETNAME, WeatherGetName);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_LOADICON, WeatherLoadIcon);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_SETSTATUS, WeatherSetStatus);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_GETSTATUS, WeatherGetStatus);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_BASICSEARCHT, WeatherBasicSearch);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_SEARCHBYEMAILT, WeatherBasicSearch);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_ADDTOLIST, WeatherAddToList);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PSS_GETINFO, WeatherGetInfo);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_GETAVATARINFOT, WeatherGetAvatarInfo);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PSS_GETAWAYMSG, WeatherGetAwayMsg);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_CREATEADVSEARCHUI, WeatherCreateAdvancedSearchUI);
+ CreateProtoServiceFunction(WEATHERPROTONAME, PS_SEARCHBYADVANCED, WeatherAdvancedSearch);
+
+ CreateProtoServiceFunction(WEATHERPROTONAME, MS_WEATHER_GETDISPLAY, GetDisplaySvcFunc);
+}
+
+//============ MENU INITIALIZATION ============
+
+void UpdateMenu(BOOL State)
+{
+ // update option setting
+ opt.CAutoUpdate = State;
+ db_set_b(NULL, WEATHERPROTONAME, "AutoUpdate", (BYTE)opt.AutoUpdate);
+
+ CLISTMENUITEM mi = { sizeof(mi) };
+
+ if (State) { // to enable auto-update
+ mi.pszName = LPGEN("Auto Update Enabled");
+ mi.icolibItem = GetIconHandle("main");
+ }
+ else { // to disable auto-update
+ mi.pszName = LPGEN("Auto Update Disabled");
+ mi.icolibItem = GetIconHandle("disabled");
+ }
+
+ mi.flags = CMIM_ICON | CMIM_NAME | CMIF_ICONFROMICOLIB;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hEnableDisableMenu, (LPARAM)&mi);
+}
+
+void UpdatePopupMenu(BOOL State)
+{
+ // update option setting
+ opt.UsePopup = State;
+ db_set_b(NULL, WEATHERPROTONAME, "UsePopUp", (BYTE)opt.UsePopup);
+
+ CLISTMENUITEM mi = { sizeof(mi) };
+ if (State)
+ { // to enable popup
+ mi.pszName = LPGEN("Disable &weather notification");
+ mi.icolibItem = GetIconHandle("popup");
+ }
+ else
+ { // to disable popup
+ mi.pszName = LPGEN("Enable &weather notification");
+ mi.icolibItem = GetIconHandle("nopopup");
+ }
+
+ mi.flags = CMIM_ICON | CMIM_NAME | CMIF_ICONFROMICOLIB;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hEnableDisablePopupMenu, (LPARAM)&mi);
+}
+
+// update the weather auto-update menu item when click on it
+INT_PTR EnableDisableCmd(WPARAM wParam,LPARAM lParam)
+{
+ UpdateMenu(wParam == TRUE ? (BOOL)lParam : !opt.CAutoUpdate);
+ return 0;
+}
+
+// update the weather popup menu item when click on it
+INT_PTR MenuitemNotifyCmd(WPARAM wParam,LPARAM lParam)
+{
+ UpdatePopupMenu(!opt.UsePopup);
+ return 0;
+}
+
+// adding weather contact menus
+// copied and modified form "modified MSN Protocol"
+void AddMenuItems(void)
+{
+ CLISTMENUITEM mi = { sizeof(mi) };
+ mi.pszContactOwner = WEATHERPROTONAME;
+ mi.flags = CMIF_ICONFROMICOLIB;
+
+ // contact menu
+ CreateServiceFunction(MS_WEATHER_UPDATE, UpdateSingleStation);
+ mi.position = -0x7FFFFFFA;
+ mi.icolibItem = GetIconHandle("update");
+ mi.pszName = LPGEN("Update Weather");
+ mi.pszService = MS_WEATHER_UPDATE;
+ Menu_AddContactMenuItem(&mi);
+
+ CreateServiceFunction(MS_WEATHER_REFRESH, UpdateSingleRemove);
+ mi.position = -0x7FFFFFF9;
+ mi.icolibItem = GetIconHandle("update2");
+ mi.pszName = LPGEN("Remove Old Data then Update");
+ mi.pszService = MS_WEATHER_REFRESH;
+ Menu_AddContactMenuItem(&mi);
+
+ CreateServiceFunction(MS_WEATHER_BRIEF, BriefInfoSvc);
+ mi.position = -0x7FFFFFF8;
+ mi.icolibItem = GetIconHandle("brief");
+ mi.pszName = LPGEN("Brief Information");
+ mi.pszService = MS_WEATHER_BRIEF;
+ Menu_AddContactMenuItem(&mi);
+
+ CreateServiceFunction(MS_WEATHER_COMPLETE, LoadForecast);
+ mi.position = -0x7FFFFFF7;
+ mi.icolibItem = GetIconHandle("read");
+ mi.pszName = LPGEN("Read Complete Forecast");
+ mi.pszService = MS_WEATHER_COMPLETE;
+ Menu_AddContactMenuItem(&mi);
+
+ CreateServiceFunction(MS_WEATHER_MAP, WeatherMap);
+ mi.position = -0x7FFFFFF6;
+ mi.icolibItem = GetIconHandle("map");
+ mi.pszName = LPGEN("Weather Map");
+ mi.pszService = MS_WEATHER_MAP;
+ Menu_AddContactMenuItem(&mi);
+
+ CreateServiceFunction(MS_WEATHER_LOG, ViewLog);
+ mi.position = -0x7FFFFFF5;
+ mi.icolibItem = GetIconHandle("log");
+ mi.pszName = LPGEN("View Log");
+ mi.pszService = MS_WEATHER_LOG;
+ Menu_AddContactMenuItem(&mi);
+
+ CreateServiceFunction(MS_WEATHER_EDIT, EditSettings);
+ mi.position = -0x7FFFFFF4;
+ mi.icolibItem = GetIconHandle("edit");
+ mi.pszName = LPGEN("Edit Settings");
+ mi.pszService = MS_WEATHER_EDIT;
+ Menu_AddContactMenuItem(&mi);
+
+ // adding main menu items
+ mi.pszPopupName = LPGEN("Weather");
+ mi.popupPosition = 500099000;
+
+ CreateServiceFunction(MS_WEATHER_ENABLED, EnableDisableCmd);
+ mi.pszName = LPGEN("Enable/Disable Weather Update");
+ mi.icolibItem = GetIconHandle("main");
+ mi.position = 10100001;
+ mi.pszService = MS_WEATHER_ENABLED;
+ hEnableDisableMenu = Menu_AddMainMenuItem(&mi);
+ UpdateMenu(opt.AutoUpdate);
+
+ CreateServiceFunction(MS_WEATHER_UPDATEALL, UpdateAllInfo);
+ mi.position = 20100001;
+ mi.icolibItem = GetIconHandle("update");
+ mi.pszName = LPGEN("Update All Weather");
+ mi.pszService = MS_WEATHER_UPDATEALL;
+ Menu_AddMainMenuItem(&mi);
+
+ CreateServiceFunction(MS_WEATHER_REFRESHALL, UpdateAllRemove);
+ mi.position = 20100002;
+ mi.icolibItem = GetIconHandle("update2");
+ mi.pszName = LPGEN("Remove Old Data then Update All");
+ mi.pszService = MS_WEATHER_REFRESHALL;
+ Menu_AddMainMenuItem(&mi);
+
+ // only run if popup service exists
+ if ( ServiceExists(MS_POPUP_ADDPOPUPT)) {
+ CreateServiceFunction(WEATHERPROTONAME "/PopupMenu", MenuitemNotifyCmd);
+ mi.pszName = LPGEN("Weather Notification");
+ mi.icolibItem = GetIconHandle("popup");
+ mi.position = 0;
+ mi.pszPopupName = LPGEN("PopUps");
+ mi.pszService = WEATHERPROTONAME "/PopupMenu";
+ hEnableDisablePopupMenu = Menu_AddMainMenuItem(&mi);
+ UpdatePopupMenu(opt.UsePopup);
+ }
+
+ if ( ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) {
+ CreateServiceFunction("Weather/mwin_menu", Mwin_MenuClicked);
+ mi.position = -0x7FFFFFF0;
+ mi.hIcon = NULL;
+ mi.flags = 0;
+ mi.pszName = LPGEN("Display in a frame");
+ mi.pszService = "Weather/mwin_menu";
+ hMwinMenu = Menu_AddContactMenuItem(&mi);
+ }
+}
diff --git a/plugins/Weather/src/weather_update.cpp b/plugins/Weather/src/weather_update.cpp
new file mode 100644
index 0000000000..d07af7865b
--- /dev/null
+++ b/plugins/Weather/src/weather_update.cpp
@@ -0,0 +1,615 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related to updating new weather
+information, both automatic (by timer) and manually (by selecting
+menu items).
+*/
+
+#include "weather.h"
+
+UPDATELIST *UpdateListHead;
+UPDATELIST *UpdateListTail;
+
+extern HANDLE hUpdateMutex;
+
+//============ RETRIEVE NEW WEATHER ============
+
+// retrieve weather info and display / log them
+// hContact = current contact
+int UpdateWeather(HANDLE hContact)
+{
+ TCHAR str[256], str2[MAX_TEXT_SIZE];
+ DBVARIANT dbv;
+ BOOL Ch = FALSE;
+
+ if (hContact == NULL) return 1; // some error prevention
+
+ dbv.pszVal = "";
+
+ // log to netlib log for debug purpose
+ Netlib_LogfT(hNetlibUser, _T("************************************************************************"));
+ int dbres = DBGetContactSettingTString(hContact, WEATHERPROTONAME, "Nick", &dbv);
+
+ Netlib_LogfT(hNetlibUser, _T("<-- Start update for station -->"));
+
+ // download the info and parse it
+ // result are stored in database
+ int code = GetWeatherData(hContact);
+ if (code != 0)
+ {
+ // error occurs if the return value is not equals to 0
+ if (opt.ShowWarnings)
+ { // show warnings by popup
+ mir_sntprintf(str, SIZEOF(str)-105,
+ TranslateT("Unable to retrieve weather information for %s"), dbv.ptszVal);
+ _tcscat(str, _T("\n"));
+ _tcscat(str, GetError(code));
+ WPShowMessage(str, SM_WARNING);
+ }
+ // log to netlib
+ Netlib_LogfT(hNetlibUser, _T("Error! Update cannot continue... Start to free memory"));
+ Netlib_LogfT(hNetlibUser, _T("<-- Error occurs while updating station: %s -->"), dbv.ptszVal);
+ if ( !dbres) db_free(&dbv);
+ return 1;
+ }
+ if ( !dbres) db_free(&dbv);
+
+ // initialize, load new weather Data
+ WEATHERINFO winfo = LoadWeatherInfo(hContact);
+
+ // translate weather condition
+ _tcscpy(winfo.cond, TranslateTS(winfo.cond));
+
+ // compare the old condition and determine if the weather had changed
+ if (opt.UpdateOnlyConditionChanged) { // consider condition change
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "LastCondition", &dbv)) {
+ if (_tcsicmp(winfo.cond, dbv.ptszVal)) Ch = TRUE; // the weather condition is changed
+ db_free(&dbv);
+ }
+ else Ch = TRUE;
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "LastTemperature", &dbv)) {
+ if (_tcsicmp(winfo.temp, dbv.ptszVal)) Ch = TRUE; // the temperature is changed
+ db_free(&dbv);
+ }
+ else Ch = TRUE;
+ }
+ else { // consider update time change
+ if ( !DBGetContactSettingTString(hContact, WEATHERPROTONAME, "LastUpdate", &dbv)) {
+ if (_tcsicmp(winfo.update, dbv.ptszVal)) Ch = TRUE; // the update time is changed
+ db_free(&dbv);
+ }
+ else Ch = TRUE;
+ }
+
+ // have weather alert issued?
+ dbres = DBGetContactSettingTString(hContact, WEATHERCONDITION, "Alert", &dbv);
+ if ( !dbres && dbv.ptszVal[0] != 0) {
+ if (opt.AlertPopup && !db_get_b(hContact, WEATHERPROTONAME, "DPopUp", 0) && Ch) {
+ // display alert popup
+ wsprintf(str, _T("Alert for %s%c%s"), winfo.city, 255, dbv.ptszVal);
+ WPShowMessage(str, SM_WEATHERALERT);
+ }
+ // alert issued, set display to italic
+ if (opt.MakeItalic)
+ db_set_w(hContact, WEATHERPROTONAME, "ApparentMode", ID_STATUS_OFFLINE);
+ SkinPlaySound("weatheralert");
+ }
+ // alert dropped, set the display back to normal
+ else db_unset(hContact, WEATHERPROTONAME, "ApparentMode");
+ if ( !dbres) db_free(&dbv);
+
+ // backup current condition for checking if the weather is changed or not
+ db_set_ts(hContact, WEATHERPROTONAME, "LastLog", winfo.update);
+ db_set_ts(hContact, WEATHERPROTONAME, "LastCondition", winfo.cond);
+ db_set_ts(hContact, WEATHERPROTONAME, "LastTemperature", winfo.temp);
+ db_set_ts(hContact, WEATHERPROTONAME, "LastUpdate", winfo.update);
+
+ // display condition on contact list
+ if (opt.DisCondIcon && winfo.status != ID_STATUS_OFFLINE)
+ db_set_w(hContact, WEATHERPROTONAME, "Status", ID_STATUS_ONLINE);
+ else
+ db_set_w(hContact, WEATHERPROTONAME, "Status", winfo.status);
+ AvatarDownloaded(hContact);
+
+ GetDisplay(&winfo, opt.cText, str2);
+ db_set_ts(hContact, "CList", "MyHandle", str2);
+
+ GetDisplay(&winfo, opt.sText, str2);
+ if (str2[0])
+ db_set_ts(hContact, "CList", "StatusMsg", str2);
+ else
+ db_unset(hContact, "CList", "StatusMsg");
+
+ ProtoBroadcastAck(WEATHERPROTONAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, NULL, (LPARAM)(str2[0] ? str2 : 0));
+
+ // save descriptions in MyNotes
+ GetDisplay(&winfo, opt.nText, str2);
+ db_set_ts(hContact, "UserInfo", "MyNotes", str2);
+ GetDisplay(&winfo, opt.xText, str2);
+ db_set_ts(hContact, WEATHERCONDITION, "WeatherInfo", str2);
+
+ // set the update tag
+ db_set_b(hContact, WEATHERPROTONAME, "IsUpdated", TRUE);
+
+ // save info for default weather condition
+ if ( !_tcscmp(winfo.id, opt.Default) && !opt.NoProtoCondition) {
+ // save current condition for default station to be displayed after the update
+ old_status = status;
+ status = winfo.status;
+ // a workaround for a default station that currently have an n/a icon assigned
+ if (status == ID_STATUS_OFFLINE) status = NOSTATUSDATA;
+ ProtoBroadcastAck(WEATHERPROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status);
+ }
+
+ // logging
+ if (Ch) {
+ // play the sound event
+ SkinPlaySound("weatherupdated");
+
+ if (db_get_b(hContact, WEATHERPROTONAME, "File", 0)) {
+ // external log
+ if ( !DBGetContactSettingTString(hContact,WEATHERPROTONAME, "Log",&dbv)) {
+ // for the option for overwriting the file, delete old file first
+ if (db_get_b(hContact,WEATHERPROTONAME, "Overwrite",0))
+ DeleteFile(dbv.ptszVal);
+ // open the file and set point to the end of file
+ FILE *file = _tfopen( dbv.ptszVal, _T("a"));
+ db_free(&dbv);
+ if (file != NULL) {
+ // write data to the file and close
+ GetDisplay(&winfo, opt.eText, str2);
+ _fputts(str2, file);
+ fclose(file);
+ } } }
+
+ if (db_get_b(hContact, WEATHERPROTONAME, "History", 0)) {
+ DBEVENTINFO dbei = {0};
+ // internal log using history
+ GetDisplay(&winfo, opt.hText, str2);
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = WEATHERPROTONAME;
+ dbei.timestamp = (DWORD)time(NULL);
+ dbei.flags = DBEF_READ|DBEF_UTF;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.pBlob = (PBYTE)mir_utf8encodeT(str2);
+ dbei.cbBlob = (DWORD)strlen((char*)dbei.pBlob)+1;
+
+ // add the history event
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei);
+ }
+
+ // show the popup
+ NotifyEventHooks(hHookWeatherUpdated, (WPARAM)hContact, (LPARAM)Ch);
+ }
+
+ Netlib_LogfT(hNetlibUser, _T("Update Completed - Start to free memory"));
+ Netlib_LogfT(hNetlibUser, _T("<-- Update successful for station -->"));
+
+ // Update frame data
+ UpdateMwinData(hContact);
+
+ // update brief info if its opened
+ HWND hMoreDataDlg = WindowList_Find(hDataWindowList, hContact);
+ if (hMoreDataDlg != NULL) PostMessage(hMoreDataDlg, WM_UPDATEDATA, 0, 0);
+ 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(HANDLE hContact)
+{
+ UPDATELIST *newItem = (UPDATELIST*)mir_alloc(sizeof(UPDATELIST));
+ newItem->hContact = hContact;
+ newItem->next = NULL;
+
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ if (UpdateListTail == NULL) UpdateListHead = newItem;
+ else UpdateListTail->next = newItem;
+ UpdateListTail = newItem;
+
+ ReleaseMutex(hUpdateMutex);
+}
+
+// get the first item from the update queue and remove it from the queue
+// return value = the contact for next update
+HANDLE UpdateGetFirst()
+{
+ HANDLE hContact = NULL;
+
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ if (UpdateListHead != NULL)
+ {
+ UPDATELIST* Item = UpdateListHead;
+
+ hContact = Item->hContact;
+ UpdateListHead = Item->next;
+ mir_free(Item);
+
+ if (UpdateListHead == NULL) UpdateListTail = NULL;
+ }
+
+ ReleaseMutex(hUpdateMutex);
+
+ return hContact;
+}
+
+void DestroyUpdateList(void)
+{
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ UPDATELIST *temp = UpdateListHead;
+
+ // free the list one by one
+ while (temp != NULL)
+ {
+ UpdateListHead = temp->next;
+ mir_free(temp);
+ temp = UpdateListHead;
+ }
+ // make sure the entire list is clear
+ UpdateListTail = NULL;
+
+ ReleaseMutex(hUpdateMutex);
+}
+
+
+//============ 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)
+{
+ // add all weather contact to the update queue list
+ HANDLE hContact = db_find_first();
+ while (hContact != NULL)
+ {
+ if (IsMyContact(hContact))
+ {
+ if ( !db_get_b(hContact,WEATHERPROTONAME, "AutoUpdate",FALSE) || !AutoUpdate)
+ {
+ if (RemoveData) DBDataManage((HANDLE)hContact, WDBM_REMOVE, 0, 0);
+ UpdateListAdd(hContact);
+ }
+ }
+ hContact = db_find_next(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, NULL);
+}
+
+// update a single station
+// wParam = handle for the weather station that is going to be updated
+INT_PTR UpdateSingleStation(WPARAM wParam, LPARAM lParam)
+{
+ if (IsMyContact((HANDLE)wParam))
+ {
+ // add the station to the end of the update queue
+ UpdateListAdd((HANDLE)wParam);
+
+ // 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, NULL);
+ }
+
+ 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 lParam)
+{
+ if (IsMyContact((HANDLE)wParam))
+ {
+ // add the station to the end of the update queue, and also remove old data
+ DBDataManage((HANDLE)wParam, WDBM_REMOVE, 0, 0);
+ UpdateListAdd((HANDLE)wParam);
+
+ // 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, NULL);
+ }
+
+ return 0;
+}
+
+// update all weather thread
+// this thread update each weather station from the queue
+void UpdateThreadProc(LPVOID hWnd)
+{
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+ if (ThreadRunning)
+ {
+ ReleaseMutex(hUpdateMutex);
+ return;
+ }
+ 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 != NULL && !Miranda_Terminated())
+ UpdateWeather(UpdateGetFirst());
+
+ NetlibHttpDisconnect();
+
+ // exit the update thread
+ ThreadRunning = FALSE;
+}
+
+// the "Update All" menu item in main menu
+INT_PTR UpdateAllInfo(WPARAM wParam,LPARAM lParam)
+{
+ if ( !ThreadRunning) UpdateAll(FALSE, FALSE);
+ return 0;
+}
+
+// the "Update All" menu item in main menu and remove the old data
+INT_PTR UpdateAllRemove(WPARAM wParam,LPARAM lParam) {
+ if ( !ThreadRunning) 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(HANDLE hContact)
+{
+ // get eacnh part of the id's
+ TCHAR id[256];
+ GetStationID(hContact, id, SIZEOF(id));
+
+ // test ID format
+ TCHAR* szInfo = _tcschr(id, '/');
+ if (szInfo == NULL)
+ return INVALID_ID_FORMAT;
+
+ GetID(id);
+
+ TCHAR Svc[256];
+ GetStationID(hContact, Svc, SIZEOF(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 == NULL)
+ return SVC_NOT_FOUND; // the ini for the station cannot be found
+
+ WIDATAITEMLIST* Item;
+ WORD cond = NA;
+ char loc[256];
+ char* szId = mir_t2a( id );
+ for ( int i=0; i<4; ++i) {
+ // generate update URL
+ switch(i) {
+ case 0:
+ _snprintf(loc, SIZEOF(loc), Data->UpdateURL, szId);
+ break;
+
+ case 1:
+ _snprintf(loc, SIZEOF(loc), Data->UpdateURL2, szId);
+ break;
+
+ case 2:
+ _snprintf(loc, SIZEOF(loc), Data->UpdateURL3, szId);
+ break;
+
+ case 3:
+ _snprintf(loc, SIZEOF(loc), Data->UpdateURL4, szId);
+ break;
+ }
+
+ if ( loc[0] == 0 )
+ continue;
+
+ // download the html file from the internet
+ TCHAR* szData = NULL;
+ int retval = InternetDownloadFile(loc, Data->Cookie, &szData);
+ if (retval != 0) {
+ mir_free(szData);
+ return retval;
+ }
+ if ( _tcsstr(szData, _T("Document Not Found")) != NULL) {
+ mir_free(szData);
+ return DOC_NOT_FOUND;
+ }
+
+ szInfo = szData;
+ Item = Data->UpdateData;
+
+ // begin parsing item by item
+ while (Item != NULL) {
+ if (Item->Item.Url[0] != 0 && Item->Item.Url[0] != (i + '1')) {
+ Item = Item->Next;
+ continue;
+ }
+
+ TCHAR 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 ( _tcscmp(Item->Item.Name, _T("Condition")) && _tcsicmp(Item->Item.Unit, _T("Cond")))
+ _tcscpy(DataValue, TranslateTS(DataValue));
+ break;
+
+ case WID_SET:
+ {
+ // for the "Set Data=" operation
+ DBVARIANT dbv;
+ TCHAR *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 = _tcsstr(str, _T(" & "));
+ if (chop == NULL)
+ chop = _tcschr(str, '\0');
+
+ stl = min(sizeof(str2)-1, (unsigned)(chop-str-2));
+ _tcsncpy(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)) {
+ _tcsncat(DataValue, dbv.ptszVal, SIZEOF(DataValue) - _tcslen(DataValue));
+ DataValue[SIZEOF(DataValue)-1] = 0;
+ db_free(&dbv);
+ }
+ break;
+
+ case'\"': // constant, add it to the result string
+ _tcsncat(DataValue, TranslateTS(str2), SIZEOF(DataValue) - _tcslen(DataValue));
+ DataValue[SIZEOF(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)) {
+ _tcsncpy(DataValue, dbv.ptszVal, SIZEOF(DataValue));
+ DataValue[SIZEOF(DataValue)-1] = 0;
+ db_free(&dbv);
+ }
+ else {
+ DataValue[0] = 0;
+ break; // do not continue if the source is invalid
+ }
+
+ // generate the strings
+ TCHAR* end = _tcsstr(DataValue, Item->Item.Break);
+ if (end == NULL) {
+ DataValue[0] = 0;
+ break; // exit if break string is not found
+ }
+ *end = '\0';
+ end += _tcslen(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_ts(hContact, WEATHERCONDITION, _T2A(Item->Item.End), end);
+ break;
+ } }
+
+ // don't store data if it is not available
+ if ((DataValue[0] != 0 && _tcscmp(DataValue, NODATA) &&
+ _tcscmp(DataValue, TranslateTS(NODATA)) && _tcscmp(Item->Item.Name, _T("Ignore"))) ||
+ ( !_tcscmp(Item->Item.Name, _T("Alert")) && i == 0))
+ {
+ // temporary workaround for mToolTip to show feel-like temperature
+ if ( !_tcscmp(Item->Item.Name, _T("Feel")))
+ db_set_ts(hContact, WEATHERCONDITION, "Heat Index", DataValue);
+ GetStationID(hContact, Svc, SIZEOF(Svc));
+ if ( !_tcscmp(Svc, opt.Default))
+ db_set_ts(NULL, DEFCURRENTWEATHER, _T2A(Item->Item.Name), DataValue);
+ if ( !_tcscmp(Item->Item.Name, _T("Condition"))) {
+ TCHAR buf[128], *cbuf;
+ mir_sntprintf(buf, SIZEOF(buf), _T("#%s Weather"), DataValue);
+ cbuf = TranslateTS(buf);
+ if (cbuf[0] == '#')
+ cbuf = TranslateTS(DataValue);
+ db_set_ts(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), cbuf);
+ CharLowerBuff(DataValue, (DWORD)_tcslen(DataValue));
+ cond = GetIcon(DataValue, Data);
+ }
+ else if ( _tcsicmp(Item->Item.Unit, _T("Cond")) == 0) {
+ TCHAR buf[128], *cbuf;
+ mir_sntprintf(buf, SIZEOF(buf), _T("#%s Weather"), DataValue);
+ cbuf = TranslateTS(buf);
+ if (cbuf[0] == '#')
+ cbuf = TranslateTS(DataValue);
+ db_set_ts(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), cbuf);
+ }
+ else db_set_ts(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), DataValue);
+ }
+ Item = Item->Next;
+ }
+ mir_free(szData);
+ }
+
+ // assign condition icon
+ db_set_w(hContact, WEATHERPROTONAME, "StatusIcon", cond);
+ db_set_ts(hContact, WEATHERPROTONAME, "MirVer", Data->DisplayName);
+ return 0;
+}
+
+//============ UPDATE TIMERS ============
+
+// main auto-update timer
+void CALLBACK timerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ // only run if it is not current updating and the auto update option is enabled
+ if ( !ThreadRunning && opt.CAutoUpdate && !Miranda_Terminated() &&
+ (!opt.NoProtoCondition || status == 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 hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ KillTimer(NULL, timerId);
+ ThreadRunning = FALSE;
+
+ if ( !Miranda_Terminated()) {
+ if (opt.StartupUpdate && !opt.NoProtoCondition)
+ UpdateAll(FALSE, FALSE);
+ timerId = SetTimer(NULL, 0, ((int)opt.UpdateTime)*60000, (TIMERPROC)timerProc);
+ }
+}
+
diff --git a/plugins/Weather/src/weather_userinfo.cpp b/plugins/Weather/src/weather_userinfo.cpp
new file mode 100644
index 0000000000..1d716a58ef
--- /dev/null
+++ b/plugins/Weather/src/weather_userinfo.cpp
@@ -0,0 +1,402 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG Team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+This file contain the source that is related to display contact
+information, including the one shows in user detail and the brief
+information
+*/
+
+#include "weather.h"
+
+extern INT_PTR CALLBACK DlgProcINIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+//============ CONTACT INFORMATION ============
+
+// initialize user info
+// lParam = current contact
+int UserInfoInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hInst;
+ odp.position = 100000000;
+ odp.ptszTitle = _T(WEATHERPROTONAME);
+
+ if (lParam == 0)
+ {
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO);
+ odp.pfnDlgProc = DlgProcINIPage;
+ odp.flags = ODPF_TCHAR;
+ UserInfo_AddPage(wParam, &odp);
+ }
+ else
+ {
+ // check if it is a weather contact
+ if (IsMyContact((HANDLE)lParam))
+ {
+ // register the contact info page
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_USERINFO);
+ odp.pfnDlgProc = DlgProcUIPage;
+ odp.flags = ODPF_BOLDGROUPS|ODPF_TCHAR;
+ UserInfo_AddPage(wParam, &odp);
+ }
+ }
+
+ return 0;
+}
+
+// dialog process for the weather tab under user info
+// lParam = current contact
+INT_PTR CALLBACK DlgProcUIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WEATHERINFO w;
+ TCHAR str[MAX_TEXT_SIZE];
+
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(GetDlgItem(hwndDlg,IDC_MOREDETAIL), BUTTONSETASFLATBTN, TRUE, 0);
+ // save the contact handle for later use
+ hContact = (HANDLE)lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact);
+ // load weather info for the contact
+ w = LoadWeatherInfo((HANDLE)lParam);
+ SetDlgItemText(hwndDlg, IDC_INFO1, GetDisplay(&w, TranslateT("Current condition for %n"), str));
+
+ SendDlgItemMessage(hwndDlg, IDC_INFOICON, STM_SETICON,
+ (WPARAM)LoadSkinnedProtoIcon(WEATHERPROTONAME,
+ db_get_w(hContact, WEATHERPROTONAME, "StatusIcon",0)), 0);
+
+ { // bold and enlarge the current condition
+ LOGFONT lf;
+ HFONT hNormalFont = (HFONT)SendDlgItemMessage(hwndDlg,IDC_INFO2,WM_GETFONT,0,0);
+ GetObject(hNormalFont,sizeof(lf),&lf);
+ lf.lfWeight = FW_BOLD;
+ lf.lfWidth = 7;
+ lf.lfHeight = 15;
+ SendDlgItemMessage(hwndDlg, IDC_INFO2, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), 0);
+ }
+ // set the text for displaying other current weather conditions data
+ GetDisplay(&w, _T("%c %t"), str);
+ SetDlgItemText(hwndDlg, IDC_INFO2, str);
+ SetDlgItemText(hwndDlg, IDC_INFO3, w.feel);
+ SetDlgItemText(hwndDlg, IDC_INFO4, w.pressure);
+ GetDisplay(&w, _T("%i %w"), str);
+ SetDlgItemText(hwndDlg, IDC_INFO5, str);
+ SetDlgItemText(hwndDlg, IDC_INFO6, w.dewpoint);
+ SetDlgItemText(hwndDlg, IDC_INFO7, w.sunrise);
+ SetDlgItemText(hwndDlg, IDC_INFO8, w.sunset);
+ SetDlgItemText(hwndDlg, IDC_INFO9, w.high);
+ SetDlgItemText(hwndDlg, IDC_INFO10, w.low);
+ GetDisplay(&w, TranslateT("Last update on: %u"), str);
+ SetDlgItemText(hwndDlg, IDC_INFO11, str);
+ SetDlgItemText(hwndDlg, IDC_INFO12, w.humid);
+ SetDlgItemText(hwndDlg, IDC_INFO13, w.vis);
+ break;
+
+ case WM_DESTROY:
+ Skin_ReleaseIcon((HICON)SendDlgItemMessage(hwndDlg, IDC_INFOICON, STM_SETICON, 0, 0));
+ DeleteObject((HFONT)SendDlgItemMessage(hwndDlg, IDC_INFO2, WM_GETFONT, 0, 0));
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_MOREDETAIL:
+ {
+ HWND hMoreDataDlg = WindowList_Find(hDataWindowList, hContact);
+ if (hMoreDataDlg == NULL)
+ hMoreDataDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_BRIEF), NULL,
+ DlgProcMoreData, (LPARAM)hContact);
+ else
+ {
+ SetForegroundWindow(hMoreDataDlg);
+ SetFocus(hMoreDataDlg);
+ }
+ ShowWindow(GetDlgItem(hMoreDataDlg, IDC_MTEXT), 0);
+ ShowWindow(GetDlgItem(hMoreDataDlg, IDC_DATALIST), 1);
+ break;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+//============ BRIEF INFORMATION ============
+
+static int BriefDlgResizer(HWND hwnd, LPARAM lParam, UTILRESIZECONTROL *urc)
+{
+ switch(urc->wId)
+ {
+ case IDC_HEADERBAR:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH;
+
+ case IDC_MTEXT:
+ case IDC_DATALIST:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+
+ case IDC_MUPDATE:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+
+ case IDC_MTOGGLE:
+ case IDC_MWEBPAGE:
+ case IDCANCEL:
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+
+
+// dialog process for more data in the user info window
+// lParam = contact handle
+INT_PTR CALLBACK DlgProcMoreData(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static const unsigned tabstops = 48;
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // save the contact handle for later use
+ hContact = (HANDLE)lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact);
+
+ SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_AUTOURLDETECT, (WPARAM) TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETEVENTMASK, 0, ENM_LINK);
+ SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETMARGINS, EC_LEFTMARGIN, 5);
+ SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETTABSTOPS, 1, (LPARAM)&tabstops);
+
+ // get the list to display
+ {
+ LV_COLUMN lvc = { 0 };
+ HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST);
+ RECT aRect = { 0 };
+ GetClientRect(hList, &aRect);
+
+ // managing styles
+ lvc.mask = LVCF_WIDTH | LVCF_TEXT;
+ ListView_SetExtendedListViewStyleEx(hList,
+ LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP,
+ LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+
+ // inserting columns
+ lvc.cx = LIST_COLUMN;
+ lvc.pszText = TranslateT("Variable");
+ ListView_InsertColumn(hList, 0, &lvc);
+
+ lvc.cx = aRect.right - LIST_COLUMN - GetSystemMetrics(SM_CXVSCROLL) - 3;
+ lvc.pszText = TranslateT("Information");
+ ListView_InsertColumn(hList, 1, &lvc);
+
+ // inserting data
+ SendMessage(hwndDlg, WM_UPDATEDATA, 0, 0);
+ }
+ TranslateDialogDefault(hwndDlg);
+
+ // prevent dups of the window
+ WindowList_Add(hDataWindowList, hwndDlg, hContact);
+
+ // restore window position
+ Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, WEATHERPROTONAME, "BriefInfo_");
+ return TRUE;
+
+ case WM_UPDATEDATA:
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_DATALIST));
+ LoadBriefInfoText(hwndDlg, hContact);
+ DBDataManage(hContact, WDBM_DETAILDISPLAY, (WPARAM)hwndDlg, 0);
+
+ // set icons
+ {
+ WORD statusIcon = db_get_w(hContact, WEATHERPROTONAME, "StatusIcon", 0);
+
+ ReleaseIconEx((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedProtoIconBig(WEATHERPROTONAME, statusIcon)));
+ ReleaseIconEx((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedProtoIcon(WEATHERPROTONAME, statusIcon)));
+ }
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_HEADERBAR), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+ break;
+
+ case WM_SIZE:
+ {
+ RECT rc;
+ HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST);
+ GetWindowRect(hList, &rc);
+ ListView_SetColumnWidth(hList, 1, ListView_GetColumnWidth(hList, 1) +
+ (int)LOWORD(lParam) - (rc.right - rc.left));
+ }
+ {
+ UTILRESIZEDIALOG urd = {0};
+ urd.cbSize = sizeof(urd);
+ urd.hwndDlg = hwndDlg;
+ urd.hInstance = hInst;
+ urd.lpTemplate = MAKEINTRESOURCEA(IDD_BRIEF);
+ urd.pfnResizer = BriefDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd);
+ }
+ break;
+
+ case WM_GETMINMAXINFO:
+ {
+ LPMINMAXINFO mmi = (LPMINMAXINFO)lParam;
+
+ // The minimum width in points
+ mmi->ptMinTrackSize.x = 350;
+ // The minimum height in points
+ mmi->ptMinTrackSize.y = 300;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDCANCEL:
+ // close the info window
+ DestroyWindow(hwndDlg);
+ break;
+
+ case IDC_MUPDATE:
+ {
+ LV_ITEM lvi = {0};
+ HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST);
+
+ // update current data
+ // set the text to "updating"
+ SetDlgItemText(hwndDlg, IDC_MTEXT, TranslateT("Retrieving new data, please wait..."));
+ ListView_DeleteAllItems(hList);
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.lParam = 1;
+ lvi.pszText = _T("");
+ lvi.iItem = ListView_InsertItem(hList, &lvi);
+ lvi.pszText = TranslateT("Retrieving new data, please wait...");
+ ListView_SetItemText(hList, lvi.iItem, 1, lvi.pszText);
+ UpdateSingleStation((WPARAM)hContact, 0);
+ break;
+ }
+
+ case IDC_MWEBPAGE:
+ LoadForecast((WPARAM)hContact, 0); // read complete forecast
+ break;
+
+ case IDC_MTOGGLE:
+ if (IsWindowVisible(GetDlgItem(hwndDlg,IDC_DATALIST)))
+ SetDlgItemText(hwndDlg, IDC_MTOGGLE, TranslateT("More Info"));
+ else
+ SetDlgItemText(hwndDlg, IDC_MTOGGLE, TranslateT("Brief Info"));
+ ShowWindow(GetDlgItem(hwndDlg,IDC_DATALIST), (int)!IsWindowVisible(
+ GetDlgItem(hwndDlg,IDC_DATALIST)));
+ ShowWindow(GetDlgItem(hwndDlg,IDC_MTEXT), (int)!IsWindowVisible(GetDlgItem(hwndDlg,IDC_MTEXT)));
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR pNmhdr = (LPNMHDR)lParam;
+ if (pNmhdr->idFrom == IDC_MTEXT && pNmhdr->code == EN_LINK)
+ {
+ ENLINK *enlink = (ENLINK *) lParam;
+ TEXTRANGE tr;
+ switch (enlink->msg)
+ {
+ case WM_LBUTTONUP:
+ tr.chrg = enlink->chrg;
+ tr.lpstrText = ( LPTSTR )mir_alloc( sizeof(TCHAR)*(tr.chrg.cpMax - tr.chrg.cpMin + 8));
+ SendMessage(pNmhdr->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+ CallService(MS_UTILS_OPENURL, OUF_NEWWINDOW | OUF_TCHAR, (LPARAM) tr.lpstrText);
+ mir_free(tr.lpstrText);
+ break;
+ }
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ ReleaseIconEx((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0));
+ ReleaseIconEx((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, 0));
+
+ Utils_SaveWindowPosition(hwndDlg, NULL, WEATHERPROTONAME, "BriefInfo_");
+ WindowList_Remove(hDataWindowList, hwndDlg);
+ break;
+ }
+
+ return FALSE;
+}
+
+// set the title of the dialog and on the which rectangle
+// also load brief info into message box
+void LoadBriefInfoText(HWND hwndDlg, HANDLE hContact)
+{
+ WEATHERINFO winfo;
+ TCHAR str[4096], str2[4096];
+
+ // load weather information from the contact into the WEATHERINFO struct
+ winfo = LoadWeatherInfo(hContact);
+ // check if data exist. If not, display error message box
+ if ( !(BOOL)db_get_b(hContact, WEATHERPROTONAME, "IsUpdated", FALSE))
+ _tcscpy(str, TranslateT("No information available.\r\nPlease update weather condition first."));
+ else
+ // set the display text and show the message box
+ GetDisplay(&winfo, opt.bText, str);
+ SetDlgItemText(hwndDlg, IDC_MTEXT, str);
+
+ GetDisplay(&winfo, opt.bTitle, str);
+ SetWindowText(hwndDlg, str);
+ GetDisplay(&winfo, _T("%c, %t"), str);
+ mir_sntprintf(str2, SIZEOF(str2), _T("%s\n%s"), winfo.city, str);
+ SetDlgItemText(hwndDlg, IDC_HEADERBAR, str2);
+}
+
+// show brief information dialog
+// wParam = current contact
+int BriefInfo(WPARAM wParam, LPARAM lParam)
+{
+ // make sure that the contact is actually a weather one
+ if (IsMyContact((HANDLE)wParam))
+ {
+ HWND hMoreDataDlg = WindowList_Find(hDataWindowList,(HANDLE)wParam);
+ if (hMoreDataDlg != NULL)
+ {
+ SetForegroundWindow(hMoreDataDlg);
+ SetFocus(hMoreDataDlg);
+ }
+ else
+ {
+ hMoreDataDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_BRIEF), NULL, DlgProcMoreData,
+ (LPARAM)wParam);
+ }
+ ShowWindow(GetDlgItem(hMoreDataDlg, IDC_DATALIST), 0);
+ ShowWindow(GetDlgItem(hMoreDataDlg, IDC_MTEXT), 1);
+ SetDlgItemText(hMoreDataDlg, IDC_MTOGGLE, TranslateT("More Info"));
+ return 1;
+ }
+ return 0;
+}
+
+INT_PTR BriefInfoSvc(WPARAM wParam, LPARAM lParam)
+{
+ return BriefInfo(wParam, lParam);
+}